Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
vm_backtrace.c
Go to the documentation of this file.
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/vm.h"
15#include "iseq.h"
16#include "ruby/debug.h"
17#include "ruby/encoding.h"
18#include "vm_core.h"
19
20static VALUE rb_cBacktrace;
21static VALUE rb_cBacktraceLocation;
22
23static VALUE
24id2str(ID id)
25{
26 VALUE str = rb_id2str(id);
27 if (!str) return Qnil;
28 return str;
29}
30#define rb_id2str(id) id2str(id)
31
32#define BACKTRACE_START 0
33#define ALL_BACKTRACE_LINES -1
34
35inline static int
36calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
37{
38 VM_ASSERT(iseq);
39 VM_ASSERT(iseq->body);
41 VM_ASSERT(iseq->body->iseq_size);
42 if (! pc) {
43 /* This can happen during VM bootup. */
44 VM_ASSERT(iseq->body->type == ISEQ_TYPE_TOP);
45 VM_ASSERT(! iseq->body->local_table);
47 return 0;
48 }
49 else {
50 ptrdiff_t n = pc - iseq->body->iseq_encoded;
51 VM_ASSERT(n <= iseq->body->iseq_size);
52 VM_ASSERT(n >= 0);
53 ASSUME(n >= 0);
54 size_t pos = n; /* no overflow */
55 if (LIKELY(pos)) {
56 /* use pos-1 because PC points next instruction at the beginning of instruction */
57 pos--;
58 }
59#if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
60 else {
61 /* SDR() is not possible; that causes infinite loop. */
63 __builtin_trap();
64 }
65#endif
66 return rb_iseq_line_no(iseq, pos);
67 }
68}
69
70int
72{
73 if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
74 const rb_iseq_t *iseq = cfp->iseq;
75 int line = calc_lineno(iseq, cfp->pc);
76 if (line != 0) {
77 return line;
78 }
79 else {
80 return FIX2INT(rb_iseq_first_lineno(iseq));
81 }
82 }
83 else {
84 return 0;
85 }
86}
87
94
95 union {
96 struct {
98 union {
99 const VALUE *pc;
103 struct {
109
113};
114
115static void
116location_mark(void *ptr)
117{
118 struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
119 rb_gc_mark(vfi->btobj);
120}
121
122static void
123location_mark_entry(rb_backtrace_location_t *fi)
124{
125 switch (fi->type) {
126 case LOCATION_TYPE_ISEQ:
127 case LOCATION_TYPE_ISEQ_CALCED:
129 break;
130 case LOCATION_TYPE_CFUNC:
131 default:
132 break;
133 }
134}
135
136static size_t
137location_memsize(const void *ptr)
138{
139 /* rb_backtrace_location_t *fi = (rb_backtrace_location_t *)ptr; */
140 return sizeof(rb_backtrace_location_t);
141}
142
143static const rb_data_type_t location_data_type = {
144 "frame_info",
145 {location_mark, RUBY_TYPED_DEFAULT_FREE, location_memsize,},
147};
148
149static inline rb_backtrace_location_t *
150location_ptr(VALUE locobj)
151{
152 struct valued_frame_info *vloc;
153 GetCoreDataFromValue(locobj, struct valued_frame_info, vloc);
154 return vloc->loc;
155}
156
157static int
158location_lineno(rb_backtrace_location_t *loc)
159{
160 switch (loc->type) {
161 case LOCATION_TYPE_ISEQ:
162 loc->type = LOCATION_TYPE_ISEQ_CALCED;
163 return (loc->body.iseq.lineno.lineno = calc_lineno(loc->body.iseq.iseq, loc->body.iseq.lineno.pc));
164 case LOCATION_TYPE_ISEQ_CALCED:
165 return loc->body.iseq.lineno.lineno;
166 case LOCATION_TYPE_CFUNC:
167 if (loc->body.cfunc.prev_loc) {
168 return location_lineno(loc->body.cfunc.prev_loc);
169 }
170 return 0;
171 default:
172 rb_bug("location_lineno: unreachable");
174 }
175}
176
177/*
178 * Returns the line number of this frame.
179 *
180 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
181 *
182 * loc = c(0..1).first
183 * loc.lineno #=> 2
184 */
185static VALUE
186location_lineno_m(VALUE self)
187{
188 return INT2FIX(location_lineno(location_ptr(self)));
189}
190
191static VALUE
192location_label(rb_backtrace_location_t *loc)
193{
194 switch (loc->type) {
195 case LOCATION_TYPE_ISEQ:
196 case LOCATION_TYPE_ISEQ_CALCED:
197 return loc->body.iseq.iseq->body->location.label;
198 case LOCATION_TYPE_CFUNC:
199 return rb_id2str(loc->body.cfunc.mid);
200 default:
201 rb_bug("location_label: unreachable");
203 }
204}
205
206/*
207 * Returns the label of this frame.
208 *
209 * Usually consists of method, class, module, etc names with decoration.
210 *
211 * Consider the following example:
212 *
213 * def foo
214 * puts caller_locations(0).first.label
215 *
216 * 1.times do
217 * puts caller_locations(0).first.label
218 *
219 * 1.times do
220 * puts caller_locations(0).first.label
221 * end
222 *
223 * end
224 * end
225 *
226 * The result of calling +foo+ is this:
227 *
228 * label: foo
229 * label: block in foo
230 * label: block (2 levels) in foo
231 *
232 */
233static VALUE
234location_label_m(VALUE self)
235{
236 return location_label(location_ptr(self));
237}
238
239static VALUE
240location_base_label(rb_backtrace_location_t *loc)
241{
242 switch (loc->type) {
243 case LOCATION_TYPE_ISEQ:
244 case LOCATION_TYPE_ISEQ_CALCED:
245 return loc->body.iseq.iseq->body->location.base_label;
246 case LOCATION_TYPE_CFUNC:
247 return rb_id2str(loc->body.cfunc.mid);
248 default:
249 rb_bug("location_base_label: unreachable");
251 }
252}
253
254/*
255 * Returns the base label of this frame.
256 *
257 * Usually same as #label, without decoration.
258 */
259static VALUE
260location_base_label_m(VALUE self)
261{
262 return location_base_label(location_ptr(self));
263}
264
265static VALUE
266location_path(rb_backtrace_location_t *loc)
267{
268 switch (loc->type) {
269 case LOCATION_TYPE_ISEQ:
270 case LOCATION_TYPE_ISEQ_CALCED:
271 return rb_iseq_path(loc->body.iseq.iseq);
272 case LOCATION_TYPE_CFUNC:
273 if (loc->body.cfunc.prev_loc) {
274 return location_path(loc->body.cfunc.prev_loc);
275 }
276 return Qnil;
277 default:
278 rb_bug("location_path: unreachable");
280 }
281}
282
283/*
284 * Returns the file name of this frame. This will generally be an absolute
285 * path, unless the frame is in the main script, in which case it will be the
286 * script location passed on the command line.
287 *
288 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
289 *
290 * loc = c(0..1).first
291 * loc.path #=> caller_locations.rb
292 */
293static VALUE
294location_path_m(VALUE self)
295{
296 return location_path(location_ptr(self));
297}
298
299static VALUE
300location_realpath(rb_backtrace_location_t *loc)
301{
302 switch (loc->type) {
303 case LOCATION_TYPE_ISEQ:
304 case LOCATION_TYPE_ISEQ_CALCED:
305 return rb_iseq_realpath(loc->body.iseq.iseq);
306 case LOCATION_TYPE_CFUNC:
307 if (loc->body.cfunc.prev_loc) {
308 return location_realpath(loc->body.cfunc.prev_loc);
309 }
310 return Qnil;
311 default:
312 rb_bug("location_realpath: unreachable");
314 }
315}
316
317/*
318 * Returns the full file path of this frame.
319 *
320 * Same as #path, except that it will return absolute path
321 * even if the frame is in the main script.
322 */
323static VALUE
324location_absolute_path_m(VALUE self)
325{
326 return location_realpath(location_ptr(self));
327}
328
329static VALUE
330location_format(VALUE file, int lineno, VALUE name)
331{
333 if (lineno != 0) {
334 rb_str_catf(s, ":%d", lineno);
335 }
336 rb_str_cat_cstr(s, ":in ");
337 if (NIL_P(name)) {
338 rb_str_cat_cstr(s, "unknown method");
339 }
340 else {
341 rb_str_catf(s, "`%s'", RSTRING_PTR(name));
342 }
343 return s;
344}
345
346static VALUE
347location_to_str(rb_backtrace_location_t *loc)
348{
349 VALUE file, name;
350 int lineno;
351
352 switch (loc->type) {
353 case LOCATION_TYPE_ISEQ:
354 file = rb_iseq_path(loc->body.iseq.iseq);
355 name = loc->body.iseq.iseq->body->location.label;
356
357 lineno = loc->body.iseq.lineno.lineno = calc_lineno(loc->body.iseq.iseq, loc->body.iseq.lineno.pc);
358 loc->type = LOCATION_TYPE_ISEQ_CALCED;
359 break;
360 case LOCATION_TYPE_ISEQ_CALCED:
361 file = rb_iseq_path(loc->body.iseq.iseq);
362 lineno = loc->body.iseq.lineno.lineno;
363 name = loc->body.iseq.iseq->body->location.label;
364 break;
365 case LOCATION_TYPE_CFUNC:
366 if (loc->body.cfunc.prev_loc) {
368 lineno = location_lineno(loc->body.cfunc.prev_loc);
369 }
370 else {
371 file = GET_VM()->progname;
372 lineno = 0;
373 }
375 break;
376 default:
377 rb_bug("location_to_str: unreachable");
378 }
379
380 return location_format(file, lineno, name);
381}
382
383/*
384 * Returns a Kernel#caller style string representing this frame.
385 */
386static VALUE
387location_to_str_m(VALUE self)
388{
389 return location_to_str(location_ptr(self));
390}
391
392/*
393 * Returns the same as calling +inspect+ on the string representation of
394 * #to_str
395 */
396static VALUE
397location_inspect_m(VALUE self)
398{
399 return rb_str_inspect(location_to_str(location_ptr(self)));
400}
401
402typedef struct rb_backtrace_struct {
408
409static void
410backtrace_mark(void *ptr)
411{
413 size_t i, s = bt->backtrace_size;
414
415 for (i=0; i<s; i++) {
416 location_mark_entry(&bt->backtrace[i]);
417 }
420}
421
422static void
423backtrace_free(void *ptr)
424{
426 if (bt->backtrace) ruby_xfree(bt->backtrace);
427 ruby_xfree(bt);
428}
429
430static void
431location_update_entry(rb_backtrace_location_t *fi)
432{
433 switch (fi->type) {
434 case LOCATION_TYPE_ISEQ:
435 case LOCATION_TYPE_ISEQ_CALCED:
436 fi->body.iseq.iseq = (rb_iseq_t*)rb_gc_location((VALUE)fi->body.iseq.iseq);
437 break;
438 case LOCATION_TYPE_CFUNC:
439 default:
440 break;
441 }
442}
443
444static void
445backtrace_update(void *ptr)
446{
448 size_t i, s = bt->backtrace_size;
449
450 for (i=0; i<s; i++) {
451 location_update_entry(&bt->backtrace[i]);
452 }
453 bt->strary = rb_gc_location(bt->strary);
454 bt->locary = rb_gc_location(bt->locary);
455}
456
457static size_t
458backtrace_memsize(const void *ptr)
459{
461 return sizeof(rb_backtrace_t) + sizeof(rb_backtrace_location_t) * bt->backtrace_size;
462}
463
464static const rb_data_type_t backtrace_data_type = {
465 "backtrace",
466 {backtrace_mark, backtrace_free, backtrace_memsize, backtrace_update},
468};
469
470int
472{
473 return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
474}
475
476static VALUE
477backtrace_alloc(VALUE klass)
478{
479 rb_backtrace_t *bt;
480 VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
481 return obj;
482}
483
484static long
485backtrace_size(const rb_execution_context_t *ec)
486{
487 const rb_control_frame_t *last_cfp = ec->cfp;
488 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
489
490 if (start_cfp == NULL) {
491 return -1;
492 }
493
494 start_cfp =
496 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
497
498 if (start_cfp < last_cfp) {
499 return 0;
500 }
501
502 return start_cfp - last_cfp + 1;
503}
504
505static bool is_internal_location(const rb_control_frame_t *cfp);
506static void bt_iter_skip_skip_internal(void *ptr, const rb_control_frame_t *cfp);
507
508static int
509backtrace_each(const rb_execution_context_t *ec,
510 ptrdiff_t from_last,
511 long num_frames,
512 void (*init)(void *arg, size_t size),
513 void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
514 void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
515 void (*iter_skip)(void *arg, const rb_control_frame_t *cfp),
516 void *arg)
517{
518 const rb_control_frame_t *last_cfp = ec->cfp;
519 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
520 const rb_control_frame_t *cfp;
521 ptrdiff_t size, real_size, i, j, last, start = 0;
522 int ret = 0;
523
524 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
525 if (start_cfp == NULL) {
526 init(arg, 0);
527 return ret;
528 }
529
530 /* <- start_cfp (end control frame)
531 * top frame (dummy)
532 * top frame (dummy)
533 * top frame <- start_cfp
534 * top frame
535 * ...
536 * 2nd frame <- lev:0
537 * current frame <- ec->cfp
538 */
539
540 start_cfp =
542 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
543
544 if (start_cfp < last_cfp) {
545 real_size = size = last = 0;
546 }
547 else {
548 /* Ensure we don't look at frames beyond the ones requested */
549 for(; from_last > 0 && start_cfp >= last_cfp; from_last--) {
550 if (last_cfp->iseq && !last_cfp->pc) {
551 from_last++;
552 }
553 last_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(last_cfp);
554 }
555
556 real_size = size = start_cfp - last_cfp + 1;
557
558 if (from_last > size) {
559 size = last = 0;
560 ret = 1;
561 }
562 else if (num_frames >= 0 && num_frames < size) {
563 if (from_last + num_frames > size) {
564 size -= from_last;
565 last = size;
566 }
567 else {
568 start = size - from_last - num_frames;
569 size = num_frames;
570 last = start + size;
571 }
572 }
573 else {
574 size -= from_last;
575 last = size;
576 }
577 }
578
579 init(arg, size);
580
581 /* If a limited number of frames is requested, scan the VM stack for
582 * from the current frame (after skipping the number of frames requested above)
583 * towards the earliest frame (start_cfp). Track the total number of frames
584 * and the number of frames that will be part of the backtrace. Start the
585 * scan at the oldest frame that should still be part of the backtrace.
586 *
587 * If the last frame in the backtrace is a cfunc frame, continue scanning
588 * till earliest frame to find the first iseq frame with pc, so that the
589 * location can be used for the trailing cfunc frames in the backtrace.
590 */
591 if (start > 0 && num_frames >= 0 && num_frames < real_size) {
592 int found_frames = 0, total_frames = 0;
593 bool last_frame_cfunc = FALSE;
594 const rb_control_frame_t *new_start_cfp;
595
596 for (cfp = last_cfp; found_frames < num_frames && start_cfp >= cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp), total_frames++) {
597 if ((cfp->iseq && cfp->pc) || RUBYVM_CFUNC_FRAME_P(cfp)) {
598 last_frame_cfunc = RUBYVM_CFUNC_FRAME_P(cfp);
599 found_frames++;
600 }
601 }
602 new_start_cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp);
603 if (iter_skip && (last_frame_cfunc || iter_skip == bt_iter_skip_skip_internal)) {
604 for (; start_cfp >= cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
605 if (cfp->iseq && cfp->pc && (iter_skip != bt_iter_skip_skip_internal || !is_internal_location(cfp))) {
606 iter_skip(arg, cfp);
607 break;
608 }
609 }
610 }
611
612 last = found_frames;
613 real_size = total_frames;
614 start = 0;
615 start_cfp = new_start_cfp;
616 }
617
618 for (i=0, j=0, cfp = start_cfp; i<last && j<real_size; i++, j++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
619 if (j < start) {
620 if (iter_skip) {
621 iter_skip(arg, cfp);
622 }
623 continue;
624 }
625
626 /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
627 if (cfp->iseq) {
628 if (cfp->pc) {
629 iter_iseq(arg, cfp);
630 } else {
631 i--;
632 }
633 }
634 else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
636 ID mid = me->def->original_id;
637
638 iter_cfunc(arg, cfp, mid);
639 }
640 }
641
642 return ret;
643}
644
651};
652
653static bool
654is_internal_location(const rb_control_frame_t *cfp)
655{
656 static const char prefix[] = "<internal:";
657 const size_t prefix_len = sizeof(prefix) - 1;
658 VALUE file = rb_iseq_path(cfp->iseq);
659 return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0;
660}
661
662static void
663bt_init(void *ptr, size_t size)
664{
665 struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
666 arg->btobj = backtrace_alloc(rb_cBacktrace);
669 arg->bt->backtrace_size = 1;
670 arg->prev_cfp = NULL;
671 arg->init_loc = &arg->bt->backtrace[size];
672}
673
674static void
675bt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
676{
677 const rb_iseq_t *iseq = cfp->iseq;
678 const VALUE *pc = cfp->pc;
679 struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
680 rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++-1];
681 loc->type = LOCATION_TYPE_ISEQ;
682 loc->body.iseq.iseq = iseq;
683 loc->body.iseq.lineno.pc = pc;
684 arg->prev_loc = loc;
685}
686
687static void
688bt_iter_iseq_skip_internal(void *ptr, const rb_control_frame_t *cfp)
689{
690 struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
691 rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++-1];
692
693 if (!is_internal_location(cfp)) {
694 loc->type = LOCATION_TYPE_ISEQ;
695 loc->body.iseq.iseq = cfp->iseq;
696 loc->body.iseq.lineno.pc = cfp->pc;
697 arg->prev_loc = loc;
698 } else if (arg->prev_cfp) {
699 loc->type = LOCATION_TYPE_ISEQ;
700 loc->body.iseq.iseq = arg->prev_cfp->iseq;
701 loc->body.iseq.lineno.pc = arg->prev_cfp->pc;
702 arg->prev_loc = loc;
703 } else {
704 rb_bug("No non-internal backtrace entry before an <internal: backtrace entry");
705 }
706}
707
708static void
709bt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
710{
711 struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
712 rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++-1];
713 loc->type = LOCATION_TYPE_CFUNC;
714 loc->body.cfunc.mid = mid;
715 if (arg->prev_loc) {
716 loc->body.cfunc.prev_loc = arg->prev_loc;
717 }
718 else if (arg->prev_cfp) {
719 const rb_iseq_t *iseq = arg->prev_cfp->iseq;
720 const VALUE *pc = arg->prev_cfp->pc;
721 arg->init_loc->type = LOCATION_TYPE_ISEQ;
722 arg->init_loc->body.iseq.iseq = iseq;
723 arg->init_loc->body.iseq.lineno.pc = pc;
724 loc->body.cfunc.prev_loc = arg->prev_loc = arg->init_loc;
725 } else {
726 loc->body.cfunc.prev_loc = NULL;
727 }
728}
729
730static void
731bt_iter_skip(void *ptr, const rb_control_frame_t *cfp)
732{
733 if (cfp->iseq && cfp->pc) {
734 ((struct bt_iter_arg *)ptr)->prev_cfp = cfp;
735 }
736}
737
738static void
739bt_iter_skip_skip_internal(void *ptr, const rb_control_frame_t *cfp)
740{
741 if (cfp->iseq && cfp->pc) {
742 if (!is_internal_location(cfp)) {
743 ((struct bt_iter_arg *) ptr)->prev_cfp = cfp;
744 }
745 }
746}
747
748static VALUE
749rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long lev, long n, int* level_too_large, bool skip_internal)
750{
751 struct bt_iter_arg arg;
752 int too_large;
753 arg.prev_loc = 0;
754
755 too_large = backtrace_each(ec,
756 lev,
757 n,
758 bt_init,
759 skip_internal ? bt_iter_iseq_skip_internal : bt_iter_iseq,
760 bt_iter_cfunc,
761 skip_internal ? bt_iter_skip_skip_internal : bt_iter_skip,
762 &arg);
763
764 if (level_too_large) *level_too_large = too_large;
765
766 return arg.btobj;
767}
768
771{
772 return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL, FALSE);
773}
774
775static VALUE
776backtrace_collect(rb_backtrace_t *bt, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
777{
778 VALUE btary;
779 int i;
780
781 btary = rb_ary_new2(bt->backtrace_size-1);
782
783 for (i=0; i<bt->backtrace_size-1; i++) {
785 rb_ary_push(btary, func(loc, arg));
786 }
787
788 return btary;
789}
790
791static VALUE
792location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
793{
794 return location_to_str(loc);
795}
796
797static VALUE
798backtrace_to_str_ary(VALUE self)
799{
800 VALUE r;
803 r = backtrace_collect(bt, location_to_str_dmyarg, 0);
804 RB_GC_GUARD(self);
805 return r;
806}
807
808VALUE
810{
813
814 if (!bt->strary) {
815 bt->strary = backtrace_to_str_ary(self);
816 }
817 return bt->strary;
818}
819
822{
823 const rb_backtrace_t *bt;
824 const rb_iseq_t *iseq;
826
829
830 loc = &bt->backtrace[bt->backtrace_size - 2];
831 iseq = loc->body.iseq.iseq;
832
833 VM_ASSERT(loc->type == LOCATION_TYPE_ISEQ);
834
835 loc->body.iseq.lineno.lineno = FIX2INT(iseq->body->location.first_lineno);
836 loc->type = LOCATION_TYPE_ISEQ_CALCED;
837}
838
839static VALUE
840location_create(rb_backtrace_location_t *srcloc, void *btobj)
841{
842 VALUE obj;
843 struct valued_frame_info *vloc;
844 obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
845
846 vloc->loc = srcloc;
847 vloc->btobj = (VALUE)btobj;
848
849 return obj;
850}
851
852static VALUE
853backtrace_to_location_ary(VALUE self)
854{
855 VALUE r;
856 rb_backtrace_t *bt;
858 r = backtrace_collect(bt, location_create, (void *)self);
859 RB_GC_GUARD(self);
860 return r;
861}
862
863VALUE
865{
866 rb_backtrace_t *bt;
868
869 if (!bt->locary) {
870 bt->locary = backtrace_to_location_ary(self);
871 }
872 return bt->locary;
873}
874
875static VALUE
876backtrace_dump_data(VALUE self)
877{
879 return str;
880}
881
882static VALUE
883backtrace_load_data(VALUE self, VALUE str)
884{
885 rb_backtrace_t *bt;
887 bt->strary = str;
888 return self;
889}
890
891VALUE
893{
894 return backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE));
895}
896
897VALUE
898rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal)
899{
900 return backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal));
901}
902
903/* make old style backtrace directly */
904
905struct oldbt_arg {
908 void (*func)(void *data, VALUE file, int lineno, VALUE name);
909 void *data; /* result */
910};
911
912static void
913oldbt_init(void *ptr, size_t dmy)
914{
915 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
916 arg->filename = GET_VM()->progname;
917 arg->lineno = 0;
918}
919
920static void
921oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
922{
923 const rb_iseq_t *iseq = cfp->iseq;
924 const VALUE *pc = cfp->pc;
925 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
926 VALUE file = arg->filename = rb_iseq_path(iseq);
927 VALUE name = iseq->body->location.label;
928 int lineno = arg->lineno = calc_lineno(iseq, pc);
929
930 (arg->func)(arg->data, file, lineno, name);
931}
932
933static void
934oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
935{
936 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
937 VALUE file = arg->filename;
938 VALUE name = rb_id2str(mid);
939 int lineno = arg->lineno;
940
941 (arg->func)(arg->data, file, lineno, name);
942}
943
944static void
945oldbt_print(void *data, VALUE file, int lineno, VALUE name)
946{
947 FILE *fp = (FILE *)data;
948
949 if (NIL_P(name)) {
950 fprintf(fp, "\tfrom %s:%d:in unknown method\n",
952 }
953 else {
954 fprintf(fp, "\tfrom %s:%d:in `%s'\n",
956 }
957}
958
959static void
960vm_backtrace_print(FILE *fp)
961{
962 struct oldbt_arg arg;
963
964 arg.func = oldbt_print;
965 arg.data = (void *)fp;
966 backtrace_each(GET_EC(),
969 oldbt_init,
970 oldbt_iter_iseq,
971 oldbt_iter_cfunc,
972 NULL,
973 &arg);
974}
975
976static void
977oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
978{
979 const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
980 if (!*(int *)arg) {
981 fprintf(stderr, "-- Ruby level backtrace information "
982 "----------------------------------------\n");
983 *(int *)arg = 1;
984 }
985 if (NIL_P(method)) {
986 fprintf(stderr, "%s:%d:in unknown method\n", filename, line);
987 }
988 else {
989 fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
990 }
991}
992
993void
995{
996 struct oldbt_arg arg;
997 int i = 0;
998
999 arg.func = oldbt_bugreport;
1000 arg.data = (int *)&i;
1001
1002 backtrace_each(GET_EC(),
1005 oldbt_init,
1006 oldbt_iter_iseq,
1007 oldbt_iter_cfunc,
1008 NULL,
1009 &arg);
1010}
1011
1012void
1014{
1015 vm_backtrace_print(stderr);
1016}
1017
1021};
1022
1023static void
1024oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
1025{
1026 const struct print_to_arg *arg = data;
1027 VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
1028
1029 if (NIL_P(name)) {
1030 rb_str_cat2(str, "unknown method\n");
1031 }
1032 else {
1033 rb_str_catf(str, " `%"PRIsVALUE"'\n", name);
1034 }
1035 (*arg->iter)(arg->output, str);
1036}
1037
1038void
1040{
1041 struct oldbt_arg arg;
1042 struct print_to_arg parg;
1043
1044 parg.iter = iter;
1045 parg.output = output;
1046 arg.func = oldbt_print_to;
1047 arg.data = &parg;
1048 backtrace_each(GET_EC(),
1051 oldbt_init,
1052 oldbt_iter_iseq,
1053 oldbt_iter_cfunc,
1054 NULL,
1055 &arg);
1056}
1057
1058VALUE
1060{
1062}
1063
1064static VALUE
1065ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str)
1066{
1067 VALUE level, vn;
1068 long lev, n;
1069 VALUE btval;
1070 VALUE r;
1071 int too_large;
1072
1073 rb_scan_args(argc, argv, "02", &level, &vn);
1074
1075 if (argc == 2 && NIL_P(vn)) argc--;
1076
1077 switch (argc) {
1078 case 0:
1079 lev = lev_default + lev_plus;
1081 break;
1082 case 1:
1083 {
1084 long beg, len, bt_size = backtrace_size(ec);
1085 switch (rb_range_beg_len(level, &beg, &len, bt_size - lev_plus, 0)) {
1086 case Qfalse:
1087 lev = NUM2LONG(level);
1088 if (lev < 0) {
1089 rb_raise(rb_eArgError, "negative level (%ld)", lev);
1090 }
1091 lev += lev_plus;
1093 break;
1094 case Qnil:
1095 return Qnil;
1096 default:
1097 lev = beg + lev_plus;
1098 n = len;
1099 break;
1100 }
1101 break;
1102 }
1103 case 2:
1104 lev = NUM2LONG(level);
1105 n = NUM2LONG(vn);
1106 if (lev < 0) {
1107 rb_raise(rb_eArgError, "negative level (%ld)", lev);
1108 }
1109 if (n < 0) {
1110 rb_raise(rb_eArgError, "negative size (%ld)", n);
1111 }
1112 lev += lev_plus;
1113 break;
1114 default:
1115 lev = n = 0; /* to avoid warning */
1116 break;
1117 }
1118
1119 if (n == 0) {
1120 return rb_ary_new();
1121 }
1122
1123 btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE);
1124
1125 if (too_large) {
1126 return Qnil;
1127 }
1128
1129 if (to_str) {
1130 r = backtrace_to_str_ary(btval);
1131 }
1132 else {
1133 r = backtrace_to_location_ary(btval);
1134 }
1135 RB_GC_GUARD(btval);
1136 return r;
1137}
1138
1139static VALUE
1140thread_backtrace_to_ary(int argc, const VALUE *argv, VALUE thval, int to_str)
1141{
1142 rb_thread_t *target_th = rb_thread_ptr(thval);
1143
1144 if (target_th->to_kill || target_th->status == THREAD_KILLED)
1145 return Qnil;
1146
1147 return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1148}
1149
1150VALUE
1152{
1153 return thread_backtrace_to_ary(argc, argv, thval, 1);
1154}
1155
1156VALUE
1158{
1159 return thread_backtrace_to_ary(argc, argv, thval, 0);
1160}
1161
1163{
1164 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1165}
1166
1168{
1169 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1170}
1171
1172/*
1173 * call-seq:
1174 * caller(start=1, length=nil) -> array or nil
1175 * caller(range) -> array or nil
1176 *
1177 * Returns the current execution stack---an array containing strings in
1178 * the form <code>file:line</code> or <code>file:line: in
1179 * `method'</code>.
1180 *
1181 * The optional _start_ parameter determines the number of initial stack
1182 * entries to omit from the top of the stack.
1183 *
1184 * A second optional +length+ parameter can be used to limit how many entries
1185 * are returned from the stack.
1186 *
1187 * Returns +nil+ if _start_ is greater than the size of
1188 * current execution stack.
1189 *
1190 * Optionally you can pass a range, which will return an array containing the
1191 * entries within the specified range.
1192 *
1193 * def a(skip)
1194 * caller(skip)
1195 * end
1196 * def b(skip)
1197 * a(skip)
1198 * end
1199 * def c(skip)
1200 * b(skip)
1201 * end
1202 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1203 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1204 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1205 * c(3) #=> ["prog:13:in `<main>'"]
1206 * c(4) #=> []
1207 * c(5) #=> nil
1208 */
1209
1210static VALUE
1211rb_f_caller(int argc, VALUE *argv, VALUE _)
1212{
1213 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1214}
1215
1216/*
1217 * call-seq:
1218 * caller_locations(start=1, length=nil) -> array or nil
1219 * caller_locations(range) -> array or nil
1220 *
1221 * Returns the current execution stack---an array containing
1222 * backtrace location objects.
1223 *
1224 * See Thread::Backtrace::Location for more information.
1225 *
1226 * The optional _start_ parameter determines the number of initial stack
1227 * entries to omit from the top of the stack.
1228 *
1229 * A second optional +length+ parameter can be used to limit how many entries
1230 * are returned from the stack.
1231 *
1232 * Returns +nil+ if _start_ is greater than the size of
1233 * current execution stack.
1234 *
1235 * Optionally you can pass a range, which will return an array containing the
1236 * entries within the specified range.
1237 */
1238static VALUE
1239rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
1240{
1241 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1242}
1243
1244/* called from Init_vm() in vm.c */
1245void
1247{
1248 /* :nodoc: */
1249 rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
1250 rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
1251 rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
1252 rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
1253
1254 /*
1255 * An object representation of a stack frame, initialized by
1256 * Kernel#caller_locations.
1257 *
1258 * For example:
1259 *
1260 * # caller_locations.rb
1261 * def a(skip)
1262 * caller_locations(skip)
1263 * end
1264 * def b(skip)
1265 * a(skip)
1266 * end
1267 * def c(skip)
1268 * b(skip)
1269 * end
1270 *
1271 * c(0..2).map do |call|
1272 * puts call.to_s
1273 * end
1274 *
1275 * Running <code>ruby caller_locations.rb</code> will produce:
1276 *
1277 * caller_locations.rb:2:in `a'
1278 * caller_locations.rb:5:in `b'
1279 * caller_locations.rb:8:in `c'
1280 *
1281 * Here's another example with a slightly different result:
1282 *
1283 * # foo.rb
1284 * class Foo
1285 * attr_accessor :locations
1286 * def initialize(skip)
1287 * @locations = caller_locations(skip)
1288 * end
1289 * end
1290 *
1291 * Foo.new(0..2).locations.map do |call|
1292 * puts call.to_s
1293 * end
1294 *
1295 * Now run <code>ruby foo.rb</code> and you should see:
1296 *
1297 * init.rb:4:in `initialize'
1298 * init.rb:8:in `new'
1299 * init.rb:8:in `<main>'
1300 */
1301 rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
1302 rb_undef_alloc_func(rb_cBacktraceLocation);
1303 rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
1304 rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
1305 rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
1306 rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
1307 rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
1308 rb_define_method(rb_cBacktraceLocation, "absolute_path", location_absolute_path_m, 0);
1309 rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
1310 rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
1311
1312 rb_define_global_function("caller", rb_f_caller, -1);
1313 rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1314}
1315
1316/* debugger API */
1317
1318RUBY_SYMBOL_EXPORT_BEGIN
1319
1320RUBY_SYMBOL_EXPORT_END
1321
1326 VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1328};
1329
1330enum {
1337
1340};
1341
1342static void
1343collect_caller_bindings_init(void *arg, size_t size)
1344{
1345 /* */
1346}
1347
1348static VALUE
1349get_klass(const rb_control_frame_t *cfp)
1350{
1351 VALUE klass;
1352 if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
1353 if (RB_TYPE_P(klass, T_ICLASS)) {
1354 return RBASIC(klass)->klass;
1355 }
1356 else {
1357 return klass;
1358 }
1359 }
1360 else {
1361 return Qnil;
1362 }
1363}
1364
1365static void
1366collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
1367{
1369 VALUE frame = rb_ary_new2(5);
1370
1372 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1373 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
1374 rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? (VALUE)cfp->iseq : Qnil);
1376
1377 rb_ary_push(data->ary, frame);
1378}
1379
1380static void
1381collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
1382{
1384 VALUE frame = rb_ary_new2(5);
1385
1387 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1388 rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
1389 rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
1391
1392 rb_ary_push(data->ary, frame);
1393}
1394
1395static VALUE
1396collect_caller_bindings(const rb_execution_context_t *ec)
1397{
1398 struct collect_caller_bindings_data data;
1399 VALUE result;
1400 int i;
1401
1402 data.ary = rb_ary_new();
1403
1404 backtrace_each(ec,
1407 collect_caller_bindings_init,
1408 collect_caller_bindings_iseq,
1409 collect_caller_bindings_cfunc,
1410 NULL,
1411 &data);
1412
1413 result = rb_ary_reverse(data.ary);
1414
1415 /* bindings should be created from top of frame */
1416 for (i=0; i<RARRAY_LEN(result); i++) {
1417 VALUE entry = rb_ary_entry(result, i);
1418 VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
1419
1420 if (!NIL_P(cfp_val)) {
1421 rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
1423 }
1424 }
1425
1426 return result;
1427}
1428
1429/*
1430 * Note that the passed `rb_debug_inspector_t' will be disabled
1431 * after `rb_debug_inspector_open'.
1432 */
1433
1434VALUE
1436{
1437 rb_debug_inspector_t dbg_context;
1438 rb_execution_context_t *ec = GET_EC();
1439 enum ruby_tag_type state;
1440 volatile VALUE MAYBE_UNUSED(result);
1441
1442 /* escape all env to heap */
1444
1445 dbg_context.ec = ec;
1446 dbg_context.cfp = dbg_context.ec->cfp;
1448 dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
1449 dbg_context.contexts = collect_caller_bindings(ec);
1450
1451 EC_PUSH_TAG(ec);
1452 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1453 result = (*func)(&dbg_context, data);
1454 }
1455 EC_POP_TAG();
1456
1457 /* invalidate bindings? */
1458
1459 if (state) {
1460 EC_JUMP_TAG(ec, state);
1461 }
1462
1463 return result;
1464}
1465
1466static VALUE
1467frame_get(const rb_debug_inspector_t *dc, long index)
1468{
1469 if (index < 0 || index >= dc->backtrace_size) {
1470 rb_raise(rb_eArgError, "no such frame");
1471 }
1472 return rb_ary_entry(dc->contexts, index);
1473}
1474
1475VALUE
1477{
1478 VALUE frame = frame_get(dc, index);
1479 return rb_ary_entry(frame, CALLER_BINDING_SELF);
1480}
1481
1482VALUE
1484{
1485 VALUE frame = frame_get(dc, index);
1486 return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1487}
1488
1489VALUE
1491{
1492 VALUE frame = frame_get(dc, index);
1493 return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1494}
1495
1496VALUE
1498{
1499 VALUE frame = frame_get(dc, index);
1500 VALUE iseq = rb_ary_entry(frame, CALLER_BINDING_ISEQ);
1501
1502 return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) : Qnil;
1503}
1504
1505VALUE
1507{
1508 return dc->backtrace;
1509}
1510
1511int
1512rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
1513{
1514 int i;
1515 const rb_execution_context_t *ec = GET_EC();
1516 const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
1517 const rb_callable_method_entry_t *cme;
1518
1519 for (i=0; i<limit && cfp != end_cfp;) {
1520 if (VM_FRAME_RUBYFRAME_P(cfp)) {
1521 if (start > 0) {
1522 start--;
1523 continue;
1524 }
1525
1526 /* record frame info */
1527 cme = rb_vm_frame_method_entry(cfp);
1528 if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
1529 buff[i] = (VALUE)cme;
1530 }
1531 else {
1532 buff[i] = (VALUE)cfp->iseq;
1533 }
1534
1535 if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc);
1536
1537 i++;
1538 }
1539 else {
1540 cme = rb_vm_frame_method_entry(cfp);
1541 if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
1542 buff[i] = (VALUE)cme;
1543 if (lines) lines[i] = 0;
1544 i++;
1545 }
1546 }
1548 }
1549
1550 return i;
1551}
1552
1553static const rb_iseq_t *
1554frame2iseq(VALUE frame)
1555{
1556 if (frame == Qnil) return NULL;
1557
1558 if (RB_TYPE_P(frame, T_IMEMO)) {
1559 switch (imemo_type(frame)) {
1560 case imemo_iseq:
1561 return (const rb_iseq_t *)frame;
1562 case imemo_ment:
1563 {
1565 switch (cme->def->type) {
1567 return cme->def->body.iseq.iseqptr;
1568 default:
1569 return NULL;
1570 }
1571 }
1572 default:
1573 break;
1574 }
1575 }
1576 rb_bug("frame2iseq: unreachable");
1577}
1578
1579VALUE
1581{
1582 const rb_iseq_t *iseq = frame2iseq(frame);
1583 return iseq ? rb_iseq_path(iseq) : Qnil;
1584}
1585
1586static const rb_callable_method_entry_t *
1587cframe(VALUE frame)
1588{
1589 if (frame == Qnil) return NULL;
1590
1591 if (RB_TYPE_P(frame, T_IMEMO)) {
1592 switch (imemo_type(frame)) {
1593 case imemo_ment:
1594 {
1596 switch (cme->def->type) {
1598 return cme;
1599 default:
1600 return NULL;
1601 }
1602 }
1603 default:
1604 return NULL;
1605 }
1606 }
1607
1608 return NULL;
1609}
1610
1611VALUE
1613{
1614 if (cframe(frame)) {
1615 static VALUE cfunc_str = Qfalse;
1616 if (!cfunc_str) {
1617 cfunc_str = rb_str_new_literal("<cfunc>");
1618 rb_gc_register_mark_object(cfunc_str);
1619 }
1620 return cfunc_str;
1621 }
1622 const rb_iseq_t *iseq = frame2iseq(frame);
1623 return iseq ? rb_iseq_realpath(iseq) : Qnil;
1624}
1625
1626VALUE
1628{
1629 const rb_iseq_t *iseq = frame2iseq(frame);
1630 return iseq ? rb_iseq_label(iseq) : Qnil;
1631}
1632
1633VALUE
1635{
1636 const rb_iseq_t *iseq = frame2iseq(frame);
1637 return iseq ? rb_iseq_base_label(iseq) : Qnil;
1638}
1639
1640VALUE
1642{
1643 const rb_iseq_t *iseq = frame2iseq(frame);
1644 return iseq ? rb_iseq_first_lineno(iseq) : Qnil;
1645}
1646
1647static VALUE
1648frame2klass(VALUE frame)
1649{
1650 if (frame == Qnil) return Qnil;
1651
1652 if (RB_TYPE_P(frame, T_IMEMO)) {
1654
1655 if (imemo_type(frame) == imemo_ment) {
1656 return cme->defined_class;
1657 }
1658 }
1659 return Qnil;
1660}
1661
1662VALUE
1664{
1665 VALUE klass = frame2klass(frame);
1666
1667 if (klass && !NIL_P(klass)) {
1668 if (RB_TYPE_P(klass, T_ICLASS)) {
1669 klass = RBASIC(klass)->klass;
1670 }
1671 else if (FL_TEST(klass, FL_SINGLETON)) {
1672 klass = rb_ivar_get(klass, id__attached__);
1673 if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE))
1674 return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass);
1675 }
1676 return rb_class_path(klass);
1677 }
1678 else {
1679 return Qnil;
1680 }
1681}
1682
1683VALUE
1685{
1686 VALUE klass = frame2klass(frame);
1687
1688 if (klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON)) {
1689 return Qtrue;
1690 }
1691 else {
1692 return Qfalse;
1693 }
1694}
1695
1696VALUE
1698{
1699 const rb_callable_method_entry_t *cme = cframe(frame);
1700 if (cme) {
1701 ID mid = cme->def->original_id;
1702 return id2str(mid);
1703 }
1704 const rb_iseq_t *iseq = frame2iseq(frame);
1705 return iseq ? rb_iseq_method_name(iseq) : Qnil;
1706}
1707
1708static VALUE
1709qualified_method_name(VALUE frame, VALUE method_name)
1710{
1711 if (method_name != Qnil) {
1712 VALUE classpath = rb_profile_frame_classpath(frame);
1713 VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
1714
1715 if (classpath != Qnil) {
1716 return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
1717 classpath, singleton_p == Qtrue ? "." : "#", method_name);
1718 }
1719 else {
1720 return method_name;
1721 }
1722 }
1723 else {
1724 return Qnil;
1725 }
1726}
1727
1728VALUE
1730{
1731 VALUE method_name = rb_profile_frame_method_name(frame);
1732
1733 return qualified_method_name(frame, method_name);
1734}
1735
1736VALUE
1738{
1739 const rb_callable_method_entry_t *cme = cframe(frame);
1740 if (cme) {
1741 ID mid = cme->def->original_id;
1742 VALUE method_name = id2str(mid);
1743 return qualified_method_name(frame, method_name);
1744 }
1745
1746 VALUE label = rb_profile_frame_label(frame);
1747 VALUE base_label = rb_profile_frame_base_label(frame);
1748 VALUE qualified_method_name = rb_profile_frame_qualified_method_name(frame);
1749
1750 if (NIL_P(qualified_method_name) || base_label == qualified_method_name) {
1751 return label;
1752 }
1753 else {
1754 long label_length = RSTRING_LEN(label);
1755 long base_label_length = RSTRING_LEN(base_label);
1756 int prefix_len = rb_long2int(label_length - base_label_length);
1757
1758 return rb_sprintf("%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);
1759 }
1760}
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:1141
VALUE rb_ary_reverse(VALUE ary)
Definition: array.c:2998
VALUE rb_cArray
Definition: array.c:40
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
VALUE rb_ary_new(void)
Definition: array.c:749
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1672
#define UNREACHABLE
Definition: assume.h:30
#define ASSUME
Definition: assume.h:29
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Definition: cxxanyargs.hpp:678
struct RIMemo * ptr
Definition: debug.c:88
VALUE(* rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *)
Definition: debug.h:38
#define MJIT_FUNC_EXPORTED
Definition: dllexport.h:55
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Definition: encoding.c:1172
uint8_t len
Definition: escape.c:17
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
#define EC_EXEC_TAG()
Definition: eval_intern.h:193
#define EC_PUSH_TAG(ec)
Definition: eval_intern.h:130
#define EC_JUMP_TAG(ec, st)
Definition: eval_intern.h:196
#define EC_POP_TAG()
Definition: eval_intern.h:138
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
#define MAYBE_UNUSED
Definition: ffi_common.h:30
#define LIKELY(x)
Definition: ffi_common.h:125
#define FL_SINGLETON
Definition: fl_type.h:49
#define PRIsVALUE
Definition: function.c:10
void ruby_xfree(void *x)
Deallocates a storage instance.
Definition: gc.c:10914
VALUE rb_gc_location(VALUE value)
Definition: gc.c:9003
void rb_gc_mark_movable(VALUE ptr)
Definition: gc.c:6106
void rb_gc_mark(VALUE ptr)
Definition: gc.c:6112
void rb_gc_register_mark_object(VALUE obj)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Definition: gc.c:8022
#define CLASS_OF
Definition: globals.h:153
VALUE rb_cThread
Definition: vm.c:374
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:797
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1777
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
#define FL_TEST
Definition: fl_type.h:130
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:1007
void rb_bug(const char *fmt,...)
Definition: error.c:768
VALUE rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal)
Definition: vm_backtrace.c:898
VALUE rb_eArgError
Definition: error.c:1058
VALUE rb_iseqw_new(const rb_iseq_t *)
Definition: iseq.c:1217
VALUE rb_cObject
Object class.
Definition: object.c:49
VALUE rb_obj_class(VALUE)
Definition: object.c:245
unsigned short prefix[65536]
Definition: gun.c:163
imemo_type
Definition: imemo.h:34
@ imemo_ment
Definition: imemo.h:41
@ imemo_iseq
Definition: imemo.h:42
VALUE rb_enc_sprintf(rb_encoding *, const char *,...)
Definition: sprintf.c:1184
#define rb_ary_new2
Definition: array.h:72
VALUE rb_range_beg_len(VALUE, long *, long *, long, int)
Definition: range.c:1398
#define rb_str_cat2
Definition: string.h:285
#define rb_str_new_literal(str)
Definition: string.h:291
VALUE rb_str_inspect(VALUE)
Definition: string.c:6199
#define rb_str_cat_cstr(buf, str)
Definition: string.h:266
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1234
VALUE rb_class_path(VALUE)
Definition: variable.c:169
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
void rb_undef_alloc_func(VALUE)
Definition: vm_method.c:954
#define FIX2INT
Definition: int.h:41
Internal header for RubyVM.
void rb_print_backtrace(void)
Definition: vm_dump.c:753
voidpf void uLong size
Definition: ioapi.h:138
const char * filename
Definition: ioapi.h:137
VALUE rb_iseq_path(const rb_iseq_t *iseq)
Definition: iseq.c:1087
unsigned int rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
Definition: iseq.c:1821
VALUE rb_iseq_label(const rb_iseq_t *iseq)
Definition: iseq.c:1105
VALUE rb_iseq_base_label(const rb_iseq_t *iseq)
Definition: iseq.c:1111
VALUE rb_iseq_first_lineno(const rb_iseq_t *iseq)
Definition: iseq.c:1117
VALUE rb_iseq_method_name(const rb_iseq_t *iseq)
Definition: iseq.c:1123
VALUE rb_iseq_realpath(const rb_iseq_t *iseq)
Definition: iseq.c:1093
#define INT2FIX
Definition: long.h:48
#define rb_long2int
Definition: long.h:62
#define NUM2LONG
Definition: long.h:51
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Definition: marshal.c:146
#define ZALLOC_N
Definition: memory.h:135
#define RB_GC_GUARD(v)
Definition: memory.h:91
@ VM_METHOD_TYPE_ISEQ
Ruby method.
Definition: method.h:110
@ VM_METHOD_TYPE_CFUNC
C method.
Definition: method.h:111
const char * name
Definition: nkf.c:208
unsigned int last
Definition: nkf.c:4324
#define FALSE
Definition: nkf.h:174
#define RARRAY_LEN
Definition: rarray.h:52
#define RBASIC(obj)
Definition: rbasic.h:34
#define NULL
Definition: regenc.h:69
#define RUBY_TYPED_DEFAULT_FREE
Definition: rtypeddata.h:44
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: rtypeddata.h:122
const char * rb_class2name(VALUE)
Definition: variable.c:299
int argc
Definition: ruby.c:240
char ** argv
Definition: ruby.c:241
#define Qtrue
#define RTEST
#define Qnil
#define Qfalse
#define NIL_P
VALUE rb_str_catf(VALUE, const char *,...)
Definition: sprintf.c:1243
VALUE rb_sprintf(const char *,...)
Definition: sprintf.c:1203
#define _(args)
Definition: stdarg.h:31
rb_backtrace_location_t * init_loc
Definition: vm_backtrace.c:650
const rb_control_frame_t * prev_cfp
Definition: vm_backtrace.c:649
rb_backtrace_location_t * prev_loc
Definition: vm_backtrace.c:648
rb_backtrace_t * bt
Definition: vm_backtrace.c:646
Definition: gzappend.c:170
void * data
Definition: vm_backtrace.c:909
void(* func)(void *data, VALUE file, int lineno, VALUE name)
Definition: vm_backtrace.c:908
VALUE filename
Definition: vm_backtrace.c:906
VALUE(* iter)(VALUE recv, VALUE str)
struct rb_backtrace_location_struct * prev_loc
Definition: vm_backtrace.c:105
struct rb_backtrace_location_struct::@180::@182 cfunc
const rb_iseq_t * iseq
Definition: vm_backtrace.c:97
enum rb_backtrace_location_struct::LOCATION_TYPE type
union rb_backtrace_location_struct::@180 body
rb_backtrace_location_t * backtrace
Definition: vm_backtrace.c:403
Definition: method.h:62
const VALUE defined_class
Definition: method.h:64
struct rb_method_definition_struct *const def
Definition: method.h:65
const rb_iseq_t * iseq
Definition: vm_core.h:772
const VALUE * pc
Definition: vm_core.h:770
rb_execution_context_t * ec
rb_control_frame_t * cfp
rb_control_frame_t * cfp
Definition: vm_core.h:858
enum rb_iseq_constant_body::iseq_type type
unsigned int local_table_size
Definition: vm_core.h:424
VALUE * iseq_encoded
Definition: vm_core.h:319
unsigned int iseq_size
Definition: vm_core.h:318
rb_iseq_location_t location
Definition: vm_core.h:393
const ID * local_table
Definition: vm_core.h:405
struct rb_iseq_constant_body * body
Definition: vm_core.h:448
rb_method_iseq_t iseq
Definition: method.h:179
union rb_method_definition_struct::@123 body
rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
Definition: method.h:135
unsigned int to_kill
Definition: vm_core.h:959
rb_execution_context_t * ec
Definition: vm_core.h:941
Definition: blast.c:41
rb_backtrace_location_t * loc
Definition: vm_backtrace.c:111
unsigned long VALUE
Definition: value.h:38
unsigned long ID
Definition: value.h:39
#define T_IMEMO
Definition: value_type.h:66
#define T_MODULE
Definition: value_type.h:69
#define T_ICLASS
Definition: value_type.h:65
#define T_CLASS
Definition: value_type.h:57
void rb_vm_stack_to_heap(rb_execution_context_t *ec)
Definition: vm.c:820
VALUE rb_vm_make_binding(const rb_execution_context_t *ec, const rb_control_frame_t *src_cfp)
Definition: vm.c:1172
int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp)
Definition: vm.c:2424
int rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
VALUE rb_profile_frame_full_label(VALUE frame)
#define BACKTRACE_START
Definition: vm_backtrace.c:32
@ CALLER_BINDING_ISEQ
@ CALLER_BINDING_CLASS
@ CALLER_BINDING_SELF
@ CALLER_BINDING_CFP
@ CALLER_BINDING_BINDING
VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
void rb_backtrace_each(VALUE(*iter)(VALUE recv, VALUE str), VALUE output)
VALUE rb_vm_backtrace_locations(int argc, const VALUE *argv, struct rb_execution_context_struct *ec)
struct rb_backtrace_location_struct rb_backtrace_location_t
struct rb_backtrace_struct rb_backtrace_t
VALUE rb_profile_frame_method_name(VALUE frame)
VALUE rb_vm_backtrace(int argc, const VALUE *argv, struct rb_execution_context_struct *ec)
VALUE rb_ec_backtrace_object(const rb_execution_context_t *ec)
Definition: vm_backtrace.c:770
VALUE rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n)
Definition: vm_backtrace.c:892
VALUE rb_profile_frame_qualified_method_name(VALUE frame)
VALUE rb_profile_frame_label(VALUE frame)
void rb_backtrace_print_as_bugreport(void)
Definition: vm_backtrace.c:994
void Init_vm_backtrace(void)
VALUE rb_profile_frame_singleton_method_p(VALUE frame)
VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
Definition: vm_backtrace.c:71
VALUE rb_profile_frame_absolute_path(VALUE frame)
VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
int rb_backtrace_p(VALUE obj)
Definition: vm_backtrace.c:471
VALUE rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval)
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
#define ALL_BACKTRACE_LINES
Definition: vm_backtrace.c:33
void rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self)
Definition: vm_backtrace.c:821
VALUE rb_backtrace_to_location_ary(VALUE self)
Definition: vm_backtrace.c:864
VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
VALUE rb_profile_frame_classpath(VALUE frame)
VALUE rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval)
VALUE rb_profile_frame_path(VALUE frame)
VALUE rb_profile_frame_first_lineno(VALUE frame)
#define rb_id2str(id)
Definition: vm_backtrace.c:30
VALUE rb_make_backtrace(void)
VALUE rb_backtrace_to_str_ary(VALUE self)
Definition: vm_backtrace.c:809
void rb_backtrace(void)
VALUE rb_profile_frame_base_label(VALUE frame)
@ THREAD_KILLED
Definition: vm_core.h:795
const rb_callable_method_entry_t * rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
#define TAG_NONE
Definition: vm_core.h:198
ruby_tag_type
Definition: vm_core.h:185
#define GC_GUARDED_PTR_REF(p)
Definition: vm_core.h:1164
#define RUBY_VM_NEXT_CONTROL_FRAME(cfp)
Definition: vm_core.h:1393
#define GC_GUARDED_PTR(p)
Definition: vm_core.h:1163
#define VM_ASSERT(expr)
Definition: vm_core.h:61
#define GetCoreDataFromValue(obj, type, ptr)
Definition: vm_core.h:264
#define RUBYVM_CFUNC_FRAME_P(cfp)
Definition: vm_core.h:1295
#define RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)
Definition: vm_core.h:1392