12#include "eval_intern.h"
14#include "internal/class.h"
15#include "internal/error.h"
16#include "internal/object.h"
17#include "internal/proc.h"
18#include "internal/ruby_parser.h"
19#include "internal/vm.h"
21#include "prism_compile.h"
28static VALUE rb_cBacktrace;
29static VALUE rb_cBacktraceLocation;
34 VALUE str = rb_id2str(
id);
35 if (!str)
return Qnil;
38#define rb_id2str(id) id2str(id)
41calc_pos(
const rb_iseq_t *iseq,
const VALUE *pc,
int *lineno,
int *node_id)
46 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_TOP) {
47 VM_ASSERT(! ISEQ_BODY(iseq)->local_table);
48 VM_ASSERT(! ISEQ_BODY(iseq)->local_table_size);
51 if (lineno) *lineno = ISEQ_BODY(iseq)->location.first_lineno;
52#ifdef USE_ISEQ_NODE_ID
53 if (node_id) *node_id = ISEQ_BODY(iseq)->location.node_id;
58 VM_ASSERT(ISEQ_BODY(iseq));
59 VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
60 VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
62 ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
64#if SIZEOF_PTRDIFF_T > SIZEOF_INT
65 VM_ASSERT(n <= (ptrdiff_t)UINT_MAX);
67 VM_ASSERT((
unsigned int)n <= ISEQ_BODY(iseq)->iseq_size);
74#if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
77 rb_print_backtrace(stderr);
81 if (lineno) *lineno = rb_iseq_line_no(iseq, pos);
82#ifdef USE_ISEQ_NODE_ID
83 if (node_id) *node_id = rb_iseq_node_id(iseq, pos);
93 if (calc_pos(iseq, pc, &lineno, NULL))
return lineno;
97#ifdef USE_ISEQ_NODE_ID
102 if (calc_pos(iseq, pc, NULL, &node_id))
return node_id;
110 if (VM_FRAME_RUBYFRAME_P(cfp) && CFP_ISEQ(cfp)) {
112 int line = calc_lineno(iseq, CFP_PC(cfp));
117 return ISEQ_BODY(iseq)->location.first_lineno;
137location_mark(
void *ptr)
140 rb_gc_mark_movable(vfi->btobj);
144location_ref_update(
void *ptr)
147 rb_gc_update_moved(&vfi->btobj);
153 rb_gc_mark((
VALUE)fi->cme);
154 if (fi->iseq) rb_gc_mark_movable((
VALUE)fi->iseq);
165 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
169rb_frame_info_p(
VALUE obj)
171 return rb_typeddata_is_kind_of(obj, &location_data_type);
175location_ptr(
VALUE locobj)
186 return calc_lineno(loc->iseq, loc->pc);
200location_lineno_m(
VALUE self)
202 return INT2FIX(location_lineno(location_ptr(self)));
205VALUE rb_mod_name0(
VALUE klass,
bool *permanent);
212 if (RCLASS_SINGLETON_P(owner)) {
213 VALUE v = RCLASS_ATTACHED_OBJECT(owner);
215 v = rb_mod_name0(v, &permanent);
216 if (permanent && !
NIL_P(v)) {
217 return rb_sprintf(
"%"PRIsVALUE
".%"PRIsVALUE, v, name);
222 owner = rb_mod_name0(owner, &permanent);
223 if (permanent && !
NIL_P(owner)) {
224 return rb_sprintf(
"%"PRIsVALUE
"#%"PRIsVALUE, owner, name);
235 switch (ISEQ_BODY(iseq)->
type) {
237 case ISEQ_TYPE_CLASS:
239 return ISEQ_BODY(iseq)->location.label;
240 case ISEQ_TYPE_METHOD:
241 return rb_gen_method_name(owner, ISEQ_BODY(iseq)->location.label);
242 case ISEQ_TYPE_BLOCK:
243 case ISEQ_TYPE_PLAIN: {
246 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
247 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
248 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK) {
251 iseq = ISEQ_BODY(iseq)->parent_iseq;
255 return rb_sprintf(
"block in %"PRIsVALUE, calculate_iseq_label(owner, iseq));
258 return rb_sprintf(
"block (%d levels) in %"PRIsVALUE, level, calculate_iseq_label(owner, iseq));
261 case ISEQ_TYPE_RESCUE:
262 case ISEQ_TYPE_ENSURE:
264 iseq = ISEQ_BODY(iseq)->parent_iseq;
267 rb_bug(
"calculate_iseq_label: unreachable");
272is_internal_location(
const rb_iseq_t *iseq)
274 static const char prefix[] =
"<internal:";
275 const size_t prefix_len =
sizeof(prefix) - 1;
276 VALUE file = rb_iseq_path(iseq);
277 return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0;
284 if (!loc->cme)
return false;
286 switch (loc->cme->def->type) {
287 case VM_METHOD_TYPE_CFUNC:
289 case VM_METHOD_TYPE_ISEQ:
290 return is_internal_location(loc->cme->def->body.iseq.
iseqptr);
317 if (!cme || !cme->def)
return Qnil;
318 VALUE owner = cme->owner;
319 VALUE defined_in = cme->def->original_module;
320 if (!defined_in)
return owner;
321 if (defined_in != owner &&
323 RCLASS_ATTACHED_OBJECT(owner) == defined_in) {
332 if (location_cfunc_p(loc)) {
333 return rb_gen_method_name(location_original_module(loc->cme), rb_id2str(loc->cme->def->original_id));
336 return calculate_iseq_label(location_original_module(loc->cme), loc->iseq);
366location_label_m(
VALUE self)
368 return location_label(location_ptr(self));
374 if (location_cfunc_p(loc)) {
375 return rb_id2str(loc->cme->def->original_id);
378 return rb_iseq_base_label(loc->iseq);
406location_base_label_m(
VALUE self)
408 return location_base_label(location_ptr(self));
428location_path_m(
VALUE self)
430 const rb_iseq_t *iseq = location_iseq(location_ptr(self));
431 return iseq ? rb_iseq_path(iseq) :
Qnil;
434#ifdef USE_ISEQ_NODE_ID
439 return calc_node_id(loc->iseq, loc->pc);
444extern VALUE rb_e_script;
447location_source_end_marker_p(
const uint8_t *line,
size_t length)
449 return (length == 7 && memcmp(line,
"__END__", 7) == 0) ||
450 (length == 8 && memcmp(line,
"__END__\n", 8) == 0) ||
451 (length == 9 && memcmp(line,
"__END__\r\n", 9) == 0);
455location_source_hash_matches(
VALUE source, uint64_t source_hash)
458 const uint8_t *bytes = (
const uint8_t *)RSTRING_PTR(source);
459 size_t length = (size_t)RSTRING_LEN(source);
460 size_t line_start = 0;
462 rb_source_hash_init(&state);
464 for (
size_t index = 0; index < length; index++) {
465 if (bytes[index] !=
'\n')
continue;
467 size_t line_length = index + 1 - line_start;
468 rb_source_hash_update(&state, bytes + line_start, line_length);
469 if (location_source_end_marker_p(bytes + line_start, line_length) &&
470 rb_source_hash_finalize(&state) == source_hash) {
473 line_start = index + 1;
476 if (line_start < length) {
477 size_t line_length = length - line_start;
478 rb_source_hash_update(&state, bytes + line_start, line_length);
479 if (location_source_end_marker_p(bytes + line_start, line_length) &&
480 rb_source_hash_finalize(&state) == source_hash) {
485 return rb_source_hash_finalize(&state) == source_hash;
489location_source_read(
VALUE io)
501location_source_read_file(
VALUE path)
510 return left->beg_pos.lineno == right->beg_pos.lineno &&
511 left->beg_pos.column == right->beg_pos.column &&
512 left->end_pos.lineno == right->end_pos.lineno &&
513 left->end_pos.column == right->end_pos.column;
517iseq_from_e_script_p(
const rb_iseq_t *iseq,
VALUE path, uint64_t source_hash)
520 RSTRING_LEN(path) != 2 ||
521 memcmp(RSTRING_PTR(path),
"-e", 2) != 0 ||
522 !
RTEST(rb_e_script)) {
525 bool matches = ISEQ_BODY(iseq)->prism ?
526 pm_source_hash_matches(rb_e_script, path, source_hash) :
527 location_source_hash_matches(rb_e_script, source_hash);
528 if (!matches)
return false;
531 for (; source_iseq; source_iseq = ISEQ_BODY(source_iseq)->parent_iseq) {
532 if (ISEQ_BODY(source_iseq)->type == ISEQ_TYPE_EVAL)
return false;
533 if (ISEQ_BODY(source_iseq)->type == ISEQ_TYPE_MAIN)
return true;
536 int node_id = ISEQ_BODY(iseq)->location.node_id;
537 if (node_id == -1)
return false;
541 if (ISEQ_BODY(iseq)->prism) {
542 found = pm_node_source_location(rb_e_script, path, 1, node_id, source_hash, &source_location);
545 found = rb_ast_node_source_location(
550 ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK,
556 return found && location_code_location_equal(
557 &source_location, &ISEQ_BODY(iseq)->location.code_location);
561location_source_first_lineno(
const rb_iseq_t *iseq,
VALUE script_lines)
565 while (ISEQ_BODY(source_iseq)->parent_iseq) {
566 const rb_iseq_t *parent = ISEQ_BODY(source_iseq)->parent_iseq;
567 if (ISEQ_SCRIPT_LINES(parent) != script_lines)
break;
568 source_iseq = parent;
571 return ISEQ_BODY(source_iseq)->location.first_lineno;
594location_source_range_m(
VALUE self)
596#ifdef USE_ISEQ_NODE_ID
598 const rb_iseq_t *iseq = location_iseq(backtrace_location);
600 rb_raise(
rb_eRuntimeError,
"cannot get source range for location without Ruby bytecode");
604 int node_id = location_node_id(backtrace_location);
606 rb_raise(
rb_eRuntimeError,
"cannot get source range for location without a node ID");
608 if (!ISEQ_BODY(iseq)->source_hash) {
609 rb_raise(
rb_eRuntimeError,
"cannot get source range because the source hash is unavailable");
611 uint64_t source_hash = ISEQ_BODY(iseq)->source_hash;
613 VALUE path = rb_iseq_path(iseq);
614 VALUE absolute_path = rb_iseq_realpath(iseq);
615 VALUE script_lines = ISEQ_SCRIPT_LINES(iseq);
617 VALUE parser_path = path;
618 int first_lineno = 1;
620 if (!
NIL_P(script_lines)) {
622 first_lineno = location_source_first_lineno(iseq, script_lines);
624 else if (iseq_from_e_script_p(iseq, path, source_hash)) {
625 source = rb_e_script;
627 else if (!
NIL_P(absolute_path)) {
628 source = location_source_read_file(absolute_path);
629 parser_path = absolute_path;
632 rb_raise(rb_eArgError,
"cannot get source range for location in eval");
635 if (
NIL_P(parser_path)) {
640 if (!ISEQ_BODY(iseq)->prism && !location_source_hash_matches(source, source_hash)) {
647 if (ISEQ_BODY(iseq)->prism) {
648 found = pm_node_source_location(
658 found = rb_ast_node_source_location(
663 ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK,
664 ISEQ_BODY(iseq)->location.node_id,
670 rb_raise(
rb_eRuntimeError,
"cannot find node ID %d in parsed source", node_id);
673 return rb_source_range_new(path, absolute_path, &code_location);
675 rb_raise(
rb_eRuntimeError,
"cannot get source range because node IDs are disabled");
680rb_get_node_id_from_frame_info(
VALUE obj)
682#ifdef USE_ISEQ_NODE_ID
684 return location_node_id(loc);
691rb_get_iseq_from_frame_info(
VALUE obj)
694 const rb_iseq_t *iseq = location_iseq(loc);
702 return rb_iseq_realpath(loc->iseq);
714location_absolute_path_m(
VALUE self)
716 return location_realpath(location_ptr(self));
720location_format(
VALUE file,
int lineno,
VALUE name)
724 rb_str_catf(s,
":%d", lineno);
731 rb_str_catf(s,
"'%"PRIsVALUE
"'", name);
743 if (location_cfunc_p(loc)) {
744 if (loc->iseq && loc->pc) {
745 file = rb_iseq_path(loc->iseq);
746 lineno = calc_lineno(loc->iseq, loc->pc);
749 file = GET_VM()->progname;
752 name = rb_gen_method_name(location_original_module(loc->cme), rb_id2str(loc->cme->def->original_id));
755 file = rb_iseq_path(loc->iseq);
756 lineno = calc_lineno(loc->iseq, loc->pc);
758 owner = location_original_module(loc->cme);
760 name = calculate_iseq_label(owner, loc->iseq);
763 return location_format(file, lineno, name);
770location_to_str_m(
VALUE self)
772 return location_to_str(location_ptr(self));
780location_inspect_m(
VALUE self)
793backtrace_mark(
void *ptr)
796 size_t i, s = bt->backtrace_size;
798 for (i=0; i<s; i++) {
799 location_mark_entry(&bt->backtrace[i]);
801 rb_gc_mark_movable(bt->strary);
802 rb_gc_mark_movable(bt->locary);
808 rb_gc_update_moved_ptr(&fi->cme);
810 rb_gc_update_moved_ptr(&fi->iseq);
815backtrace_update(
void *ptr)
818 size_t i, s = bt->backtrace_size;
820 for (i=0; i<s; i++) {
821 location_update_entry(&bt->backtrace[i]);
823 rb_gc_update_moved(&bt->strary);
824 rb_gc_update_moved(&bt->locary);
838 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
842rb_backtrace_p(
VALUE obj)
844 return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
851 VALUE btobj = rb_data_typed_object_zalloc(rb_cBacktrace, memsize, &backtrace_data_type);
860rb_backtrace_dup(
VALUE btobj)
865 VALUE dupobj = backtrace_alloc_capa(src->backtrace_size, &dst);
866 dst->backtrace_size = src->backtrace_size;
868 for (
int i = 0; i < dst->backtrace_size; i++) {
882rb_backtrace_blob_dump(
VALUE btobj,
int *size_out)
887 int size = bt->backtrace_size;
895rb_backtrace_blob_load(
const void *blob_,
int size)
899 VALUE btobj = backtrace_alloc_capa(size, &dst);
901 dst->backtrace_size = size;
903 for (
int i = 0; i < size; i++) {
913rb_backtrace_blob_mark_ctx(
const struct rb_gc_mark_ctx *ctx,
const void *blob_,
int size)
916 for (
int i = 0; i < size; i++) {
928 if (start_cfp == NULL) {
933 RUBY_VM_NEXT_CONTROL_FRAME(
934 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp));
936 if (start_cfp < last_cfp) {
940 return start_cfp - last_cfp + 1;
946 enum rb_iseq_type
type = ISEQ_BODY(CFP_ISEQ(cfp))->type;
947 return type == ISEQ_TYPE_RESCUE ||
type == ISEQ_TYPE_ENSURE;
953 for (; backpatch_counter > 0; backpatch_counter--, loc--) {
964 for (; num_frames > 0; num_frames--, loc++) {
965 rb_yield(location_create(loc, (
void *)btobj));
978 unsigned long backpatch_counter = 0;
979 bool skip_next_frame = FALSE;
982 if (end_cfp == NULL) {
986 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
998 size = end_cfp - cfp + 1;
1002 else if (num_frames < 0 || num_frames > size) {
1007 btobj = backtrace_alloc_capa(num_frames, &bt);
1009 bt->backtrace_size = 0;
1010 if (num_frames == 0) {
1011 if (start_too_large) *start_too_large = 0;
1015 for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
1016 if (CFP_ISEQ(cfp)) {
1018 if (start_frame > 0) {
1022 bool internal = is_internal_location(CFP_ISEQ(cfp));
1023 if (skip_internal && internal)
continue;
1024 if (!skip_next_frame) {
1026 const VALUE *pc = CFP_PC(cfp);
1027 if (internal && backpatch_counter > 0) {
1029 bt->backtrace_size -= backpatch_counter;
1030 backpatch_counter = 0;
1032 loc = &bt->backtrace[bt->backtrace_size++];
1033 RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1041 backpatch_counter++;
1045 if ((VM_FRAME_TYPE(cfp) & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_DUMMY) {
1051 bt_backpatch_loc(backpatch_counter, loc-1, iseq, pc);
1053 bt_yield_loc(loc - backpatch_counter, backpatch_counter+1, btobj);
1055 backpatch_counter = 0;
1058 skip_next_frame = is_rescue_or_ensure_frame(cfp);
1063 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
1064 if (start_frame > 0) {
1068 loc = &bt->backtrace[bt->backtrace_size++];
1069 RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1072 backpatch_counter++;
1079 if (backpatch_counter > 0) {
1080 for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
1081 if (CFP_ISEQ(cfp) && CFP_PC(cfp) && !(skip_internal && is_internal_location(CFP_ISEQ(cfp)))) {
1082 VM_ASSERT(!skip_next_frame);
1083 bt_backpatch_loc(backpatch_counter, loc, CFP_ISEQ(cfp), CFP_PC(cfp));
1086 bt_yield_loc(loc - backpatch_counter + 1, backpatch_counter, btobj);
1093 if (start_too_large) *start_too_large = (start_frame > 0 ? -1 : 0);
1100 return rb_ec_partial_backtrace_object(ec, RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES, NULL, FALSE, FALSE);
1111 for (i=0; i<bt->backtrace_size; i++) {
1122 return location_to_str(loc);
1126backtrace_to_str_ary(
VALUE self)
1131 r = backtrace_collect(bt, location_to_str_dmyarg, 0);
1137rb_backtrace_to_str_ary(
VALUE self)
1143 RB_OBJ_WRITE(self, &bt->strary, backtrace_to_str_ary(self));
1162backtrace_to_location_ary(
VALUE self)
1167 r = backtrace_collect(bt, location_create, (
void *)self);
1173rb_backtrace_to_location_ary(
VALUE self)
1179 RB_OBJ_WRITE(self, &bt->locary, backtrace_to_location_ary(self));
1185rb_location_ary_to_backtrace(
VALUE ary)
1193 VALUE btobj = backtrace_alloc_capa(num_frames, &new_backtrace);
1198 if (!rb_frame_info_p(locobj)) {
1206 RB_OBJ_WRITE(btobj, &dst_location->cme, src_vloc->loc->cme);
1207 RB_OBJ_WRITE(btobj, &dst_location->iseq, src_vloc->loc->iseq);
1208 dst_location->pc = src_vloc->loc->pc;
1210 new_backtrace->backtrace_size++;
1219backtrace_dump_data(
VALUE self)
1221 VALUE str = rb_backtrace_to_str_ary(self);
1285backtrace_limit(
VALUE self)
1287 return LONG2NUM(rb_backtrace_length_limit);
1292backtrace_clone(
VALUE self)
1298 VALUE clone = backtrace_alloc_capa(bt->backtrace_size, &other_bt);
1300 rb_obj_clone_setup(self, clone,
Qfalse);
1307backtrace_dup(
VALUE self)
1316backtrace_initialize_copy(
VALUE self,
VALUE original)
1324 bt->backtrace_size = original_bt->backtrace_size;
1326 rb_gc_writebarrier_remember(self);
1334 return rb_backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, FALSE));
1340 return rb_backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal, FALSE));
1347 void (*init)(
void *arg,
size_t size),
1358 if (start_cfp == NULL) {
1374 RUBY_VM_NEXT_CONTROL_FRAME(
1375 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp));
1377 if (start_cfp < last_cfp) {
1381 size = start_cfp - last_cfp + 1;
1387 for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
1389 if (CFP_ISEQ(cfp)) {
1391 iter_iseq(arg, cfp);
1395 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
1397 ID mid = me->def->original_id;
1399 iter_cfunc(arg, cfp, mid);
1407 void (*func)(
void *data,
VALUE file,
int lineno,
VALUE name);
1412oldbt_init(
void *ptr,
size_t dmy)
1415 arg->filename = GET_VM()->progname;
1423 const VALUE *pc = CFP_PC(cfp);
1425 VALUE file = arg->filename = rb_iseq_path(iseq);
1426 VALUE name = ISEQ_BODY(iseq)->location.label;
1427 int lineno = arg->lineno = calc_lineno(iseq, pc);
1429 (arg->func)(arg->data, file, lineno, name);
1436 VALUE file = arg->filename;
1437 VALUE name = rb_id2str(mid);
1438 int lineno = arg->lineno;
1440 (arg->func)(arg->data, file, lineno, name);
1444oldbt_print(
void *data,
VALUE file,
int lineno,
VALUE name)
1449 fprintf(fp,
"\tfrom %.*s:%d:in unknown method\n",
1453 fprintf(fp,
"\tfrom %.*s:%d:in '%.*s'\n",
1460vm_backtrace_print(
FILE *fp)
1464 arg.func = oldbt_print;
1465 arg.data = (
void *)fp;
1466 backtrace_each(GET_EC(),
1479oldbt_bugreport(
void *arg,
VALUE file,
int line,
VALUE method)
1483 const char *filename =
NIL_P(file) ?
"ruby" : RSTRING_PTR(file);
1486 fprintf(fp,
"-- Ruby level backtrace information "
1487 "----------------------------------------\n");
1490 if (
NIL_P(method)) {
1491 fprintf(fp,
"%.*s:%d:in unknown method\n",
1492 filename_len, filename, line);
1495 fprintf(fp,
"%.*s:%d:in '%.*s'\n",
1496 filename_len, filename, line,
1502rb_backtrace_print_as_bugreport(
FILE *fp)
1507 arg.func = oldbt_bugreport;
1510 backtrace_each(GET_EC(),
1520 vm_backtrace_print(stderr);
1529oldbt_print_to(
void *data,
VALUE file,
int lineno,
VALUE name)
1532 VALUE str = rb_sprintf(
"\tfrom %"PRIsVALUE
":%d:in ", file, lineno);
1538 rb_str_catf(str,
" '%"PRIsVALUE
"'\n", name);
1540 (*arg->iter)(arg->output, str);
1550 parg.output = output;
1551 arg.func = oldbt_print_to;
1553 backtrace_each(GET_EC(),
1561rb_make_backtrace(
void)
1563 return rb_ec_backtrace_str_ary(GET_EC(), RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES);
1569 VALUE level, vn, opts;
1577 if (argc == 2 &&
NIL_P(vn)) argc--;
1581 lev = lev_default + lev_plus;
1582 n = RUBY_ALL_BACKTRACE_LINES;
1591 rb_raise(rb_eArgError,
"negative level (%"PRIdLEN
")", lev);
1594 n = RUBY_ALL_BACKTRACE_LINES;
1599 lev = beg + lev_plus;
1609 rb_raise(rb_eArgError,
"negative level (%"PRIdLEN
")", lev);
1612 rb_raise(rb_eArgError,
"negative size (%"PRIdLEN
")", n);
1632 lev = ec_backtrace_range(ec, argc, argv, lev_default, lev_plus, &n);
1633 if (lev < 0)
return Qnil;
1639 btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE, FALSE);
1646 r = backtrace_to_str_ary(btval);
1649 r = backtrace_to_location_ary(btval);
1656thread_backtrace_to_ary(
int argc,
const VALUE *argv,
VALUE thval,
int to_str)
1660 if (target_th->to_kill || target_th->status == THREAD_KILLED)
1663 return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1667rb_vm_thread_backtrace(
int argc,
const VALUE *argv,
VALUE thval)
1669 return thread_backtrace_to_ary(argc, argv, thval, 1);
1673rb_vm_thread_backtrace_locations(
int argc,
const VALUE *argv,
VALUE thval)
1675 return thread_backtrace_to_ary(argc, argv, thval, 0);
1681 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1687 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1731 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1757rb_f_caller_locations(
int argc,
VALUE *argv,
VALUE _)
1759 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1770each_caller_location(
int argc,
VALUE *argv,
VALUE _)
1773 rb_len_t n, lev = ec_backtrace_range(ec, argc, argv, 1, 1, &n);
1774 if (lev >= 0 && n != 0) {
1775 rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, TRUE);
1781backtrace_no_allocator(
VALUE klass)
1790Init_vm_backtrace(
void)
1808 rb_define_method(rb_cBacktrace,
"initialize_copy", backtrace_initialize_copy, 1);
1857 rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace,
"Location",
rb_cObject);
1862 rb_define_method(rb_cBacktraceLocation,
"base_label", location_base_label_m, 0);
1864 rb_define_method(rb_cBacktraceLocation,
"absolute_path", location_absolute_path_m, 0);
1865 rb_define_method(rb_cBacktraceLocation,
"source_range", location_source_range_m, 0);
1877RUBY_SYMBOL_EXPORT_BEGIN
1879RUBY_SYMBOL_EXPORT_END
1885 VALUE raw_backtrace;
1889 CALLER_BINDING_SELF,
1890 CALLER_BINDING_CLASS,
1891 CALLER_BINDING_BINDING,
1892 CALLER_BINDING_ISEQ,
1895 CALLER_BINDING_DEPTH,
1906collect_caller_bindings_init(
void *arg,
size_t num_frames)
1909 data->btobj = backtrace_alloc_capa(num_frames, &data->bt);
1916 if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
1918 return RBASIC(klass)->klass;
1932 VM_ASSERT(RUBY_VM_END_CONTROL_FRAME(ec) >= cfp);
1933 return (
int)(RUBY_VM_END_CONTROL_FRAME(ec) - cfp);
1944 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1945 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp));
1947 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1950 RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1952 loc->pc = CFP_PC(cfp);
1953 VALUE vloc = location_create(loc, (
void *)data->btobj);
1968 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1971 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1974 RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1977 VALUE vloc = location_create(loc, (
void *)data->btobj);
1995 collect_caller_bindings_init,
1996 collect_caller_bindings_iseq,
1997 collect_caller_bindings_cfunc,
2007 if (!
NIL_P(cfp_val)) {
2009 rb_ary_store(entry, CALLER_BINDING_BINDING, rb_vm_make_binding(ec, cfp));
2026 enum ruby_tag_type state;
2027 volatile VALUE MAYBE_UNUSED(result);
2031 rb_vm_stack_to_heap(ec);
2033 dbg_context.ec = ec;
2034 dbg_context.cfp = dbg_context.ec->cfp;
2035 dbg_context.contexts = collect_caller_bindings(ec);
2037 for (i=0; i<
RARRAY_LEN(dbg_context.contexts); i++) {
2043 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
2044 result = (*func)(&dbg_context, data);
2051 EC_JUMP_TAG(ec, state);
2060 if (index < 0 || index >=
RARRAY_LEN(dc->contexts)) {
2061 rb_raise(rb_eArgError,
"no such frame");
2069 VALUE frame = frame_get(dc, index);
2076 VALUE frame = frame_get(dc, index);
2083 VALUE frame = frame_get(dc, index);
2090 VALUE frame = frame_get(dc, index);
2099 VALUE frame = frame_get(dc, index);
2107 return INT2FIX(frame_depth(ec, ec->cfp));
2113 return dc->raw_backtrace;
2134 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
2136 for (i=0; i<limit && cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
2137 if (VM_FRAME_RUBYFRAME_P_UNCHECKED(cfp) && CFP_PC(cfp)) {
2144 cme = rb_vm_frame_method_entry_unchecked(cfp);
2146 if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
2147 buff[i] = (
VALUE)cme;
2150 buff[i] = (
VALUE)iseq;
2154 const VALUE *pc = CFP_PC(cfp);
2155 VALUE *iseq_encoded = ISEQ_BODY(iseq)->iseq_encoded;
2156 VALUE *pc_end = iseq_encoded + ISEQ_BODY(iseq)->iseq_size;
2163 if (cfp == top && (pc < iseq_encoded || pc > pc_end)) {
2167 lines[i] = calc_lineno(iseq, pc);
2174 cme = rb_vm_frame_method_entry_unchecked(cfp);
2175 if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
2180 buff[i] = (
VALUE)cme;
2181 if (lines) lines[i] = 0;
2201 return thread_profile_frames(ec, start, limit, buff, lines);
2208 return thread_profile_frames(th->ec, start, limit, buff, lines);
2212frame2iseq(
VALUE frame)
2214 if (
NIL_P(frame))
return NULL;
2217 switch (imemo_type(frame)) {
2223 switch (cme->def->type) {
2224 case VM_METHOD_TYPE_ISEQ:
2225 return cme->def->body.iseq.
iseqptr;
2234 rb_bug(
"frame2iseq: unreachable");
2240 const rb_iseq_t *iseq = frame2iseq(frame);
2241 return iseq ? rb_iseq_path(iseq) :
Qnil;
2247 if (
NIL_P(frame))
return NULL;
2250 switch (imemo_type(frame)) {
2254 switch (cme->def->type) {
2255 case VM_METHOD_TYPE_CFUNC:
2272 if (cframe(frame)) {
2276 rb_vm_register_global_object(cfunc_str);
2280 const rb_iseq_t *iseq = frame2iseq(frame);
2281 return iseq ? rb_iseq_realpath(iseq) :
Qnil;
2287 const rb_iseq_t *iseq = frame2iseq(frame);
2288 return iseq ? rb_iseq_label(iseq) :
Qnil;
2294 const rb_iseq_t *iseq = frame2iseq(frame);
2295 return iseq ? rb_iseq_base_label(iseq) :
Qnil;
2301 const rb_iseq_t *iseq = frame2iseq(frame);
2302 return iseq ? rb_iseq_first_lineno(iseq) :
Qnil;
2306frame2klass(
VALUE frame)
2313 if (imemo_type(frame) == imemo_ment) {
2314 return cme->defined_class;
2323 VALUE klass = frame2klass(frame);
2325 if (klass && !
NIL_P(klass)) {
2327 klass =
RBASIC(klass)->klass;
2329 else if (RCLASS_SINGLETON_P(klass)) {
2330 klass = RCLASS_ATTACHED_OBJECT(klass);
2344 VALUE klass = frame2klass(frame);
2346 return RBOOL(klass && !
NIL_P(klass) && RCLASS_SINGLETON_P(klass));
2354 ID mid = cme->def->original_id;
2357 const rb_iseq_t *iseq = frame2iseq(frame);
2358 return iseq ? rb_iseq_method_name(iseq) :
Qnil;
2362qualified_method_name(
VALUE frame,
VALUE method_name)
2364 if (method_name !=
Qnil) {
2368 if (classpath !=
Qnil) {
2369 return rb_sprintf(
"%"PRIsVALUE
"%s%"PRIsVALUE,
2370 classpath, singleton_p ==
Qtrue ?
"." :
"#", method_name);
2386 return qualified_method_name(frame, method_name);
2394 ID mid = cme->def->original_id;
2395 VALUE method_name = id2str(mid);
2396 return qualified_method_name(frame, method_name);
2403 if (
NIL_P(qualified_method_name) || base_label == qualified_method_name) {
2407 rb_len_t label_length = RSTRING_LEN(label);
2408 rb_len_t base_label_length = RSTRING_LEN(base_label);
2409 int prefix_len =
rb_len2int(label_length - base_label_length);
2411 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_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, rb_len_t index)
Queries the binding of the passed context's upper frame.
VALUE rb_profile_frame_full_label(VALUE frame)
Identical to rb_profile_frame_label(), except it returns a qualified result.
VALUE rb_debug_inspector_current_depth(void)
Return current frame depth.
VALUE rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, rb_len_t index)
Queries the depth of the passed context's upper frame.
VALUE rb_profile_frame_method_name(VALUE frame)
Queries the name of the method of the passed 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_class_get(const rb_debug_inspector_t *dc, rb_len_t index)
Queries the current class of the passed context's upper frame.
VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, rb_len_t index)
Queries the instruction sequence 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.
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, rb_len_t index)
Queries the current receiver of the passed context's upper frame.
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.
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.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define T_STRING
Old name of RUBY_T_STRING.
#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 T_IMEMO
Old name of RUBY_T_IMEMO.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#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 ALLOC_N
Old name of RB_ALLOC_N.
#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 T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
#define NUM2LEN
Old name of RB_NUM2LEN.
#define rb_ary_new2
Old name of rb_ary_new_capa.
VALUE rb_eRuntimeError
RuntimeError exception.
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object 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_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
void rb_ary_store(VALUE ary, rb_len_t key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
Public APIs related to rb_cIO.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
VALUE rb_io_close(VALUE io)
Closes the IO.
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
VALUE rb_range_beg_len(VALUE range, rb_len_t *begp, rb_len_t *lenp, rb_len_t len, int err)
Deconstructs a numerical range.
#define rb_str_new_literal(str)
Just another name of rb_str_new_lit.
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
VALUE rb_str_buf_new(rb_len_t capa)
Allocates a "string buffer".
#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.
#define rb_str_new_cstr(str)
Identical to rb_str_new, 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_len2int
Just another name of rb_len2int_inline.
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
VALUE type(ANYARGS)
ANYARGS-ed function type.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
References an object in an array.
#define RBASIC(obj)
Convenient casting macro.
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
#define StringValue(v)
Ensures that the parameter object is a String.
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
#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.
#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.
This is the struct that holds necessary info for a struct.
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.