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