void rb_dump_stack() { rb_thread_t *th = GET_THREAD(); rb_control_frame_t *cfp = th->cfp; rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(th); ID func; printf("\n\n*********************\n"); while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) { printf("cfp (%p):\n", cfp); printf(" type: 0x%x\n", VM_FRAME_TYPE(cfp)); printf(" pc: %p\n", cfp->pc); printf(" iseq: %p\n", cfp->iseq); if (cfp->iseq) { printf(" type: %d\n", FIX2INT(cfp->iseq->type)); printf(" self: %p\n", cfp->iseq->self); printf(" klass: %p (%s)\n", cfp->iseq->klass, cfp->iseq->klass ? rb_class2name(cfp->iseq->klass) : ""); printf(" method: %p (%s)\n", cfp->iseq->defined_method_id, cfp->iseq->defined_method_id ? rb_id2name(cfp->iseq->defined_method_id) : ""); } printf(" self: %p\n", cfp->self); printf(" klass: %p (%s)\n", cfp->method_class, cfp->method_class ? rb_class2name(cfp->method_class) : ""); printf(" method: %p (%s)\n", cfp->method_id, cfp->method_id ? rb_id2name(cfp->method_id) : ""); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); printf("\n"); } printf("*********************\n\n"); }
int rb_stack_trace(void** result, int max_depth) { rb_thread_t *th = GET_THREAD(); rb_control_frame_t *cfp = th->cfp; rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(th); VALUE klass, self; ID method; int depth = 0; if (max_depth == 0) return 0; if (rb_during_gc()) { result[0] = rb_gc; return 1; } while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp) && depth+3 <= max_depth) { rb_iseq_t *iseq = cfp->iseq; if (iseq && iseq->type == ISEQ_TYPE_METHOD) { self = 0; // maybe use cfp->self here, but iseq->self is a ISeq ruby obj klass = iseq->klass; method = iseq->defined_method_id; SAVE_FRAME(); } if (depth+3 > max_depth) break; switch (VM_FRAME_TYPE(cfp)) { case VM_FRAME_MAGIC_METHOD: case VM_FRAME_MAGIC_CFUNC: self = cfp->self; #ifdef HAVE_METHOD_H if (!cfp->me) break; klass = cfp->me->klass; method = cfp->me->called_id; #else klass = cfp->method_class; method = cfp->method_id; #endif SAVE_FRAME(); break; } cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); } assert(depth <= max_depth); return depth; }
void debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp) { rb_iseq_t *iseq = cfp->iseq; if (iseq != 0 && VM_FRAME_TYPE(cfp) != FRAME_MAGIC_FINISH) { VALUE *seq = iseq->iseq; int pc = cfp->pc - iseq->iseq_encoded; printf("%3td ", VM_CFP_CNT(th, cfp)); ruby_iseq_disasm_insn(0, seq, pc, iseq, 0); } #if VMDEBUG > 3 fprintf(stderr, " (1)"); debug_print_register(th); #endif }
VALUE rb_vm_make_env_object(rb_thread_t * th, rb_control_frame_t *cfp) { VALUE envval; if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_FINISH) { /* for method_missing */ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); } envval = vm_make_env_each(th, cfp, cfp->dfp, cfp->lfp); if (PROCDEBUG) { check_env_value(envval); } return envval; }
static const char * vm_frametype_name(const rb_control_frame_t *cfp) { switch (VM_FRAME_TYPE(cfp)) { case VM_FRAME_MAGIC_METHOD: return "method"; case VM_FRAME_MAGIC_BLOCK: return "block"; case VM_FRAME_MAGIC_CLASS: return "class"; case VM_FRAME_MAGIC_TOP: return "top"; case VM_FRAME_MAGIC_FINISH: return "finish"; case VM_FRAME_MAGIC_CFUNC: return "cfunc"; case VM_FRAME_MAGIC_PROC: return "proc"; case VM_FRAME_MAGIC_IFUNC: return "ifunc"; case VM_FRAME_MAGIC_EVAL: return "eval"; case VM_FRAME_MAGIC_LAMBDA: return "lambda"; default: rb_bug("unknown frame"); } }
void rb_vmdebug_debug_print_pre(rb_thread_t *th, rb_control_frame_t *cfp) { rb_iseq_t *iseq = cfp->iseq; if (iseq != 0 && VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_FINISH) { VALUE *seq = iseq->iseq; ptrdiff_t pc = cfp->pc - iseq->iseq_encoded; printf("%3"PRIdPTRDIFF" ", VM_CFP_CNT(th, cfp)); if (pc >= 0) { rb_iseq_disasm_insn(0, seq, (size_t)pc, iseq, 0); } } #if VMDEBUG > 3 fprintf(stderr, " (1)"); rb_vmdebug_debug_print_register(th); #endif }
static VALUE vm_exec_core(rb_thread_t *th, VALUE initial) { register rb_control_frame_t *reg_cfp = th->cfp; VALUE ret; while (*GET_PC()) { reg_cfp = ((rb_insn_func_t) (*GET_PC()))(th, reg_cfp); if (reg_cfp == 0) { VALUE err = th->errinfo; th->errinfo = Qnil; return err; } } if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_FINISH) { rb_bug("cfp consistency error"); } ret = *(th->cfp->sp-1); /* pop */ th->cfp++; /* pop cf */ return ret; }
static void vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp) { int i; VALUE rstr; VALUE *sp = cfp->sp; VALUE *lfp = cfp->lfp; VALUE *dfp = cfp->dfp; int argc = 0, local_size = 0; const char *name; rb_iseq_t *iseq = cfp->iseq; if (iseq == 0) { if (RUBYVM_CFUNC_FRAME_P(cfp)) { name = rb_id2name(cfp->me->original_id); } else { name = "?"; } } else if (RUBY_VM_IFUNC_P(iseq)) { name = "<ifunc>"; } else { argc = iseq->argc; local_size = iseq->local_size; name = RSTRING_PTR(iseq->name); } /* stack trace header */ if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CLASS || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_PROC || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL) { VALUE *ptr = dfp - local_size; vm_stack_dump_each(th, cfp + 1); control_frame_dump(th, cfp); if (lfp != dfp) { local_size++; } for (i = 0; i < argc; i++) { rstr = rb_inspect(*ptr); fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr), (void *)ptr++); } for (; i < local_size - 1; i++) { rstr = rb_inspect(*ptr); fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr), (void *)ptr++); } ptr = cfp->bp; for (; ptr < sp; ptr++, i++) { if (*ptr == Qundef) { rstr = rb_str_new2("undef"); } else { rstr = rb_inspect(*ptr); } fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr), (ptr - th->stack)); } } else if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_FINISH) { if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 2)) { vm_stack_dump_each(th, cfp + 1); } else { /* SDR(); */ } } else { rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp)); } }
static void control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp) { ptrdiff_t pc = -1, bp = -1; ptrdiff_t lfp = cfp->lfp - th->stack; ptrdiff_t dfp = cfp->dfp - th->stack; char lfp_in_heap = ' ', dfp_in_heap = ' '; char posbuf[MAX_POSBUF+1]; int line = 0; int nopos = 0; const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-"; VALUE tmp; if (cfp->block_iseq != 0 && BUILTIN_TYPE(cfp->block_iseq) != T_NODE) { biseq_name = ""; /* RSTRING(cfp->block_iseq->name)->ptr; */ } if (lfp < 0 || (size_t)lfp > th->stack_size) { lfp = (ptrdiff_t)cfp->lfp; lfp_in_heap = 'p'; } if (dfp < 0 || (size_t)dfp > th->stack_size) { dfp = (ptrdiff_t)cfp->dfp; dfp_in_heap = 'p'; } if (cfp->bp) { bp = cfp->bp - th->stack; } switch (VM_FRAME_TYPE(cfp)) { case VM_FRAME_MAGIC_TOP: magic = "TOP"; break; case VM_FRAME_MAGIC_METHOD: magic = "METHOD"; break; case VM_FRAME_MAGIC_CLASS: magic = "CLASS"; break; case VM_FRAME_MAGIC_BLOCK: magic = "BLOCK"; break; case VM_FRAME_MAGIC_FINISH: magic = "FINISH"; nopos = 1; break; case VM_FRAME_MAGIC_CFUNC: magic = "CFUNC"; break; case VM_FRAME_MAGIC_PROC: magic = "PROC"; break; case VM_FRAME_MAGIC_LAMBDA: magic = "LAMBDA"; break; case VM_FRAME_MAGIC_IFUNC: magic = "IFUNC"; break; case VM_FRAME_MAGIC_EVAL: magic = "EVAL"; break; case 0: magic = "------"; break; default: magic = "(none)"; break; } if (0) { tmp = rb_inspect(cfp->self); selfstr = StringValueCStr(tmp); } else { selfstr = ""; } if (nopos) { /* no name */ } else if (cfp->iseq != 0) { if (RUBY_VM_IFUNC_P(cfp->iseq)) { iseq_name = "<ifunc>"; } else { pc = cfp->pc - cfp->iseq->iseq_encoded; iseq_name = RSTRING_PTR(cfp->iseq->name); line = rb_vm_get_sourceline(cfp); if (line) { snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(cfp->iseq->filename), line); } } } else if (cfp->me) { iseq_name = rb_id2name(cfp->me->def->original_id); snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name); line = -1; } fprintf(stderr, "c:%04"PRIdPTRDIFF" ", ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp)); if (pc == -1) { fprintf(stderr, "p:---- "); } else { fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc); } fprintf(stderr, "s:%04"PRIdPTRDIFF" b:%04"PRIdPTRDIFF" ", (cfp->sp - th->stack), bp); fprintf(stderr, lfp_in_heap == ' ' ? "l:%06"PRIdPTRDIFF" " : "l:%06"PRIxPTRDIFF" ", lfp % 10000); fprintf(stderr, dfp_in_heap == ' ' ? "d:%06"PRIdPTRDIFF" " : "d:%06"PRIxPTRDIFF" ", dfp % 10000); fprintf(stderr, "%-6s", magic); if (line && !nopos) { fprintf(stderr, " %s", posbuf); } if (0) { fprintf(stderr, " \t"); fprintf(stderr, "iseq: %-24s ", iseq_name); fprintf(stderr, "self: %-24s ", selfstr); fprintf(stderr, "%-1s ", biseq_name); } fprintf(stderr, "\n"); }
static void control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp) { ptrdiff_t pc = -1; ptrdiff_t ep = cfp->ep - th->stack; char ep_in_heap = ' '; char posbuf[MAX_POSBUF+1]; int line = 0; const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-"; VALUE tmp; const rb_callable_method_entry_t *me; if (ep < 0 || (size_t)ep > th->stack_size) { ep = (ptrdiff_t)cfp->ep; ep_in_heap = 'p'; } switch (VM_FRAME_TYPE(cfp)) { case VM_FRAME_MAGIC_TOP: magic = "TOP"; break; case VM_FRAME_MAGIC_METHOD: magic = "METHOD"; break; case VM_FRAME_MAGIC_CLASS: magic = "CLASS"; break; case VM_FRAME_MAGIC_BLOCK: magic = "BLOCK"; break; case VM_FRAME_MAGIC_CFUNC: magic = "CFUNC"; break; case VM_FRAME_MAGIC_PROC: magic = "PROC"; break; case VM_FRAME_MAGIC_LAMBDA: magic = "LAMBDA"; break; case VM_FRAME_MAGIC_IFUNC: magic = "IFUNC"; break; case VM_FRAME_MAGIC_EVAL: magic = "EVAL"; break; case VM_FRAME_MAGIC_RESCUE: magic = "RESCUE"; break; case 0: magic = "------"; break; default: magic = "(none)"; break; } if (0) { tmp = rb_inspect(cfp->self); selfstr = StringValueCStr(tmp); } else { selfstr = ""; } if (cfp->iseq != 0) { #define RUBY_VM_IFUNC_P(ptr) (RB_TYPE_P((VALUE)(ptr), T_IMEMO) && imemo_type((VALUE)ptr) == imemo_ifunc) if (RUBY_VM_IFUNC_P(cfp->iseq)) { iseq_name = "<ifunc>"; } else if (SYMBOL_P(cfp->iseq)) { tmp = rb_sym2str((VALUE)cfp->iseq); iseq_name = RSTRING_PTR(tmp); snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name); line = -1; } else { pc = cfp->pc - cfp->iseq->body->iseq_encoded; iseq_name = RSTRING_PTR(cfp->iseq->body->location.label); line = rb_vm_get_sourceline(cfp); if (line) { snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(cfp->iseq->body->location.path), line); } } } else if ((me = rb_vm_frame_method_entry(cfp)) != NULL) { iseq_name = rb_id2name(me->def->original_id); snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name); line = -1; } fprintf(stderr, "c:%04"PRIdPTRDIFF" ", ((rb_control_frame_t *)(th->stack + th->stack_size) - cfp)); if (pc == -1) { fprintf(stderr, "p:---- "); } else { fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc); } fprintf(stderr, "s:%04"PRIdPTRDIFF" ", cfp->sp - th->stack); fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000); fprintf(stderr, "%-6s", magic); if (line) { fprintf(stderr, " %s", posbuf); } if (VM_FRAME_FINISHED_P(cfp)) { fprintf(stderr, " [FINISH]"); } if (0) { fprintf(stderr, " \t"); fprintf(stderr, "iseq: %-24s ", iseq_name); fprintf(stderr, "self: %-24s ", selfstr); fprintf(stderr, "%-1s ", biseq_name); } fprintf(stderr, "\n"); }
static void vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp) { int i, argc = 0, local_size = 0; VALUE rstr; VALUE *sp = cfp->sp; VALUE *ep = cfp->ep; if (VM_FRAME_RUBYFRAME_P(cfp)) { rb_iseq_t *iseq = cfp->iseq; argc = iseq->body->param.lead_num; local_size = iseq->body->local_size; } /* stack trace header */ if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_METHOD|| VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_TOP || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_BLOCK || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CLASS || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_PROC || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA|| VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_IFUNC || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_EVAL || VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_RESCUE) { VALUE *ptr = ep - local_size; control_frame_dump(th, cfp); for (i = 0; i < argc; i++) { rstr = rb_inspect(*ptr); fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr), (void *)ptr++); } for (; i < local_size - 1; i++) { rstr = rb_inspect(*ptr); fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr), (void *)ptr++); } ptr = vm_base_ptr(cfp); for (; ptr < sp; ptr++, i++) { if (*ptr == Qundef) { rstr = rb_str_new2("undef"); } else { rstr = rb_inspect(*ptr); } fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr), (ptr - th->stack)); } } else if (VM_FRAME_FINISHED_P(cfp)) { if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 1)) { vm_stack_dump_each(th, cfp + 1); } else { /* SDR(); */ } } else { rb_bug("unsupport frame type: %08lx", VM_FRAME_TYPE(cfp)); } }
static VALUE vm_exec(rb_thread_t *th) { int state; VALUE result, err; VALUE initial = 0; VALUE *escape_dfp = NULL; TH_PUSH_TAG(th); _tag.retval = Qnil; if ((state = EXEC_TAG()) == 0) { vm_loop_start: result = vm_exec_core(th, initial); if ((state = th->state) != 0) { err = result; th->state = 0; goto exception_handler; } } else { int i; struct iseq_catch_table_entry *entry; unsigned long epc, cont_pc, cont_sp; VALUE catch_iseqval; rb_control_frame_t *cfp; VALUE type; err = th->errinfo; exception_handler: cont_pc = cont_sp = catch_iseqval = 0; while (th->cfp->pc == 0 || th->cfp->iseq == 0) { if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) { const rb_method_entry_t *me = th->cfp->me; EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass); } th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); } cfp = th->cfp; epc = cfp->pc - cfp->iseq->iseq_encoded; if (state == TAG_BREAK || state == TAG_RETURN) { escape_dfp = GET_THROWOBJ_CATCH_POINT(err); if (cfp->dfp == escape_dfp) { if (state == TAG_RETURN) { if ((cfp + 1)->pc != &finish_insn_seq[0]) { SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp + 1)->dfp); SET_THROWOBJ_STATE(err, state = TAG_BREAK); } else { for (i = 0; i < cfp->iseq->catch_table_size; i++) { entry = &cfp->iseq->catch_table[i]; if (entry->start < epc && entry->end >= epc) { if (entry->type == CATCH_TYPE_ENSURE) { catch_iseqval = entry->iseq; cont_pc = entry->cont; cont_sp = entry->sp; break; } } } if (!catch_iseqval) { result = GET_THROWOBJ_VAL(err); th->errinfo = Qnil; th->cfp += 2; goto finish_vme; } } /* through */ } else { /* TAG_BREAK */ #if OPT_STACK_CACHING initial = (GET_THROWOBJ_VAL(err)); #else *th->cfp->sp++ = (GET_THROWOBJ_VAL(err)); #endif th->errinfo = Qnil; goto vm_loop_start; } } } if (state == TAG_RAISE) { for (i = 0; i < cfp->iseq->catch_table_size; i++) { entry = &cfp->iseq->catch_table[i]; if (entry->start < epc && entry->end >= epc) { if (entry->type == CATCH_TYPE_RESCUE || entry->type == CATCH_TYPE_ENSURE) { catch_iseqval = entry->iseq; cont_pc = entry->cont; cont_sp = entry->sp; break; } } } } else if (state == TAG_RETRY) { for (i = 0; i < cfp->iseq->catch_table_size; i++) { entry = &cfp->iseq->catch_table[i]; if (entry->start < epc && entry->end >= epc) { if (entry->type == CATCH_TYPE_ENSURE) { catch_iseqval = entry->iseq; cont_pc = entry->cont; cont_sp = entry->sp; break; } else if (entry->type == CATCH_TYPE_RETRY) { VALUE *escape_dfp; escape_dfp = GET_THROWOBJ_CATCH_POINT(err); if (cfp->dfp == escape_dfp) { cfp->pc = cfp->iseq->iseq_encoded + entry->cont; th->errinfo = Qnil; goto vm_loop_start; } } } } } else if (state == TAG_BREAK && ((VALUE)escape_dfp & ~0x03) == 0) { type = CATCH_TYPE_BREAK; search_restart_point: for (i = 0; i < cfp->iseq->catch_table_size; i++) { entry = &cfp->iseq->catch_table[i]; if (entry->start < epc && entry->end >= epc) { if (entry->type == CATCH_TYPE_ENSURE) { catch_iseqval = entry->iseq; cont_pc = entry->cont; cont_sp = entry->sp; break; } else if (entry->type == type) { cfp->pc = cfp->iseq->iseq_encoded + entry->cont; cfp->sp = cfp->bp + entry->sp; if (state != TAG_REDO) { #if OPT_STACK_CACHING initial = (GET_THROWOBJ_VAL(err)); #else *th->cfp->sp++ = (GET_THROWOBJ_VAL(err)); #endif } th->errinfo = Qnil; goto vm_loop_start; } } } } else if (state == TAG_REDO) { type = CATCH_TYPE_REDO; goto search_restart_point; } else if (state == TAG_NEXT) { type = CATCH_TYPE_NEXT; goto search_restart_point; } else { for (i = 0; i < cfp->iseq->catch_table_size; i++) { entry = &cfp->iseq->catch_table[i]; if (entry->start < epc && entry->end >= epc) { if (entry->type == CATCH_TYPE_ENSURE) { catch_iseqval = entry->iseq; cont_pc = entry->cont; cont_sp = entry->sp; break; } } } } if (catch_iseqval != 0) { /* found catch table */ rb_iseq_t *catch_iseq; /* enter catch scope */ GetISeqPtr(catch_iseqval, catch_iseq); cfp->sp = cfp->bp + cont_sp; cfp->pc = cfp->iseq->iseq_encoded + cont_pc; /* push block frame */ cfp->sp[0] = err; vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK, cfp->self, (VALUE)cfp->dfp, catch_iseq->iseq_encoded, cfp->sp + 1 /* push value */, cfp->lfp, catch_iseq->local_size - 1); state = 0; th->state = 0; th->errinfo = Qnil; goto vm_loop_start; } else { /* skip frame */ switch (VM_FRAME_TYPE(th->cfp)) { case VM_FRAME_MAGIC_METHOD: EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0); break; case VM_FRAME_MAGIC_CLASS: EXEC_EVENT_HOOK(th, RUBY_EVENT_END, th->cfp->self, 0, 0); break; } th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_FINISH) { goto exception_handler; } else { vm_pop_frame(th); th->errinfo = err; TH_POP_TAG2(); JUMP_TAG(state); } } } finish_vme: TH_POP_TAG(); return result; }
void ruby_backtrace_each(sanspleur_backtrace_iter_func* iterator, void* arg) { rb_thread_t* ruby_current_thread = (rb_thread_t*)(DATA_PTR(rb_thread_current())); rb_control_frame_t *cfp = ruby_current_thread->cfp; const rb_control_frame_t *cfp_limit = (rb_control_frame_t*)(ruby_current_thread->stack + ruby_current_thread->stack_size); cfp_limit -= 2; while (cfp < cfp_limit) { const char* class_name = NULL; ID function_id = 0; VALUE klass = 0; const char* file_name = NULL; int line_number = -1; int no_pos = -1; rb_iseq_t *iseq = cfp->iseq; if (!iseq && cfp->me) { function_id = cfp->me->def->original_id; klass = cfp->me->klass; no_pos = 1; } while (iseq) { if (RUBY_VM_IFUNC_P(iseq)) { CONST_ID(function_id, "<ifunc>"); klass = 0; break; } klass = iseq->klass; if (iseq->defined_method_id) { function_id = iseq->defined_method_id; break; } if (iseq->local_iseq == iseq) { break; } iseq = iseq->parent_iseq; } if (iseq != 0 && cfp->pc != 0) { file_name = ISEQ_FILENAME(iseq); } const char* function_name = NULL; if (function_id) function_name = rb_id2name(function_id); if (cfp->self) { if (TYPE(cfp->self) == RUBY_T_CLASS || TYPE(cfp->self) == RUBY_T_ICLASS) { class_name = rb_class2name(cfp->self); } else if (TYPE(cfp->self) == RUBY_T_MODULE) { VALUE str = rb_obj_as_string(cfp->self); char* object_description = RSTRING_PTR(str); class_name = object_description; } } if (klass && !class_name) { class_name = rb_class2name(klass); } if (no_pos < 0) { line_number = CFP_LINENO(cfp); } ID class_id = 0; if (VM_FRAME_TYPE(cfp) != 0x51) { iterator(arg, file_name, line_number, function_name, function_id, class_name, class_id); } cfp++; } }