int rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, VALUE *klassp) { rb_control_frame_t *cfp = th->cfp; rb_iseq_t *iseq = cfp->iseq; if (!iseq) { if (idp) *idp = cfp->me->def->original_id; if (klassp) *klassp = cfp->me->klass; return 1; } while (iseq) { if (RUBY_VM_IFUNC_P(iseq)) { if (idp) CONST_ID(*idp, "<ifunc>"); if (klassp) *klassp = 0; return 1; } if (iseq->defined_method_id) { if (idp) *idp = iseq->defined_method_id; if (klassp) *klassp = iseq->klass; return 1; } if (iseq->local_iseq == iseq) { break; } iseq = iseq->parent_iseq; } return 0; }
static void vm_caller_setup_arg_block(const rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, rb_iseq_t *blockiseq, const int is_super) { if (ci->flag & VM_CALL_ARGS_BLOCKARG) { rb_proc_t *po; VALUE proc; proc = *(--reg_cfp->sp); if (NIL_P(proc)) { calling->blockptr = NULL; } else if (SYMBOL_P(proc) && rb_method_basic_definition_p(rb_cSymbol, idTo_proc)) { calling->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp); calling->blockptr->iseq = (rb_iseq_t *)proc; calling->blockptr->proc = proc; } else if (RUBY_VM_IFUNC_P(proc)) { calling->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp); calling->blockptr->iseq = (rb_iseq_t *)proc; calling->blockptr->proc = proc; } else { if (!rb_obj_is_proc(proc)) { VALUE b; b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); if (NIL_P(b) || !rb_obj_is_proc(b)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)", rb_obj_classname(proc)); } proc = b; } GetProcPtr(proc, po); calling->blockptr = &po->block; RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp)->proc = proc; } } else if (blockiseq != 0) { /* likely */ rb_block_t *blockptr = calling->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp); blockptr->iseq = blockiseq; blockptr->proc = 0; } else { if (is_super) { calling->blockptr = GET_BLOCK_PTR(); } else { calling->blockptr = NULL; } } }
static void proc_mark(void *ptr) { rb_proc_t *proc; MARK_REPORT_ENTER("proc"); if (ptr) { proc = ptr; MARK_UNLESS_NULL(proc->envval); MARK_UNLESS_NULL(proc->blockprocval); MARK_UNLESS_NULL((VALUE)proc->special_cref_stack); if (proc->block.iseq && RUBY_VM_IFUNC_P(proc->block.iseq)) { MARK_UNLESS_NULL((VALUE)(proc->block.iseq)); } } MARK_REPORT_LEAVE("proc"); }
static void proc_mark(void *ptr) { rb_proc_t *proc; RUBY_MARK_ENTER("proc"); if (ptr) { proc = ptr; RUBY_MARK_UNLESS_NULL(proc->envval); RUBY_MARK_UNLESS_NULL(proc->blockprocval); RUBY_MARK_UNLESS_NULL(proc->block.proc); RUBY_MARK_UNLESS_NULL(proc->block.self); if (proc->block.iseq && RUBY_VM_IFUNC_P(proc->block.iseq)) { RUBY_MARK_UNLESS_NULL((VALUE)(proc->block.iseq)); } } RUBY_MARK_LEAVE("proc"); }
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"); }
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++; } }