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; }
static void backtrace_each(rb_thread_t *th, void (*init)(void *arg, size_t size), void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp), void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid), void *arg) { rb_control_frame_t *last_cfp = th->cfp; rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(th); rb_control_frame_t *cfp; ptrdiff_t size, i; /* <- start_cfp (end control frame) * top frame (dummy) * top frame (dummy) * top frame <- start_cfp * top frame * ... * 2nd frame <- lev:0 * current frame <- th->cfp */ start_cfp = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */ if (start_cfp < last_cfp) { size = 0; } else { size = start_cfp - last_cfp + 1; } init(arg, size); /* SDR(); */ for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) { /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(th->stack + th->stack_size) - cfp); */ if (cfp->iseq) { if (cfp->pc) { iter_iseq(arg, cfp); } } else if (RUBYVM_CFUNC_FRAME_P(cfp)) { ID mid = cfp->me->def ? cfp->me->def->original_id : cfp->me->called_id; iter_cfunc(arg, cfp, mid); } } }
int rb_profile_frames(int start, int limit, VALUE *buff, int *lines) { int i; rb_thread_t *th = GET_THREAD(); rb_control_frame_t *cfp = th->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(th); for (i=0; i<limit && cfp != end_cfp;) { if (cfp->iseq && cfp->pc) { /* should be NORMAL_ISEQ */ if (start > 0) { start--; continue; } /* record frame info */ buff[i] = cfp->iseq->self; if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc); i++; } cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); } return i; }