Ruby 4.1.0dev (2026-09-07 revision b57404b461ba8bf34e802d86b0db78388216e182)
vm_backtrace.c (b57404b461ba8bf34e802d86b0db78388216e182)
1/**********************************************************************
2
3 vm_backtrace.c -
4
5 $Author: ko1 $
6 created at: Sun Jun 03 00:14:20 2012
7
8 Copyright (C) 1993-2012 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#include "eval_intern.h"
13#include "internal.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"
20#include "iseq.h"
21#include "ruby/debug.h"
22#include "ruby/encoding.h"
24#include "vm_core.h"
25#include "zjit.h"
26
27static VALUE rb_cBacktrace;
28static VALUE rb_cBacktraceLocation;
29
30static VALUE
31id2str(ID id)
32{
33 VALUE str = rb_id2str(id);
34 if (!str) return Qnil;
35 return str;
36}
37#define rb_id2str(id) id2str(id)
38
39inline static int
40calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
41{
42 VM_ASSERT(iseq);
43
44 if (pc == NULL) {
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);
48 return 0;
49 }
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;
53#endif
54 return 1;
55 }
56 else {
57 VM_ASSERT(ISEQ_BODY(iseq));
58 VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
59 VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
60
61 ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
62 VM_ASSERT(n >= 0);
63#if SIZEOF_PTRDIFF_T > SIZEOF_INT
64 VM_ASSERT(n <= (ptrdiff_t)UINT_MAX);
65#endif
66 VM_ASSERT((unsigned int)n <= ISEQ_BODY(iseq)->iseq_size);
67 ASSUME(n >= 0);
68 size_t pos = n; /* no overflow */
69 if (LIKELY(pos)) {
70 /* use pos-1 because PC points next instruction at the beginning of instruction */
71 pos--;
72 }
73#if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
74 else {
75 /* SDR() is not possible; that causes infinite loop. */
76 rb_print_backtrace(stderr);
77 __builtin_trap();
78 }
79#endif
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);
83#endif
84 return 1;
85 }
86}
87
88inline static int
89calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
90{
91 int lineno;
92 if (calc_pos(iseq, pc, &lineno, NULL)) return lineno;
93 return 0;
94}
95
96#ifdef USE_ISEQ_NODE_ID
97inline static int
98calc_node_id(const rb_iseq_t *iseq, const VALUE *pc)
99{
100 int node_id;
101 if (calc_pos(iseq, pc, NULL, &node_id)) return node_id;
102 return -1;
103}
104#endif
105
106int
107rb_vm_get_sourceline(const rb_control_frame_t *cfp)
108{
109 if (VM_FRAME_RUBYFRAME_P(cfp) && CFP_ISEQ(cfp)) {
110 const rb_iseq_t *iseq = CFP_ISEQ(cfp);
111 int line = calc_lineno(iseq, CFP_PC(cfp));
112 if (line != 0) {
113 return line;
114 }
115 else {
116 return ISEQ_BODY(iseq)->location.first_lineno;
117 }
118 }
119 else {
120 return 0;
121 }
122}
123
126 const rb_iseq_t *iseq;
127 const VALUE *pc;
129
132 VALUE btobj;
133};
134
135static void
136location_mark(void *ptr)
137{
138 struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
139 rb_gc_mark_movable(vfi->btobj);
140}
141
142static void
143location_ref_update(void *ptr)
144{
145 struct valued_frame_info *vfi = ptr;
146 vfi->btobj = rb_gc_location(vfi->btobj);
147}
148
149static void
150location_mark_entry(rb_backtrace_location_t *fi)
151{
152 rb_gc_mark((VALUE)fi->cme);
153 if (fi->iseq) rb_gc_mark_movable((VALUE)fi->iseq);
154}
155
156static const rb_data_type_t location_data_type = {
157 "frame_info",
158 {
159 location_mark,
161 NULL, // No external memory to report,
162 location_ref_update,
163 },
164 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
165};
166
167int
168rb_frame_info_p(VALUE obj)
169{
170 return rb_typeddata_is_kind_of(obj, &location_data_type);
171}
172
173static inline rb_backtrace_location_t *
174location_ptr(VALUE locobj)
175{
176 struct valued_frame_info *vloc;
177 TypedData_Get_Struct(locobj, struct valued_frame_info, &location_data_type, vloc);
178 return vloc->loc;
179}
180
181static int
182location_lineno(rb_backtrace_location_t *loc)
183{
184 if (loc->iseq) {
185 return calc_lineno(loc->iseq, loc->pc);
186 }
187 return 0;
188}
189
190/*
191 * Returns the line number of this frame.
192 *
193 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
194 *
195 * loc = c(0..1).first
196 * loc.lineno #=> 2
197 */
198static VALUE
199location_lineno_m(VALUE self)
200{
201 return INT2FIX(location_lineno(location_ptr(self)));
202}
203
204VALUE rb_mod_name0(VALUE klass, bool *permanent);
205
206VALUE
207rb_gen_method_name(VALUE owner, VALUE name)
208{
209 bool permanent;
210 if (RB_TYPE_P(owner, T_CLASS) || RB_TYPE_P(owner, T_MODULE)) {
211 if (RCLASS_SINGLETON_P(owner)) {
212 VALUE v = RCLASS_ATTACHED_OBJECT(owner);
213 if (RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE)) {
214 v = rb_mod_name0(v, &permanent);
215 if (permanent && !NIL_P(v)) {
216 return rb_sprintf("%"PRIsVALUE".%"PRIsVALUE, v, name);
217 }
218 }
219 }
220 else {
221 owner = rb_mod_name0(owner, &permanent);
222 if (permanent && !NIL_P(owner)) {
223 return rb_sprintf("%"PRIsVALUE"#%"PRIsVALUE, owner, name);
224 }
225 }
226 }
227 return name;
228}
229
230static VALUE
231calculate_iseq_label(VALUE owner, const rb_iseq_t *iseq)
232{
233retry:
234 switch (ISEQ_BODY(iseq)->type) {
235 case ISEQ_TYPE_TOP:
236 case ISEQ_TYPE_CLASS:
237 case ISEQ_TYPE_MAIN:
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: {
243 int level = 0;
244 const rb_iseq_t *orig_iseq = iseq;
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) {
248 level++;
249 }
250 iseq = ISEQ_BODY(iseq)->parent_iseq;
251 }
252 }
253 if (level <= 1) {
254 return rb_sprintf("block in %"PRIsVALUE, calculate_iseq_label(owner, iseq));
255 }
256 else {
257 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, calculate_iseq_label(owner, iseq));
258 }
259 }
260 case ISEQ_TYPE_RESCUE:
261 case ISEQ_TYPE_ENSURE:
262 case ISEQ_TYPE_EVAL:
263 iseq = ISEQ_BODY(iseq)->parent_iseq;
264 goto retry;
265 default:
266 rb_bug("calculate_iseq_label: unreachable");
267 }
268}
269
270static bool
271is_internal_location(const rb_iseq_t *iseq)
272{
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;
277}
278
279// Return true if a given location is a C method or supposed to behave like one.
280static inline bool
281location_cfunc_p(rb_backtrace_location_t *loc)
282{
283 if (!loc->cme) return false;
284
285 switch (loc->cme->def->type) {
286 case VM_METHOD_TYPE_CFUNC:
287 return true;
288 case VM_METHOD_TYPE_ISEQ:
289 return is_internal_location(loc->cme->def->body.iseq.iseqptr);
290 default:
291 return false;
292 }
293}
294
295/* Return the module where the running method body was actually defined.
296 *
297 * For an alias or a method installed via define_method(UnboundMethod), the CME's
298 * owner points at the site where the alias/copy was installed, not where the body
299 * was originally defined. Combined with the method name (taken from the original
300 * definition) that yields a "Class#method" pair which never existed -- e.g. an
301 * alias in a subclass reported as Child#original instead of Parent#original, or
302 * define_method(Original.instance_method(:m)) reported as A#m instead of
303 * Original#m ([Bug #22197]).
304 *
305 * The definition module is recorded once on the (reference-counted, shared)
306 * method definition when the body is first created, so every alias/define_method
307 * copy keeps pointing at the original module.
308 *
309 * The exception is module_function, which installs the instance method's *shared*
310 * def onto the module's singleton class as well: that copy must be labeled as a
311 * class method of the module (M.f), i.e. by its owner. Such a copy is exactly the
312 * one whose owner is the singleton class of the definition module. */
313static VALUE
314location_original_module(const rb_callable_method_entry_t *cme)
315{
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 &&
321 RB_TYPE_P(owner, T_CLASS) && RCLASS_SINGLETON_P(owner) &&
322 RCLASS_ATTACHED_OBJECT(owner) == defined_in) {
323 return owner;
324 }
325 return defined_in;
326}
327
328static VALUE
329location_label(rb_backtrace_location_t *loc)
330{
331 if (location_cfunc_p(loc)) {
332 return rb_gen_method_name(location_original_module(loc->cme), rb_id2str(loc->cme->def->original_id));
333 }
334 else {
335 return calculate_iseq_label(location_original_module(loc->cme), loc->iseq);
336 }
337}
338/*
339 * Returns the label of this frame.
340 *
341 * Usually consists of method, class, module, etc names with decoration.
342 *
343 * Consider the following example:
344 *
345 * def foo
346 * puts caller_locations(0).first.label
347 *
348 * 1.times do
349 * puts caller_locations(0).first.label
350 *
351 * 1.times do
352 * puts caller_locations(0).first.label
353 * end
354 * end
355 * end
356 *
357 * The result of calling +foo+ is this:
358 *
359 * foo
360 * block in foo
361 * block (2 levels) in foo
362 *
363 */
364static VALUE
365location_label_m(VALUE self)
366{
367 return location_label(location_ptr(self));
368}
369
370static VALUE
371location_base_label(rb_backtrace_location_t *loc)
372{
373 if (location_cfunc_p(loc)) {
374 return rb_id2str(loc->cme->def->original_id);
375 }
376
377 return rb_iseq_base_label(loc->iseq);
378}
379
380/*
381 * Returns the base label of this frame, which is usually equal to the label,
382 * without decoration.
383 *
384 * Consider the following example:
385 *
386 * def foo
387 * puts caller_locations(0).first.base_label
388 *
389 * 1.times do
390 * puts caller_locations(0).first.base_label
391 *
392 * 1.times do
393 * puts caller_locations(0).first.base_label
394 * end
395 * end
396 * end
397 *
398 * The result of calling +foo+ is this:
399 *
400 * foo
401 * foo
402 * foo
403 */
404static VALUE
405location_base_label_m(VALUE self)
406{
407 return location_base_label(location_ptr(self));
408}
409
410static const rb_iseq_t *
411location_iseq(rb_backtrace_location_t *loc)
412{
413 return loc->iseq;
414}
415
416/*
417 * Returns the file name of this frame. This will generally be an absolute
418 * path, unless the frame is in the main script, in which case it will be the
419 * script location passed on the command line.
420 *
421 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
422 *
423 * loc = c(0..1).first
424 * loc.path #=> caller_locations.rb
425 */
426static VALUE
427location_path_m(VALUE self)
428{
429 const rb_iseq_t *iseq = location_iseq(location_ptr(self));
430 return iseq ? rb_iseq_path(iseq) : Qnil;
431}
432
433#ifdef USE_ISEQ_NODE_ID
434static int
435location_node_id(rb_backtrace_location_t *loc)
436{
437 if (loc->iseq) {
438 return calc_node_id(loc->iseq, loc->pc);
439 }
440 return -1;
441}
442
443extern VALUE rb_e_script;
444
445static bool
446location_source_end_marker_p(const uint8_t *line, size_t length)
447{
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);
451}
452
453static bool
454location_source_hash_matches(VALUE source, uint64_t source_hash)
455{
456 StringValue(source);
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);
462
463 for (size_t index = 0; index < length; index++) {
464 if (bytes[index] != '\n') continue;
465
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) {
470 return true;
471 }
472 line_start = index + 1;
473 }
474
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) {
480 return true;
481 }
482 }
483
484 return rb_source_hash_finalize(&state) == source_hash;
485}
486
487static VALUE
488location_source_read(VALUE io)
489{
490 VALUE source = rb_str_buf_new(0);
491 VALUE line;
492
493 while (!NIL_P(line = rb_io_gets(io))) {
494 rb_str_buf_append(source, line);
495 }
496 return source;
497}
498
499static VALUE
500location_source_read_file(VALUE path)
501{
502 VALUE file = rb_file_open_str(path, "rb");
503 return rb_ensure(location_source_read, file, rb_io_close, file);
504}
505
506static bool
507location_code_location_equal(const rb_code_location_t *left, const rb_code_location_t *right)
508{
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;
513}
514
515static bool
516iseq_from_e_script_p(const rb_iseq_t *iseq, VALUE path, uint64_t source_hash)
517{
518 if (!RB_TYPE_P(path, T_STRING) ||
519 RSTRING_LEN(path) != 2 ||
520 memcmp(RSTRING_PTR(path), "-e", 2) != 0 ||
521 !RTEST(rb_e_script)) {
522 return false;
523 }
524 if (!location_source_hash_matches(rb_e_script, source_hash)) return false;
525
526 const rb_iseq_t *source_iseq = iseq;
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;
530 }
531
532 int node_id = ISEQ_BODY(iseq)->location.node_id;
533 if (node_id == -1) return false;
534
535 rb_code_location_t source_location;
536 bool found;
537 if (ISEQ_BODY(iseq)->prism) {
538 found = pm_node_source_location(rb_e_script, path, 1, node_id, &source_location);
539 }
540 else {
541 found = rb_ast_node_source_location(
542 rb_e_script,
543 path,
544 1,
545 node_id,
546 ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK,
547 node_id,
548 &source_location
549 );
550 }
551
552 return found && location_code_location_equal(
553 &source_location, &ISEQ_BODY(iseq)->location.code_location);
554}
555
556static int
557location_source_first_lineno(const rb_iseq_t *iseq, VALUE script_lines)
558{
559 const rb_iseq_t *source_iseq = iseq;
560
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;
565 }
566
567 return ISEQ_BODY(source_iseq)->location.first_lineno;
568}
569#endif
570
571/*
572 * call-seq:
573 * location.source_range -> Ruby::SourceRange
574 *
575 * Returns the Ruby::SourceRange for the Ruby expression associated with this
576 * backtrace location.
577 *
578 * On CRuby, this method re-reads and re-parses the source file to determine
579 * the range. File errors encountered while reading the source are propagated.
580 * RuntimeError is raised if required source location information is
581 * unavailable, or if the source has changed.
582 *
583 * RubyVM.keep_script_lines = true can be used to retain source files in
584 * memory and avoid re-reading them from the filesystem.
585 *
586 * Locations from eval'd code are only available with
587 * RubyVM.keep_script_lines = true.
588 */
589static VALUE
590location_source_range_m(VALUE self)
591{
592#ifdef USE_ISEQ_NODE_ID
593 rb_backtrace_location_t *backtrace_location = location_ptr(self);
594 const rb_iseq_t *iseq = location_iseq(backtrace_location);
595 if (!iseq) {
596 rb_raise(rb_eRuntimeError, "cannot get source range for location without Ruby bytecode");
597 }
598
599 rb_iseq_check(iseq);
600 int node_id = location_node_id(backtrace_location);
601 if (node_id == -1) {
602 rb_raise(rb_eRuntimeError, "cannot get source range for location without a node ID");
603 }
604 if (!ISEQ_BODY(iseq)->source_hash) {
605 rb_raise(rb_eRuntimeError, "cannot get source range because the source hash is unavailable");
606 }
607 uint64_t source_hash = ISEQ_BODY(iseq)->source_hash;
608
609 VALUE path = rb_iseq_path(iseq);
610 VALUE absolute_path = rb_iseq_realpath(iseq);
611 VALUE script_lines = ISEQ_SCRIPT_LINES(iseq);
612 VALUE source;
613 VALUE parser_path = path;
614 int first_lineno = 1;
615
616 if (!NIL_P(script_lines)) {
617 source = rb_ary_join(script_lines, Qnil);
618 first_lineno = location_source_first_lineno(iseq, script_lines);
619 }
620 else if (iseq_from_e_script_p(iseq, path, source_hash)) {
621 source = rb_e_script;
622 }
623 else if (!NIL_P(absolute_path)) {
624 source = location_source_read_file(absolute_path);
625 parser_path = absolute_path;
626 }
627 else {
628 rb_raise(rb_eArgError, "cannot get source range for location in eval");
629 }
630
631 if (NIL_P(parser_path)) {
632 parser_path = rb_str_new_cstr("(eval)");
633 }
634 if (!location_source_hash_matches(source, source_hash)) {
635 rb_raise(rb_eRuntimeError, "source has been modified");
636 }
637
638 rb_code_location_t code_location;
639 bool found;
640
641 if (ISEQ_BODY(iseq)->prism) {
642 found = pm_node_source_location(
643 source,
644 parser_path,
645 first_lineno,
646 node_id,
647 &code_location
648 );
649 }
650 else {
651 found = rb_ast_node_source_location(
652 source,
653 parser_path,
654 first_lineno,
655 node_id,
656 ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK,
657 ISEQ_BODY(iseq)->location.node_id,
658 &code_location
659 );
660 }
661
662 if (!found) {
663 rb_raise(rb_eRuntimeError, "cannot find node ID %d in parsed source", node_id);
664 }
665
666 return rb_source_range_new(path, absolute_path, &code_location);
667#else
668 rb_raise(rb_eRuntimeError, "cannot get source range because node IDs are disabled");
669#endif
670}
671
672int
673rb_get_node_id_from_frame_info(VALUE obj)
674{
675#ifdef USE_ISEQ_NODE_ID
676 rb_backtrace_location_t *loc = location_ptr(obj);
677 return location_node_id(loc);
678#else
679 return -1;
680#endif
681}
682
683const rb_iseq_t *
684rb_get_iseq_from_frame_info(VALUE obj)
685{
686 rb_backtrace_location_t *loc = location_ptr(obj);
687 const rb_iseq_t *iseq = location_iseq(loc);
688 return iseq;
689}
690
691static VALUE
692location_realpath(rb_backtrace_location_t *loc)
693{
694 if (loc->iseq) {
695 return rb_iseq_realpath(loc->iseq);
696 }
697 return Qnil;
698}
699
700/*
701 * Returns the full file path of this frame.
702 *
703 * Same as #path, except that it will return absolute path
704 * even if the frame is in the main script.
705 */
706static VALUE
707location_absolute_path_m(VALUE self)
708{
709 return location_realpath(location_ptr(self));
710}
711
712static VALUE
713location_format(VALUE file, int lineno, VALUE name)
714{
715 VALUE s = rb_enc_sprintf(rb_enc_compatible(file, name), "%"PRIsVALUE, file);
716 if (lineno != 0) {
717 rb_str_catf(s, ":%d", lineno);
718 }
719 rb_str_cat_cstr(s, ":in ");
720 if (NIL_P(name)) {
721 rb_str_cat_cstr(s, "unknown method");
722 }
723 else {
724 rb_str_catf(s, "'%"PRIsVALUE"'", name);
725 }
726 RB_GC_GUARD(name);
727 return s;
728}
729
730static VALUE
731location_to_str(rb_backtrace_location_t *loc)
732{
733 VALUE file, owner = Qnil, name;
734 int lineno;
735
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);
740 }
741 else {
742 file = GET_VM()->progname;
743 lineno = 0;
744 }
745 name = rb_gen_method_name(location_original_module(loc->cme), rb_id2str(loc->cme->def->original_id));
746 }
747 else {
748 file = rb_iseq_path(loc->iseq);
749 lineno = calc_lineno(loc->iseq, loc->pc);
750 if (loc->cme) {
751 owner = location_original_module(loc->cme);
752 }
753 name = calculate_iseq_label(owner, loc->iseq);
754 }
755
756 return location_format(file, lineno, name);
757}
758
759/*
760 * Returns a Kernel#caller style string representing this frame.
761 */
762static VALUE
763location_to_str_m(VALUE self)
764{
765 return location_to_str(location_ptr(self));
766}
767
768/*
769 * Returns the same as calling +inspect+ on the string representation of
770 * #to_str
771 */
772static VALUE
773location_inspect_m(VALUE self)
774{
775 return rb_str_inspect(location_to_str(location_ptr(self)));
776}
777
778typedef struct rb_backtrace_struct {
779 int backtrace_size;
780 VALUE strary;
781 VALUE locary;
782 rb_backtrace_location_t backtrace[1];
784
785static void
786backtrace_mark(void *ptr)
787{
788 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
789 size_t i, s = bt->backtrace_size;
790
791 for (i=0; i<s; i++) {
792 location_mark_entry(&bt->backtrace[i]);
793 }
794 rb_gc_mark_movable(bt->strary);
795 rb_gc_mark_movable(bt->locary);
796}
797
798static void
799location_update_entry(rb_backtrace_location_t *fi)
800{
801 fi->cme = (rb_callable_method_entry_t *)rb_gc_location((VALUE)fi->cme);
802 if (fi->iseq) {
803 fi->iseq = (rb_iseq_t *)rb_gc_location((VALUE)fi->iseq);
804 }
805}
806
807static void
808backtrace_update(void *ptr)
809{
810 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
811 size_t i, s = bt->backtrace_size;
812
813 for (i=0; i<s; i++) {
814 location_update_entry(&bt->backtrace[i]);
815 }
816 bt->strary = rb_gc_location(bt->strary);
817 bt->locary = rb_gc_location(bt->locary);
818}
819
820static const rb_data_type_t backtrace_data_type = {
821 "backtrace",
822 {
823 backtrace_mark,
825 NULL, // No external memory to report,
826 backtrace_update,
827 },
828 /* Cannot set the RUBY_TYPED_EMBEDDABLE flag because the loc of frame_info
829 * points elements in the backtrace array. This can cause the loc to become
830 * incorrect if this backtrace object is moved by compaction. */
831 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
832};
833
834int
835rb_backtrace_p(VALUE obj)
836{
837 return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
838}
839
840static VALUE
841backtrace_alloc_capa(long num_frames, rb_backtrace_t **backtrace)
842{
843 size_t memsize = offsetof(rb_backtrace_t, backtrace) + num_frames * sizeof(rb_backtrace_location_t);
844 VALUE btobj = rb_data_typed_object_zalloc(rb_cBacktrace, memsize, &backtrace_data_type);
845 TypedData_Get_Struct(btobj, rb_backtrace_t, &backtrace_data_type, *backtrace);
846 return btobj;
847}
848
849/* Duplicate the backtrace so an exception copy carries no raw pointer to the sender's.
850 * A frame only references shareable iseq / method-entry imemos, so duplicating is safe;
851 * the lazily built strings and location array are regenerated on the receiving side. */
852VALUE
853rb_backtrace_dup(VALUE btobj)
854{
855 rb_backtrace_t *src, *dst;
856 TypedData_Get_Struct(btobj, rb_backtrace_t, &backtrace_data_type, src);
857
858 VALUE dupobj = backtrace_alloc_capa(src->backtrace_size, &dst);
859 dst->backtrace_size = src->backtrace_size;
860 MEMCPY(dst->backtrace, src->backtrace, rb_backtrace_location_t, src->backtrace_size);
861 for (int i = 0; i < dst->backtrace_size; i++) {
862 const rb_backtrace_location_t *fi = &dst->backtrace[i];
863 if (fi->cme) RB_OBJ_WRITTEN(dupobj, Qundef, (VALUE)fi->cme);
864 if (fi->iseq) RB_OBJ_WRITTEN(dupobj, Qundef, (VALUE)fi->iseq);
865 }
866 return dupobj;
867}
868
869
870/* Copy a backtrace's frames into an off-heap blob for a Ractor copy courier. A frame
871 * only references shareable iseq / method-entry imemos, so the blob can carry them as
872 * they are. It has no compaction update hook, so rb_backtrace_blob_mark pins them
873 * (rb_gc_mark, not _movable) for as long as the message is in flight. */
874void *
875rb_backtrace_blob_dump(VALUE btobj, int *size_out)
876{
877 rb_backtrace_t *bt;
878 TypedData_Get_Struct(btobj, rb_backtrace_t, &backtrace_data_type, bt);
879
880 int size = bt->backtrace_size;
881 *size_out = size;
882 rb_backtrace_location_t *blob = ALLOC_N(rb_backtrace_location_t, size > 0 ? size : 1);
883 MEMCPY(blob, bt->backtrace, rb_backtrace_location_t, size);
884 return blob;
885}
886
887VALUE
888rb_backtrace_blob_load(const void *blob_, int size)
889{
890 const rb_backtrace_location_t *blob = blob_;
891 rb_backtrace_t *dst;
892 VALUE btobj = backtrace_alloc_capa(size, &dst);
893
894 dst->backtrace_size = size;
895 MEMCPY(dst->backtrace, blob, rb_backtrace_location_t, size);
896 for (int i = 0; i < size; i++) {
897 const rb_backtrace_location_t *fi = &dst->backtrace[i];
898 if (fi->cme) RB_OBJ_WRITTEN(btobj, Qundef, (VALUE)fi->cme);
899 if (fi->iseq) RB_OBJ_WRITTEN(btobj, Qundef, (VALUE)fi->iseq);
900 }
901 /* strary / locary stay unset: the receiver rebuilds them lazily. */
902 return btobj;
903}
904
905void
906rb_backtrace_blob_mark(const void *blob_, int size)
907{
908 const rb_backtrace_location_t *blob = blob_;
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);
912 }
913}
914
915static long
916backtrace_size(const rb_execution_context_t *ec)
917{
918 const rb_control_frame_t *last_cfp = ec->cfp;
919 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
920
921 if (start_cfp == NULL) {
922 return -1;
923 }
924
925 start_cfp =
926 RUBY_VM_NEXT_CONTROL_FRAME(
927 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
928
929 if (start_cfp < last_cfp) {
930 return 0;
931 }
932
933 return start_cfp - last_cfp + 1;
934}
935
936static bool
937is_rescue_or_ensure_frame(const rb_control_frame_t *cfp)
938{
939 enum rb_iseq_type type = ISEQ_BODY(CFP_ISEQ(cfp))->type;
940 return type == ISEQ_TYPE_RESCUE || type == ISEQ_TYPE_ENSURE;
941}
942
943static void
944bt_backpatch_loc(unsigned long backpatch_counter, rb_backtrace_location_t *loc, const rb_iseq_t *iseq, const VALUE *pc)
945{
946 for (; backpatch_counter > 0; backpatch_counter--, loc--) {
947 loc->iseq = iseq;
948 loc->pc = pc;
949 }
950}
951
952static VALUE location_create(rb_backtrace_location_t *srcloc, void *btobj);
953
954static void
955bt_yield_loc(rb_backtrace_location_t *loc, long num_frames, VALUE btobj)
956{
957 for (; num_frames > 0; num_frames--, loc++) {
958 rb_yield(location_create(loc, (void *)btobj));
959 }
960}
961
962static VALUE
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)
964{
965 const rb_control_frame_t *cfp = ec->cfp;
966 const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
967 ptrdiff_t size;
968 rb_backtrace_t *bt = NULL;
969 VALUE btobj = Qnil;
970 rb_backtrace_location_t *loc = NULL;
971 unsigned long backpatch_counter = 0;
972 bool skip_next_frame = FALSE;
973
974 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
975 if (end_cfp == NULL) {
976 num_frames = 0;
977 }
978 else {
979 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
980
981 /*
982 * top frame (dummy) <- RUBY_VM_END_CONTROL_FRAME
983 * top frame (dummy) <- end_cfp
984 * top frame <- main script
985 * top frame
986 * ...
987 * 2nd frame <- lev:0
988 * current frame <- ec->cfp
989 */
990
991 size = end_cfp - cfp + 1;
992 if (size < 0) {
993 num_frames = 0;
994 }
995 else if (num_frames < 0 || num_frames > size) {
996 num_frames = size;
997 }
998 }
999
1000 btobj = backtrace_alloc_capa(num_frames, &bt);
1001
1002 bt->backtrace_size = 0;
1003 if (num_frames == 0) {
1004 if (start_too_large) *start_too_large = 0;
1005 return btobj;
1006 }
1007
1008 for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
1009 if (CFP_ISEQ(cfp)) {
1010 if (CFP_PC(cfp)) {
1011 if (start_frame > 0) {
1012 start_frame--;
1013 }
1014 else {
1015 bool internal = is_internal_location(CFP_ISEQ(cfp));
1016 if (skip_internal && internal) continue;
1017 if (!skip_next_frame) {
1018 const rb_iseq_t *iseq = CFP_ISEQ(cfp);
1019 const VALUE *pc = CFP_PC(cfp);
1020 if (internal && backpatch_counter > 0) {
1021 // To keep only one internal frame, discard the previous backpatch frames
1022 bt->backtrace_size -= backpatch_counter;
1023 backpatch_counter = 0;
1024 }
1025 loc = &bt->backtrace[bt->backtrace_size++];
1026 RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1027 // internal frames (`<internal:...>`) should behave like C methods
1028 if (internal) {
1029 // Typically, these iseq and pc are not needed because they will be backpatched later.
1030 // But when the call stack starts with an internal frame (i.e., prelude.rb),
1031 // they will be used to show the `<internal:...>` location.
1032 RB_OBJ_WRITE(btobj, &loc->iseq, iseq);
1033 loc->pc = pc;
1034 backpatch_counter++;
1035 }
1036 else {
1037 RB_OBJ_WRITE(btobj, &loc->iseq, iseq);
1038 if ((VM_FRAME_TYPE(cfp) & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_DUMMY) {
1039 loc->pc = NULL; // means location.first_lineno
1040 }
1041 else {
1042 loc->pc = pc;
1043 }
1044 bt_backpatch_loc(backpatch_counter, loc-1, iseq, pc);
1045 if (do_yield) {
1046 bt_yield_loc(loc - backpatch_counter, backpatch_counter+1, btobj);
1047 }
1048 backpatch_counter = 0;
1049 }
1050 }
1051 skip_next_frame = is_rescue_or_ensure_frame(cfp);
1052 }
1053 }
1054 }
1055 else {
1056 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
1057 if (start_frame > 0) {
1058 start_frame--;
1059 }
1060 else {
1061 loc = &bt->backtrace[bt->backtrace_size++];
1062 RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1063 loc->iseq = NULL;
1064 loc->pc = NULL;
1065 backpatch_counter++;
1066 }
1067 }
1068 }
1069
1070 // When a backtrace entry corresponds to a method defined in C (e.g. rb_define_method), the reported file:line
1071 // is the one of the caller Ruby frame, so if the last entry is a C frame we find the caller Ruby frame here.
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); // ISEQ_TYPE_RESCUE/ISEQ_TYPE_ENSURE should have a caller Ruby ISEQ, not a cfunc
1076 bt_backpatch_loc(backpatch_counter, loc, CFP_ISEQ(cfp), CFP_PC(cfp));
1077 RB_OBJ_WRITTEN(btobj, Qundef, CFP_ISEQ(cfp));
1078 if (do_yield) {
1079 bt_yield_loc(loc - backpatch_counter + 1, backpatch_counter, btobj);
1080 }
1081 break;
1082 }
1083 }
1084 }
1085
1086 if (start_too_large) *start_too_large = (start_frame > 0 ? -1 : 0);
1087 return btobj;
1088}
1089
1090VALUE
1091rb_ec_backtrace_object(const rb_execution_context_t *ec)
1092{
1093 return rb_ec_partial_backtrace_object(ec, RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES, NULL, FALSE, FALSE);
1094}
1095
1096static VALUE
1097backtrace_collect(rb_backtrace_t *bt, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
1098{
1099 VALUE btary;
1100 int i;
1101
1102 btary = rb_ary_new2(bt->backtrace_size);
1103
1104 for (i=0; i<bt->backtrace_size; i++) {
1105 rb_backtrace_location_t *loc = &bt->backtrace[i];
1106 rb_ary_push(btary, func(loc, arg));
1107 }
1108
1109 return btary;
1110}
1111
1112static VALUE
1113location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
1114{
1115 return location_to_str(loc);
1116}
1117
1118static VALUE
1119backtrace_to_str_ary(VALUE self)
1120{
1121 VALUE r;
1122 rb_backtrace_t *bt;
1123 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
1124 r = backtrace_collect(bt, location_to_str_dmyarg, 0);
1125 RB_GC_GUARD(self);
1126 return r;
1127}
1128
1129VALUE
1130rb_backtrace_to_str_ary(VALUE self)
1131{
1132 rb_backtrace_t *bt;
1133 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
1134
1135 if (!bt->strary) {
1136 RB_OBJ_WRITE(self, &bt->strary, backtrace_to_str_ary(self));
1137 }
1138 return bt->strary;
1139}
1140
1141static VALUE
1142location_create(rb_backtrace_location_t *srcloc, void *btobj)
1143{
1144 VALUE obj;
1145 struct valued_frame_info *vloc;
1146 obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
1147
1148 vloc->loc = srcloc;
1149 RB_OBJ_WRITE(obj, &vloc->btobj, (VALUE)btobj);
1150
1151 return obj;
1152}
1153
1154static VALUE
1155backtrace_to_location_ary(VALUE self)
1156{
1157 VALUE r;
1158 rb_backtrace_t *bt;
1159 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
1160 r = backtrace_collect(bt, location_create, (void *)self);
1161 RB_GC_GUARD(self);
1162 return r;
1163}
1164
1165VALUE
1166rb_backtrace_to_location_ary(VALUE self)
1167{
1168 rb_backtrace_t *bt;
1169 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
1170
1171 if (!bt->locary) {
1172 RB_OBJ_WRITE(self, &bt->locary, backtrace_to_location_ary(self));
1173 }
1174 return bt->locary;
1175}
1176
1177VALUE
1178rb_location_ary_to_backtrace(VALUE ary)
1179{
1180 if (!RB_TYPE_P(ary, T_ARRAY) || RARRAY_LEN(ary) == 0 || !rb_frame_info_p(RARRAY_AREF(ary, 0))) {
1181 return Qfalse;
1182 }
1183
1184 rb_backtrace_t *new_backtrace;
1185 long num_frames = RARRAY_LEN(ary);
1186 VALUE btobj = backtrace_alloc_capa(num_frames, &new_backtrace);
1187
1188 for (long index = 0; index < RARRAY_LEN(ary); index++) {
1189 VALUE locobj = RARRAY_AREF(ary, index);
1190
1191 if (!rb_frame_info_p(locobj)) {
1192 return Qfalse;
1193 }
1194
1195 struct valued_frame_info *src_vloc;
1196 TypedData_Get_Struct(locobj, struct valued_frame_info, &location_data_type, src_vloc);
1197
1198 rb_backtrace_location_t *dst_location = &new_backtrace->backtrace[index];
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;
1202
1203 new_backtrace->backtrace_size++;
1204
1205 RB_GC_GUARD(locobj);
1206 }
1207
1208 return btobj;
1209}
1210
1211static VALUE
1212backtrace_dump_data(VALUE self)
1213{
1214 VALUE str = rb_backtrace_to_str_ary(self);
1215 return str;
1216}
1217
1218static VALUE
1219backtrace_load_data(VALUE self, VALUE str)
1220{
1221 rb_backtrace_t *bt;
1222 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
1223 RB_OBJ_WRITE(self, &bt->strary, str);
1224 return self;
1225}
1226
1227/*
1228 * call-seq: Thread::Backtrace::limit -> integer
1229 *
1230 * Returns maximum backtrace length set by <tt>--backtrace-limit</tt>
1231 * command-line option. The default is <tt>-1</tt> which means unlimited
1232 * backtraces. If the value is zero or positive, the error backtraces,
1233 * produced by Exception#full_message, are abbreviated and the extra lines
1234 * are replaced by <tt>... 3 levels... </tt>
1235 *
1236 * $ ruby -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
1237 * - 1
1238 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': Failed to open TCP connection to wrong.address:80 (getaddrinfo: Name or service not known) (SocketError)
1239 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
1240 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
1241 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
1242 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
1243 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
1244 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
1245 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
1246 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
1247 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
1248 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
1249 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
1250 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
1251 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
1252 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
1253 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
1254 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
1255 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
1256 * from -e:1:in `<main>'
1257 *
1258 * $ ruby --backtrace-limit 2 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
1259 * 2
1260 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': Failed to open TCP connection to wrong.address:80 (getaddrinfo: Name or service not known) (SocketError)
1261 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
1262 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
1263 * ... 7 levels...
1264 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
1265 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
1266 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
1267 * ... 7 levels...
1268 *
1269 * $ ruby --backtrace-limit 0 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
1270 * 0
1271 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': Failed to open TCP connection to wrong.address:80 (getaddrinfo: Name or service not known) (SocketError)
1272 * ... 9 levels...
1273 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
1274 * ... 9 levels...
1275 *
1276 */
1277static VALUE
1278backtrace_limit(VALUE self)
1279{
1280 return LONG2NUM(rb_backtrace_length_limit);
1281}
1282
1283/* :nodoc: */
1284static VALUE
1285backtrace_clone(VALUE self)
1286{
1287 rb_backtrace_t *bt;
1288 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
1289
1290 rb_backtrace_t *other_bt;
1291 VALUE clone = backtrace_alloc_capa(bt->backtrace_size, &other_bt);
1292
1293 rb_obj_clone_setup(self, clone, Qfalse);
1294
1295 return clone;
1296}
1297
1298/* :nodoc: */
1299static VALUE
1300backtrace_dup(VALUE self)
1301{
1302 rb_notimplement();
1303
1305}
1306
1307/* :nodoc: */
1308static VALUE
1309backtrace_initialize_copy(VALUE self, VALUE original)
1310{
1311 rb_backtrace_t *bt;
1312 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
1313
1314 rb_backtrace_t *original_bt;
1315 TypedData_Get_Struct(original, rb_backtrace_t, &backtrace_data_type, original_bt);
1316
1317 bt->backtrace_size = original_bt->backtrace_size;
1318 MEMCPY(bt->backtrace, original_bt->backtrace, rb_backtrace_location_t, original_bt->backtrace_size);
1319 rb_gc_writebarrier_remember(self);
1320
1321 return Qnil;
1322}
1323
1324VALUE
1325rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n)
1326{
1327 return rb_backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, FALSE));
1328}
1329
1330VALUE
1331rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal)
1332{
1333 return rb_backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal, FALSE));
1334}
1335
1336/* make old style backtrace directly */
1337
1338static void
1339backtrace_each(const rb_execution_context_t *ec,
1340 void (*init)(void *arg, size_t size),
1341 void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
1342 void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
1343 void *arg)
1344{
1345 const rb_control_frame_t *last_cfp = ec->cfp;
1346 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
1347 const rb_control_frame_t *cfp;
1348 ptrdiff_t size, i;
1349
1350 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
1351 if (start_cfp == NULL) {
1352 init(arg, 0);
1353 return;
1354 }
1355
1356 /* <- start_cfp (end control frame)
1357 * top frame (dummy)
1358 * top frame (dummy)
1359 * top frame <- start_cfp
1360 * top frame
1361 * ...
1362 * 2nd frame <- lev:0
1363 * current frame <- ec->cfp
1364 */
1365
1366 start_cfp =
1367 RUBY_VM_NEXT_CONTROL_FRAME(
1368 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
1369
1370 if (start_cfp < last_cfp) {
1371 size = 0;
1372 }
1373 else {
1374 size = start_cfp - last_cfp + 1;
1375 }
1376
1377 init(arg, size);
1378
1379 /* SDR(); */
1380 for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
1381 /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
1382 if (CFP_ISEQ(cfp)) {
1383 if (CFP_PC(cfp)) {
1384 iter_iseq(arg, cfp);
1385 }
1386 }
1387 else {
1388 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
1389 const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
1390 ID mid = me->def->original_id;
1391
1392 iter_cfunc(arg, cfp, mid);
1393 }
1394 }
1395}
1396
1398 VALUE filename;
1399 int lineno;
1400 void (*func)(void *data, VALUE file, int lineno, VALUE name);
1401 void *data; /* result */
1402};
1403
1404static void
1405oldbt_init(void *ptr, size_t dmy)
1406{
1407 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
1408 arg->filename = GET_VM()->progname;
1409 arg->lineno = 0;
1410}
1411
1412static void
1413oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
1414{
1415 const rb_iseq_t *iseq = CFP_ISEQ(cfp);
1416 const VALUE *pc = CFP_PC(cfp);
1417 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
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);
1421
1422 (arg->func)(arg->data, file, lineno, name);
1423}
1424
1425static void
1426oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
1427{
1428 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
1429 VALUE file = arg->filename;
1430 VALUE name = rb_id2str(mid);
1431 int lineno = arg->lineno;
1432
1433 (arg->func)(arg->data, file, lineno, name);
1434}
1435
1436static void
1437oldbt_print(void *data, VALUE file, int lineno, VALUE name)
1438{
1439 FILE *fp = (FILE *)data;
1440
1441 if (NIL_P(name)) {
1442 fprintf(fp, "\tfrom %.*s:%d:in unknown method\n",
1443 RSTRING_LENINT(file), RSTRING_PTR(file), lineno);
1444 }
1445 else {
1446 fprintf(fp, "\tfrom %.*s:%d:in '%.*s'\n",
1447 RSTRING_LENINT(file), RSTRING_PTR(file), lineno,
1448 RSTRING_LENINT(name), RSTRING_PTR(name));
1449 }
1450}
1451
1452static void
1453vm_backtrace_print(FILE *fp)
1454{
1455 struct oldbt_arg arg;
1456
1457 arg.func = oldbt_print;
1458 arg.data = (void *)fp;
1459 backtrace_each(GET_EC(),
1460 oldbt_init,
1461 oldbt_iter_iseq,
1462 oldbt_iter_cfunc,
1463 &arg);
1464}
1465
1467 FILE *fp;
1468 int count;
1469};
1470
1471static void
1472oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
1473{
1474 struct oldbt_bugreport_arg *p = arg;
1475 FILE *fp = p->fp;
1476 const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
1477 int filename_len = NIL_P(file) ? 4 : RSTRING_LENINT(file);
1478 if (!p->count) {
1479 fprintf(fp, "-- Ruby level backtrace information "
1480 "----------------------------------------\n");
1481 p->count = 1;
1482 }
1483 if (NIL_P(method)) {
1484 fprintf(fp, "%.*s:%d:in unknown method\n",
1485 filename_len, filename, line);
1486 }
1487 else {
1488 fprintf(fp, "%.*s:%d:in '%.*s'\n",
1489 filename_len, filename, line,
1490 RSTRING_LENINT(method), RSTRING_PTR(method));
1491 }
1492}
1493
1494void
1495rb_backtrace_print_as_bugreport(FILE *fp)
1496{
1497 struct oldbt_arg arg;
1498 struct oldbt_bugreport_arg barg = {fp, 0};
1499
1500 arg.func = oldbt_bugreport;
1501 arg.data = &barg;
1502
1503 backtrace_each(GET_EC(),
1504 oldbt_init,
1505 oldbt_iter_iseq,
1506 oldbt_iter_cfunc,
1507 &arg);
1508}
1509
1510void
1512{
1513 vm_backtrace_print(stderr);
1514}
1515
1517 VALUE (*iter)(VALUE recv, VALUE str);
1518 VALUE output;
1519};
1520
1521static void
1522oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
1523{
1524 const struct print_to_arg *arg = data;
1525 VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
1526
1527 if (NIL_P(name)) {
1528 rb_str_cat2(str, "unknown method\n");
1529 }
1530 else {
1531 rb_str_catf(str, " '%"PRIsVALUE"'\n", name);
1532 }
1533 (*arg->iter)(arg->output, str);
1534}
1535
1536void
1537rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output)
1538{
1539 struct oldbt_arg arg;
1540 struct print_to_arg parg;
1541
1542 parg.iter = iter;
1543 parg.output = output;
1544 arg.func = oldbt_print_to;
1545 arg.data = &parg;
1546 backtrace_each(GET_EC(),
1547 oldbt_init,
1548 oldbt_iter_iseq,
1549 oldbt_iter_cfunc,
1550 &arg);
1551}
1552
1553VALUE
1554rb_make_backtrace(void)
1555{
1556 return rb_ec_backtrace_str_ary(GET_EC(), RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES);
1557}
1558
1559static long
1560ec_backtrace_range(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, long *len_ptr)
1561{
1562 VALUE level, vn, opts;
1563 long lev, n;
1564
1565 rb_scan_args(argc, argv, "02:", &level, &vn, &opts);
1566
1567 if (!NIL_P(opts)) {
1568 rb_get_kwargs(opts, (ID []){0}, 0, 0, NULL);
1569 }
1570 if (argc == 2 && NIL_P(vn)) argc--;
1571
1572 switch (argc) {
1573 case 0:
1574 lev = lev_default + lev_plus;
1575 n = RUBY_ALL_BACKTRACE_LINES;
1576 break;
1577 case 1:
1578 {
1579 long beg, len, bt_size = backtrace_size(ec);
1580 switch (rb_range_beg_len(level, &beg, &len, bt_size - lev_plus, 0)) {
1581 case Qfalse:
1582 lev = NUM2LONG(level);
1583 if (lev < 0) {
1584 rb_raise(rb_eArgError, "negative level (%ld)", lev);
1585 }
1586 lev += lev_plus;
1587 n = RUBY_ALL_BACKTRACE_LINES;
1588 break;
1589 case Qnil:
1590 return -1;
1591 default:
1592 lev = beg + lev_plus;
1593 n = len;
1594 break;
1595 }
1596 break;
1597 }
1598 case 2:
1599 lev = NUM2LONG(level);
1600 n = NUM2LONG(vn);
1601 if (lev < 0) {
1602 rb_raise(rb_eArgError, "negative level (%ld)", lev);
1603 }
1604 if (n < 0) {
1605 rb_raise(rb_eArgError, "negative size (%ld)", n);
1606 }
1607 lev += lev_plus;
1608 break;
1609 default:
1610 lev = n = 0; /* to avoid warning */
1611 break;
1612 }
1613
1614 *len_ptr = n;
1615 return lev;
1616}
1617
1618static VALUE
1619ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str)
1620{
1621 long lev, n;
1622 VALUE btval, r;
1623 int too_large;
1624
1625 lev = ec_backtrace_range(ec, argc, argv, lev_default, lev_plus, &n);
1626 if (lev < 0) return Qnil;
1627
1628 if (n == 0) {
1629 return rb_ary_new();
1630 }
1631
1632 btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE, FALSE);
1633
1634 if (too_large) {
1635 return Qnil;
1636 }
1637
1638 if (to_str) {
1639 r = backtrace_to_str_ary(btval);
1640 }
1641 else {
1642 r = backtrace_to_location_ary(btval);
1643 }
1644 RB_GC_GUARD(btval);
1645 return r;
1646}
1647
1648static VALUE
1649thread_backtrace_to_ary(int argc, const VALUE *argv, VALUE thval, int to_str)
1650{
1651 rb_thread_t *target_th = rb_thread_ptr(thval);
1652
1653 if (target_th->to_kill || target_th->status == THREAD_KILLED)
1654 return Qnil;
1655
1656 return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1657}
1658
1659VALUE
1660rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval)
1661{
1662 return thread_backtrace_to_ary(argc, argv, thval, 1);
1663}
1664
1665VALUE
1666rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval)
1667{
1668 return thread_backtrace_to_ary(argc, argv, thval, 0);
1669}
1670
1671VALUE
1672rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1673{
1674 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1675}
1676
1677VALUE
1678rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1679{
1680 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1681}
1682
1683/*
1684 * call-seq:
1685 * caller(start=1, length=nil) -> array or nil
1686 * caller(range) -> array or nil
1687 *
1688 * Returns the current execution stack---an array containing strings in
1689 * the form <code>file:line</code> or <code>file:line: in
1690 * `method'</code>.
1691 *
1692 * The optional _start_ parameter determines the number of initial stack
1693 * entries to omit from the top of the stack.
1694 *
1695 * A second optional +length+ parameter can be used to limit how many entries
1696 * are returned from the stack.
1697 *
1698 * Returns +nil+ if _start_ is greater than the size of
1699 * current execution stack.
1700 *
1701 * Optionally you can pass a range, which will return an array containing the
1702 * entries within the specified range.
1703 *
1704 * def a(skip)
1705 * caller(skip)
1706 * end
1707 * def b(skip)
1708 * a(skip)
1709 * end
1710 * def c(skip)
1711 * b(skip)
1712 * end
1713 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1714 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1715 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1716 * c(3) #=> ["prog:13:in `<main>'"]
1717 * c(4) #=> []
1718 * c(5) #=> nil
1719 */
1720
1721static VALUE
1722rb_f_caller(int argc, VALUE *argv, VALUE _)
1723{
1724 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1725}
1726
1727/*
1728 * call-seq:
1729 * caller_locations(start=1, length=nil) -> array or nil
1730 * caller_locations(range) -> array or nil
1731 *
1732 * Returns the current execution stack---an array containing
1733 * backtrace location objects.
1734 *
1735 * See Thread::Backtrace::Location for more information.
1736 *
1737 * The optional _start_ parameter determines the number of initial stack
1738 * entries to omit from the top of the stack.
1739 *
1740 * A second optional +length+ parameter can be used to limit how many entries
1741 * are returned from the stack.
1742 *
1743 * Returns +nil+ if _start_ is greater than the size of
1744 * current execution stack.
1745 *
1746 * Optionally you can pass a range, which will return an array containing the
1747 * entries within the specified range.
1748 */
1749static VALUE
1750rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
1751{
1752 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1753}
1754
1755/*
1756 * call-seq:
1757 * Thread.each_caller_location(...) { |loc| ... } -> nil
1758 *
1759 * Yields each frame of the current execution stack as a
1760 * backtrace location object.
1761 */
1762static VALUE
1763each_caller_location(int argc, VALUE *argv, VALUE _)
1764{
1765 rb_execution_context_t *ec = GET_EC();
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);
1769 }
1770 return Qnil;
1771}
1772
1773static VALUE
1774backtrace_no_allocator(VALUE klass)
1775{
1776 rb_notimplement();
1777
1779}
1780
1781/* called from Init_vm() in vm.c */
1782void
1783Init_vm_backtrace(void)
1784{
1785 /*
1786 * An internal representation of the backtrace. The user will never interact with
1787 * objects of this class directly, but class methods can be used to get backtrace
1788 * settings of the current session.
1789 */
1790 rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
1791
1792 // Can't undefine the allocator, as it's needed as a key by Marshal
1793 rb_define_alloc_func(rb_cBacktrace, backtrace_no_allocator);
1794 rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
1795
1796 rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
1797 rb_define_singleton_method(rb_cBacktrace, "limit", backtrace_limit, 0);
1798
1799 rb_define_method(rb_cBacktrace, "clone", backtrace_clone, 0);
1800 rb_define_method(rb_cBacktrace, "dup", backtrace_dup, 0);
1801 rb_define_method(rb_cBacktrace, "initialize_copy", backtrace_initialize_copy, 1);
1802
1803 /*
1804 * An object representation of a stack frame, initialized by
1805 * Kernel#caller_locations.
1806 *
1807 * For example:
1808 *
1809 * # caller_locations.rb
1810 * def a(skip)
1811 * caller_locations(skip)
1812 * end
1813 * def b(skip)
1814 * a(skip)
1815 * end
1816 * def c(skip)
1817 * b(skip)
1818 * end
1819 *
1820 * c(0..2).map do |call|
1821 * puts call.to_s
1822 * end
1823 *
1824 * Running <code>ruby caller_locations.rb</code> will produce:
1825 *
1826 * caller_locations.rb:2:in `a'
1827 * caller_locations.rb:5:in `b'
1828 * caller_locations.rb:8:in `c'
1829 *
1830 * Here's another example with a slightly different result:
1831 *
1832 * # foo.rb
1833 * class Foo
1834 * attr_accessor :locations
1835 * def initialize(skip)
1836 * @locations = caller_locations(skip)
1837 * end
1838 * end
1839 *
1840 * Foo.new(0..2).locations.map do |call|
1841 * puts call.to_s
1842 * end
1843 *
1844 * Now run <code>ruby foo.rb</code> and you should see:
1845 *
1846 * init.rb:4:in `initialize'
1847 * init.rb:8:in `new'
1848 * init.rb:8:in `<main>'
1849 */
1850 rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
1851 rb_undef_alloc_func(rb_cBacktraceLocation);
1852 rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
1853 rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
1854 rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
1855 rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
1856 rb_define_method(rb_cBacktraceLocation, "path", location_path_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);
1859 rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
1860 rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
1861
1862 rb_define_global_function("caller", rb_f_caller, -1);
1863 rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1864
1865 rb_define_singleton_method(rb_cThread, "each_caller_location", each_caller_location, -1);
1866}
1867
1868/* debugger API */
1869
1870RUBY_SYMBOL_EXPORT_BEGIN
1871
1872RUBY_SYMBOL_EXPORT_END
1873
1876 rb_control_frame_t *cfp;
1877 VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1878 VALUE raw_backtrace;
1879};
1880
1881enum {
1882 CALLER_BINDING_SELF,
1883 CALLER_BINDING_CLASS,
1884 CALLER_BINDING_BINDING,
1885 CALLER_BINDING_ISEQ,
1886 CALLER_BINDING_CFP,
1887 CALLER_BINDING_LOC,
1888 CALLER_BINDING_DEPTH,
1889};
1890
1892 VALUE ary;
1893 const rb_execution_context_t *ec;
1894 VALUE btobj;
1895 rb_backtrace_t *bt;
1896};
1897
1898static void
1899collect_caller_bindings_init(void *arg, size_t num_frames)
1900{
1902 data->btobj = backtrace_alloc_capa(num_frames, &data->bt);
1903}
1904
1905static VALUE
1906get_klass(const rb_control_frame_t *cfp)
1907{
1908 VALUE klass;
1909 if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
1910 if (RB_TYPE_P(klass, T_ICLASS)) {
1911 return RBASIC(klass)->klass;
1912 }
1913 else {
1914 return klass;
1915 }
1916 }
1917 else {
1918 return Qnil;
1919 }
1920}
1921
1922static int
1923frame_depth(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
1924{
1925 VM_ASSERT(RUBY_VM_END_CONTROL_FRAME(ec) >= cfp);
1926 return (int)(RUBY_VM_END_CONTROL_FRAME(ec) - cfp);
1927}
1928
1929static void
1930collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
1931{
1933 VALUE frame = rb_ary_new2(6);
1934 const rb_iseq_t *iseq = CFP_ISEQ(cfp);
1935
1936 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1937 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1938 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
1939 rb_ary_store(frame, CALLER_BINDING_ISEQ, iseq ? (VALUE)iseq : Qnil);
1940 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1941
1942 rb_backtrace_location_t *loc = &data->bt->backtrace[data->bt->backtrace_size++];
1943 RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1944 RB_OBJ_WRITE(data->btobj, &loc->iseq, iseq);
1945 loc->pc = CFP_PC(cfp);
1946 VALUE vloc = location_create(loc, (void *)data->btobj);
1947 rb_ary_store(frame, CALLER_BINDING_LOC, vloc);
1948
1949 rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
1950
1951 rb_ary_push(data->ary, frame);
1952}
1953
1954static void
1955collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
1956{
1958 VALUE frame = rb_ary_new2(6);
1959
1960 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1961 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1962 rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
1963 rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
1964 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1965
1966 rb_backtrace_location_t *loc = &data->bt->backtrace[data->bt->backtrace_size++];
1967 RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1968 loc->iseq = NULL;
1969 loc->pc = NULL;
1970 VALUE vloc = location_create(loc, (void *)data->btobj);
1971 rb_ary_store(frame, CALLER_BINDING_LOC, vloc);
1972
1973 rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
1974
1975 rb_ary_push(data->ary, frame);
1976}
1977
1978static VALUE
1979collect_caller_bindings(const rb_execution_context_t *ec)
1980{
1981 int i;
1982 VALUE result;
1983 struct collect_caller_bindings_data data = {
1984 rb_ary_new(), ec
1985 };
1986
1987 backtrace_each(ec,
1988 collect_caller_bindings_init,
1989 collect_caller_bindings_iseq,
1990 collect_caller_bindings_cfunc,
1991 &data);
1992
1993 result = rb_ary_reverse(data.ary);
1994
1995 /* bindings should be created from top of frame */
1996 for (i=0; i<RARRAY_LEN(result); i++) {
1997 VALUE entry = rb_ary_entry(result, i);
1998 VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
1999
2000 if (!NIL_P(cfp_val)) {
2001 rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
2002 rb_ary_store(entry, CALLER_BINDING_BINDING, rb_vm_make_binding(ec, cfp));
2003 }
2004 }
2005
2006 return result;
2007}
2008
2009/*
2010 * Note that the passed `rb_debug_inspector_t' will be disabled
2011 * after `rb_debug_inspector_open'.
2012 */
2013
2014VALUE
2016{
2017 rb_debug_inspector_t dbg_context;
2018 rb_execution_context_t *ec = GET_EC();
2019 enum ruby_tag_type state;
2020 volatile VALUE MAYBE_UNUSED(result);
2021 int i;
2022
2023 /* escape all env to heap */
2024 rb_vm_stack_to_heap(ec);
2025
2026 dbg_context.ec = ec;
2027 dbg_context.cfp = dbg_context.ec->cfp;
2028 dbg_context.contexts = collect_caller_bindings(ec);
2029 dbg_context.raw_backtrace = rb_ary_new();
2030 for (i=0; i<RARRAY_LEN(dbg_context.contexts); i++) {
2031 VALUE frame = rb_ary_entry(dbg_context.contexts, i);
2032 rb_ary_push(dbg_context.raw_backtrace, rb_ary_entry(frame, CALLER_BINDING_LOC));
2033 }
2034
2035 EC_PUSH_TAG(ec);
2036 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
2037 result = (*func)(&dbg_context, data);
2038 }
2039 EC_POP_TAG();
2040
2041 /* invalidate bindings? */
2042
2043 if (state) {
2044 EC_JUMP_TAG(ec, state);
2045 }
2046
2047 return result;
2048}
2049
2050static VALUE
2051frame_get(const rb_debug_inspector_t *dc, long index)
2052{
2053 if (index < 0 || index >= RARRAY_LEN(dc->contexts)) {
2054 rb_raise(rb_eArgError, "no such frame");
2055 }
2056 return rb_ary_entry(dc->contexts, index);
2057}
2058
2059VALUE
2061{
2062 VALUE frame = frame_get(dc, index);
2063 return rb_ary_entry(frame, CALLER_BINDING_SELF);
2064}
2065
2066VALUE
2068{
2069 VALUE frame = frame_get(dc, index);
2070 return rb_ary_entry(frame, CALLER_BINDING_CLASS);
2071}
2072
2073VALUE
2075{
2076 VALUE frame = frame_get(dc, index);
2077 return rb_ary_entry(frame, CALLER_BINDING_BINDING);
2078}
2079
2080VALUE
2082{
2083 VALUE frame = frame_get(dc, index);
2084 VALUE iseq = rb_ary_entry(frame, CALLER_BINDING_ISEQ);
2085
2086 return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) : Qnil;
2087}
2088
2089VALUE
2091{
2092 VALUE frame = frame_get(dc, index);
2093 return rb_ary_entry(frame, CALLER_BINDING_DEPTH);
2094}
2095
2096VALUE
2098{
2099 rb_execution_context_t *ec = GET_EC();
2100 return INT2FIX(frame_depth(ec, ec->cfp));
2101}
2102
2103VALUE
2105{
2106 return dc->raw_backtrace;
2107}
2108
2109static int
2110thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *buff, int *lines)
2111{
2112 int i;
2113 const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
2114 const rb_control_frame_t *top = cfp;
2115 const rb_callable_method_entry_t *cme;
2116
2117 // If this function is called inside a thread after thread creation, but
2118 // before the CFP has been created, just return 0. This can happen when
2119 // sampling via signals. Threads can be interrupted randomly by the
2120 // signal, including during the time after the thread has been created, but
2121 // before the CFP has been allocated
2122 if (!cfp) {
2123 return 0;
2124 }
2125
2126 // Skip dummy frame; see `rb_ec_partial_backtrace_object` for details
2127 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
2128
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)) {
2131 if (start > 0) {
2132 start--;
2133 continue;
2134 }
2135
2136 /* record frame info */
2137 cme = rb_vm_frame_method_entry_unchecked(cfp);
2138 const rb_iseq_t *iseq = CFP_ISEQ(cfp);
2139 if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
2140 buff[i] = (VALUE)cme;
2141 }
2142 else {
2143 buff[i] = (VALUE)iseq;
2144 }
2145
2146 if (lines) {
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;
2150
2151 // The topmost frame may have an invalid PC because the JIT
2152 // may leave it uninitialized for speed. JIT code must update the PC
2153 // before entering a non-leaf method (so that `caller` will work),
2154 // so only the topmost frame could possibly have an out-of-date PC.
2155 // Avoid passing invalid PC to calc_lineno() to avoid crashing.
2156 if (cfp == top && (pc < iseq_encoded || pc > pc_end)) {
2157 lines[i] = 0;
2158 }
2159 else {
2160 lines[i] = calc_lineno(iseq, pc);
2161 }
2162 }
2163
2164 i++;
2165 }
2166 else {
2167 cme = rb_vm_frame_method_entry_unchecked(cfp);
2168 if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
2169 if (start > 0) {
2170 start--;
2171 continue;
2172 }
2173 buff[i] = (VALUE)cme;
2174 if (lines) lines[i] = 0;
2175 i++;
2176 }
2177 }
2178 }
2179
2180 return i;
2181}
2182
2183int
2184rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
2185{
2186 rb_execution_context_t *ec = rb_current_execution_context(false);
2187
2188 // If there is no EC, we may be attempting to profile a non-Ruby thread or a
2189 // M:N shared native thread which has no active Ruby thread.
2190 if (!ec) {
2191 return 0;
2192 }
2193
2194 return thread_profile_frames(ec, start, limit, buff, lines);
2195}
2196
2197int
2198rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines)
2199{
2200 rb_thread_t *th = rb_thread_ptr(thread);
2201 return thread_profile_frames(th->ec, start, limit, buff, lines);
2202}
2203
2204static const rb_iseq_t *
2205frame2iseq(VALUE frame)
2206{
2207 if (NIL_P(frame)) return NULL;
2208
2209 if (RB_TYPE_P(frame, T_IMEMO)) {
2210 switch (imemo_type(frame)) {
2211 case imemo_iseq:
2212 return (const rb_iseq_t *)frame;
2213 case imemo_ment:
2214 {
2216 switch (cme->def->type) {
2217 case VM_METHOD_TYPE_ISEQ:
2218 return cme->def->body.iseq.iseqptr;
2219 default:
2220 return NULL;
2221 }
2222 }
2223 default:
2224 break;
2225 }
2226 }
2227 rb_bug("frame2iseq: unreachable");
2228}
2229
2230VALUE
2232{
2233 const rb_iseq_t *iseq = frame2iseq(frame);
2234 return iseq ? rb_iseq_path(iseq) : Qnil;
2235}
2236
2237static const rb_callable_method_entry_t *
2238cframe(VALUE frame)
2239{
2240 if (NIL_P(frame)) return NULL;
2241
2242 if (RB_TYPE_P(frame, T_IMEMO)) {
2243 switch (imemo_type(frame)) {
2244 case imemo_ment:
2245 {
2247 switch (cme->def->type) {
2248 case VM_METHOD_TYPE_CFUNC:
2249 return cme;
2250 default:
2251 return NULL;
2252 }
2253 }
2254 default:
2255 return NULL;
2256 }
2257 }
2258
2259 return NULL;
2260}
2261
2262VALUE
2264{
2265 if (cframe(frame)) {
2266 static VALUE cfunc_str = Qfalse;
2267 if (!cfunc_str) {
2268 cfunc_str = rb_str_new_literal("<cfunc>");
2269 rb_vm_register_global_object(cfunc_str);
2270 }
2271 return cfunc_str;
2272 }
2273 const rb_iseq_t *iseq = frame2iseq(frame);
2274 return iseq ? rb_iseq_realpath(iseq) : Qnil;
2275}
2276
2277VALUE
2279{
2280 const rb_iseq_t *iseq = frame2iseq(frame);
2281 return iseq ? rb_iseq_label(iseq) : Qnil;
2282}
2283
2284VALUE
2286{
2287 const rb_iseq_t *iseq = frame2iseq(frame);
2288 return iseq ? rb_iseq_base_label(iseq) : Qnil;
2289}
2290
2291VALUE
2293{
2294 const rb_iseq_t *iseq = frame2iseq(frame);
2295 return iseq ? rb_iseq_first_lineno(iseq) : Qnil;
2296}
2297
2298static VALUE
2299frame2klass(VALUE frame)
2300{
2301 if (NIL_P(frame)) return Qnil;
2302
2303 if (RB_TYPE_P(frame, T_IMEMO)) {
2305
2306 if (imemo_type(frame) == imemo_ment) {
2307 return cme->defined_class;
2308 }
2309 }
2310 return Qnil;
2311}
2312
2313VALUE
2315{
2316 VALUE klass = frame2klass(frame);
2317
2318 if (klass && !NIL_P(klass)) {
2319 if (RB_TYPE_P(klass, T_ICLASS)) {
2320 klass = RBASIC(klass)->klass;
2321 }
2322 else if (RCLASS_SINGLETON_P(klass)) {
2323 klass = RCLASS_ATTACHED_OBJECT(klass);
2324 if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE))
2325 return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass);
2326 }
2327 return rb_class_path(klass);
2328 }
2329 else {
2330 return Qnil;
2331 }
2332}
2333
2334VALUE
2336{
2337 VALUE klass = frame2klass(frame);
2338
2339 return RBOOL(klass && !NIL_P(klass) && RCLASS_SINGLETON_P(klass));
2340}
2341
2342VALUE
2344{
2345 const rb_callable_method_entry_t *cme = cframe(frame);
2346 if (cme) {
2347 ID mid = cme->def->original_id;
2348 return id2str(mid);
2349 }
2350 const rb_iseq_t *iseq = frame2iseq(frame);
2351 return iseq ? rb_iseq_method_name(iseq) : Qnil;
2352}
2353
2354static VALUE
2355qualified_method_name(VALUE frame, VALUE method_name)
2356{
2357 if (method_name != Qnil) {
2358 VALUE classpath = rb_profile_frame_classpath(frame);
2359 VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
2360
2361 if (classpath != Qnil) {
2362 return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
2363 classpath, singleton_p == Qtrue ? "." : "#", method_name);
2364 }
2365 else {
2366 return method_name;
2367 }
2368 }
2369 else {
2370 return Qnil;
2371 }
2372}
2373
2374VALUE
2376{
2377 VALUE method_name = rb_profile_frame_method_name(frame);
2378
2379 return qualified_method_name(frame, method_name);
2380}
2381
2382VALUE
2384{
2385 const rb_callable_method_entry_t *cme = cframe(frame);
2386 if (cme) {
2387 ID mid = cme->def->original_id;
2388 VALUE method_name = id2str(mid);
2389 return qualified_method_name(frame, method_name);
2390 }
2391
2392 VALUE label = rb_profile_frame_label(frame);
2393 VALUE base_label = rb_profile_frame_base_label(frame);
2394 VALUE qualified_method_name = rb_profile_frame_qualified_method_name(frame);
2395
2396 if (NIL_P(qualified_method_name) || base_label == qualified_method_name) {
2397 return label;
2398 }
2399 else {
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);
2403
2404 return rb_sprintf("%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);
2405 }
2406}
#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().
Definition debug.h:218
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.
Definition sprintf.c:1209
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2723
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.
Definition class.c:3203
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2992
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define T_IMEMO
Old name of RUBY_T_IMEMO.
Definition value_type.h:67
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_ICLASS
Old name of RUBY_T_ICLASS.
Definition value_type.h:66
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#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.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:234
VALUE rb_cThread
Thread class.
Definition vm.c:697
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:468
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:456
Encoding relates APIs.
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.
Definition io.c:4339
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.
Definition io.c:7321
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5803
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Deconstructs a numerical range.
Definition range.c:1970
#define rb_str_new_literal(str)
Just another name of rb_str_new_lit.
Definition string.h:1751
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.
Definition string.c:3864
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
Definition string.c:7825
#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.
Definition string.h:1657
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1755
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition variable.c:395
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1809
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.
Definition io.h:8
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1378
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
Definition marshal.c:137
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
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.
Definition rarray.h:50
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:56
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:81
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:773
#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...
Definition rtypeddata.h:604
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
Definition variable.c:521
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition method.h:63
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:238
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
Definition method.h:143
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376