Example #1
0
  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");
  }
Example #2
0
  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;
  }
Example #3
0
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
}
Example #4
0
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;
}
Example #5
0
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");
    }
}
Example #6
0
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;
}
Example #8
0
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));
    }
}
Example #9
0
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");
}
Example #10
0
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");
}
Example #11
0
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));
    }
}
Example #12
0
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++;
    }
}