|
@@ -413,6 +413,13 @@ document rp_id |
|
|
Print an ID. |
|
|
end |
|
|
|
|
|
define output_string |
|
|
set $flags = ((struct RBasic*)($arg0))->flags |
|
|
printf "%s", (char *)(($flags & RUBY_FL_USER1) ? \ |
|
|
((struct RString*)($arg0))->as.heap.ptr : \ |
|
|
((struct RString*)($arg0))->as.ary) |
|
|
end |
|
|
|
|
|
define rp_string |
|
|
set $flags = ((struct RBasic*)($arg0))->flags |
|
|
set print address off |
|
@@ -936,11 +943,226 @@ document rb_ps_vm |
|
|
Dump all threads in a (rb_vm_t*) and their callstacks |
|
|
end |
|
|
|
|
|
define print_lineno |
|
|
set $cfp = $arg0 |
|
|
set $iseq = $cfp->iseq |
|
|
set $pos = $cfp->pc - $iseq->body->iseq_encoded |
|
|
if $pos != 0 |
|
|
set $pos = $pos - 1 |
|
|
end |
|
|
|
|
|
set $i = 0 |
|
|
set $size = $iseq->body->line_info_size |
|
|
set $table = $iseq->body->line_info_table |
|
|
#printf "size: %d\n", $size |
|
|
if $size == 0 |
|
|
else |
|
|
set $i = 1 |
|
|
while $i < $size |
|
|
#printf "table[%d]: position: %d, line: %d, pos: %d\n", $i, $table[$i].position, $table[$i].line_no, $pos |
|
|
if $table[$i].position > $pos |
|
|
loop_break |
|
|
end |
|
|
set $i = $i + 1 |
|
|
if $table[$i].position == $pos |
|
|
loop_break |
|
|
end |
|
|
end |
|
|
printf "%d", $table[$i-1].line_no |
|
|
end |
|
|
end |
|
|
|
|
|
define check_method_entry |
|
|
# get $immeo and $can_be_svar and return $me |
|
|
set $imemo = (struct RBasic *)$arg0 |
|
|
set $can_be_svar = $arg1 |
|
|
if $imemo != Qfalse |
|
|
set $type = ($imemo->flags >> 12) & 0x07 |
|
|
if $type == imemo_ment |
|
|
set $me = (rb_callable_method_entry_t *)$imemo |
|
|
else |
|
|
if $type == imemo_svar |
|
|
set $imemo == ((struct vm_svar *)$imemo)->cref_or_me |
|
|
check_method_entry $imemo 0 |
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
define output_id |
|
|
set $id = $arg0 |
|
|
# rb_id_to_serial |
|
|
if $id > tLAST_OP_ID |
|
|
set $serial = (rb_id_serial_t)($id >> ID_SCOPE_SHIFT) |
|
|
else |
|
|
set $serial = (rb_id_serial_t)$id |
|
|
end |
|
|
if $serial && $serial <= global_symbols.last_id |
|
|
set $idx = $serial / ID_ENTRY_UNIT |
|
|
set $ids = (struct RArray *)global_symbols.ids |
|
|
set $flags = $ids->basic.flags |
|
|
if ($flags & RUBY_FL_USER1) |
|
|
set $idsptr = $ids->as.ary |
|
|
set $idslen = (($flags & (RUBY_FL_USER3|RUBY_FL_USER4)) >> (RUBY_FL_USHIFT+3)) |
|
|
else |
|
|
set $idsptr = $ids->as.heap.ptr |
|
|
set $idslen = $ids->as.heap.len |
|
|
end |
|
|
if $idx < $idslen |
|
|
set $t = 0 |
|
|
set $ary = (struct RArray *)$idsptr[$idx] |
|
|
if $ary != Qnil |
|
|
set $flags = $ary->basic.flags |
|
|
if ($flags & RUBY_FL_USER1) |
|
|
set $aryptr = $ary->as.ary |
|
|
set $arylen = (($flags & (RUBY_FL_USER3|RUBY_FL_USER4)) >> (RUBY_FL_USHIFT+3)) |
|
|
else |
|
|
set $aryptr = $ary->as.heap.ptr |
|
|
set $arylen = $ary->as.heap.len |
|
|
end |
|
|
set $result = $aryptr[($serial % ID_ENTRY_UNIT) * ID_ENTRY_SIZE + $t] |
|
|
output_string $result |
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
define rb_ps_thread |
|
|
set $ps_thread = (struct RTypedData*)$arg0 |
|
|
set $ps_thread_th = (rb_thread_t*)$ps_thread->data |
|
|
printf "* #<Thread:%p rb_thread_t:%p native_thread:%p>\n", \ |
|
|
$ps_thread, $ps_thread_th, $ps_thread_th->thread_id |
|
|
set $cfp = $ps_thread_th->cfp |
|
|
set $cfpend = (rb_control_frame_t *)($ps_thread_th->stack + $ps_thread_th->stack_size)-1 |
|
|
while $cfp < $cfpend |
|
|
if $cfp->iseq |
|
|
if $cfp->pc |
|
|
set $location = $cfp->iseq->body->location |
|
|
output_string $location.path |
|
|
printf ":" |
|
|
print_lineno $cfp |
|
|
printf ":in `" |
|
|
output_string $location.label |
|
|
printf "'\n" |
|
|
else |
|
|
printf "???.rb:???:in `???'\n" |
|
|
end |
|
|
else |
|
|
# if ($cfp->flag & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_CFUNC |
|
|
if ($cfp->flag & 255) == 0x61 |
|
|
#define VM_ENVVAL_BLOCK_PTR_FLAG 0x02 |
|
|
#define VM_EP_PREV_EP(ep) ((VALUE *)GC_GUARDED_PTR_REF((ep)[0])) |
|
|
set $ep = $cfp->ep |
|
|
set $me = NULL |
|
|
while ($ep[0] & 0x02) != 0 |
|
|
check_method_entry $ep[-1] 0 |
|
|
if $me != NULL |
|
|
loop_break |
|
|
end |
|
|
set $ep = $ep[0] |
|
|
end |
|
|
if $me == NULL |
|
|
check_method_entry $ep[-1] 1 |
|
|
end |
|
|
set print symbol-filename on |
|
|
output/a $me->def->body.cfunc.func |
|
|
set print symbol-filename off |
|
|
set $mid = $me->def->original_id |
|
|
printf ":in `" |
|
|
output_id $mid |
|
|
printf "'\n" |
|
|
else |
|
|
printf "unknown_frame:???:in `???'\n" |
|
|
end |
|
|
end |
|
|
set $cfp = $cfp + 1 |
|
|
end |
|
|
end |
|
|
|
|
|
define rb_count_objects |
|
|
set $objspace = ruby_current_vm->objspace |
|
|
set $counts_00 = 0 |
|
|
set $counts_01 = 0 |
|
|
set $counts_02 = 0 |
|
|
set $counts_03 = 0 |
|
|
set $counts_04 = 0 |
|
|
set $counts_05 = 0 |
|
|
set $counts_06 = 0 |
|
|
set $counts_07 = 0 |
|
|
set $counts_08 = 0 |
|
|
set $counts_09 = 0 |
|
|
set $counts_0a = 0 |
|
|
set $counts_0b = 0 |
|
|
set $counts_0c = 0 |
|
|
set $counts_0d = 0 |
|
|
set $counts_0e = 0 |
|
|
set $counts_0f = 0 |
|
|
set $counts_10 = 0 |
|
|
set $counts_11 = 0 |
|
|
set $counts_12 = 0 |
|
|
set $counts_13 = 0 |
|
|
set $counts_14 = 0 |
|
|
set $counts_15 = 0 |
|
|
set $counts_16 = 0 |
|
|
set $counts_17 = 0 |
|
|
set $counts_18 = 0 |
|
|
set $counts_19 = 0 |
|
|
set $counts_1a = 0 |
|
|
set $counts_1b = 0 |
|
|
set $counts_1c = 0 |
|
|
set $counts_1d = 0 |
|
|
set $counts_1e = 0 |
|
|
set $counts_1f = 0 |
|
|
set $total = 0 |
|
|
set $i = 0 |
|
|
while $i < $objspace->heap_pages.allocated_pages |
|
|
printf "\rcounting... %d/%d", $i, $objspace->heap_pages.allocated_pages |
|
|
set $page = $objspace->heap_pages.sorted[$i] |
|
|
set $p = $page->start |
|
|
set $pend = $p + $page->total_slots |
|
|
while $p < $pend |
|
|
set $flags = $p->as.basic.flags & 0x1f |
|
|
eval "set $counts_%02x = $counts_%02x + 1", $flags, $flags |
|
|
set $p = $p + 1 |
|
|
end |
|
|
set $total = $total + $page->total_slots |
|
|
set $i = $i + 1 |
|
|
end |
|
|
printf "\rTOTAL: %d, FREE: %d\n", $total, $counts_00 |
|
|
printf "T_OBJECT: %d\n", $counts_01 |
|
|
printf "T_CLASS: %d\n", $counts_02 |
|
|
printf "T_MODULE: %d\n", $counts_03 |
|
|
printf "T_FLOAT: %d\n", $counts_04 |
|
|
printf "T_STRING: %d\n", $counts_05 |
|
|
printf "T_REGEXP: %d\n", $counts_06 |
|
|
printf "T_ARRAY: %d\n", $counts_07 |
|
|
printf "T_HASH: %d\n", $counts_08 |
|
|
printf "T_STRUCT: %d\n", $counts_09 |
|
|
printf "T_BIGNUM: %d\n", $counts_0a |
|
|
printf "T_FILE: %d\n", $counts_0b |
|
|
printf "T_DATA: %d\n", $counts_0c |
|
|
printf "T_MATCH: %d\n", $counts_0d |
|
|
printf "T_COMPLEX: %d\n", $counts_0e |
|
|
printf "T_RATIONAL: %d\n", $counts_0f |
|
|
#printf "UNKNOWN_10: %d\n", $counts_10 |
|
|
printf "T_NIL: %d\n", $counts_11 |
|
|
printf "T_TRUE: %d\n", $counts_12 |
|
|
printf "T_FALSE: %d\n", $counts_13 |
|
|
printf "T_SYMBOL: %d\n", $counts_14 |
|
|
printf "T_FIXNUM: %d\n", $counts_15 |
|
|
printf "T_UNDEF: %d\n", $counts_16 |
|
|
#printf "UNKNOWN_17: %d\n", $counts_17 |
|
|
#printf "UNKNOWN_18: %d\n", $counts_18 |
|
|
#printf "UNKNOWN_19: %d\n", $counts_19 |
|
|
printf "T_IMEMO: %d\n", $counts_1a |
|
|
printf "T_NODE: %d\n", $counts_1b |
|
|
printf "T_ICLASS: %d\n", $counts_1c |
|
|
printf "T_ZOMBIE: %d\n", $counts_1d |
|
|
#printf "UNKNOWN_1E: %d\n", $counts_1e |
|
|
printf "T_MASK: %d\n", $counts_1f |
|
|
end |
|
|
document rb_count_objects |
|
|
Counts all objects grouped by type. |
|
|
end |
|
|
|
|
|
# Details: https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/MachineInstructionsTraceWithGDB |
|
|