Ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a25176072e02db9254f0e0c84c805cd)
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 "ruby/encoding.h"
13#include "ruby/debug.h"
14#include "internal.h"
15
16#include "vm_core.h"
17#include "eval_intern.h"
18#include "iseq.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
32inline static int
33calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
34{
39 if (! pc) {
40 /* This can happen during VM bootup. */
41 VM_ASSERT(iseq->body->type == ISEQ_TYPE_TOP);
44 return 0;
45 }
46 else {
48 VM_ASSERT(n <= iseq->body->iseq_size);
49 VM_ASSERT(n >= 0);
50 ASSUME(n >= 0);
51 size_t pos = n; /* no overflow */
52 if (LIKELY(pos)) {
53 /* use pos-1 because PC points next instruction at the beginning of instruction */
54 pos--;
55 }
56#if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
57 else {
58 /* SDR() is not possible; that causes infinite loop. */
60 __builtin_trap();
61 }
62#endif
63 return rb_iseq_line_no(iseq, pos);
64 }
65}
66
67int
69{
70 if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
71 const rb_iseq_t *iseq = cfp->iseq;
72 int line = calc_lineno(iseq, cfp->pc);
73 if (line != 0) {
74 return line;
75 }
76 else {
78 }
79 }
80 else {
81 return 0;
82 }
83}
84
92
93 union {
94 struct {
96 union {
97 const VALUE *pc;
98 int lineno;
101 struct {
107
111};
112
113static void
114location_mark(void *ptr)
115{
116 struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
117 rb_gc_mark(vfi->btobj);
118}
119
120static void
121location_mark_entry(rb_backtrace_location_t *fi)
122{
123 switch (fi->type) {
124 case LOCATION_TYPE_ISEQ:
125 case LOCATION_TYPE_ISEQ_CALCED:
126 rb_gc_mark((VALUE)fi->body.iseq.iseq);
127 break;
128 case LOCATION_TYPE_CFUNC:
129 case LOCATION_TYPE_IFUNC:
130 default:
131 break;
132 }
133}
134
135static size_t
136location_memsize(const void *ptr)
137{
138 /* rb_backtrace_location_t *fi = (rb_backtrace_location_t *)ptr; */
139 return sizeof(rb_backtrace_location_t);
140}
141
142static const rb_data_type_t location_data_type = {
143 "frame_info",
144 {location_mark, RUBY_TYPED_DEFAULT_FREE, location_memsize,},
146};
147
148static inline rb_backtrace_location_t *
149location_ptr(VALUE locobj)
150{
151 struct valued_frame_info *vloc;
152 GetCoreDataFromValue(locobj, struct valued_frame_info, vloc);
153 return vloc->loc;
154}
155
156static int
157location_lineno(rb_backtrace_location_t *loc)
158{
159 switch (loc->type) {
160 case LOCATION_TYPE_ISEQ:
161 loc->type = LOCATION_TYPE_ISEQ_CALCED;
162 return (loc->body.iseq.lineno.lineno = calc_lineno(loc->body.iseq.iseq, loc->body.iseq.lineno.pc));
163 case LOCATION_TYPE_ISEQ_CALCED:
164 return loc->body.iseq.lineno.lineno;
165 case LOCATION_TYPE_CFUNC:
166 if (loc->body.cfunc.prev_loc) {
167 return location_lineno(loc->body.cfunc.prev_loc);
168 }
169 return 0;
170 default:
171 rb_bug("location_lineno: unreachable");
173 }
174}
175
176/*
177 * Returns the line number of this frame.
178 *
179 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
180 *
181 * loc = c(0..1).first
182 * loc.lineno #=> 2
183 */
184static VALUE
185location_lineno_m(VALUE self)
186{
187 return INT2FIX(location_lineno(location_ptr(self)));
188}
189
190static VALUE
191location_label(rb_backtrace_location_t *loc)
192{
193 switch (loc->type) {
194 case LOCATION_TYPE_ISEQ:
195 case LOCATION_TYPE_ISEQ_CALCED:
196 return loc->body.iseq.iseq->body->location.label;
197 case LOCATION_TYPE_CFUNC:
198 return rb_id2str(loc->body.cfunc.mid);
199 case LOCATION_TYPE_IFUNC:
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 case LOCATION_TYPE_IFUNC:
249 default:
250 rb_bug("location_base_label: unreachable");
252 }
253}
254
255/*
256 * Returns the base label of this frame.
257 *
258 * Usually same as #label, without decoration.
259 */
260static VALUE
261location_base_label_m(VALUE self)
262{
263 return location_base_label(location_ptr(self));
264}
265
266static VALUE
267location_path(rb_backtrace_location_t *loc)
268{
269 switch (loc->type) {
270 case LOCATION_TYPE_ISEQ:
271 case LOCATION_TYPE_ISEQ_CALCED:
272 return rb_iseq_path(loc->body.iseq.iseq);
273 case LOCATION_TYPE_CFUNC:
274 if (loc->body.cfunc.prev_loc) {
275 return location_path(loc->body.cfunc.prev_loc);
276 }
277 return Qnil;
278 case LOCATION_TYPE_IFUNC:
279 default:
280 rb_bug("location_path: unreachable");
282 }
283}
284
285/*
286 * Returns the file name of this frame.
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 case LOCATION_TYPE_IFUNC:
312 default:
313 rb_bug("location_realpath: unreachable");
315 }
316}
317
318/*
319 * Returns the full file path of this frame.
320 *
321 * Same as #path, but includes the absolute path.
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{
332 VALUE s = rb_enc_sprintf(rb_enc_compatible(file, name), "%s", RSTRING_PTR(file));
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) {
367 file = rb_iseq_path(loc->body.cfunc.prev_loc->body.iseq.iseq);
368 lineno = location_lineno(loc->body.cfunc.prev_loc);
369 }
370 else {
371 file = GET_VM()->progname;
372 lineno = 0;
373 }
375 break;
376 case LOCATION_TYPE_IFUNC:
377 default:
378 rb_bug("location_to_str: unreachable");
379 }
380
381 return location_format(file, lineno, name);
382}
383
384/*
385 * Returns a Kernel#caller style string representing this frame.
386 */
387static VALUE
388location_to_str_m(VALUE self)
389{
390 return location_to_str(location_ptr(self));
391}
392
393/*
394 * Returns the same as calling +inspect+ on the string representation of
395 * #to_str
396 */
397static VALUE
398location_inspect_m(VALUE self)
399{
400 return rb_str_inspect(location_to_str(location_ptr(self)));
401}
402
403typedef struct rb_backtrace_struct {
410
411static void
412backtrace_mark(void *ptr)
413{
415 size_t i, s = bt->backtrace_size;
416
417 for (i=0; i<s; i++) {
418 location_mark_entry(&bt->backtrace[i]);
419 }
420 rb_gc_mark(bt->strary);
421 rb_gc_mark(bt->locary);
422}
423
424static void
425backtrace_free(void *ptr)
426{
428 if (bt->backtrace) ruby_xfree(bt->backtrace_base);
429 ruby_xfree(bt);
430}
431
432static size_t
433backtrace_memsize(const void *ptr)
434{
436 return sizeof(rb_backtrace_t) + sizeof(rb_backtrace_location_t) * bt->backtrace_size;
437}
438
439static const rb_data_type_t backtrace_data_type = {
440 "backtrace",
441 {backtrace_mark, backtrace_free, backtrace_memsize,},
443};
444
445int
447{
448 return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
449}
450
451static VALUE
452backtrace_alloc(VALUE klass)
453{
454 rb_backtrace_t *bt;
455 VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
456 return obj;
457}
458
459static void
460backtrace_each(const rb_execution_context_t *ec,
461 void (*init)(void *arg, size_t size),
462 void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
463 void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
464 void *arg)
465{
466 const rb_control_frame_t *last_cfp = ec->cfp;
467 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
468 const rb_control_frame_t *cfp;
470
471 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
472 if (start_cfp == NULL) {
473 init(arg, 0);
474 return;
475 }
476
477 /* <- start_cfp (end control frame)
478 * top frame (dummy)
479 * top frame (dummy)
480 * top frame <- start_cfp
481 * top frame
482 * ...
483 * 2nd frame <- lev:0
484 * current frame <- ec->cfp
485 */
486
487 start_cfp =
489 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
490
491 if (start_cfp < last_cfp) {
492 size = 0;
493 }
494 else {
495 size = start_cfp - last_cfp + 1;
496 }
497
498 init(arg, size);
499
500 /* SDR(); */
501 for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
502 /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
503 if (cfp->iseq) {
504 if (cfp->pc) {
505 iter_iseq(arg, cfp);
506 }
507 }
508 else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
510 ID mid = me->def->original_id;
511
512 iter_cfunc(arg, cfp, mid);
513 }
514 }
515}
516
521};
522
523static void
524bt_init(void *ptr, size_t size)
525{
526 struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
527 arg->btobj = backtrace_alloc(rb_cBacktrace);
529 arg->bt->backtrace_base = arg->bt->backtrace = ALLOC_N(rb_backtrace_location_t, size);
530 arg->bt->backtrace_size = 0;
531}
532
533static void
534bt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
535{
536 const rb_iseq_t *iseq = cfp->iseq;
537 const VALUE *pc = cfp->pc;
538 struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
539 rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
540 loc->type = LOCATION_TYPE_ISEQ;
541 loc->body.iseq.iseq = iseq;
542 loc->body.iseq.lineno.pc = pc;
543 arg->prev_loc = loc;
544}
545
546static void
547bt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
548{
549 struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
550 rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
551 loc->type = LOCATION_TYPE_CFUNC;
552 loc->body.cfunc.mid = mid;
553 loc->body.cfunc.prev_loc = arg->prev_loc;
554}
555
558{
559 struct bt_iter_arg arg;
560 arg.prev_loc = 0;
561
562 backtrace_each(ec,
563 bt_init,
564 bt_iter_iseq,
565 bt_iter_cfunc,
566 &arg);
567
568 return arg.btobj;
569}
570
571static VALUE
572backtrace_collect(rb_backtrace_t *bt, long lev, long n, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
573{
574 VALUE btary;
575 int i;
576
577 if (UNLIKELY(lev < 0 || n < 0)) {
578 rb_bug("backtrace_collect: unreachable");
579 }
580
581 btary = rb_ary_new2(n);
582
583 for (i=0; i+lev<bt->backtrace_size && i<n; i++) {
584 rb_backtrace_location_t *loc = &bt->backtrace[bt->backtrace_size - 1 - (lev+i)];
585 rb_ary_push(btary, func(loc, arg));
586 }
587
588 return btary;
589}
590
591static VALUE
592location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
593{
594 return location_to_str(loc);
595}
596
597static VALUE
598backtrace_to_str_ary(VALUE self, long lev, long n)
599{
601 int size;
602 VALUE r;
603
606
607 if (n == 0) {
608 n = size;
609 }
610 if (lev > size) {
611 return Qnil;
612 }
613
614 r = backtrace_collect(bt, lev, n, location_to_str_dmyarg, 0);
615 RB_GC_GUARD(self);
616 return r;
617}
618
619VALUE
621{
624
625 if (!bt->strary) {
626 bt->strary = backtrace_to_str_ary(self, 0, bt->backtrace_size);
627 }
628 return bt->strary;
629}
630
633{
634 const rb_backtrace_t *bt;
635 const rb_iseq_t *iseq;
637
640
641 loc = &bt->backtrace[bt->backtrace_size - 1];
642 iseq = loc->body.iseq.iseq;
643
644 VM_ASSERT(loc->type == LOCATION_TYPE_ISEQ);
645
646 loc->body.iseq.lineno.lineno = FIX2INT(iseq->body->location.first_lineno);
647 loc->type = LOCATION_TYPE_ISEQ_CALCED;
648}
649
650static VALUE
651location_create(rb_backtrace_location_t *srcloc, void *btobj)
652{
653 VALUE obj;
654 struct valued_frame_info *vloc;
655 obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
656
657 vloc->loc = srcloc;
658 vloc->btobj = (VALUE)btobj;
659
660 return obj;
661}
662
663static VALUE
664backtrace_to_location_ary(VALUE self, long lev, long n)
665{
666 rb_backtrace_t *bt;
667 int size;
668 VALUE r;
669
671 size = bt->backtrace_size;
672
673 if (n == 0) {
674 n = size;
675 }
676 if (lev > size) {
677 return Qnil;
678 }
679
680 r = backtrace_collect(bt, lev, n, location_create, (void *)self);
681 RB_GC_GUARD(self);
682 return r;
683}
684
685VALUE
687{
688 rb_backtrace_t *bt;
690
691 if (!bt->locary) {
692 bt->locary = backtrace_to_location_ary(self, 0, 0);
693 }
694 return bt->locary;
695}
696
697static VALUE
698backtrace_dump_data(VALUE self)
699{
701 return str;
702}
703
704static VALUE
705backtrace_load_data(VALUE self, VALUE str)
706{
707 rb_backtrace_t *bt;
709 bt->strary = str;
710 return self;
711}
712
713VALUE
715{
716 return backtrace_to_str_ary(rb_ec_backtrace_object(ec), lev, n);
717}
718
719VALUE
721{
722 return backtrace_to_location_ary(rb_ec_backtrace_object(ec), lev, n);
723}
724
725/* make old style backtrace directly */
726
727struct oldbt_arg {
730 void (*func)(void *data, VALUE file, int lineno, VALUE name);
731 void *data; /* result */
732};
733
734static void
735oldbt_init(void *ptr, size_t dmy)
736{
737 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
738 arg->filename = GET_VM()->progname;
739 arg->lineno = 0;
740}
741
742static void
743oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
744{
745 const rb_iseq_t *iseq = cfp->iseq;
746 const VALUE *pc = cfp->pc;
747 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
748 VALUE file = arg->filename = rb_iseq_path(iseq);
750 int lineno = arg->lineno = calc_lineno(iseq, pc);
751
752 (arg->func)(arg->data, file, lineno, name);
753}
754
755static void
756oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
757{
758 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
759 VALUE file = arg->filename;
760 VALUE name = rb_id2str(mid);
761 int lineno = arg->lineno;
762
763 (arg->func)(arg->data, file, lineno, name);
764}
765
766static void
767oldbt_print(void *data, VALUE file, int lineno, VALUE name)
768{
769 FILE *fp = (FILE *)data;
770
771 if (NIL_P(name)) {
772 fprintf(fp, "\tfrom %s:%d:in unknown method\n",
773 RSTRING_PTR(file), lineno);
774 }
775 else {
776 fprintf(fp, "\tfrom %s:%d:in `%s'\n",
778 }
779}
780
781static void
782vm_backtrace_print(FILE *fp)
783{
784 struct oldbt_arg arg;
785
786 arg.func = oldbt_print;
787 arg.data = (void *)fp;
788 backtrace_each(GET_EC(),
789 oldbt_init,
790 oldbt_iter_iseq,
791 oldbt_iter_cfunc,
792 &arg);
793}
794
795static void
796oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
797{
798 const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
799 if (!*(int *)arg) {
800 fprintf(stderr, "-- Ruby level backtrace information "
801 "----------------------------------------\n");
802 *(int *)arg = 1;
803 }
804 if (NIL_P(method)) {
805 fprintf(stderr, "%s:%d:in unknown method\n", filename, line);
806 }
807 else {
808 fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
809 }
810}
811
812void
814{
815 struct oldbt_arg arg;
816 int i = 0;
817
818 arg.func = oldbt_bugreport;
819 arg.data = (int *)&i;
820
821 backtrace_each(GET_EC(),
822 oldbt_init,
823 oldbt_iter_iseq,
824 oldbt_iter_cfunc,
825 &arg);
826}
827
828void
830{
831 vm_backtrace_print(stderr);
832}
833
837};
838
839static void
840oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
841{
842 const struct print_to_arg *arg = data;
843 VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
844
845 if (NIL_P(name)) {
846 rb_str_cat2(str, "unknown method\n");
847 }
848 else {
849 rb_str_catf(str, " `%"PRIsVALUE"'\n", name);
850 }
851 (*arg->iter)(arg->output, str);
852}
853
854void
856{
857 struct oldbt_arg arg;
858 struct print_to_arg parg;
859
860 parg.iter = iter;
861 parg.output = output;
862 arg.func = oldbt_print_to;
863 arg.data = &parg;
864 backtrace_each(GET_EC(),
865 oldbt_init,
866 oldbt_iter_iseq,
867 oldbt_iter_cfunc,
868 &arg);
869}
870
871VALUE
873{
874 return rb_ec_backtrace_str_ary(GET_EC(), 0, 0);
875}
876
877static VALUE
878ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str)
879{
880 VALUE level, vn;
881 long lev, n;
882 VALUE btval = rb_ec_backtrace_object(ec);
883 VALUE r;
884 rb_backtrace_t *bt;
885
887
888 rb_scan_args(argc, argv, "02", &level, &vn);
889
890 if (argc == 2 && NIL_P(vn)) argc--;
891
892 switch (argc) {
893 case 0:
894 lev = lev_default + lev_plus;
895 n = bt->backtrace_size - lev;
896 break;
897 case 1:
898 {
899 long beg, len;
900 switch (rb_range_beg_len(level, &beg, &len, bt->backtrace_size - lev_plus, 0)) {
901 case Qfalse:
902 lev = NUM2LONG(level);
903 if (lev < 0) {
904 rb_raise(rb_eArgError, "negative level (%ld)", lev);
905 }
906 lev += lev_plus;
907 n = bt->backtrace_size - lev;
908 break;
909 case Qnil:
910 return Qnil;
911 default:
912 lev = beg + lev_plus;
913 n = len;
914 break;
915 }
916 break;
917 }
918 case 2:
919 lev = NUM2LONG(level);
920 n = NUM2LONG(vn);
921 if (lev < 0) {
922 rb_raise(rb_eArgError, "negative level (%ld)", lev);
923 }
924 if (n < 0) {
925 rb_raise(rb_eArgError, "negative size (%ld)", n);
926 }
927 lev += lev_plus;
928 break;
929 default:
930 lev = n = 0; /* to avoid warning */
931 break;
932 }
933
934 if (n == 0) {
935 return rb_ary_new();
936 }
937
938 if (to_str) {
939 r = backtrace_to_str_ary(btval, lev, n);
940 }
941 else {
942 r = backtrace_to_location_ary(btval, lev, n);
943 }
944 RB_GC_GUARD(btval);
945 return r;
946}
947
948static VALUE
949thread_backtrace_to_ary(int argc, const VALUE *argv, VALUE thval, int to_str)
950{
951 rb_thread_t *target_th = rb_thread_ptr(thval);
952
953 if (target_th->to_kill || target_th->status == THREAD_KILLED)
954 return Qnil;
955
956 return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
957}
958
959VALUE
961{
962 return thread_backtrace_to_ary(argc, argv, thval, 1);
963}
964
965VALUE
967{
968 return thread_backtrace_to_ary(argc, argv, thval, 0);
969}
970
971/*
972 * call-seq:
973 * caller(start=1, length=nil) -> array or nil
974 * caller(range) -> array or nil
975 *
976 * Returns the current execution stack---an array containing strings in
977 * the form <code>file:line</code> or <code>file:line: in
978 * `method'</code>.
979 *
980 * The optional _start_ parameter determines the number of initial stack
981 * entries to omit from the top of the stack.
982 *
983 * A second optional +length+ parameter can be used to limit how many entries
984 * are returned from the stack.
985 *
986 * Returns +nil+ if _start_ is greater than the size of
987 * current execution stack.
988 *
989 * Optionally you can pass a range, which will return an array containing the
990 * entries within the specified range.
991 *
992 * def a(skip)
993 * caller(skip)
994 * end
995 * def b(skip)
996 * a(skip)
997 * end
998 * def c(skip)
999 * b(skip)
1000 * end
1001 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1002 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1003 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1004 * c(3) #=> ["prog:13:in `<main>'"]
1005 * c(4) #=> []
1006 * c(5) #=> nil
1007 */
1008
1009static VALUE
1010rb_f_caller(int argc, VALUE *argv, VALUE _)
1011{
1012 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1013}
1014
1015/*
1016 * call-seq:
1017 * caller_locations(start=1, length=nil) -> array or nil
1018 * caller_locations(range) -> array or nil
1019 *
1020 * Returns the current execution stack---an array containing
1021 * backtrace location objects.
1022 *
1023 * See Thread::Backtrace::Location for more information.
1024 *
1025 * The optional _start_ parameter determines the number of initial stack
1026 * entries to omit from the top of the stack.
1027 *
1028 * A second optional +length+ parameter can be used to limit how many entries
1029 * are returned from the stack.
1030 *
1031 * Returns +nil+ if _start_ is greater than the size of
1032 * current execution stack.
1033 *
1034 * Optionally you can pass a range, which will return an array containing the
1035 * entries within the specified range.
1036 */
1037static VALUE
1038rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
1039{
1040 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1041}
1042
1043/* called from Init_vm() in vm.c */
1044void
1046{
1047 /* :nodoc: */
1048 rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
1049 rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
1050 rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
1051 rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
1052
1053 /*
1054 * An object representation of a stack frame, initialized by
1055 * Kernel#caller_locations.
1056 *
1057 * For example:
1058 *
1059 * # caller_locations.rb
1060 * def a(skip)
1061 * caller_locations(skip)
1062 * end
1063 * def b(skip)
1064 * a(skip)
1065 * end
1066 * def c(skip)
1067 * b(skip)
1068 * end
1069 *
1070 * c(0..2).map do |call|
1071 * puts call.to_s
1072 * end
1073 *
1074 * Running <code>ruby caller_locations.rb</code> will produce:
1075 *
1076 * caller_locations.rb:2:in `a'
1077 * caller_locations.rb:5:in `b'
1078 * caller_locations.rb:8:in `c'
1079 *
1080 * Here's another example with a slightly different result:
1081 *
1082 * # foo.rb
1083 * class Foo
1084 * attr_accessor :locations
1085 * def initialize(skip)
1086 * @locations = caller_locations(skip)
1087 * end
1088 * end
1089 *
1090 * Foo.new(0..2).locations.map do |call|
1091 * puts call.to_s
1092 * end
1093 *
1094 * Now run <code>ruby foo.rb</code> and you should see:
1095 *
1096 * init.rb:4:in `initialize'
1097 * init.rb:8:in `new'
1098 * init.rb:8:in `<main>'
1099 */
1100 rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
1101 rb_undef_alloc_func(rb_cBacktraceLocation);
1102 rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
1103 rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
1104 rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
1105 rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
1106 rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
1107 rb_define_method(rb_cBacktraceLocation, "absolute_path", location_absolute_path_m, 0);
1108 rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
1109 rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
1110
1111 rb_define_global_function("caller", rb_f_caller, -1);
1112 rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1113}
1114
1115/* debugger API */
1116
1118
1120
1125 VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1127};
1128
1129enum {
1136
1139};
1140
1141static void
1142collect_caller_bindings_init(void *arg, size_t size)
1143{
1144 /* */
1145}
1146
1147static VALUE
1148get_klass(const rb_control_frame_t *cfp)
1149{
1150 VALUE klass;
1152 if (RB_TYPE_P(klass, T_ICLASS)) {
1153 return RBASIC(klass)->klass;
1154 }
1155 else {
1156 return klass;
1157 }
1158 }
1159 else {
1160 return Qnil;
1161 }
1162}
1163
1164static void
1165collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
1166{
1168 VALUE frame = rb_ary_new2(5);
1169
1171 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1172 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
1175
1176 rb_ary_push(data->ary, frame);
1177}
1178
1179static void
1180collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
1181{
1183 VALUE frame = rb_ary_new2(5);
1184
1186 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1187 rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
1188 rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
1190
1191 rb_ary_push(data->ary, frame);
1192}
1193
1194static VALUE
1195collect_caller_bindings(const rb_execution_context_t *ec)
1196{
1197 struct collect_caller_bindings_data data;
1198 VALUE result;
1199 int i;
1200
1201 data.ary = rb_ary_new();
1202
1203 backtrace_each(ec,
1204 collect_caller_bindings_init,
1205 collect_caller_bindings_iseq,
1206 collect_caller_bindings_cfunc,
1207 &data);
1208
1209 result = rb_ary_reverse(data.ary);
1210
1211 /* bindings should be created from top of frame */
1212 for (i=0; i<RARRAY_LEN(result); i++) {
1213 VALUE entry = rb_ary_entry(result, i);
1214 VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
1215
1216 if (!NIL_P(cfp_val)) {
1219 }
1220 }
1221
1222 return result;
1223}
1224
1225/*
1226 * Note that the passed `rb_debug_inspector_t' will be disabled
1227 * after `rb_debug_inspector_open'.
1228 */
1229
1230VALUE
1232{
1233 rb_debug_inspector_t dbg_context;
1235 enum ruby_tag_type state;
1236 volatile VALUE MAYBE_UNUSED(result);
1237
1238 /* escape all env to heap */
1240
1241 dbg_context.ec = ec;
1242 dbg_context.cfp = dbg_context.ec->cfp;
1243 dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, 0, 0);
1244 dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
1245 dbg_context.contexts = collect_caller_bindings(ec);
1246
1247 EC_PUSH_TAG(ec);
1248 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1249 result = (*func)(&dbg_context, data);
1250 }
1251 EC_POP_TAG();
1252
1253 /* invalidate bindings? */
1254
1255 if (state) {
1256 EC_JUMP_TAG(ec, state);
1257 }
1258
1259 return result;
1260}
1261
1262static VALUE
1263frame_get(const rb_debug_inspector_t *dc, long index)
1264{
1265 if (index < 0 || index >= dc->backtrace_size) {
1266 rb_raise(rb_eArgError, "no such frame");
1267 }
1268 return rb_ary_entry(dc->contexts, index);
1269}
1270
1271VALUE
1273{
1274 VALUE frame = frame_get(dc, index);
1275 return rb_ary_entry(frame, CALLER_BINDING_SELF);
1276}
1277
1278VALUE
1280{
1281 VALUE frame = frame_get(dc, index);
1282 return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1283}
1284
1285VALUE
1287{
1288 VALUE frame = frame_get(dc, index);
1289 return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1290}
1291
1292VALUE
1294{
1295 VALUE frame = frame_get(dc, index);
1297
1298 return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) : Qnil;
1299}
1300
1301VALUE
1303{
1304 return dc->backtrace;
1305}
1306
1307int
1308rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
1309{
1310 int i;
1311 const rb_execution_context_t *ec = GET_EC();
1312 const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
1313 const rb_callable_method_entry_t *cme;
1314
1315 for (i=0; i<limit && cfp != end_cfp;) {
1316 if (VM_FRAME_RUBYFRAME_P(cfp)) {
1317 if (start > 0) {
1318 start--;
1319 continue;
1320 }
1321
1322 /* record frame info */
1324 if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
1325 buff[i] = (VALUE)cme;
1326 }
1327 else {
1328 buff[i] = (VALUE)cfp->iseq;
1329 }
1330
1331 if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc);
1332
1333 i++;
1334 }
1336 }
1337
1338 return i;
1339}
1340
1341static const rb_iseq_t *
1342frame2iseq(VALUE frame)
1343{
1344 if (frame == Qnil) return NULL;
1345
1346 if (RB_TYPE_P(frame, T_IMEMO)) {
1347 switch (imemo_type(frame)) {
1348 case imemo_iseq:
1349 return (const rb_iseq_t *)frame;
1350 case imemo_ment:
1351 {
1353 switch (cme->def->type) {
1355 return cme->def->body.iseq.iseqptr;
1356 default:
1357 return NULL;
1358 }
1359 }
1360 default:
1361 break;
1362 }
1363 }
1364 rb_bug("frame2iseq: unreachable");
1365}
1366
1367VALUE
1369{
1370 const rb_iseq_t *iseq = frame2iseq(frame);
1371 return iseq ? rb_iseq_path(iseq) : Qnil;
1372}
1373
1374VALUE
1376{
1377 const rb_iseq_t *iseq = frame2iseq(frame);
1378 return iseq ? rb_iseq_realpath(iseq) : Qnil;
1379}
1380
1381VALUE
1383{
1384 const rb_iseq_t *iseq = frame2iseq(frame);
1385 return iseq ? rb_iseq_label(iseq) : Qnil;
1386}
1387
1388VALUE
1390{
1391 const rb_iseq_t *iseq = frame2iseq(frame);
1392 return iseq ? rb_iseq_base_label(iseq) : Qnil;
1393}
1394
1395VALUE
1397{
1398 const rb_iseq_t *iseq = frame2iseq(frame);
1399 return iseq ? rb_iseq_first_lineno(iseq) : Qnil;
1400}
1401
1402static VALUE
1403frame2klass(VALUE frame)
1404{
1405 if (frame == Qnil) return Qnil;
1406
1407 if (RB_TYPE_P(frame, T_IMEMO)) {
1409
1410 if (imemo_type(frame) == imemo_ment) {
1411 return cme->defined_class;
1412 }
1413 }
1414 return Qnil;
1415}
1416
1417VALUE
1419{
1420 VALUE klass = frame2klass(frame);
1421
1422 if (klass && !NIL_P(klass)) {
1423 if (RB_TYPE_P(klass, T_ICLASS)) {
1424 klass = RBASIC(klass)->klass;
1425 }
1426 else if (FL_TEST(klass, FL_SINGLETON)) {
1429 return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass);
1430 }
1431 return rb_class_path(klass);
1432 }
1433 else {
1434 return Qnil;
1435 }
1436}
1437
1438VALUE
1440{
1441 VALUE klass = frame2klass(frame);
1442
1443 if (klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON)) {
1444 return Qtrue;
1445 }
1446 else {
1447 return Qfalse;
1448 }
1449}
1450
1451VALUE
1453{
1454 const rb_iseq_t *iseq = frame2iseq(frame);
1455 return iseq ? rb_iseq_method_name(iseq) : Qnil;
1456}
1457
1458VALUE
1460{
1461 VALUE method_name = rb_profile_frame_method_name(frame);
1462
1463 if (method_name != Qnil) {
1464 VALUE classpath = rb_profile_frame_classpath(frame);
1465 VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
1466
1467 if (classpath != Qnil) {
1468 return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
1469 classpath, singleton_p == Qtrue ? "." : "#", method_name);
1470 }
1471 else {
1472 return method_name;
1473 }
1474 }
1475 else {
1476 return Qnil;
1477 }
1478}
1479
1480VALUE
1482{
1483 VALUE label = rb_profile_frame_label(frame);
1484 VALUE base_label = rb_profile_frame_base_label(frame);
1485 VALUE qualified_method_name = rb_profile_frame_qualified_method_name(frame);
1486
1487 if (NIL_P(qualified_method_name) || base_label == qualified_method_name) {
1488 return label;
1489 }
1490 else {
1491 long label_length = RSTRING_LEN(label);
1492 long base_label_length = RSTRING_LEN(base_label);
1493 int prefix_len = rb_long2int(label_length - base_label_length);
1494
1495 return rb_sprintf("%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);
1496 }
1497}
struct RIMemo * ptr
Definition: debug.c:65
VALUE(* rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *)
Definition: debug.h:43
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Definition: encoding.c:974
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
VALUE rb_define_class_under(VALUE, const char *, VALUE)
Defines a class under the namespace of outer.
Definition: class.c:711
void rb_undef_method(VALUE, const char *)
Definition: class.c:1593
VALUE rb_cArray
Definition: array.c:27
VALUE rb_cThread
Definition: ruby.h:2049
VALUE rb_cObject
Object class.
Definition: ruby.h:2012
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:874
void rb_bug(const char *fmt,...)
Definition: error.c:636
VALUE rb_eArgError
Definition: error.c:925
VALUE rb_obj_class(VALUE)
Equivalent to Object#class in Ruby.
Definition: object.c:217
const char * name
Definition: nkf.c:208
#define RARRAY_LEN(a)
#define NULL
VALUE rb_iseq_path(const rb_iseq_t *iseq)
Definition: iseq.c:1027
#define FL_SINGLETON
void rb_print_backtrace(void)
Definition: vm_dump.c:750
#define RSTRING_LEN(str)
#define _(args)
#define RTEST(v)
#define TAG_NONE
#define FL_TEST(x, f)
#define RBASIC(obj)
long int ptrdiff_t
unsigned int rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
Definition: iseq.c:1761
rb_control_frame_t * cfp
void rb_define_global_function(const char *, VALUE(*)(), int)
VALUE rb_range_beg_len(VALUE, long *, long *, long, int)
Definition: range.c:1278
#define MAYBE_UNUSED(x)
#define rb_str_cat2
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1070
const VALUE VALUE obj
void rb_vm_stack_to_heap(rb_execution_context_t *ec)
Definition: vm.c:786
#define GC_GUARDED_PTR_REF(p)
#define UNREACHABLE
#define RSTRING_PTR(str)
#define T_IMEMO
#define GET_EC()
#define RUBY_VM_NEXT_CONTROL_FRAME(cfp)
#define NIL_P(v)
const rb_callable_method_entry_t * me
#define GC_GUARDED_PTR(p)
#define VM_ASSERT(expr)
#define EC_EXEC_TAG()
#define GetCoreDataFromValue(obj, type, ptr)
VALUE rb_iseq_label(const rb_iseq_t *iseq)
Definition: iseq.c:1045
#define RUBY_TYPED_DEFAULT_FREE
int fprintf(FILE *__restrict__, const char *__restrict__,...) __attribute__((__format__(__printf__
const char size_t n
#define RUBY_SYMBOL_EXPORT_BEGIN
VALUE rb_vm_make_binding(const rb_execution_context_t *ec, const rb_control_frame_t *src_cfp)
Definition: vm.c:953
unsigned long VALUE
VALUE rb_ary_push(VALUE, VALUE)
Definition: array.c:1195
#define stderr
#define EC_PUSH_TAG(ec)
#define EC_JUMP_TAG(ec, st)
VALUE rb_iseq_base_label(const rb_iseq_t *iseq)
Definition: iseq.c:1051
VALUE rb_str_inspect(VALUE)
Definition: string.c:5930
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define T_MODULE
#define GET_VM()
uint32_t i
__inline__ const void *__restrict__ size_t len
VALUE rb_class_path(VALUE)
Definition: variable.c:153
#define ALLOC_N(type, n)
VALUE rb_iseqw_new(const rb_iseq_t *iseq)
Definition: iseq.c:1157
#define T_ICLASS
#define rb_long2int(n)
#define RB_GC_GUARD(v)
#define RUBY_TYPED_FREE_IMMEDIATELY
int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp)
Definition: vm.c:2184
#define RUBY_SYMBOL_EXPORT_END
#define PRIsVALUE
#define FIX2INT(x)
VALUE rb_ary_new(void)
Definition: array.c:723
#define rb_scan_args(argc, argvp, fmt,...)
#define EC_POP_TAG()
#define rb_str_cat_cstr(str, ptr)
void rb_gc_mark(VALUE)
Definition: gc.c:5228
VALUE rb_ary_reverse(VALUE)
Definition: array.c:2544
const rb_iseq_t * iseq
VALUE rb_str_catf(VALUE, const char *,...) __attribute__((format(printf
unsigned int size
#define Qtrue
#define UNLIKELY(x)
VALUE rb_iseq_first_lineno(const rb_iseq_t *iseq)
Definition: iseq.c:1057
#define Qnil
#define Qfalse
#define RB_TYPE_P(obj, type)
#define INT2FIX(i)
#define TypedData_Make_Struct(klass, type, data_type, sval)
#define MJIT_FUNC_EXPORTED
const VALUE * argv
void void ruby_xfree(void *)
Definition: gc.c:10183
VALUE rb_iseq_method_name(const rb_iseq_t *iseq)
Definition: iseq.c:1063
#define T_CLASS
#define CLASS_OF(v)
void rb_undef_alloc_func(VALUE)
Definition: vm_method.c:729
rb_control_frame_t const VALUE * pc
#define RUBYVM_CFUNC_FRAME_P(cfp)
VALUE rb_sprintf(const char *,...) __attribute__((format(printf
unsigned long ID
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Definition: marshal.c:134
#define NUM2LONG(x)
void rb_define_method(VALUE, const char *, VALUE(*)(), int)
#define rb_ary_new2
VALUE rb_iseq_realpath(const rb_iseq_t *iseq)
Definition: iseq.c:1033
#define RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)
const char * rb_class2name(VALUE)
Definition: variable.c:280
void rb_ary_store(VALUE, long, VALUE)
Definition: array.c:1079
VALUE rb_ary_entry(VALUE, long)
Definition: array.c:1512
#define ASSUME(x)
#define LIKELY(x)
VALUE rb_enc_sprintf(rb_encoding *enc, const char *format,...)
Definition: sprintf.c:1178
rb_backtrace_location_t * prev_loc
Definition: vm_backtrace.c:520
rb_backtrace_t * bt
Definition: vm_backtrace.c:518
void * data
Definition: vm_backtrace.c:731
void(* func)(void *data, VALUE file, int lineno, VALUE name)
Definition: vm_backtrace.c:730
VALUE filename
Definition: vm_backtrace.c:728
VALUE(* iter)(VALUE recv, VALUE str)
Definition: vm_backtrace.c:835
struct rb_backtrace_location_struct * prev_loc
Definition: vm_backtrace.c:103
const rb_iseq_t * iseq
Definition: vm_backtrace.c:95
enum rb_backtrace_location_struct::LOCATION_TYPE type
union rb_backtrace_location_struct::@233 body
struct rb_backtrace_location_struct::@233::@235 cfunc
rb_backtrace_location_t * backtrace
Definition: vm_backtrace.c:404
rb_backtrace_location_t * backtrace_base
Definition: vm_backtrace.c:405
struct rb_method_definition_struct *const def
const VALUE defined_class
rb_execution_context_t * ec
rb_control_frame_t * cfp
enum rb_iseq_constant_body::iseq_type type
struct rb_iseq_constant_body * body
union rb_method_definition_struct::@41 body
rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
rb_execution_context_t * ec
enum rb_thread_status status
rb_backtrace_location_t * loc
Definition: vm_backtrace.c:109
int rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
VALUE rb_profile_frame_full_label(VALUE frame)
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)
Definition: vm_backtrace.c:855
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_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n)
Definition: vm_backtrace.c:714
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:813
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:68
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:446
MJIT_FUNC_EXPORTED VALUE rb_ec_backtrace_object(const rb_execution_context_t *ec)
Definition: vm_backtrace.c:557
VALUE rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval)
Definition: vm_backtrace.c:960
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
MJIT_FUNC_EXPORTED void rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self)
Definition: vm_backtrace.c:632
VALUE rb_backtrace_to_location_ary(VALUE self)
Definition: vm_backtrace.c:686
@ CALLER_BINDING_ISEQ
@ CALLER_BINDING_CLASS
@ CALLER_BINDING_SELF
@ CALLER_BINDING_CFP
@ CALLER_BINDING_BINDING
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)
Definition: vm_backtrace.c:966
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_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n)
Definition: vm_backtrace.c:720
VALUE rb_make_backtrace(void)
Definition: vm_backtrace.c:872
VALUE rb_backtrace_to_str_ary(VALUE self)
Definition: vm_backtrace.c:620
void rb_backtrace(void)
Definition: vm_backtrace.c:829
VALUE rb_profile_frame_base_label(VALUE frame)
MJIT_STATIC const rb_callable_method_entry_t * rb_vm_frame_method_entry(const rb_control_frame_t *cfp)