12#include "eval_intern.h"
14#include "internal/class.h"
15#include "internal/error.h"
16#include "internal/vm.h"
22static VALUE rb_cBacktrace;
23static VALUE rb_cBacktraceLocation;
28 VALUE str = rb_id2str(
id);
29 if (!str)
return Qnil;
32#define rb_id2str(id) id2str(id)
34#define BACKTRACE_START 0
35#define ALL_BACKTRACE_LINES -1
38calc_pos(
const rb_iseq_t *iseq,
const VALUE *pc,
int *lineno,
int *node_id)
43 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_TOP) {
44 VM_ASSERT(! ISEQ_BODY(iseq)->local_table);
45 VM_ASSERT(! ISEQ_BODY(iseq)->local_table_size);
48 if (lineno) *lineno = ISEQ_BODY(iseq)->location.first_lineno;
49#ifdef USE_ISEQ_NODE_ID
50 if (node_id) *node_id = -1;
55 VM_ASSERT(ISEQ_BODY(iseq));
56 VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
57 VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
59 ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
61#if SIZEOF_PTRDIFF_T > SIZEOF_INT
62 VM_ASSERT(n <= (ptrdiff_t)UINT_MAX);
64 VM_ASSERT((
unsigned int)n <= ISEQ_BODY(iseq)->iseq_size);
71#if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
74 rb_print_backtrace(stderr);
78 if (lineno) *lineno = rb_iseq_line_no(iseq, pos);
79#ifdef USE_ISEQ_NODE_ID
80 if (node_id) *node_id = rb_iseq_node_id(iseq, pos);
87calc_lineno(
const rb_iseq_t *iseq,
const VALUE *pc)
90 if (calc_pos(iseq, pc, &lineno, NULL))
return lineno;
94#ifdef USE_ISEQ_NODE_ID
96calc_node_id(
const rb_iseq_t *iseq,
const VALUE *pc)
99 if (calc_pos(iseq, pc, NULL, &node_id))
return node_id;
105rb_vm_get_sourceline(
const rb_control_frame_t *cfp)
107 if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
108 const rb_iseq_t *iseq = cfp->iseq;
109 int line = calc_lineno(iseq, cfp->pc);
114 return ISEQ_BODY(iseq)->location.first_lineno;
124 LOCATION_TYPE_ISEQ = 1,
128 const rb_iseq_t *iseq;
131} rb_backtrace_location_t;
134 rb_backtrace_location_t *loc;
139location_mark(
void *ptr)
142 rb_gc_mark(vfi->btobj);
146location_mark_entry(rb_backtrace_location_t *fi)
149 case LOCATION_TYPE_ISEQ:
150 rb_gc_mark_movable((
VALUE)fi->iseq);
152 case LOCATION_TYPE_CFUNC:
154 rb_gc_mark_movable((
VALUE)fi->iseq);
169 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
173rb_frame_info_p(
VALUE obj)
178static inline rb_backtrace_location_t *
179location_ptr(
VALUE locobj)
187location_lineno(rb_backtrace_location_t *loc)
190 case LOCATION_TYPE_ISEQ:
191 return calc_lineno(loc->iseq, loc->pc);
192 case LOCATION_TYPE_CFUNC:
193 if (loc->iseq && loc->pc) {
194 return calc_lineno(loc->iseq, loc->pc);
198 rb_bug(
"location_lineno: unreachable");
212location_lineno_m(
VALUE self)
214 return INT2FIX(location_lineno(location_ptr(self)));
218location_label(rb_backtrace_location_t *loc)
221 case LOCATION_TYPE_ISEQ:
222 return ISEQ_BODY(loc->iseq)->location.label;
223 case LOCATION_TYPE_CFUNC:
224 return rb_id2str(loc->mid);
226 rb_bug(
"location_label: unreachable");
259location_label_m(
VALUE self)
261 return location_label(location_ptr(self));
265location_base_label(rb_backtrace_location_t *loc)
268 case LOCATION_TYPE_ISEQ:
269 return ISEQ_BODY(loc->iseq)->location.base_label;
270 case LOCATION_TYPE_CFUNC:
271 return rb_id2str(loc->mid);
273 rb_bug(
"location_base_label: unreachable");
284location_base_label_m(
VALUE self)
286 return location_base_label(location_ptr(self));
289static const rb_iseq_t *
290location_iseq(rb_backtrace_location_t *loc)
293 case LOCATION_TYPE_ISEQ:
295 case LOCATION_TYPE_CFUNC:
298 rb_bug(
"location_iseq: unreachable");
314location_path_m(
VALUE self)
316 const rb_iseq_t *iseq = location_iseq(location_ptr(self));
317 return iseq ? rb_iseq_path(iseq) :
Qnil;
320#ifdef USE_ISEQ_NODE_ID
322location_node_id(rb_backtrace_location_t *loc)
325 case LOCATION_TYPE_ISEQ:
326 return calc_node_id(loc->iseq, loc->pc);
327 case LOCATION_TYPE_CFUNC:
328 if (loc->iseq && loc->pc) {
329 return calc_node_id(loc->iseq, loc->pc);
333 rb_bug(
"location_node_id: unreachable");
340rb_get_node_id_from_frame_info(
VALUE obj)
342#ifdef USE_ISEQ_NODE_ID
343 rb_backtrace_location_t *loc = location_ptr(obj);
344 return location_node_id(loc);
351rb_get_iseq_from_frame_info(
VALUE obj)
353 rb_backtrace_location_t *loc = location_ptr(obj);
354 const rb_iseq_t *iseq = location_iseq(loc);
359location_realpath(rb_backtrace_location_t *loc)
362 case LOCATION_TYPE_ISEQ:
363 return rb_iseq_realpath(loc->iseq);
364 case LOCATION_TYPE_CFUNC:
366 return rb_iseq_realpath(loc->iseq);
370 rb_bug(
"location_realpath: unreachable");
382location_absolute_path_m(
VALUE self)
384 return location_realpath(location_ptr(self));
388location_format(
VALUE file,
int lineno,
VALUE name)
392 rb_str_catf(s,
":%d", lineno);
399 rb_str_catf(s,
"`%s'", RSTRING_PTR(name));
405location_to_str(rb_backtrace_location_t *loc)
411 case LOCATION_TYPE_ISEQ:
412 file = rb_iseq_path(loc->iseq);
413 name = ISEQ_BODY(loc->iseq)->location.label;
415 lineno = calc_lineno(loc->iseq, loc->pc);
417 case LOCATION_TYPE_CFUNC:
418 if (loc->iseq && loc->pc) {
419 file = rb_iseq_path(loc->iseq);
420 lineno = calc_lineno(loc->iseq, loc->pc);
423 file = GET_VM()->progname;
426 name = rb_id2str(loc->mid);
429 rb_bug(
"location_to_str: unreachable");
432 return location_format(file, lineno, name);
439location_to_str_m(
VALUE self)
441 return location_to_str(location_ptr(self));
449location_inspect_m(
VALUE self)
458 rb_backtrace_location_t backtrace[1];
462backtrace_mark(
void *ptr)
464 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
465 size_t i, s = bt->backtrace_size;
467 for (i=0; i<s; i++) {
468 location_mark_entry(&bt->backtrace[i]);
470 rb_gc_mark_movable(bt->strary);
471 rb_gc_mark_movable(bt->locary);
475location_update_entry(rb_backtrace_location_t *fi)
478 case LOCATION_TYPE_ISEQ:
479 fi->iseq = (rb_iseq_t*)rb_gc_location((
VALUE)fi->iseq);
481 case LOCATION_TYPE_CFUNC:
483 fi->iseq = (rb_iseq_t*)rb_gc_location((
VALUE)fi->iseq);
492backtrace_update(
void *ptr)
494 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
495 size_t i, s = bt->backtrace_size;
497 for (i=0; i<s; i++) {
498 location_update_entry(&bt->backtrace[i]);
500 bt->strary = rb_gc_location(bt->strary);
501 bt->locary = rb_gc_location(bt->locary);
512 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
516rb_backtrace_p(
VALUE obj)
522backtrace_alloc(
VALUE klass)
530backtrace_size(
const rb_execution_context_t *ec)
532 const rb_control_frame_t *last_cfp = ec->cfp;
533 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
535 if (start_cfp == NULL) {
540 RUBY_VM_NEXT_CONTROL_FRAME(
541 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp));
543 if (start_cfp < last_cfp) {
547 return start_cfp - last_cfp + 1;
551is_internal_location(
const rb_control_frame_t *cfp)
553 static const char prefix[] =
"<internal:";
554 const size_t prefix_len =
sizeof(prefix) - 1;
555 VALUE file = rb_iseq_path(cfp->iseq);
556 return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0;
560bt_update_cfunc_loc(
unsigned long cfunc_counter, rb_backtrace_location_t *cfunc_loc,
const rb_iseq_t *iseq,
const VALUE *pc)
562 for (; cfunc_counter > 0; cfunc_counter--, cfunc_loc--) {
563 cfunc_loc->iseq = iseq;
568static VALUE location_create(rb_backtrace_location_t *srcloc,
void *btobj);
571bt_yield_loc(rb_backtrace_location_t *loc,
long num_frames,
VALUE btobj)
573 for (; num_frames > 0; num_frames--, loc++) {
574 rb_yield(location_create(loc, (
void *)btobj));
579rb_ec_partial_backtrace_object(
const rb_execution_context_t *ec,
long start_frame,
long num_frames,
int* start_too_large,
bool skip_internal,
bool do_yield)
581 const rb_control_frame_t *cfp = ec->cfp;
582 const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
584 rb_backtrace_t *bt = NULL;
586 rb_backtrace_location_t *loc = NULL;
587 unsigned long cfunc_counter = 0;
590 if (end_cfp == NULL) {
594 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
606 size = end_cfp - cfp + 1;
610 else if (num_frames < 0 || num_frames > size) {
615 size_t memsize = offsetof(rb_backtrace_t, backtrace) + num_frames *
sizeof(rb_backtrace_location_t);
616 btobj = rb_data_typed_object_zalloc(rb_cBacktrace, memsize, &backtrace_data_type);
619 bt->backtrace_size = 0;
620 if (num_frames == 0) {
621 if (start_too_large) *start_too_large = 0;
625 for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
628 if (start_frame > 0) {
631 else if (!skip_internal || !is_internal_location(cfp)) {
632 const rb_iseq_t *iseq = cfp->iseq;
633 const VALUE *pc = cfp->pc;
634 loc = &bt->backtrace[bt->backtrace_size++];
635 loc->type = LOCATION_TYPE_ISEQ;
638 bt_update_cfunc_loc(cfunc_counter, loc-1, iseq, pc);
640 bt_yield_loc(loc - cfunc_counter, cfunc_counter+1, btobj);
647 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
648 if (start_frame > 0) {
652 loc = &bt->backtrace[bt->backtrace_size++];
653 loc->type = LOCATION_TYPE_CFUNC;
656 loc->mid = rb_vm_frame_method_entry(cfp)->def->original_id;
662 if (cfunc_counter > 0) {
663 for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
664 if (cfp->iseq && cfp->pc && (!skip_internal || !is_internal_location(cfp))) {
665 bt_update_cfunc_loc(cfunc_counter, loc, cfp->iseq, cfp->pc);
668 bt_yield_loc(loc - cfunc_counter, cfunc_counter, btobj);
675 if (start_too_large) *start_too_large = (start_frame > 0 ? -1 : 0);
680rb_ec_backtrace_object(
const rb_execution_context_t *ec)
682 return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL, FALSE, FALSE);
686backtrace_collect(rb_backtrace_t *bt,
VALUE (*func)(rb_backtrace_location_t *,
void *arg),
void *arg)
693 for (i=0; i<bt->backtrace_size; i++) {
694 rb_backtrace_location_t *loc = &bt->backtrace[i];
695 rb_ary_push(btary, func(loc, arg));
702location_to_str_dmyarg(rb_backtrace_location_t *loc,
void *dmy)
704 return location_to_str(loc);
708backtrace_to_str_ary(
VALUE self)
713 r = backtrace_collect(bt, location_to_str_dmyarg, 0);
719rb_backtrace_to_str_ary(
VALUE self)
725 RB_OBJ_WRITE(self, &bt->strary, backtrace_to_str_ary(self));
731rb_backtrace_use_iseq_first_lineno_for_last_location(
VALUE self)
734 rb_backtrace_location_t *loc;
737 VM_ASSERT(bt->backtrace_size > 0);
739 loc = &bt->backtrace[0];
741 VM_ASSERT(loc->type == LOCATION_TYPE_ISEQ);
747location_create(rb_backtrace_location_t *srcloc,
void *btobj)
760backtrace_to_location_ary(
VALUE self)
765 r = backtrace_collect(bt, location_create, (
void *)self);
771rb_backtrace_to_location_ary(
VALUE self)
777 RB_OBJ_WRITE(self, &bt->locary, backtrace_to_location_ary(self));
783backtrace_dump_data(
VALUE self)
785 VALUE str = rb_backtrace_to_str_ary(self);
849backtrace_limit(
VALUE self)
851 return LONG2NUM(rb_backtrace_length_limit);
855rb_ec_backtrace_str_ary(
const rb_execution_context_t *ec,
long lev,
long n)
857 return rb_backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, FALSE));
861rb_ec_backtrace_location_ary(
const rb_execution_context_t *ec,
long lev,
long n,
bool skip_internal)
863 return rb_backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal, FALSE));
869backtrace_each(
const rb_execution_context_t *ec,
870 void (*init)(
void *arg,
size_t size),
871 void (*iter_iseq)(
void *arg,
const rb_control_frame_t *cfp),
872 void (*iter_cfunc)(
void *arg,
const rb_control_frame_t *cfp,
ID mid),
875 const rb_control_frame_t *last_cfp = ec->cfp;
876 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
877 const rb_control_frame_t *cfp;
881 if (start_cfp == NULL) {
897 RUBY_VM_NEXT_CONTROL_FRAME(
898 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp));
900 if (start_cfp < last_cfp) {
904 size = start_cfp - last_cfp + 1;
910 for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
918 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
919 const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
920 ID mid = me->def->original_id;
922 iter_cfunc(arg, cfp, mid);
930 void (*func)(
void *data,
VALUE file,
int lineno,
VALUE name);
935oldbt_init(
void *ptr,
size_t dmy)
938 arg->filename = GET_VM()->progname;
943oldbt_iter_iseq(
void *ptr,
const rb_control_frame_t *cfp)
945 const rb_iseq_t *iseq = cfp->iseq;
946 const VALUE *pc = cfp->pc;
948 VALUE file = arg->filename = rb_iseq_path(iseq);
949 VALUE name = ISEQ_BODY(iseq)->location.label;
950 int lineno = arg->lineno = calc_lineno(iseq, pc);
952 (arg->func)(arg->data, file, lineno, name);
956oldbt_iter_cfunc(
void *ptr,
const rb_control_frame_t *cfp,
ID mid)
959 VALUE file = arg->filename;
960 VALUE name = rb_id2str(mid);
961 int lineno = arg->lineno;
963 (arg->func)(arg->data, file, lineno, name);
967oldbt_print(
void *data,
VALUE file,
int lineno,
VALUE name)
969 FILE *fp = (FILE *)data;
972 fprintf(fp,
"\tfrom %s:%d:in unknown method\n",
973 RSTRING_PTR(file), lineno);
976 fprintf(fp,
"\tfrom %s:%d:in `%s'\n",
977 RSTRING_PTR(file), lineno, RSTRING_PTR(name));
982vm_backtrace_print(FILE *fp)
986 arg.func = oldbt_print;
987 arg.data = (
void *)fp;
988 backtrace_each(GET_EC(),
1001oldbt_bugreport(
void *arg,
VALUE file,
int line,
VALUE method)
1005 const char *filename =
NIL_P(file) ?
"ruby" : RSTRING_PTR(file);
1007 fprintf(fp,
"-- Ruby level backtrace information "
1008 "----------------------------------------\n");
1011 if (
NIL_P(method)) {
1012 fprintf(fp,
"%s:%d:in unknown method\n", filename, line);
1015 fprintf(fp,
"%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
1020rb_backtrace_print_as_bugreport(FILE *fp)
1025 arg.func = oldbt_bugreport;
1028 backtrace_each(GET_EC(),
1038 vm_backtrace_print(stderr);
1047oldbt_print_to(
void *data,
VALUE file,
int lineno,
VALUE name)
1050 VALUE str = rb_sprintf(
"\tfrom %"PRIsVALUE
":%d:in ", file, lineno);
1056 rb_str_catf(str,
" `%"PRIsVALUE
"'\n", name);
1058 (*arg->iter)(arg->output, str);
1068 parg.output = output;
1069 arg.func = oldbt_print_to;
1071 backtrace_each(GET_EC(),
1079rb_make_backtrace(
void)
1081 return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START, ALL_BACKTRACE_LINES);
1085ec_backtrace_to_ary(
const rb_execution_context_t *ec,
int argc,
const VALUE *argv,
int lev_default,
int lev_plus,
int to_str)
1095 if (argc == 2 &&
NIL_P(vn)) argc--;
1099 lev = lev_default + lev_plus;
1100 n = ALL_BACKTRACE_LINES;
1104 long beg,
len, bt_size = backtrace_size(ec);
1109 rb_raise(rb_eArgError,
"negative level (%ld)", lev);
1112 n = ALL_BACKTRACE_LINES;
1117 lev = beg + lev_plus;
1127 rb_raise(rb_eArgError,
"negative level (%ld)", lev);
1130 rb_raise(rb_eArgError,
"negative size (%ld)", n);
1140 return rb_ary_new();
1143 btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE, FALSE);
1150 r = backtrace_to_str_ary(btval);
1153 r = backtrace_to_location_ary(btval);
1160thread_backtrace_to_ary(
int argc,
const VALUE *argv,
VALUE thval,
int to_str)
1162 rb_thread_t *target_th = rb_thread_ptr(thval);
1164 if (target_th->to_kill || target_th->status == THREAD_KILLED)
1167 return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1171rb_vm_thread_backtrace(
int argc,
const VALUE *argv,
VALUE thval)
1173 return thread_backtrace_to_ary(argc, argv, thval, 1);
1177rb_vm_thread_backtrace_locations(
int argc,
const VALUE *argv,
VALUE thval)
1179 return thread_backtrace_to_ary(argc, argv, thval, 0);
1185 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1191 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1235 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1261rb_f_caller_locations(
int argc,
VALUE *argv,
VALUE _)
1263 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1274each_caller_location(
VALUE unused)
1276 rb_ec_partial_backtrace_object(GET_EC(), 2, ALL_BACKTRACE_LINES, NULL, FALSE, TRUE);
1282Init_vm_backtrace(
void)
1347 rb_define_method(rb_cBacktraceLocation,
"base_label", location_base_label_m, 0);
1349 rb_define_method(rb_cBacktraceLocation,
"absolute_path", location_absolute_path_m, 0);
1361RUBY_SYMBOL_EXPORT_BEGIN
1363RUBY_SYMBOL_EXPORT_END
1366 rb_execution_context_t *ec;
1367 rb_control_frame_t *cfp;
1370 long backtrace_size;
1374 CALLER_BINDING_SELF,
1375 CALLER_BINDING_CLASS,
1376 CALLER_BINDING_BINDING,
1377 CALLER_BINDING_ISEQ,
1379 CALLER_BINDING_DEPTH,
1384 const rb_execution_context_t *ec;
1388collect_caller_bindings_init(
void *arg,
size_t size)
1394get_klass(
const rb_control_frame_t *cfp)
1397 if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
1399 return RBASIC(klass)->klass;
1411frame_depth(
const rb_execution_context_t *ec,
const rb_control_frame_t *cfp)
1413 VM_ASSERT(RUBY_VM_END_CONTROL_FRAME(ec) >= cfp);
1414 return (
int)(RUBY_VM_END_CONTROL_FRAME(ec) - cfp);
1418collect_caller_bindings_iseq(
void *arg,
const rb_control_frame_t *cfp)
1423 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1424 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1425 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp));
1426 rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? (
VALUE)cfp->iseq :
Qnil);
1427 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1428 rb_ary_store(frame, CALLER_BINDING_DEPTH,
INT2FIX(frame_depth(data->ec, cfp)));
1430 rb_ary_push(data->ary, frame);
1434collect_caller_bindings_cfunc(
void *arg,
const rb_control_frame_t *cfp,
ID mid)
1439 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1440 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1441 rb_ary_store(frame, CALLER_BINDING_BINDING,
Qnil);
1442 rb_ary_store(frame, CALLER_BINDING_ISEQ,
Qnil);
1443 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1444 rb_ary_store(frame, CALLER_BINDING_DEPTH,
INT2FIX(frame_depth(data->ec, cfp)));
1446 rb_ary_push(data->ary, frame);
1450collect_caller_bindings(
const rb_execution_context_t *ec)
1459 collect_caller_bindings_init,
1460 collect_caller_bindings_iseq,
1461 collect_caller_bindings_cfunc,
1464 result = rb_ary_reverse(data.ary);
1468 VALUE entry = rb_ary_entry(result, i);
1469 VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
1471 if (!
NIL_P(cfp_val)) {
1472 rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
1473 rb_ary_store(entry, CALLER_BINDING_BINDING, rb_vm_make_binding(ec, cfp));
1489 rb_execution_context_t *ec = GET_EC();
1490 enum ruby_tag_type state;
1491 volatile VALUE MAYBE_UNUSED(result);
1494 rb_vm_stack_to_heap(ec);
1496 dbg_context.ec = ec;
1497 dbg_context.cfp = dbg_context.ec->cfp;
1498 dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, FALSE);
1499 dbg_context.backtrace_size =
RARRAY_LEN(dbg_context.backtrace);
1500 dbg_context.contexts = collect_caller_bindings(ec);
1503 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1504 result = (*func)(&dbg_context, data);
1511 EC_JUMP_TAG(ec, state);
1520 if (index < 0 || index >= dc->backtrace_size) {
1521 rb_raise(rb_eArgError,
"no such frame");
1523 return rb_ary_entry(dc->contexts, index);
1529 VALUE frame = frame_get(dc, index);
1530 return rb_ary_entry(frame, CALLER_BINDING_SELF);
1536 VALUE frame = frame_get(dc, index);
1537 return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1543 VALUE frame = frame_get(dc, index);
1544 return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1550 VALUE frame = frame_get(dc, index);
1551 VALUE iseq = rb_ary_entry(frame, CALLER_BINDING_ISEQ);
1553 return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) :
Qnil;
1559 VALUE frame = frame_get(dc, index);
1560 return rb_ary_entry(frame, CALLER_BINDING_DEPTH);
1566 rb_execution_context_t *ec = GET_EC();
1567 return INT2FIX(frame_depth(ec, ec->cfp));
1573 return dc->backtrace;
1577thread_profile_frames(rb_execution_context_t *ec,
int start,
int limit,
VALUE *buff,
int *lines)
1580 const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
1581 const rb_control_frame_t *top = cfp;
1582 const rb_callable_method_entry_t *cme;
1594 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
1596 for (i=0; i<limit && cfp != end_cfp;) {
1597 if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->pc != 0) {
1604 cme = rb_vm_frame_method_entry(cfp);
1605 if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
1606 buff[i] = (
VALUE)cme;
1609 buff[i] = (
VALUE)cfp->iseq;
1617 if (cfp == top && cfp->jit_return) {
1621 lines[i] = calc_lineno(cfp->iseq, cfp->pc);
1628 cme = rb_vm_frame_method_entry(cfp);
1629 if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
1630 buff[i] = (
VALUE)cme;
1631 if (lines) lines[i] = 0;
1635 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
1644 rb_execution_context_t *ec = rb_current_execution_context(
false);
1652 return thread_profile_frames(ec, start, limit, buff, lines);
1658 rb_thread_t *th = rb_thread_ptr(thread);
1659 return thread_profile_frames(th->ec, start, limit, buff, lines);
1662static const rb_iseq_t *
1663frame2iseq(
VALUE frame)
1665 if (
NIL_P(frame))
return NULL;
1667 if (RB_TYPE_P(frame,
T_IMEMO)) {
1668 switch (imemo_type(frame)) {
1670 return (
const rb_iseq_t *)frame;
1673 const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
1674 switch (cme->def->type) {
1675 case VM_METHOD_TYPE_ISEQ:
1676 return cme->def->body.iseq.
iseqptr;
1685 rb_bug(
"frame2iseq: unreachable");
1691 const rb_iseq_t *iseq = frame2iseq(frame);
1692 return iseq ? rb_iseq_path(iseq) :
Qnil;
1695static const rb_callable_method_entry_t *
1698 if (
NIL_P(frame))
return NULL;
1700 if (RB_TYPE_P(frame,
T_IMEMO)) {
1701 switch (imemo_type(frame)) {
1704 const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
1705 switch (cme->def->type) {
1706 case VM_METHOD_TYPE_CFUNC:
1723 if (cframe(frame)) {
1727 rb_gc_register_mark_object(cfunc_str);
1731 const rb_iseq_t *iseq = frame2iseq(frame);
1732 return iseq ? rb_iseq_realpath(iseq) :
Qnil;
1738 const rb_iseq_t *iseq = frame2iseq(frame);
1739 return iseq ? rb_iseq_label(iseq) :
Qnil;
1745 const rb_iseq_t *iseq = frame2iseq(frame);
1746 return iseq ? rb_iseq_base_label(iseq) :
Qnil;
1752 const rb_iseq_t *iseq = frame2iseq(frame);
1753 return iseq ? rb_iseq_first_lineno(iseq) :
Qnil;
1757frame2klass(
VALUE frame)
1761 if (RB_TYPE_P(frame,
T_IMEMO)) {
1762 const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
1764 if (imemo_type(frame) == imemo_ment) {
1765 return cme->defined_class;
1774 VALUE klass = frame2klass(frame);
1776 if (klass && !
NIL_P(klass)) {
1778 klass =
RBASIC(klass)->klass;
1781 klass = RCLASS_ATTACHED_OBJECT(klass);
1795 VALUE klass = frame2klass(frame);
1803 const rb_callable_method_entry_t *cme = cframe(frame);
1805 ID mid = cme->def->original_id;
1808 const rb_iseq_t *iseq = frame2iseq(frame);
1809 return iseq ? rb_iseq_method_name(iseq) :
Qnil;
1813qualified_method_name(
VALUE frame,
VALUE method_name)
1815 if (method_name !=
Qnil) {
1819 if (classpath !=
Qnil) {
1820 return rb_sprintf(
"%"PRIsVALUE
"%s%"PRIsVALUE,
1821 classpath, singleton_p ==
Qtrue ?
"." :
"#", method_name);
1837 return qualified_method_name(frame, method_name);
1843 const rb_callable_method_entry_t *cme = cframe(frame);
1845 ID mid = cme->def->original_id;
1846 VALUE method_name = id2str(mid);
1847 return qualified_method_name(frame, method_name);
1854 if (
NIL_P(qualified_method_name) || base_label == qualified_method_name) {
1858 long label_length = RSTRING_LEN(label);
1859 long base_label_length = RSTRING_LEN(base_label);
1860 int prefix_len =
rb_long2int(label_length - base_label_length);
1862 return rb_sprintf(
"%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
int rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
Queries mysterious "frame"s of the given range.
VALUE rb_profile_frame_full_label(VALUE frame)
Identical to rb_profile_frame_label(), except it returns a qualified result.
struct rb_debug_inspector_struct rb_debug_inspector_t
Opaque struct representing a debug inspector.
VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
Queries the instruction sequence of the passed context's upper frame.
VALUE rb_debug_inspector_current_depth(void)
Return current frmae depth.
VALUE rb_profile_frame_method_name(VALUE frame)
Queries the name of the method of the passed frame.
VALUE rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index)
Queries the depth of the passed context's upper frame.
VALUE rb_profile_frame_qualified_method_name(VALUE frame)
Identical to rb_profile_frame_method_name(), except it "qualifies" the return value with its defining...
VALUE rb_profile_frame_label(VALUE frame)
Queries human-readable "label" string.
VALUE rb_profile_frame_singleton_method_p(VALUE frame)
Queries if the method of the passed frame is a singleton class.
VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
Queries the backtrace object of the context.
VALUE rb_profile_frame_absolute_path(VALUE frame)
Identical to rb_profile_frame_path(), except it tries to expand the returning path.
VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
Prepares, executes, then cleans up a debug session.
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
Queries the current receiver of the passed context's upper frame.
VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
Queries the binding of the passed context's upper frame.
VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
Queries the current class of the passed context's upper frame.
VALUE rb_profile_frame_classpath(VALUE frame)
Queries the class path of the method that the passed frame represents.
VALUE rb_profile_frame_path(VALUE frame)
Queries the path of the passed backtrace.
VALUE rb_profile_frame_first_lineno(VALUE frame)
Queries the first line of the method of the passed frame pointer.
int rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines)
Queries mysterious "frame"s of the given range.
VALUE(* rb_debug_inspector_func_t)(const rb_debug_inspector_t *dc, void *data)
Type of the callback function passed to rb_debug_inspector_open().
VALUE rb_profile_frame_base_label(VALUE frame)
Identical to rb_profile_frame_label(), except it does not "qualify" the result.
VALUE rb_enc_sprintf(rb_encoding *enc, const char *fmt,...)
Identical to rb_sprintf(), except it additionally takes an encoding.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define T_IMEMO
Old name of RUBY_T_IMEMO.
#define CLASS_OF
Old name of rb_class_of.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define ASSUME
Old name of RBIMPL_ASSUME.
#define T_ICLASS
Old name of RUBY_T_ICLASS.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
#define FL_TEST
Old name of RB_FL_TEST.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define rb_ary_new2
Old name of rb_ary_new_capa.
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Checks if the given object is of given kind.
VALUE rb_cArray
Array class.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_cThread
Thread class.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Deconstructs a numerical range.
#define rb_str_new_literal(str)
Just another name of rb_str_new_lit.
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
void rb_backtrace(void)
Prints the backtrace out to the standard error.
int len
Length of the buffer.
VALUE rb_yield(VALUE val)
Yields the block.
#define rb_long2int
Just another name of rb_long2int_inline.
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RBASIC(obj)
Convenient casting macro.
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.