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"
27static VALUE rb_cBacktrace;
28static VALUE rb_cBacktraceLocation;
33 VALUE str = rb_id2str(
id);
34 if (!str)
return Qnil;
37#define rb_id2str(id) id2str(id)
40calc_pos(
const rb_iseq_t *iseq,
const VALUE *pc,
int *lineno,
int *node_id)
45 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_TOP) {
46 VM_ASSERT(! ISEQ_BODY(iseq)->local_table);
47 VM_ASSERT(! ISEQ_BODY(iseq)->local_table_size);
50 if (lineno) *lineno = ISEQ_BODY(iseq)->location.first_lineno;
51#ifdef USE_ISEQ_NODE_ID
52 if (node_id) *node_id = ISEQ_BODY(iseq)->location.node_id;
57 VM_ASSERT(ISEQ_BODY(iseq));
58 VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
59 VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
61 ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
63#if SIZEOF_PTRDIFF_T > SIZEOF_INT
64 VM_ASSERT(n <= (ptrdiff_t)UINT_MAX);
66 VM_ASSERT((
unsigned int)n <= ISEQ_BODY(iseq)->iseq_size);
73#if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
76 rb_print_backtrace(stderr);
80 if (lineno) *lineno = rb_iseq_line_no(iseq, pos);
81#ifdef USE_ISEQ_NODE_ID
82 if (node_id) *node_id = rb_iseq_node_id(iseq, pos);
92 if (calc_pos(iseq, pc, &lineno, NULL))
return lineno;
96#ifdef USE_ISEQ_NODE_ID
101 if (calc_pos(iseq, pc, NULL, &node_id))
return node_id;
109 if (VM_FRAME_RUBYFRAME_P(cfp) && CFP_ISEQ(cfp)) {
111 int line = calc_lineno(iseq, CFP_PC(cfp));
116 return ISEQ_BODY(iseq)->location.first_lineno;
136location_mark(
void *ptr)
139 rb_gc_mark_movable(vfi->btobj);
143location_ref_update(
void *ptr)
146 vfi->btobj = rb_gc_location(vfi->btobj);
152 rb_gc_mark((
VALUE)fi->cme);
153 if (fi->iseq) rb_gc_mark_movable((
VALUE)fi->iseq);
164 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
168rb_frame_info_p(
VALUE obj)
170 return rb_typeddata_is_kind_of(obj, &location_data_type);
174location_ptr(
VALUE locobj)
185 return calc_lineno(loc->iseq, loc->pc);
199location_lineno_m(
VALUE self)
201 return INT2FIX(location_lineno(location_ptr(self)));
204VALUE rb_mod_name0(
VALUE klass,
bool *permanent);
211 if (RCLASS_SINGLETON_P(owner)) {
212 VALUE v = RCLASS_ATTACHED_OBJECT(owner);
214 v = rb_mod_name0(v, &permanent);
215 if (permanent && !
NIL_P(v)) {
216 return rb_sprintf(
"%"PRIsVALUE
".%"PRIsVALUE, v, name);
221 owner = rb_mod_name0(owner, &permanent);
222 if (permanent && !
NIL_P(owner)) {
223 return rb_sprintf(
"%"PRIsVALUE
"#%"PRIsVALUE, owner, name);
234 switch (ISEQ_BODY(iseq)->
type) {
236 case ISEQ_TYPE_CLASS:
238 return ISEQ_BODY(iseq)->location.label;
239 case ISEQ_TYPE_METHOD:
240 return rb_gen_method_name(owner, ISEQ_BODY(iseq)->location.label);
241 case ISEQ_TYPE_BLOCK:
242 case ISEQ_TYPE_PLAIN: {
245 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
246 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
247 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK) {
250 iseq = ISEQ_BODY(iseq)->parent_iseq;
254 return rb_sprintf(
"block in %"PRIsVALUE, calculate_iseq_label(owner, iseq));
257 return rb_sprintf(
"block (%d levels) in %"PRIsVALUE, level, calculate_iseq_label(owner, iseq));
260 case ISEQ_TYPE_RESCUE:
261 case ISEQ_TYPE_ENSURE:
263 iseq = ISEQ_BODY(iseq)->parent_iseq;
266 rb_bug(
"calculate_iseq_label: unreachable");
271is_internal_location(
const rb_iseq_t *iseq)
273 static const char prefix[] =
"<internal:";
274 const size_t prefix_len =
sizeof(prefix) - 1;
275 VALUE file = rb_iseq_path(iseq);
276 return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0;
283 if (!loc->cme)
return false;
285 switch (loc->cme->def->type) {
286 case VM_METHOD_TYPE_CFUNC:
288 case VM_METHOD_TYPE_ISEQ:
289 return is_internal_location(loc->cme->def->body.iseq.
iseqptr);
316 if (!cme || !cme->def)
return Qnil;
317 VALUE owner = cme->owner;
318 VALUE defined_in = cme->def->original_module;
319 if (!defined_in)
return owner;
320 if (defined_in != owner &&
322 RCLASS_ATTACHED_OBJECT(owner) == defined_in) {
331 if (location_cfunc_p(loc)) {
332 return rb_gen_method_name(location_original_module(loc->cme), rb_id2str(loc->cme->def->original_id));
335 return calculate_iseq_label(location_original_module(loc->cme), loc->iseq);
365location_label_m(
VALUE self)
367 return location_label(location_ptr(self));
373 if (location_cfunc_p(loc)) {
374 return rb_id2str(loc->cme->def->original_id);
377 return rb_iseq_base_label(loc->iseq);
405location_base_label_m(
VALUE self)
407 return location_base_label(location_ptr(self));
427location_path_m(
VALUE self)
429 const rb_iseq_t *iseq = location_iseq(location_ptr(self));
430 return iseq ? rb_iseq_path(iseq) :
Qnil;
433#ifdef USE_ISEQ_NODE_ID
438 return calc_node_id(loc->iseq, loc->pc);
443extern VALUE rb_e_script;
446location_source_end_marker_p(
const uint8_t *line,
size_t length)
448 return (length == 7 && memcmp(line,
"__END__", 7) == 0) ||
449 (length == 8 && memcmp(line,
"__END__\n", 8) == 0) ||
450 (length == 9 && memcmp(line,
"__END__\r\n", 9) == 0);
454location_source_hash_matches(
VALUE source, uint64_t source_hash)
457 const uint8_t *bytes = (
const uint8_t *)RSTRING_PTR(source);
458 size_t length = (size_t)RSTRING_LEN(source);
459 size_t line_start = 0;
461 rb_source_hash_init(&state);
463 for (
size_t index = 0; index < length; index++) {
464 if (bytes[index] !=
'\n')
continue;
466 size_t line_length = index + 1 - line_start;
467 rb_source_hash_update(&state, bytes + line_start, line_length);
468 if (location_source_end_marker_p(bytes + line_start, line_length) &&
469 rb_source_hash_finalize(&state) == source_hash) {
472 line_start = index + 1;
475 if (line_start < length) {
476 size_t line_length = length - line_start;
477 rb_source_hash_update(&state, bytes + line_start, line_length);
478 if (location_source_end_marker_p(bytes + line_start, line_length) &&
479 rb_source_hash_finalize(&state) == source_hash) {
484 return rb_source_hash_finalize(&state) == source_hash;
488location_source_read(
VALUE io)
500location_source_read_file(
VALUE path)
509 return left->beg_pos.lineno == right->beg_pos.lineno &&
510 left->beg_pos.column == right->beg_pos.column &&
511 left->end_pos.lineno == right->end_pos.lineno &&
512 left->end_pos.column == right->end_pos.column;
516iseq_from_e_script_p(
const rb_iseq_t *iseq,
VALUE path, uint64_t source_hash)
519 RSTRING_LEN(path) != 2 ||
520 memcmp(RSTRING_PTR(path),
"-e", 2) != 0 ||
521 !
RTEST(rb_e_script)) {
524 if (!location_source_hash_matches(rb_e_script, source_hash))
return false;
527 for (; source_iseq; source_iseq = ISEQ_BODY(source_iseq)->parent_iseq) {
528 if (ISEQ_BODY(source_iseq)->type == ISEQ_TYPE_EVAL)
return false;
529 if (ISEQ_BODY(source_iseq)->type == ISEQ_TYPE_MAIN)
return true;
532 int node_id = ISEQ_BODY(iseq)->location.node_id;
533 if (node_id == -1)
return false;
537 if (ISEQ_BODY(iseq)->prism) {
538 found = pm_node_source_location(rb_e_script, path, 1, node_id, &source_location);
541 found = rb_ast_node_source_location(
546 ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK,
552 return found && location_code_location_equal(
553 &source_location, &ISEQ_BODY(iseq)->location.code_location);
557location_source_first_lineno(
const rb_iseq_t *iseq,
VALUE script_lines)
561 while (ISEQ_BODY(source_iseq)->parent_iseq) {
562 const rb_iseq_t *parent = ISEQ_BODY(source_iseq)->parent_iseq;
563 if (ISEQ_SCRIPT_LINES(parent) != script_lines)
break;
564 source_iseq = parent;
567 return ISEQ_BODY(source_iseq)->location.first_lineno;
590location_source_range_m(
VALUE self)
592#ifdef USE_ISEQ_NODE_ID
594 const rb_iseq_t *iseq = location_iseq(backtrace_location);
596 rb_raise(
rb_eRuntimeError,
"cannot get source range for location without Ruby bytecode");
600 int node_id = location_node_id(backtrace_location);
602 rb_raise(
rb_eRuntimeError,
"cannot get source range for location without a node ID");
604 if (!ISEQ_BODY(iseq)->source_hash) {
605 rb_raise(
rb_eRuntimeError,
"cannot get source range because the source hash is unavailable");
607 uint64_t source_hash = ISEQ_BODY(iseq)->source_hash;
609 VALUE path = rb_iseq_path(iseq);
610 VALUE absolute_path = rb_iseq_realpath(iseq);
611 VALUE script_lines = ISEQ_SCRIPT_LINES(iseq);
613 VALUE parser_path = path;
614 int first_lineno = 1;
616 if (!
NIL_P(script_lines)) {
618 first_lineno = location_source_first_lineno(iseq, script_lines);
620 else if (iseq_from_e_script_p(iseq, path, source_hash)) {
621 source = rb_e_script;
623 else if (!
NIL_P(absolute_path)) {
624 source = location_source_read_file(absolute_path);
625 parser_path = absolute_path;
628 rb_raise(rb_eArgError,
"cannot get source range for location in eval");
631 if (
NIL_P(parser_path)) {
634 if (!location_source_hash_matches(source, source_hash)) {
641 if (ISEQ_BODY(iseq)->prism) {
642 found = pm_node_source_location(
651 found = rb_ast_node_source_location(
656 ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK,
657 ISEQ_BODY(iseq)->location.node_id,
663 rb_raise(
rb_eRuntimeError,
"cannot find node ID %d in parsed source", node_id);
666 return rb_source_range_new(path, absolute_path, &code_location);
668 rb_raise(
rb_eRuntimeError,
"cannot get source range because node IDs are disabled");
673rb_get_node_id_from_frame_info(
VALUE obj)
675#ifdef USE_ISEQ_NODE_ID
677 return location_node_id(loc);
684rb_get_iseq_from_frame_info(
VALUE obj)
687 const rb_iseq_t *iseq = location_iseq(loc);
695 return rb_iseq_realpath(loc->iseq);
707location_absolute_path_m(
VALUE self)
709 return location_realpath(location_ptr(self));
713location_format(
VALUE file,
int lineno,
VALUE name)
717 rb_str_catf(s,
":%d", lineno);
724 rb_str_catf(s,
"'%"PRIsVALUE
"'", name);
736 if (location_cfunc_p(loc)) {
737 if (loc->iseq && loc->pc) {
738 file = rb_iseq_path(loc->iseq);
739 lineno = calc_lineno(loc->iseq, loc->pc);
742 file = GET_VM()->progname;
745 name = rb_gen_method_name(location_original_module(loc->cme), rb_id2str(loc->cme->def->original_id));
748 file = rb_iseq_path(loc->iseq);
749 lineno = calc_lineno(loc->iseq, loc->pc);
751 owner = location_original_module(loc->cme);
753 name = calculate_iseq_label(owner, loc->iseq);
756 return location_format(file, lineno, name);
763location_to_str_m(
VALUE self)
765 return location_to_str(location_ptr(self));
773location_inspect_m(
VALUE self)
786backtrace_mark(
void *ptr)
789 size_t i, s = bt->backtrace_size;
791 for (i=0; i<s; i++) {
792 location_mark_entry(&bt->backtrace[i]);
794 rb_gc_mark_movable(bt->strary);
795 rb_gc_mark_movable(bt->locary);
808backtrace_update(
void *ptr)
811 size_t i, s = bt->backtrace_size;
813 for (i=0; i<s; i++) {
814 location_update_entry(&bt->backtrace[i]);
816 bt->strary = rb_gc_location(bt->strary);
817 bt->locary = rb_gc_location(bt->locary);
831 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
835rb_backtrace_p(
VALUE obj)
837 return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
844 VALUE btobj = rb_data_typed_object_zalloc(rb_cBacktrace, memsize, &backtrace_data_type);
853rb_backtrace_dup(
VALUE btobj)
858 VALUE dupobj = backtrace_alloc_capa(src->backtrace_size, &dst);
859 dst->backtrace_size = src->backtrace_size;
861 for (
int i = 0; i < dst->backtrace_size; i++) {
875rb_backtrace_blob_dump(
VALUE btobj,
int *size_out)
880 int size = bt->backtrace_size;
888rb_backtrace_blob_load(
const void *blob_,
int size)
892 VALUE btobj = backtrace_alloc_capa(size, &dst);
894 dst->backtrace_size = size;
896 for (
int i = 0; i < size; i++) {
906rb_backtrace_blob_mark(
const void *blob_,
int size)
909 for (
int i = 0; i < size; i++) {
910 if (blob[i].cme) rb_gc_mark((
VALUE)blob[i].cme);
911 if (blob[i].iseq) rb_gc_mark((
VALUE)blob[i].iseq);
921 if (start_cfp == NULL) {
926 RUBY_VM_NEXT_CONTROL_FRAME(
927 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp));
929 if (start_cfp < last_cfp) {
933 return start_cfp - last_cfp + 1;
939 enum rb_iseq_type
type = ISEQ_BODY(CFP_ISEQ(cfp))->type;
940 return type == ISEQ_TYPE_RESCUE ||
type == ISEQ_TYPE_ENSURE;
946 for (; backpatch_counter > 0; backpatch_counter--, loc--) {
957 for (; num_frames > 0; num_frames--, loc++) {
958 rb_yield(location_create(loc, (
void *)btobj));
963rb_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)
971 unsigned long backpatch_counter = 0;
972 bool skip_next_frame = FALSE;
975 if (end_cfp == NULL) {
979 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
991 size = end_cfp - cfp + 1;
995 else if (num_frames < 0 || num_frames > size) {
1000 btobj = backtrace_alloc_capa(num_frames, &bt);
1002 bt->backtrace_size = 0;
1003 if (num_frames == 0) {
1004 if (start_too_large) *start_too_large = 0;
1008 for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
1009 if (CFP_ISEQ(cfp)) {
1011 if (start_frame > 0) {
1015 bool internal = is_internal_location(CFP_ISEQ(cfp));
1016 if (skip_internal && internal)
continue;
1017 if (!skip_next_frame) {
1019 const VALUE *pc = CFP_PC(cfp);
1020 if (internal && backpatch_counter > 0) {
1022 bt->backtrace_size -= backpatch_counter;
1023 backpatch_counter = 0;
1025 loc = &bt->backtrace[bt->backtrace_size++];
1026 RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1034 backpatch_counter++;
1038 if ((VM_FRAME_TYPE(cfp) & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_DUMMY) {
1044 bt_backpatch_loc(backpatch_counter, loc-1, iseq, pc);
1046 bt_yield_loc(loc - backpatch_counter, backpatch_counter+1, btobj);
1048 backpatch_counter = 0;
1051 skip_next_frame = is_rescue_or_ensure_frame(cfp);
1056 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
1057 if (start_frame > 0) {
1061 loc = &bt->backtrace[bt->backtrace_size++];
1062 RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1065 backpatch_counter++;
1072 if (backpatch_counter > 0) {
1073 for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
1074 if (CFP_ISEQ(cfp) && CFP_PC(cfp) && !(skip_internal && is_internal_location(CFP_ISEQ(cfp)))) {
1075 VM_ASSERT(!skip_next_frame);
1076 bt_backpatch_loc(backpatch_counter, loc, CFP_ISEQ(cfp), CFP_PC(cfp));
1079 bt_yield_loc(loc - backpatch_counter + 1, backpatch_counter, btobj);
1086 if (start_too_large) *start_too_large = (start_frame > 0 ? -1 : 0);
1093 return rb_ec_partial_backtrace_object(ec, RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES, NULL, FALSE, FALSE);
1104 for (i=0; i<bt->backtrace_size; i++) {
1115 return location_to_str(loc);
1119backtrace_to_str_ary(
VALUE self)
1124 r = backtrace_collect(bt, location_to_str_dmyarg, 0);
1130rb_backtrace_to_str_ary(
VALUE self)
1136 RB_OBJ_WRITE(self, &bt->strary, backtrace_to_str_ary(self));
1155backtrace_to_location_ary(
VALUE self)
1160 r = backtrace_collect(bt, location_create, (
void *)self);
1166rb_backtrace_to_location_ary(
VALUE self)
1172 RB_OBJ_WRITE(self, &bt->locary, backtrace_to_location_ary(self));
1178rb_location_ary_to_backtrace(
VALUE ary)
1186 VALUE btobj = backtrace_alloc_capa(num_frames, &new_backtrace);
1188 for (
long index = 0; index <
RARRAY_LEN(ary); index++) {
1191 if (!rb_frame_info_p(locobj)) {
1199 RB_OBJ_WRITE(btobj, &dst_location->cme, src_vloc->loc->cme);
1200 RB_OBJ_WRITE(btobj, &dst_location->iseq, src_vloc->loc->iseq);
1201 dst_location->pc = src_vloc->loc->pc;
1203 new_backtrace->backtrace_size++;
1212backtrace_dump_data(
VALUE self)
1214 VALUE str = rb_backtrace_to_str_ary(self);
1278backtrace_limit(
VALUE self)
1280 return LONG2NUM(rb_backtrace_length_limit);
1285backtrace_clone(
VALUE self)
1291 VALUE clone = backtrace_alloc_capa(bt->backtrace_size, &other_bt);
1293 rb_obj_clone_setup(self, clone,
Qfalse);
1300backtrace_dup(
VALUE self)
1309backtrace_initialize_copy(
VALUE self,
VALUE original)
1317 bt->backtrace_size = original_bt->backtrace_size;
1319 rb_gc_writebarrier_remember(self);
1327 return rb_backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, FALSE));
1333 return rb_backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal, FALSE));
1340 void (*init)(
void *arg,
size_t size),
1351 if (start_cfp == NULL) {
1367 RUBY_VM_NEXT_CONTROL_FRAME(
1368 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp));
1370 if (start_cfp < last_cfp) {
1374 size = start_cfp - last_cfp + 1;
1380 for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
1382 if (CFP_ISEQ(cfp)) {
1384 iter_iseq(arg, cfp);
1388 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
1390 ID mid = me->def->original_id;
1392 iter_cfunc(arg, cfp, mid);
1400 void (*func)(
void *data,
VALUE file,
int lineno,
VALUE name);
1405oldbt_init(
void *ptr,
size_t dmy)
1408 arg->filename = GET_VM()->progname;
1416 const VALUE *pc = CFP_PC(cfp);
1418 VALUE file = arg->filename = rb_iseq_path(iseq);
1419 VALUE name = ISEQ_BODY(iseq)->location.label;
1420 int lineno = arg->lineno = calc_lineno(iseq, pc);
1422 (arg->func)(arg->data, file, lineno, name);
1429 VALUE file = arg->filename;
1430 VALUE name = rb_id2str(mid);
1431 int lineno = arg->lineno;
1433 (arg->func)(arg->data, file, lineno, name);
1437oldbt_print(
void *data,
VALUE file,
int lineno,
VALUE name)
1442 fprintf(fp,
"\tfrom %.*s:%d:in unknown method\n",
1446 fprintf(fp,
"\tfrom %.*s:%d:in '%.*s'\n",
1453vm_backtrace_print(
FILE *fp)
1457 arg.func = oldbt_print;
1458 arg.data = (
void *)fp;
1459 backtrace_each(GET_EC(),
1472oldbt_bugreport(
void *arg,
VALUE file,
int line,
VALUE method)
1476 const char *filename =
NIL_P(file) ?
"ruby" : RSTRING_PTR(file);
1479 fprintf(fp,
"-- Ruby level backtrace information "
1480 "----------------------------------------\n");
1483 if (
NIL_P(method)) {
1484 fprintf(fp,
"%.*s:%d:in unknown method\n",
1485 filename_len, filename, line);
1488 fprintf(fp,
"%.*s:%d:in '%.*s'\n",
1489 filename_len, filename, line,
1495rb_backtrace_print_as_bugreport(
FILE *fp)
1500 arg.func = oldbt_bugreport;
1503 backtrace_each(GET_EC(),
1513 vm_backtrace_print(stderr);
1522oldbt_print_to(
void *data,
VALUE file,
int lineno,
VALUE name)
1525 VALUE str = rb_sprintf(
"\tfrom %"PRIsVALUE
":%d:in ", file, lineno);
1531 rb_str_catf(str,
" '%"PRIsVALUE
"'\n", name);
1533 (*arg->iter)(arg->output, str);
1543 parg.output = output;
1544 arg.func = oldbt_print_to;
1546 backtrace_each(GET_EC(),
1554rb_make_backtrace(
void)
1556 return rb_ec_backtrace_str_ary(GET_EC(), RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES);
1562 VALUE level, vn, opts;
1570 if (argc == 2 &&
NIL_P(vn)) argc--;
1574 lev = lev_default + lev_plus;
1575 n = RUBY_ALL_BACKTRACE_LINES;
1579 long beg,
len, bt_size = backtrace_size(ec);
1584 rb_raise(rb_eArgError,
"negative level (%ld)", lev);
1587 n = RUBY_ALL_BACKTRACE_LINES;
1592 lev = beg + lev_plus;
1602 rb_raise(rb_eArgError,
"negative level (%ld)", lev);
1605 rb_raise(rb_eArgError,
"negative size (%ld)", n);
1625 lev = ec_backtrace_range(ec, argc, argv, lev_default, lev_plus, &n);
1626 if (lev < 0)
return Qnil;
1632 btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE, FALSE);
1639 r = backtrace_to_str_ary(btval);
1642 r = backtrace_to_location_ary(btval);
1649thread_backtrace_to_ary(
int argc,
const VALUE *argv,
VALUE thval,
int to_str)
1653 if (target_th->to_kill || target_th->status == THREAD_KILLED)
1656 return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1660rb_vm_thread_backtrace(
int argc,
const VALUE *argv,
VALUE thval)
1662 return thread_backtrace_to_ary(argc, argv, thval, 1);
1666rb_vm_thread_backtrace_locations(
int argc,
const VALUE *argv,
VALUE thval)
1668 return thread_backtrace_to_ary(argc, argv, thval, 0);
1674 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1680 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1724 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1750rb_f_caller_locations(
int argc,
VALUE *argv,
VALUE _)
1752 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1763each_caller_location(
int argc,
VALUE *argv,
VALUE _)
1766 long n, lev = ec_backtrace_range(ec, argc, argv, 1, 1, &n);
1767 if (lev >= 0 && n != 0) {
1768 rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, TRUE);
1774backtrace_no_allocator(
VALUE klass)
1783Init_vm_backtrace(
void)
1801 rb_define_method(rb_cBacktrace,
"initialize_copy", backtrace_initialize_copy, 1);
1850 rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace,
"Location",
rb_cObject);
1855 rb_define_method(rb_cBacktraceLocation,
"base_label", location_base_label_m, 0);
1857 rb_define_method(rb_cBacktraceLocation,
"absolute_path", location_absolute_path_m, 0);
1858 rb_define_method(rb_cBacktraceLocation,
"source_range", location_source_range_m, 0);
1870RUBY_SYMBOL_EXPORT_BEGIN
1872RUBY_SYMBOL_EXPORT_END
1878 VALUE raw_backtrace;
1882 CALLER_BINDING_SELF,
1883 CALLER_BINDING_CLASS,
1884 CALLER_BINDING_BINDING,
1885 CALLER_BINDING_ISEQ,
1888 CALLER_BINDING_DEPTH,
1899collect_caller_bindings_init(
void *arg,
size_t num_frames)
1902 data->btobj = backtrace_alloc_capa(num_frames, &data->bt);
1909 if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
1911 return RBASIC(klass)->klass;
1925 VM_ASSERT(RUBY_VM_END_CONTROL_FRAME(ec) >= cfp);
1926 return (
int)(RUBY_VM_END_CONTROL_FRAME(ec) - cfp);
1937 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1938 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp));
1940 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1943 RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1945 loc->pc = CFP_PC(cfp);
1946 VALUE vloc = location_create(loc, (
void *)data->btobj);
1961 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1964 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1967 RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1970 VALUE vloc = location_create(loc, (
void *)data->btobj);
1988 collect_caller_bindings_init,
1989 collect_caller_bindings_iseq,
1990 collect_caller_bindings_cfunc,
2000 if (!
NIL_P(cfp_val)) {
2002 rb_ary_store(entry, CALLER_BINDING_BINDING, rb_vm_make_binding(ec, cfp));
2019 enum ruby_tag_type state;
2020 volatile VALUE MAYBE_UNUSED(result);
2024 rb_vm_stack_to_heap(ec);
2026 dbg_context.ec = ec;
2027 dbg_context.cfp = dbg_context.ec->cfp;
2028 dbg_context.contexts = collect_caller_bindings(ec);
2030 for (i=0; i<
RARRAY_LEN(dbg_context.contexts); i++) {
2036 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
2037 result = (*func)(&dbg_context, data);
2044 EC_JUMP_TAG(ec, state);
2053 if (index < 0 || index >=
RARRAY_LEN(dc->contexts)) {
2054 rb_raise(rb_eArgError,
"no such frame");
2062 VALUE frame = frame_get(dc, index);
2069 VALUE frame = frame_get(dc, index);
2076 VALUE frame = frame_get(dc, index);
2083 VALUE frame = frame_get(dc, index);
2092 VALUE frame = frame_get(dc, index);
2100 return INT2FIX(frame_depth(ec, ec->cfp));
2106 return dc->raw_backtrace;
2127 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
2129 for (i=0; i<limit && cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
2130 if (VM_FRAME_RUBYFRAME_P_UNCHECKED(cfp) && CFP_PC(cfp)) {
2137 cme = rb_vm_frame_method_entry_unchecked(cfp);
2139 if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
2140 buff[i] = (
VALUE)cme;
2143 buff[i] = (
VALUE)iseq;
2147 const VALUE *pc = CFP_PC(cfp);
2148 VALUE *iseq_encoded = ISEQ_BODY(iseq)->iseq_encoded;
2149 VALUE *pc_end = iseq_encoded + ISEQ_BODY(iseq)->iseq_size;
2156 if (cfp == top && (pc < iseq_encoded || pc > pc_end)) {
2160 lines[i] = calc_lineno(iseq, pc);
2167 cme = rb_vm_frame_method_entry_unchecked(cfp);
2168 if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
2173 buff[i] = (
VALUE)cme;
2174 if (lines) lines[i] = 0;
2194 return thread_profile_frames(ec, start, limit, buff, lines);
2201 return thread_profile_frames(th->ec, start, limit, buff, lines);
2205frame2iseq(
VALUE frame)
2207 if (
NIL_P(frame))
return NULL;
2210 switch (imemo_type(frame)) {
2216 switch (cme->def->type) {
2217 case VM_METHOD_TYPE_ISEQ:
2218 return cme->def->body.iseq.
iseqptr;
2227 rb_bug(
"frame2iseq: unreachable");
2233 const rb_iseq_t *iseq = frame2iseq(frame);
2234 return iseq ? rb_iseq_path(iseq) :
Qnil;
2240 if (
NIL_P(frame))
return NULL;
2243 switch (imemo_type(frame)) {
2247 switch (cme->def->type) {
2248 case VM_METHOD_TYPE_CFUNC:
2265 if (cframe(frame)) {
2269 rb_vm_register_global_object(cfunc_str);
2273 const rb_iseq_t *iseq = frame2iseq(frame);
2274 return iseq ? rb_iseq_realpath(iseq) :
Qnil;
2280 const rb_iseq_t *iseq = frame2iseq(frame);
2281 return iseq ? rb_iseq_label(iseq) :
Qnil;
2287 const rb_iseq_t *iseq = frame2iseq(frame);
2288 return iseq ? rb_iseq_base_label(iseq) :
Qnil;
2294 const rb_iseq_t *iseq = frame2iseq(frame);
2295 return iseq ? rb_iseq_first_lineno(iseq) :
Qnil;
2299frame2klass(
VALUE frame)
2306 if (imemo_type(frame) == imemo_ment) {
2307 return cme->defined_class;
2316 VALUE klass = frame2klass(frame);
2318 if (klass && !
NIL_P(klass)) {
2320 klass =
RBASIC(klass)->klass;
2322 else if (RCLASS_SINGLETON_P(klass)) {
2323 klass = RCLASS_ATTACHED_OBJECT(klass);
2337 VALUE klass = frame2klass(frame);
2339 return RBOOL(klass && !
NIL_P(klass) && RCLASS_SINGLETON_P(klass));
2347 ID mid = cme->def->original_id;
2350 const rb_iseq_t *iseq = frame2iseq(frame);
2351 return iseq ? rb_iseq_method_name(iseq) :
Qnil;
2355qualified_method_name(
VALUE frame,
VALUE method_name)
2357 if (method_name !=
Qnil) {
2361 if (classpath !=
Qnil) {
2362 return rb_sprintf(
"%"PRIsVALUE
"%s%"PRIsVALUE,
2363 classpath, singleton_p ==
Qtrue ?
"." :
"#", method_name);
2379 return qualified_method_name(frame, method_name);
2387 ID mid = cme->def->original_id;
2388 VALUE method_name = id2str(mid);
2389 return qualified_method_name(frame, method_name);
2396 if (
NIL_P(qualified_method_name) || base_label == qualified_method_name) {
2400 long label_length = RSTRING_LEN(label);
2401 long base_label_length = RSTRING_LEN(base_label);
2402 int prefix_len =
rb_long2int(label_length - base_label_length);
2404 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.
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 frame 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.
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 NUM2LONG
Old name of RB_NUM2LONG.
#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_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_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
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.
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_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.
#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_str_buf_new(long capa)
Allocates a "string buffer".
#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_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 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)
#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
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.