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