Ruby 3.3.6p108 (2024-11-05 revision 75015d4c1f6965b5e85e96fb309f1f2129f933c0)
vm_backtrace.c
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/vm.h"
17#include "iseq.h"
18#include "ruby/debug.h"
19#include "ruby/encoding.h"
20#include "vm_core.h"
21
22static VALUE rb_cBacktrace;
23static VALUE rb_cBacktraceLocation;
24
25static VALUE
26id2str(ID id)
27{
28 VALUE str = rb_id2str(id);
29 if (!str) return Qnil;
30 return str;
31}
32#define rb_id2str(id) id2str(id)
33
34#define BACKTRACE_START 0
35#define ALL_BACKTRACE_LINES -1
36
37inline static int
38calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
39{
40 VM_ASSERT(iseq);
41
42 if (pc == NULL) {
43 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_TOP) {
44 VM_ASSERT(! ISEQ_BODY(iseq)->local_table);
45 VM_ASSERT(! ISEQ_BODY(iseq)->local_table_size);
46 return 0;
47 }
48 if (lineno) *lineno = ISEQ_BODY(iseq)->location.first_lineno;
49#ifdef USE_ISEQ_NODE_ID
50 if (node_id) *node_id = -1;
51#endif
52 return 1;
53 }
54 else {
55 VM_ASSERT(ISEQ_BODY(iseq));
56 VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
57 VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
58
59 ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
60 VM_ASSERT(n >= 0);
61#if SIZEOF_PTRDIFF_T > SIZEOF_INT
62 VM_ASSERT(n <= (ptrdiff_t)UINT_MAX);
63#endif
64 VM_ASSERT((unsigned int)n <= ISEQ_BODY(iseq)->iseq_size);
65 ASSUME(n >= 0);
66 size_t pos = n; /* no overflow */
67 if (LIKELY(pos)) {
68 /* use pos-1 because PC points next instruction at the beginning of instruction */
69 pos--;
70 }
71#if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
72 else {
73 /* SDR() is not possible; that causes infinite loop. */
74 rb_print_backtrace(stderr);
75 __builtin_trap();
76 }
77#endif
78 if (lineno) *lineno = rb_iseq_line_no(iseq, pos);
79#ifdef USE_ISEQ_NODE_ID
80 if (node_id) *node_id = rb_iseq_node_id(iseq, pos);
81#endif
82 return 1;
83 }
84}
85
86inline static int
87calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
88{
89 int lineno;
90 if (calc_pos(iseq, pc, &lineno, NULL)) return lineno;
91 return 0;
92}
93
94#ifdef USE_ISEQ_NODE_ID
95inline static int
96calc_node_id(const rb_iseq_t *iseq, const VALUE *pc)
97{
98 int node_id;
99 if (calc_pos(iseq, pc, NULL, &node_id)) return node_id;
100 return -1;
101}
102#endif
103
104int
105rb_vm_get_sourceline(const rb_control_frame_t *cfp)
106{
107 if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
108 const rb_iseq_t *iseq = cfp->iseq;
109 int line = calc_lineno(iseq, cfp->pc);
110 if (line != 0) {
111 return line;
112 }
113 else {
114 return ISEQ_BODY(iseq)->location.first_lineno;
115 }
116 }
117 else {
118 return 0;
119 }
120}
121
123 enum LOCATION_TYPE {
124 LOCATION_TYPE_ISEQ = 1,
125 LOCATION_TYPE_CFUNC,
126 } type;
127
128 const rb_iseq_t *iseq;
129 const VALUE *pc;
130 ID mid;
132
135 VALUE btobj;
136};
137
138static void
139location_mark(void *ptr)
140{
141 struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
142 rb_gc_mark(vfi->btobj);
143}
144
145static void
146location_mark_entry(rb_backtrace_location_t *fi)
147{
148 switch (fi->type) {
149 case LOCATION_TYPE_ISEQ:
150 rb_gc_mark_movable((VALUE)fi->iseq);
151 break;
152 case LOCATION_TYPE_CFUNC:
153 if (fi->iseq) {
154 rb_gc_mark_movable((VALUE)fi->iseq);
155 }
156 break;
157 default:
158 break;
159 }
160}
161
162static const rb_data_type_t location_data_type = {
163 "frame_info",
164 {
165 location_mark,
167 NULL, // No external memory to report,
168 },
169 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
170};
171
172int
173rb_frame_info_p(VALUE obj)
174{
175 return rb_typeddata_is_kind_of(obj, &location_data_type);
176}
177
178static inline rb_backtrace_location_t *
179location_ptr(VALUE locobj)
180{
181 struct valued_frame_info *vloc;
182 TypedData_Get_Struct(locobj, struct valued_frame_info, &location_data_type, vloc);
183 return vloc->loc;
184}
185
186static int
187location_lineno(rb_backtrace_location_t *loc)
188{
189 switch (loc->type) {
190 case LOCATION_TYPE_ISEQ:
191 return calc_lineno(loc->iseq, loc->pc);
192 case LOCATION_TYPE_CFUNC:
193 if (loc->iseq && loc->pc) {
194 return calc_lineno(loc->iseq, loc->pc);
195 }
196 return 0;
197 default:
198 rb_bug("location_lineno: unreachable");
200 }
201}
202
203/*
204 * Returns the line number of this frame.
205 *
206 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
207 *
208 * loc = c(0..1).first
209 * loc.lineno #=> 2
210 */
211static VALUE
212location_lineno_m(VALUE self)
213{
214 return INT2FIX(location_lineno(location_ptr(self)));
215}
216
217static VALUE
218location_label(rb_backtrace_location_t *loc)
219{
220 switch (loc->type) {
221 case LOCATION_TYPE_ISEQ:
222 return ISEQ_BODY(loc->iseq)->location.label;
223 case LOCATION_TYPE_CFUNC:
224 return rb_id2str(loc->mid);
225 default:
226 rb_bug("location_label: unreachable");
228 }
229}
230
231/*
232 * Returns the label of this frame.
233 *
234 * Usually consists of method, class, module, etc names with decoration.
235 *
236 * Consider the following example:
237 *
238 * def foo
239 * puts caller_locations(0).first.label
240 *
241 * 1.times do
242 * puts caller_locations(0).first.label
243 *
244 * 1.times do
245 * puts caller_locations(0).first.label
246 * end
247 *
248 * end
249 * end
250 *
251 * The result of calling +foo+ is this:
252 *
253 * label: foo
254 * label: block in foo
255 * label: block (2 levels) in foo
256 *
257 */
258static VALUE
259location_label_m(VALUE self)
260{
261 return location_label(location_ptr(self));
262}
263
264static VALUE
265location_base_label(rb_backtrace_location_t *loc)
266{
267 switch (loc->type) {
268 case LOCATION_TYPE_ISEQ:
269 return ISEQ_BODY(loc->iseq)->location.base_label;
270 case LOCATION_TYPE_CFUNC:
271 return rb_id2str(loc->mid);
272 default:
273 rb_bug("location_base_label: unreachable");
275 }
276}
277
278/*
279 * Returns the base label of this frame.
280 *
281 * Usually same as #label, without decoration.
282 */
283static VALUE
284location_base_label_m(VALUE self)
285{
286 return location_base_label(location_ptr(self));
287}
288
289static const rb_iseq_t *
290location_iseq(rb_backtrace_location_t *loc)
291{
292 switch (loc->type) {
293 case LOCATION_TYPE_ISEQ:
294 return loc->iseq;
295 case LOCATION_TYPE_CFUNC:
296 return loc->iseq;
297 default:
298 rb_bug("location_iseq: unreachable");
300 }
301}
302
303/*
304 * Returns the file name of this frame. This will generally be an absolute
305 * path, unless the frame is in the main script, in which case it will be the
306 * script location passed on the command line.
307 *
308 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
309 *
310 * loc = c(0..1).first
311 * loc.path #=> caller_locations.rb
312 */
313static VALUE
314location_path_m(VALUE self)
315{
316 const rb_iseq_t *iseq = location_iseq(location_ptr(self));
317 return iseq ? rb_iseq_path(iseq) : Qnil;
318}
319
320#ifdef USE_ISEQ_NODE_ID
321static int
322location_node_id(rb_backtrace_location_t *loc)
323{
324 switch (loc->type) {
325 case LOCATION_TYPE_ISEQ:
326 return calc_node_id(loc->iseq, loc->pc);
327 case LOCATION_TYPE_CFUNC:
328 if (loc->iseq && loc->pc) {
329 return calc_node_id(loc->iseq, loc->pc);
330 }
331 return -1;
332 default:
333 rb_bug("location_node_id: unreachable");
335 }
336}
337#endif
338
339int
340rb_get_node_id_from_frame_info(VALUE obj)
341{
342#ifdef USE_ISEQ_NODE_ID
343 rb_backtrace_location_t *loc = location_ptr(obj);
344 return location_node_id(loc);
345#else
346 return -1;
347#endif
348}
349
350const rb_iseq_t *
351rb_get_iseq_from_frame_info(VALUE obj)
352{
353 rb_backtrace_location_t *loc = location_ptr(obj);
354 const rb_iseq_t *iseq = location_iseq(loc);
355 return iseq;
356}
357
358static VALUE
359location_realpath(rb_backtrace_location_t *loc)
360{
361 switch (loc->type) {
362 case LOCATION_TYPE_ISEQ:
363 return rb_iseq_realpath(loc->iseq);
364 case LOCATION_TYPE_CFUNC:
365 if (loc->iseq) {
366 return rb_iseq_realpath(loc->iseq);
367 }
368 return Qnil;
369 default:
370 rb_bug("location_realpath: unreachable");
372 }
373}
374
375/*
376 * Returns the full file path of this frame.
377 *
378 * Same as #path, except that it will return absolute path
379 * even if the frame is in the main script.
380 */
381static VALUE
382location_absolute_path_m(VALUE self)
383{
384 return location_realpath(location_ptr(self));
385}
386
387static VALUE
388location_format(VALUE file, int lineno, VALUE name)
389{
390 VALUE s = rb_enc_sprintf(rb_enc_compatible(file, name), "%s", RSTRING_PTR(file));
391 if (lineno != 0) {
392 rb_str_catf(s, ":%d", lineno);
393 }
394 rb_str_cat_cstr(s, ":in ");
395 if (NIL_P(name)) {
396 rb_str_cat_cstr(s, "unknown method");
397 }
398 else {
399 rb_str_catf(s, "`%s'", RSTRING_PTR(name));
400 }
401 return s;
402}
403
404static VALUE
405location_to_str(rb_backtrace_location_t *loc)
406{
407 VALUE file, name;
408 int lineno;
409
410 switch (loc->type) {
411 case LOCATION_TYPE_ISEQ:
412 file = rb_iseq_path(loc->iseq);
413 name = ISEQ_BODY(loc->iseq)->location.label;
414
415 lineno = calc_lineno(loc->iseq, loc->pc);
416 break;
417 case LOCATION_TYPE_CFUNC:
418 if (loc->iseq && loc->pc) {
419 file = rb_iseq_path(loc->iseq);
420 lineno = calc_lineno(loc->iseq, loc->pc);
421 }
422 else {
423 file = GET_VM()->progname;
424 lineno = 0;
425 }
426 name = rb_id2str(loc->mid);
427 break;
428 default:
429 rb_bug("location_to_str: unreachable");
430 }
431
432 return location_format(file, lineno, name);
433}
434
435/*
436 * Returns a Kernel#caller style string representing this frame.
437 */
438static VALUE
439location_to_str_m(VALUE self)
440{
441 return location_to_str(location_ptr(self));
442}
443
444/*
445 * Returns the same as calling +inspect+ on the string representation of
446 * #to_str
447 */
448static VALUE
449location_inspect_m(VALUE self)
450{
451 return rb_str_inspect(location_to_str(location_ptr(self)));
452}
453
454typedef struct rb_backtrace_struct {
455 int backtrace_size;
456 VALUE strary;
457 VALUE locary;
458 rb_backtrace_location_t backtrace[1];
460
461static void
462backtrace_mark(void *ptr)
463{
464 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
465 size_t i, s = bt->backtrace_size;
466
467 for (i=0; i<s; i++) {
468 location_mark_entry(&bt->backtrace[i]);
469 }
470 rb_gc_mark_movable(bt->strary);
471 rb_gc_mark_movable(bt->locary);
472}
473
474static void
475location_update_entry(rb_backtrace_location_t *fi)
476{
477 switch (fi->type) {
478 case LOCATION_TYPE_ISEQ:
479 fi->iseq = (rb_iseq_t*)rb_gc_location((VALUE)fi->iseq);
480 break;
481 case LOCATION_TYPE_CFUNC:
482 if (fi->iseq) {
483 fi->iseq = (rb_iseq_t*)rb_gc_location((VALUE)fi->iseq);
484 }
485 break;
486 default:
487 break;
488 }
489}
490
491static void
492backtrace_update(void *ptr)
493{
494 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
495 size_t i, s = bt->backtrace_size;
496
497 for (i=0; i<s; i++) {
498 location_update_entry(&bt->backtrace[i]);
499 }
500 bt->strary = rb_gc_location(bt->strary);
501 bt->locary = rb_gc_location(bt->locary);
502}
503
504static const rb_data_type_t backtrace_data_type = {
505 "backtrace",
506 {
507 backtrace_mark,
509 NULL, // No external memory to report,
510 backtrace_update,
511 },
512 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
513};
514
515int
516rb_backtrace_p(VALUE obj)
517{
518 return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
519}
520
521static VALUE
522backtrace_alloc(VALUE klass)
523{
524 rb_backtrace_t *bt;
525 VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
526 return obj;
527}
528
529static long
530backtrace_size(const rb_execution_context_t *ec)
531{
532 const rb_control_frame_t *last_cfp = ec->cfp;
533 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
534
535 if (start_cfp == NULL) {
536 return -1;
537 }
538
539 start_cfp =
540 RUBY_VM_NEXT_CONTROL_FRAME(
541 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
542
543 if (start_cfp < last_cfp) {
544 return 0;
545 }
546
547 return start_cfp - last_cfp + 1;
548}
549
550static bool
551is_internal_location(const rb_control_frame_t *cfp)
552{
553 static const char prefix[] = "<internal:";
554 const size_t prefix_len = sizeof(prefix) - 1;
555 VALUE file = rb_iseq_path(cfp->iseq);
556 return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0;
557}
558
559static void
560bt_update_cfunc_loc(unsigned long cfunc_counter, rb_backtrace_location_t *cfunc_loc, const rb_iseq_t *iseq, const VALUE *pc)
561{
562 for (; cfunc_counter > 0; cfunc_counter--, cfunc_loc--) {
563 cfunc_loc->iseq = iseq;
564 cfunc_loc->pc = pc;
565 }
566}
567
568static VALUE location_create(rb_backtrace_location_t *srcloc, void *btobj);
569
570static void
571bt_yield_loc(rb_backtrace_location_t *loc, long num_frames, VALUE btobj)
572{
573 for (; num_frames > 0; num_frames--, loc++) {
574 rb_yield(location_create(loc, (void *)btobj));
575 }
576}
577
578static VALUE
579rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_frame, long num_frames, int* start_too_large, bool skip_internal, bool do_yield)
580{
581 const rb_control_frame_t *cfp = ec->cfp;
582 const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
583 ptrdiff_t size;
584 rb_backtrace_t *bt = NULL;
585 VALUE btobj = Qnil;
586 rb_backtrace_location_t *loc = NULL;
587 unsigned long cfunc_counter = 0;
588
589 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
590 if (end_cfp == NULL) {
591 num_frames = 0;
592 }
593 else {
594 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
595
596 /*
597 * top frame (dummy) <- RUBY_VM_END_CONTROL_FRAME
598 * top frame (dummy) <- end_cfp
599 * top frame <- main script
600 * top frame
601 * ...
602 * 2nd frame <- lev:0
603 * current frame <- ec->cfp
604 */
605
606 size = end_cfp - cfp + 1;
607 if (size < 0) {
608 num_frames = 0;
609 }
610 else if (num_frames < 0 || num_frames > size) {
611 num_frames = size;
612 }
613 }
614
615 size_t memsize = offsetof(rb_backtrace_t, backtrace) + num_frames * sizeof(rb_backtrace_location_t);
616 btobj = rb_data_typed_object_zalloc(rb_cBacktrace, memsize, &backtrace_data_type);
617 TypedData_Get_Struct(btobj, rb_backtrace_t, &backtrace_data_type, bt);
618
619 bt->backtrace_size = 0;
620 if (num_frames == 0) {
621 if (start_too_large) *start_too_large = 0;
622 return btobj;
623 }
624
625 for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
626 if (cfp->iseq) {
627 if (cfp->pc) {
628 if (start_frame > 0) {
629 start_frame--;
630 }
631 else if (!skip_internal || !is_internal_location(cfp)) {
632 const rb_iseq_t *iseq = cfp->iseq;
633 const VALUE *pc = cfp->pc;
634 loc = &bt->backtrace[bt->backtrace_size++];
635 loc->type = LOCATION_TYPE_ISEQ;
636 RB_OBJ_WRITE(btobj, &loc->iseq, iseq);
637 loc->pc = pc;
638 bt_update_cfunc_loc(cfunc_counter, loc-1, iseq, pc);
639 if (do_yield) {
640 bt_yield_loc(loc - cfunc_counter, cfunc_counter+1, btobj);
641 }
642 cfunc_counter = 0;
643 }
644 }
645 }
646 else {
647 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
648 if (start_frame > 0) {
649 start_frame--;
650 }
651 else {
652 loc = &bt->backtrace[bt->backtrace_size++];
653 loc->type = LOCATION_TYPE_CFUNC;
654 loc->iseq = NULL;
655 loc->pc = NULL;
656 loc->mid = rb_vm_frame_method_entry(cfp)->def->original_id;
657 cfunc_counter++;
658 }
659 }
660 }
661
662 if (cfunc_counter > 0) {
663 for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
664 if (cfp->iseq && cfp->pc && (!skip_internal || !is_internal_location(cfp))) {
665 bt_update_cfunc_loc(cfunc_counter, loc, cfp->iseq, cfp->pc);
666 RB_OBJ_WRITTEN(btobj, Qundef, cfp->iseq);
667 if (do_yield) {
668 bt_yield_loc(loc - cfunc_counter, cfunc_counter, btobj);
669 }
670 break;
671 }
672 }
673 }
674
675 if (start_too_large) *start_too_large = (start_frame > 0 ? -1 : 0);
676 return btobj;
677}
678
679VALUE
680rb_ec_backtrace_object(const rb_execution_context_t *ec)
681{
682 return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL, FALSE, FALSE);
683}
684
685static VALUE
686backtrace_collect(rb_backtrace_t *bt, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
687{
688 VALUE btary;
689 int i;
690
691 btary = rb_ary_new2(bt->backtrace_size);
692
693 for (i=0; i<bt->backtrace_size; i++) {
694 rb_backtrace_location_t *loc = &bt->backtrace[i];
695 rb_ary_push(btary, func(loc, arg));
696 }
697
698 return btary;
699}
700
701static VALUE
702location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
703{
704 return location_to_str(loc);
705}
706
707static VALUE
708backtrace_to_str_ary(VALUE self)
709{
710 VALUE r;
711 rb_backtrace_t *bt;
712 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
713 r = backtrace_collect(bt, location_to_str_dmyarg, 0);
714 RB_GC_GUARD(self);
715 return r;
716}
717
718VALUE
719rb_backtrace_to_str_ary(VALUE self)
720{
721 rb_backtrace_t *bt;
722 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
723
724 if (!bt->strary) {
725 RB_OBJ_WRITE(self, &bt->strary, backtrace_to_str_ary(self));
726 }
727 return bt->strary;
728}
729
730void
731rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self)
732{
733 rb_backtrace_t *bt;
735
736 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
737 VM_ASSERT(bt->backtrace_size > 0);
738
739 loc = &bt->backtrace[0];
740
741 VM_ASSERT(loc->type == LOCATION_TYPE_ISEQ);
742
743 loc->pc = NULL; // means location.first_lineno
744}
745
746static VALUE
747location_create(rb_backtrace_location_t *srcloc, void *btobj)
748{
749 VALUE obj;
750 struct valued_frame_info *vloc;
751 obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
752
753 vloc->loc = srcloc;
754 RB_OBJ_WRITE(obj, &vloc->btobj, (VALUE)btobj);
755
756 return obj;
757}
758
759static VALUE
760backtrace_to_location_ary(VALUE self)
761{
762 VALUE r;
763 rb_backtrace_t *bt;
764 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
765 r = backtrace_collect(bt, location_create, (void *)self);
766 RB_GC_GUARD(self);
767 return r;
768}
769
770VALUE
771rb_backtrace_to_location_ary(VALUE self)
772{
773 rb_backtrace_t *bt;
774 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
775
776 if (!bt->locary) {
777 RB_OBJ_WRITE(self, &bt->locary, backtrace_to_location_ary(self));
778 }
779 return bt->locary;
780}
781
782static VALUE
783backtrace_dump_data(VALUE self)
784{
785 VALUE str = rb_backtrace_to_str_ary(self);
786 return str;
787}
788
789static VALUE
790backtrace_load_data(VALUE self, VALUE str)
791{
792 rb_backtrace_t *bt;
793 TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
794 RB_OBJ_WRITE(self, &bt->strary, str);
795 return self;
796}
797
798/*
799 * call-seq: Thread::Backtrace::limit -> integer
800 *
801 * Returns maximum backtrace length set by <tt>--backtrace-limit</tt>
802 * command-line option. The default is <tt>-1</tt> which means unlimited
803 * backtraces. If the value is zero or positive, the error backtraces,
804 * produced by Exception#full_message, are abbreviated and the extra lines
805 * are replaced by <tt>... 3 levels... </tt>
806 *
807 * $ ruby -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
808 * - 1
809 * .../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)
810 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
811 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
812 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
813 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
814 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
815 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
816 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
817 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
818 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
819 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
820 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
821 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
822 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
823 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
824 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
825 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
826 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
827 * from -e:1:in `<main>'
828 *
829 * $ ruby --backtrace-limit 2 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
830 * 2
831 * .../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)
832 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
833 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
834 * ... 7 levels...
835 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
836 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
837 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
838 * ... 7 levels...
839 *
840 * $ ruby --backtrace-limit 0 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
841 * 0
842 * .../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)
843 * ... 9 levels...
844 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
845 * ... 9 levels...
846 *
847 */
848static VALUE
849backtrace_limit(VALUE self)
850{
851 return LONG2NUM(rb_backtrace_length_limit);
852}
853
854VALUE
855rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n)
856{
857 return rb_backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, FALSE));
858}
859
860VALUE
861rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal)
862{
863 return rb_backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal, FALSE));
864}
865
866/* make old style backtrace directly */
867
868static void
869backtrace_each(const rb_execution_context_t *ec,
870 void (*init)(void *arg, size_t size),
871 void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
872 void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
873 void *arg)
874{
875 const rb_control_frame_t *last_cfp = ec->cfp;
876 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
877 const rb_control_frame_t *cfp;
878 ptrdiff_t size, i;
879
880 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
881 if (start_cfp == NULL) {
882 init(arg, 0);
883 return;
884 }
885
886 /* <- start_cfp (end control frame)
887 * top frame (dummy)
888 * top frame (dummy)
889 * top frame <- start_cfp
890 * top frame
891 * ...
892 * 2nd frame <- lev:0
893 * current frame <- ec->cfp
894 */
895
896 start_cfp =
897 RUBY_VM_NEXT_CONTROL_FRAME(
898 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
899
900 if (start_cfp < last_cfp) {
901 size = 0;
902 }
903 else {
904 size = start_cfp - last_cfp + 1;
905 }
906
907 init(arg, size);
908
909 /* SDR(); */
910 for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
911 /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
912 if (cfp->iseq) {
913 if (cfp->pc) {
914 iter_iseq(arg, cfp);
915 }
916 }
917 else {
918 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
919 const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
920 ID mid = me->def->original_id;
921
922 iter_cfunc(arg, cfp, mid);
923 }
924 }
925}
926
927struct oldbt_arg {
928 VALUE filename;
929 int lineno;
930 void (*func)(void *data, VALUE file, int lineno, VALUE name);
931 void *data; /* result */
932};
933
934static void
935oldbt_init(void *ptr, size_t dmy)
936{
937 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
938 arg->filename = GET_VM()->progname;
939 arg->lineno = 0;
940}
941
942static void
943oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
944{
945 const rb_iseq_t *iseq = cfp->iseq;
946 const VALUE *pc = cfp->pc;
947 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
948 VALUE file = arg->filename = rb_iseq_path(iseq);
949 VALUE name = ISEQ_BODY(iseq)->location.label;
950 int lineno = arg->lineno = calc_lineno(iseq, pc);
951
952 (arg->func)(arg->data, file, lineno, name);
953}
954
955static void
956oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
957{
958 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
959 VALUE file = arg->filename;
960 VALUE name = rb_id2str(mid);
961 int lineno = arg->lineno;
962
963 (arg->func)(arg->data, file, lineno, name);
964}
965
966static void
967oldbt_print(void *data, VALUE file, int lineno, VALUE name)
968{
969 FILE *fp = (FILE *)data;
970
971 if (NIL_P(name)) {
972 fprintf(fp, "\tfrom %s:%d:in unknown method\n",
973 RSTRING_PTR(file), lineno);
974 }
975 else {
976 fprintf(fp, "\tfrom %s:%d:in `%s'\n",
977 RSTRING_PTR(file), lineno, RSTRING_PTR(name));
978 }
979}
980
981static void
982vm_backtrace_print(FILE *fp)
983{
984 struct oldbt_arg arg;
985
986 arg.func = oldbt_print;
987 arg.data = (void *)fp;
988 backtrace_each(GET_EC(),
989 oldbt_init,
990 oldbt_iter_iseq,
991 oldbt_iter_cfunc,
992 &arg);
993}
994
996 FILE *fp;
997 int count;
998};
999
1000static void
1001oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
1002{
1003 struct oldbt_bugreport_arg *p = arg;
1004 FILE *fp = p->fp;
1005 const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
1006 if (!p->count) {
1007 fprintf(fp, "-- Ruby level backtrace information "
1008 "----------------------------------------\n");
1009 p->count = 1;
1010 }
1011 if (NIL_P(method)) {
1012 fprintf(fp, "%s:%d:in unknown method\n", filename, line);
1013 }
1014 else {
1015 fprintf(fp, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
1016 }
1017}
1018
1019void
1020rb_backtrace_print_as_bugreport(FILE *fp)
1021{
1022 struct oldbt_arg arg;
1023 struct oldbt_bugreport_arg barg = {fp, 0};
1024
1025 arg.func = oldbt_bugreport;
1026 arg.data = &barg;
1027
1028 backtrace_each(GET_EC(),
1029 oldbt_init,
1030 oldbt_iter_iseq,
1031 oldbt_iter_cfunc,
1032 &arg);
1033}
1034
1035void
1037{
1038 vm_backtrace_print(stderr);
1039}
1040
1042 VALUE (*iter)(VALUE recv, VALUE str);
1043 VALUE output;
1044};
1045
1046static void
1047oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
1048{
1049 const struct print_to_arg *arg = data;
1050 VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
1051
1052 if (NIL_P(name)) {
1053 rb_str_cat2(str, "unknown method\n");
1054 }
1055 else {
1056 rb_str_catf(str, " `%"PRIsVALUE"'\n", name);
1057 }
1058 (*arg->iter)(arg->output, str);
1059}
1060
1061void
1062rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output)
1063{
1064 struct oldbt_arg arg;
1065 struct print_to_arg parg;
1066
1067 parg.iter = iter;
1068 parg.output = output;
1069 arg.func = oldbt_print_to;
1070 arg.data = &parg;
1071 backtrace_each(GET_EC(),
1072 oldbt_init,
1073 oldbt_iter_iseq,
1074 oldbt_iter_cfunc,
1075 &arg);
1076}
1077
1078VALUE
1079rb_make_backtrace(void)
1080{
1081 return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START, ALL_BACKTRACE_LINES);
1082}
1083
1084static VALUE
1085ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str)
1086{
1087 VALUE level, vn;
1088 long lev, n;
1089 VALUE btval;
1090 VALUE r;
1091 int too_large;
1092
1093 rb_scan_args(argc, argv, "02", &level, &vn);
1094
1095 if (argc == 2 && NIL_P(vn)) argc--;
1096
1097 switch (argc) {
1098 case 0:
1099 lev = lev_default + lev_plus;
1100 n = ALL_BACKTRACE_LINES;
1101 break;
1102 case 1:
1103 {
1104 long beg, len, bt_size = backtrace_size(ec);
1105 switch (rb_range_beg_len(level, &beg, &len, bt_size - lev_plus, 0)) {
1106 case Qfalse:
1107 lev = NUM2LONG(level);
1108 if (lev < 0) {
1109 rb_raise(rb_eArgError, "negative level (%ld)", lev);
1110 }
1111 lev += lev_plus;
1112 n = ALL_BACKTRACE_LINES;
1113 break;
1114 case Qnil:
1115 return Qnil;
1116 default:
1117 lev = beg + lev_plus;
1118 n = len;
1119 break;
1120 }
1121 break;
1122 }
1123 case 2:
1124 lev = NUM2LONG(level);
1125 n = NUM2LONG(vn);
1126 if (lev < 0) {
1127 rb_raise(rb_eArgError, "negative level (%ld)", lev);
1128 }
1129 if (n < 0) {
1130 rb_raise(rb_eArgError, "negative size (%ld)", n);
1131 }
1132 lev += lev_plus;
1133 break;
1134 default:
1135 lev = n = 0; /* to avoid warning */
1136 break;
1137 }
1138
1139 if (n == 0) {
1140 return rb_ary_new();
1141 }
1142
1143 btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE, FALSE);
1144
1145 if (too_large) {
1146 return Qnil;
1147 }
1148
1149 if (to_str) {
1150 r = backtrace_to_str_ary(btval);
1151 }
1152 else {
1153 r = backtrace_to_location_ary(btval);
1154 }
1155 RB_GC_GUARD(btval);
1156 return r;
1157}
1158
1159static VALUE
1160thread_backtrace_to_ary(int argc, const VALUE *argv, VALUE thval, int to_str)
1161{
1162 rb_thread_t *target_th = rb_thread_ptr(thval);
1163
1164 if (target_th->to_kill || target_th->status == THREAD_KILLED)
1165 return Qnil;
1166
1167 return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1168}
1169
1170VALUE
1171rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval)
1172{
1173 return thread_backtrace_to_ary(argc, argv, thval, 1);
1174}
1175
1176VALUE
1177rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval)
1178{
1179 return thread_backtrace_to_ary(argc, argv, thval, 0);
1180}
1181
1182VALUE
1183rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1184{
1185 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1186}
1187
1188VALUE
1189rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1190{
1191 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1192}
1193
1194/*
1195 * call-seq:
1196 * caller(start=1, length=nil) -> array or nil
1197 * caller(range) -> array or nil
1198 *
1199 * Returns the current execution stack---an array containing strings in
1200 * the form <code>file:line</code> or <code>file:line: in
1201 * `method'</code>.
1202 *
1203 * The optional _start_ parameter determines the number of initial stack
1204 * entries to omit from the top of the stack.
1205 *
1206 * A second optional +length+ parameter can be used to limit how many entries
1207 * are returned from the stack.
1208 *
1209 * Returns +nil+ if _start_ is greater than the size of
1210 * current execution stack.
1211 *
1212 * Optionally you can pass a range, which will return an array containing the
1213 * entries within the specified range.
1214 *
1215 * def a(skip)
1216 * caller(skip)
1217 * end
1218 * def b(skip)
1219 * a(skip)
1220 * end
1221 * def c(skip)
1222 * b(skip)
1223 * end
1224 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1225 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1226 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1227 * c(3) #=> ["prog:13:in `<main>'"]
1228 * c(4) #=> []
1229 * c(5) #=> nil
1230 */
1231
1232static VALUE
1233rb_f_caller(int argc, VALUE *argv, VALUE _)
1234{
1235 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1236}
1237
1238/*
1239 * call-seq:
1240 * caller_locations(start=1, length=nil) -> array or nil
1241 * caller_locations(range) -> array or nil
1242 *
1243 * Returns the current execution stack---an array containing
1244 * backtrace location objects.
1245 *
1246 * See Thread::Backtrace::Location for more information.
1247 *
1248 * The optional _start_ parameter determines the number of initial stack
1249 * entries to omit from the top of the stack.
1250 *
1251 * A second optional +length+ parameter can be used to limit how many entries
1252 * are returned from the stack.
1253 *
1254 * Returns +nil+ if _start_ is greater than the size of
1255 * current execution stack.
1256 *
1257 * Optionally you can pass a range, which will return an array containing the
1258 * entries within the specified range.
1259 */
1260static VALUE
1261rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
1262{
1263 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1264}
1265
1266/*
1267 * call-seq:
1268 * Thread.each_caller_location{ |loc| ... } -> nil
1269 *
1270 * Yields each frame of the current execution stack as a
1271 * backtrace location object.
1272 */
1273static VALUE
1274each_caller_location(VALUE unused)
1275{
1276 rb_ec_partial_backtrace_object(GET_EC(), 2, ALL_BACKTRACE_LINES, NULL, FALSE, TRUE);
1277 return Qnil;
1278}
1279
1280/* called from Init_vm() in vm.c */
1281void
1282Init_vm_backtrace(void)
1283{
1284 /*
1285 * An internal representation of the backtrace. The user will never interact with
1286 * objects of this class directly, but class methods can be used to get backtrace
1287 * settings of the current session.
1288 */
1289 rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
1290 rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
1291 rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
1292 rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
1293 rb_define_singleton_method(rb_cBacktrace, "limit", backtrace_limit, 0);
1294
1295 /*
1296 * An object representation of a stack frame, initialized by
1297 * Kernel#caller_locations.
1298 *
1299 * For example:
1300 *
1301 * # caller_locations.rb
1302 * def a(skip)
1303 * caller_locations(skip)
1304 * end
1305 * def b(skip)
1306 * a(skip)
1307 * end
1308 * def c(skip)
1309 * b(skip)
1310 * end
1311 *
1312 * c(0..2).map do |call|
1313 * puts call.to_s
1314 * end
1315 *
1316 * Running <code>ruby caller_locations.rb</code> will produce:
1317 *
1318 * caller_locations.rb:2:in `a'
1319 * caller_locations.rb:5:in `b'
1320 * caller_locations.rb:8:in `c'
1321 *
1322 * Here's another example with a slightly different result:
1323 *
1324 * # foo.rb
1325 * class Foo
1326 * attr_accessor :locations
1327 * def initialize(skip)
1328 * @locations = caller_locations(skip)
1329 * end
1330 * end
1331 *
1332 * Foo.new(0..2).locations.map do |call|
1333 * puts call.to_s
1334 * end
1335 *
1336 * Now run <code>ruby foo.rb</code> and you should see:
1337 *
1338 * init.rb:4:in `initialize'
1339 * init.rb:8:in `new'
1340 * init.rb:8:in `<main>'
1341 */
1342 rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
1343 rb_undef_alloc_func(rb_cBacktraceLocation);
1344 rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
1345 rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
1346 rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
1347 rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
1348 rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
1349 rb_define_method(rb_cBacktraceLocation, "absolute_path", location_absolute_path_m, 0);
1350 rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
1351 rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
1352
1353 rb_define_global_function("caller", rb_f_caller, -1);
1354 rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1355
1356 rb_define_singleton_method(rb_cThread, "each_caller_location", each_caller_location, 0);
1357}
1358
1359/* debugger API */
1360
1361RUBY_SYMBOL_EXPORT_BEGIN
1362
1363RUBY_SYMBOL_EXPORT_END
1364
1367 rb_control_frame_t *cfp;
1368 VALUE backtrace;
1369 VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1370 long backtrace_size;
1371};
1372
1373enum {
1374 CALLER_BINDING_SELF,
1375 CALLER_BINDING_CLASS,
1376 CALLER_BINDING_BINDING,
1377 CALLER_BINDING_ISEQ,
1378 CALLER_BINDING_CFP,
1379 CALLER_BINDING_DEPTH,
1380};
1381
1383 VALUE ary;
1384 const rb_execution_context_t *ec;
1385};
1386
1387static void
1388collect_caller_bindings_init(void *arg, size_t size)
1389{
1390 /* */
1391}
1392
1393static VALUE
1394get_klass(const rb_control_frame_t *cfp)
1395{
1396 VALUE klass;
1397 if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
1398 if (RB_TYPE_P(klass, T_ICLASS)) {
1399 return RBASIC(klass)->klass;
1400 }
1401 else {
1402 return klass;
1403 }
1404 }
1405 else {
1406 return Qnil;
1407 }
1408}
1409
1410static int
1411frame_depth(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
1412{
1413 VM_ASSERT(RUBY_VM_END_CONTROL_FRAME(ec) >= cfp);
1414 return (int)(RUBY_VM_END_CONTROL_FRAME(ec) - cfp);
1415}
1416
1417static void
1418collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
1419{
1421 VALUE frame = rb_ary_new2(6);
1422
1423 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1424 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1425 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
1426 rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? (VALUE)cfp->iseq : Qnil);
1427 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1428 rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
1429
1430 rb_ary_push(data->ary, frame);
1431}
1432
1433static void
1434collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
1435{
1437 VALUE frame = rb_ary_new2(6);
1438
1439 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1440 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1441 rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
1442 rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
1443 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1444 rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
1445
1446 rb_ary_push(data->ary, frame);
1447}
1448
1449static VALUE
1450collect_caller_bindings(const rb_execution_context_t *ec)
1451{
1452 int i;
1453 VALUE result;
1454 struct collect_caller_bindings_data data = {
1455 rb_ary_new(), ec
1456 };
1457
1458 backtrace_each(ec,
1459 collect_caller_bindings_init,
1460 collect_caller_bindings_iseq,
1461 collect_caller_bindings_cfunc,
1462 &data);
1463
1464 result = rb_ary_reverse(data.ary);
1465
1466 /* bindings should be created from top of frame */
1467 for (i=0; i<RARRAY_LEN(result); i++) {
1468 VALUE entry = rb_ary_entry(result, i);
1469 VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
1470
1471 if (!NIL_P(cfp_val)) {
1472 rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
1473 rb_ary_store(entry, CALLER_BINDING_BINDING, rb_vm_make_binding(ec, cfp));
1474 }
1475 }
1476
1477 return result;
1478}
1479
1480/*
1481 * Note that the passed `rb_debug_inspector_t' will be disabled
1482 * after `rb_debug_inspector_open'.
1483 */
1484
1485VALUE
1487{
1488 rb_debug_inspector_t dbg_context;
1489 rb_execution_context_t *ec = GET_EC();
1490 enum ruby_tag_type state;
1491 volatile VALUE MAYBE_UNUSED(result);
1492
1493 /* escape all env to heap */
1494 rb_vm_stack_to_heap(ec);
1495
1496 dbg_context.ec = ec;
1497 dbg_context.cfp = dbg_context.ec->cfp;
1498 dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, FALSE);
1499 dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
1500 dbg_context.contexts = collect_caller_bindings(ec);
1501
1502 EC_PUSH_TAG(ec);
1503 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1504 result = (*func)(&dbg_context, data);
1505 }
1506 EC_POP_TAG();
1507
1508 /* invalidate bindings? */
1509
1510 if (state) {
1511 EC_JUMP_TAG(ec, state);
1512 }
1513
1514 return result;
1515}
1516
1517static VALUE
1518frame_get(const rb_debug_inspector_t *dc, long index)
1519{
1520 if (index < 0 || index >= dc->backtrace_size) {
1521 rb_raise(rb_eArgError, "no such frame");
1522 }
1523 return rb_ary_entry(dc->contexts, index);
1524}
1525
1526VALUE
1528{
1529 VALUE frame = frame_get(dc, index);
1530 return rb_ary_entry(frame, CALLER_BINDING_SELF);
1531}
1532
1533VALUE
1535{
1536 VALUE frame = frame_get(dc, index);
1537 return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1538}
1539
1540VALUE
1542{
1543 VALUE frame = frame_get(dc, index);
1544 return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1545}
1546
1547VALUE
1549{
1550 VALUE frame = frame_get(dc, index);
1551 VALUE iseq = rb_ary_entry(frame, CALLER_BINDING_ISEQ);
1552
1553 return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) : Qnil;
1554}
1555
1556VALUE
1558{
1559 VALUE frame = frame_get(dc, index);
1560 return rb_ary_entry(frame, CALLER_BINDING_DEPTH);
1561}
1562
1563VALUE
1565{
1566 rb_execution_context_t *ec = GET_EC();
1567 return INT2FIX(frame_depth(ec, ec->cfp));
1568}
1569
1570VALUE
1572{
1573 return dc->backtrace;
1574}
1575
1576static int
1577thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *buff, int *lines)
1578{
1579 int i;
1580 const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
1581 const rb_control_frame_t *top = cfp;
1582 const rb_callable_method_entry_t *cme;
1583
1584 // If this function is called inside a thread after thread creation, but
1585 // before the CFP has been created, just return 0. This can happen when
1586 // sampling via signals. Threads can be interrupted randomly by the
1587 // signal, including during the time after the thread has been created, but
1588 // before the CFP has been allocated
1589 if (!cfp) {
1590 return 0;
1591 }
1592
1593 // Skip dummy frame; see `rb_ec_partial_backtrace_object` for details
1594 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
1595
1596 for (i=0; i<limit && cfp != end_cfp;) {
1597 if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->pc != 0) {
1598 if (start > 0) {
1599 start--;
1600 continue;
1601 }
1602
1603 /* record frame info */
1604 cme = rb_vm_frame_method_entry(cfp);
1605 if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
1606 buff[i] = (VALUE)cme;
1607 }
1608 else {
1609 buff[i] = (VALUE)cfp->iseq;
1610 }
1611
1612 if (lines) {
1613 // The topmost frame may not have an updated PC because the JIT
1614 // may not have set one. The JIT compiler will update the PC
1615 // before entering a new function (so that `caller` will work),
1616 // so only the topmost frame could possibly have an out of date PC
1617 if (cfp == top && cfp->jit_return) {
1618 lines[i] = 0;
1619 }
1620 else {
1621 lines[i] = calc_lineno(cfp->iseq, cfp->pc);
1622 }
1623 }
1624
1625 i++;
1626 }
1627 else {
1628 cme = rb_vm_frame_method_entry(cfp);
1629 if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
1630 buff[i] = (VALUE)cme;
1631 if (lines) lines[i] = 0;
1632 i++;
1633 }
1634 }
1635 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
1636 }
1637
1638 return i;
1639}
1640
1641int
1642rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
1643{
1644 rb_execution_context_t *ec = rb_current_execution_context(false);
1645
1646 // If there is no EC, we may be attempting to profile a non-Ruby thread or a
1647 // M:N shared native thread which has no active Ruby thread.
1648 if (!ec) {
1649 return 0;
1650 }
1651
1652 return thread_profile_frames(ec, start, limit, buff, lines);
1653}
1654
1655int
1656rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines)
1657{
1658 rb_thread_t *th = rb_thread_ptr(thread);
1659 return thread_profile_frames(th->ec, start, limit, buff, lines);
1660}
1661
1662static const rb_iseq_t *
1663frame2iseq(VALUE frame)
1664{
1665 if (NIL_P(frame)) return NULL;
1666
1667 if (RB_TYPE_P(frame, T_IMEMO)) {
1668 switch (imemo_type(frame)) {
1669 case imemo_iseq:
1670 return (const rb_iseq_t *)frame;
1671 case imemo_ment:
1672 {
1674 switch (cme->def->type) {
1675 case VM_METHOD_TYPE_ISEQ:
1676 return cme->def->body.iseq.iseqptr;
1677 default:
1678 return NULL;
1679 }
1680 }
1681 default:
1682 break;
1683 }
1684 }
1685 rb_bug("frame2iseq: unreachable");
1686}
1687
1688VALUE
1690{
1691 const rb_iseq_t *iseq = frame2iseq(frame);
1692 return iseq ? rb_iseq_path(iseq) : Qnil;
1693}
1694
1695static const rb_callable_method_entry_t *
1696cframe(VALUE frame)
1697{
1698 if (NIL_P(frame)) return NULL;
1699
1700 if (RB_TYPE_P(frame, T_IMEMO)) {
1701 switch (imemo_type(frame)) {
1702 case imemo_ment:
1703 {
1705 switch (cme->def->type) {
1706 case VM_METHOD_TYPE_CFUNC:
1707 return cme;
1708 default:
1709 return NULL;
1710 }
1711 }
1712 default:
1713 return NULL;
1714 }
1715 }
1716
1717 return NULL;
1718}
1719
1720VALUE
1722{
1723 if (cframe(frame)) {
1724 static VALUE cfunc_str = Qfalse;
1725 if (!cfunc_str) {
1726 cfunc_str = rb_str_new_literal("<cfunc>");
1727 rb_gc_register_mark_object(cfunc_str);
1728 }
1729 return cfunc_str;
1730 }
1731 const rb_iseq_t *iseq = frame2iseq(frame);
1732 return iseq ? rb_iseq_realpath(iseq) : Qnil;
1733}
1734
1735VALUE
1737{
1738 const rb_iseq_t *iseq = frame2iseq(frame);
1739 return iseq ? rb_iseq_label(iseq) : Qnil;
1740}
1741
1742VALUE
1744{
1745 const rb_iseq_t *iseq = frame2iseq(frame);
1746 return iseq ? rb_iseq_base_label(iseq) : Qnil;
1747}
1748
1749VALUE
1751{
1752 const rb_iseq_t *iseq = frame2iseq(frame);
1753 return iseq ? rb_iseq_first_lineno(iseq) : Qnil;
1754}
1755
1756static VALUE
1757frame2klass(VALUE frame)
1758{
1759 if (NIL_P(frame)) return Qnil;
1760
1761 if (RB_TYPE_P(frame, T_IMEMO)) {
1763
1764 if (imemo_type(frame) == imemo_ment) {
1765 return cme->defined_class;
1766 }
1767 }
1768 return Qnil;
1769}
1770
1771VALUE
1773{
1774 VALUE klass = frame2klass(frame);
1775
1776 if (klass && !NIL_P(klass)) {
1777 if (RB_TYPE_P(klass, T_ICLASS)) {
1778 klass = RBASIC(klass)->klass;
1779 }
1780 else if (FL_TEST(klass, FL_SINGLETON)) {
1781 klass = RCLASS_ATTACHED_OBJECT(klass);
1782 if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE))
1783 return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass);
1784 }
1785 return rb_class_path(klass);
1786 }
1787 else {
1788 return Qnil;
1789 }
1790}
1791
1792VALUE
1794{
1795 VALUE klass = frame2klass(frame);
1796
1797 return RBOOL(klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON));
1798}
1799
1800VALUE
1802{
1803 const rb_callable_method_entry_t *cme = cframe(frame);
1804 if (cme) {
1805 ID mid = cme->def->original_id;
1806 return id2str(mid);
1807 }
1808 const rb_iseq_t *iseq = frame2iseq(frame);
1809 return iseq ? rb_iseq_method_name(iseq) : Qnil;
1810}
1811
1812static VALUE
1813qualified_method_name(VALUE frame, VALUE method_name)
1814{
1815 if (method_name != Qnil) {
1816 VALUE classpath = rb_profile_frame_classpath(frame);
1817 VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
1818
1819 if (classpath != Qnil) {
1820 return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
1821 classpath, singleton_p == Qtrue ? "." : "#", method_name);
1822 }
1823 else {
1824 return method_name;
1825 }
1826 }
1827 else {
1828 return Qnil;
1829 }
1830}
1831
1832VALUE
1834{
1835 VALUE method_name = rb_profile_frame_method_name(frame);
1836
1837 return qualified_method_name(frame, method_name);
1838}
1839
1840VALUE
1842{
1843 const rb_callable_method_entry_t *cme = cframe(frame);
1844 if (cme) {
1845 ID mid = cme->def->original_id;
1846 VALUE method_name = id2str(mid);
1847 return qualified_method_name(frame, method_name);
1848 }
1849
1850 VALUE label = rb_profile_frame_label(frame);
1851 VALUE base_label = rb_profile_frame_base_label(frame);
1852 VALUE qualified_method_name = rb_profile_frame_qualified_method_name(frame);
1853
1854 if (NIL_P(qualified_method_name) || base_label == qualified_method_name) {
1855 return label;
1856 }
1857 else {
1858 long label_length = RSTRING_LEN(label);
1859 long base_label_length = RSTRING_LEN(base_label);
1860 int prefix_len = rb_long2int(label_length - base_label_length);
1861
1862 return rb_sprintf("%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);
1863 }
1864}
#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 frmae depth.
VALUE rb_profile_frame_method_name(VALUE frame)
Queries the name of the method of the passed frame.
VALUE rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index)
Queries the depth of the passed context's upper frame.
VALUE rb_profile_frame_qualified_method_name(VALUE frame)
Identical to rb_profile_frame_method_name(), except it "qualifies" the return value with its defining...
VALUE rb_profile_frame_label(VALUE frame)
Queries human-readable "label" string.
VALUE rb_profile_frame_singleton_method_p(VALUE frame)
Queries if the method of the passed frame is a singleton class.
VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
Queries the backtrace object of the context.
VALUE rb_profile_frame_absolute_path(VALUE frame)
Identical to rb_profile_frame_path(), except it tries to expand the returning path.
VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
Prepares, executes, then cleans up a debug session.
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
Queries the current receiver of the passed context's upper frame.
VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
Queries the binding of the passed context's upper frame.
VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
Queries the current class of the passed context's upper frame.
VALUE rb_profile_frame_classpath(VALUE frame)
Queries the class path of the method that the passed frame represents.
VALUE rb_profile_frame_path(VALUE frame)
Queries the path of the passed backtrace.
VALUE rb_profile_frame_first_lineno(VALUE frame)
Queries the first line of the method of the passed frame pointer.
int rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines)
Queries mysterious "frame"s of the given range.
VALUE(* rb_debug_inspector_func_t)(const rb_debug_inspector_t *dc, void *data)
Type of the callback function passed to rb_debug_inspector_open().
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:1200
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1002
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2156
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:2622
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
Definition fl_type.h:58
#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:1683
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_IMEMO
Old name of RUBY_T_IMEMO.
Definition value_type.h:67
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#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 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 NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:131
#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:651
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Checks if the given object is of given kind.
Definition error.c:1294
VALUE rb_cArray
Array class.
Definition array.c:39
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:215
VALUE rb_cThread
Thread class.
Definition vm.c:524
#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:631
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:619
Encoding relates APIs.
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Deconstructs a numerical range.
Definition range.c:1744
#define rb_str_new_literal(str)
Just another name of rb_str_new_lit.
Definition string.h:1750
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
Definition string.c:6776
#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:1656
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition variable.c:283
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1274
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:1376
#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:150
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
#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:82
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:515
#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:497
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
Definition variable.c:408
#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:62
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:200
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
Definition method.h:135
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