Stop exporting symbols for MJIT
[ruby.git] / vm_backtrace.c
blob6264082a3f7e8349da6f47282e7d1f45b1c64b8b
1 /**********************************************************************
3 vm_backtrace.c -
5 $Author: ko1 $
6 created at: Sun Jun 03 00:14:20 2012
8 Copyright (C) 1993-2012 Yukihiro Matsumoto
10 **********************************************************************/
12 #include "eval_intern.h"
13 #include "internal.h"
14 #include "internal/class.h"
15 #include "internal/error.h"
16 #include "internal/vm.h"
17 #include "iseq.h"
18 #include "ruby/debug.h"
19 #include "ruby/encoding.h"
20 #include "vm_core.h"
22 static VALUE rb_cBacktrace;
23 static VALUE rb_cBacktraceLocation;
25 static VALUE
26 id2str(ID id)
28 VALUE str = rb_id2str(id);
29 if (!str) return Qnil;
30 return str;
32 #define rb_id2str(id) id2str(id)
34 #define BACKTRACE_START 0
35 #define ALL_BACKTRACE_LINES -1
37 inline static int
38 calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
40 VM_ASSERT(iseq);
42 if (pc == NULL) {
43 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_TOP) {
44 VM_ASSERT(! ISEQ_BODY(iseq)->local_table);
45 VM_ASSERT(! ISEQ_BODY(iseq)->local_table_size);
46 return 0;
48 if (lineno) *lineno = ISEQ_BODY(iseq)->location.first_lineno;
49 #ifdef USE_ISEQ_NODE_ID
50 if (node_id) *node_id = -1;
51 #endif
52 return 1;
54 else {
55 VM_ASSERT(ISEQ_BODY(iseq));
56 VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
57 VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
59 ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
60 VM_ASSERT(n <= ISEQ_BODY(iseq)->iseq_size);
61 VM_ASSERT(n >= 0);
62 ASSUME(n >= 0);
63 size_t pos = n; /* no overflow */
64 if (LIKELY(pos)) {
65 /* use pos-1 because PC points next instruction at the beginning of instruction */
66 pos--;
68 #if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
69 else {
70 /* SDR() is not possible; that causes infinite loop. */
71 rb_print_backtrace();
72 __builtin_trap();
74 #endif
75 if (lineno) *lineno = rb_iseq_line_no(iseq, pos);
76 #ifdef USE_ISEQ_NODE_ID
77 if (node_id) *node_id = rb_iseq_node_id(iseq, pos);
78 #endif
79 return 1;
83 inline static int
84 calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
86 int lineno;
87 if (calc_pos(iseq, pc, &lineno, NULL)) return lineno;
88 return 0;
91 #ifdef USE_ISEQ_NODE_ID
92 inline static int
93 calc_node_id(const rb_iseq_t *iseq, const VALUE *pc)
95 int node_id;
96 if (calc_pos(iseq, pc, NULL, &node_id)) return node_id;
97 return -1;
99 #endif
102 rb_vm_get_sourceline(const rb_control_frame_t *cfp)
104 if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
105 const rb_iseq_t *iseq = cfp->iseq;
106 int line = calc_lineno(iseq, cfp->pc);
107 if (line != 0) {
108 return line;
110 else {
111 return ISEQ_BODY(iseq)->location.first_lineno;
114 else {
115 return 0;
119 typedef struct rb_backtrace_location_struct {
120 enum LOCATION_TYPE {
121 LOCATION_TYPE_ISEQ = 1,
122 LOCATION_TYPE_CFUNC,
123 } type;
125 const rb_iseq_t *iseq;
126 const VALUE *pc;
127 ID mid;
128 } rb_backtrace_location_t;
130 struct valued_frame_info {
131 rb_backtrace_location_t *loc;
132 VALUE btobj;
135 static void
136 location_mark(void *ptr)
138 struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
139 rb_gc_mark(vfi->btobj);
142 static void
143 location_mark_entry(rb_backtrace_location_t *fi)
145 switch (fi->type) {
146 case LOCATION_TYPE_ISEQ:
147 rb_gc_mark_movable((VALUE)fi->iseq);
148 break;
149 case LOCATION_TYPE_CFUNC:
150 if (fi->iseq) {
151 rb_gc_mark_movable((VALUE)fi->iseq);
153 break;
154 default:
155 break;
159 static size_t
160 location_memsize(const void *ptr)
162 /* rb_backtrace_location_t *fi = (rb_backtrace_location_t *)ptr; */
163 return sizeof(rb_backtrace_location_t);
166 static const rb_data_type_t location_data_type = {
167 "frame_info",
168 {location_mark, RUBY_TYPED_DEFAULT_FREE, location_memsize,},
169 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
173 rb_frame_info_p(VALUE obj)
175 return rb_typeddata_is_kind_of(obj, &location_data_type);
178 static inline rb_backtrace_location_t *
179 location_ptr(VALUE locobj)
181 struct valued_frame_info *vloc;
182 GetCoreDataFromValue(locobj, struct valued_frame_info, vloc);
183 return vloc->loc;
186 static int
187 location_lineno(rb_backtrace_location_t *loc)
189 switch (loc->type) {
190 case LOCATION_TYPE_ISEQ:
191 return calc_lineno(loc->iseq, loc->pc);
192 case LOCATION_TYPE_CFUNC:
193 if (loc->iseq && loc->pc) {
194 return calc_lineno(loc->iseq, loc->pc);
196 return 0;
197 default:
198 rb_bug("location_lineno: unreachable");
199 UNREACHABLE;
204 * Returns the line number of this frame.
206 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
208 * loc = c(0..1).first
209 * loc.lineno #=> 2
211 static VALUE
212 location_lineno_m(VALUE self)
214 return INT2FIX(location_lineno(location_ptr(self)));
217 static VALUE
218 location_label(rb_backtrace_location_t *loc)
220 switch (loc->type) {
221 case LOCATION_TYPE_ISEQ:
222 return ISEQ_BODY(loc->iseq)->location.label;
223 case LOCATION_TYPE_CFUNC:
224 return rb_id2str(loc->mid);
225 default:
226 rb_bug("location_label: unreachable");
227 UNREACHABLE;
232 * Returns the label of this frame.
234 * Usually consists of method, class, module, etc names with decoration.
236 * Consider the following example:
238 * def foo
239 * puts caller_locations(0).first.label
241 * 1.times do
242 * puts caller_locations(0).first.label
244 * 1.times do
245 * puts caller_locations(0).first.label
246 * end
248 * end
249 * end
251 * The result of calling +foo+ is this:
253 * label: foo
254 * label: block in foo
255 * label: block (2 levels) in foo
258 static VALUE
259 location_label_m(VALUE self)
261 return location_label(location_ptr(self));
264 static VALUE
265 location_base_label(rb_backtrace_location_t *loc)
267 switch (loc->type) {
268 case LOCATION_TYPE_ISEQ:
269 return ISEQ_BODY(loc->iseq)->location.base_label;
270 case LOCATION_TYPE_CFUNC:
271 return rb_id2str(loc->mid);
272 default:
273 rb_bug("location_base_label: unreachable");
274 UNREACHABLE;
279 * Returns the base label of this frame.
281 * Usually same as #label, without decoration.
283 static VALUE
284 location_base_label_m(VALUE self)
286 return location_base_label(location_ptr(self));
289 static const rb_iseq_t *
290 location_iseq(rb_backtrace_location_t *loc)
292 switch (loc->type) {
293 case LOCATION_TYPE_ISEQ:
294 return loc->iseq;
295 case LOCATION_TYPE_CFUNC:
296 return loc->iseq;
297 default:
298 rb_bug("location_iseq: unreachable");
299 UNREACHABLE;
304 * Returns the file name of this frame. This will generally be an absolute
305 * path, unless the frame is in the main script, in which case it will be the
306 * script location passed on the command line.
308 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
310 * loc = c(0..1).first
311 * loc.path #=> caller_locations.rb
313 static VALUE
314 location_path_m(VALUE self)
316 const rb_iseq_t *iseq = location_iseq(location_ptr(self));
317 return iseq ? rb_iseq_path(iseq) : Qnil;
320 #ifdef USE_ISEQ_NODE_ID
321 static int
322 location_node_id(rb_backtrace_location_t *loc)
324 switch (loc->type) {
325 case LOCATION_TYPE_ISEQ:
326 return calc_node_id(loc->iseq, loc->pc);
327 case LOCATION_TYPE_CFUNC:
328 if (loc->iseq && loc->pc) {
329 return calc_node_id(loc->iseq, loc->pc);
331 return -1;
332 default:
333 rb_bug("location_node_id: unreachable");
334 UNREACHABLE;
337 #endif
340 rb_get_node_id_from_frame_info(VALUE obj)
342 #ifdef USE_ISEQ_NODE_ID
343 rb_backtrace_location_t *loc = location_ptr(obj);
344 return location_node_id(loc);
345 #else
346 return -1;
347 #endif
350 const rb_iseq_t *
351 rb_get_iseq_from_frame_info(VALUE obj)
353 rb_backtrace_location_t *loc = location_ptr(obj);
354 const rb_iseq_t *iseq = location_iseq(loc);
355 return iseq;
358 static VALUE
359 location_realpath(rb_backtrace_location_t *loc)
361 switch (loc->type) {
362 case LOCATION_TYPE_ISEQ:
363 return rb_iseq_realpath(loc->iseq);
364 case LOCATION_TYPE_CFUNC:
365 if (loc->iseq) {
366 return rb_iseq_realpath(loc->iseq);
368 return Qnil;
369 default:
370 rb_bug("location_realpath: unreachable");
371 UNREACHABLE;
376 * Returns the full file path of this frame.
378 * Same as #path, except that it will return absolute path
379 * even if the frame is in the main script.
381 static VALUE
382 location_absolute_path_m(VALUE self)
384 return location_realpath(location_ptr(self));
387 static VALUE
388 location_format(VALUE file, int lineno, VALUE name)
390 VALUE s = rb_enc_sprintf(rb_enc_compatible(file, name), "%s", RSTRING_PTR(file));
391 if (lineno != 0) {
392 rb_str_catf(s, ":%d", lineno);
394 rb_str_cat_cstr(s, ":in ");
395 if (NIL_P(name)) {
396 rb_str_cat_cstr(s, "unknown method");
398 else {
399 rb_str_catf(s, "`%s'", RSTRING_PTR(name));
401 return s;
404 static VALUE
405 location_to_str(rb_backtrace_location_t *loc)
407 VALUE file, name;
408 int lineno;
410 switch (loc->type) {
411 case LOCATION_TYPE_ISEQ:
412 file = rb_iseq_path(loc->iseq);
413 name = ISEQ_BODY(loc->iseq)->location.label;
415 lineno = calc_lineno(loc->iseq, loc->pc);
416 break;
417 case LOCATION_TYPE_CFUNC:
418 if (loc->iseq && loc->pc) {
419 file = rb_iseq_path(loc->iseq);
420 lineno = calc_lineno(loc->iseq, loc->pc);
422 else {
423 file = GET_VM()->progname;
424 lineno = 0;
426 name = rb_id2str(loc->mid);
427 break;
428 default:
429 rb_bug("location_to_str: unreachable");
432 return location_format(file, lineno, name);
436 * Returns a Kernel#caller style string representing this frame.
438 static VALUE
439 location_to_str_m(VALUE self)
441 return location_to_str(location_ptr(self));
445 * Returns the same as calling +inspect+ on the string representation of
446 * #to_str
448 static VALUE
449 location_inspect_m(VALUE self)
451 return rb_str_inspect(location_to_str(location_ptr(self)));
454 typedef struct rb_backtrace_struct {
455 rb_backtrace_location_t *backtrace;
456 int backtrace_size;
457 VALUE strary;
458 VALUE locary;
459 } rb_backtrace_t;
461 static void
462 backtrace_mark(void *ptr)
464 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
465 size_t i, s = bt->backtrace_size;
467 for (i=0; i<s; i++) {
468 location_mark_entry(&bt->backtrace[i]);
470 rb_gc_mark_movable(bt->strary);
471 rb_gc_mark_movable(bt->locary);
474 static void
475 backtrace_free(void *ptr)
477 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
478 if (bt->backtrace) ruby_xfree(bt->backtrace);
479 ruby_xfree(bt);
482 static void
483 location_update_entry(rb_backtrace_location_t *fi)
485 switch (fi->type) {
486 case LOCATION_TYPE_ISEQ:
487 fi->iseq = (rb_iseq_t*)rb_gc_location((VALUE)fi->iseq);
488 break;
489 case LOCATION_TYPE_CFUNC:
490 if (fi->iseq) {
491 fi->iseq = (rb_iseq_t*)rb_gc_location((VALUE)fi->iseq);
493 break;
494 default:
495 break;
499 static void
500 backtrace_update(void *ptr)
502 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
503 size_t i, s = bt->backtrace_size;
505 for (i=0; i<s; i++) {
506 location_update_entry(&bt->backtrace[i]);
508 bt->strary = rb_gc_location(bt->strary);
509 bt->locary = rb_gc_location(bt->locary);
512 static size_t
513 backtrace_memsize(const void *ptr)
515 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
516 return sizeof(rb_backtrace_t) + sizeof(rb_backtrace_location_t) * bt->backtrace_size;
519 static const rb_data_type_t backtrace_data_type = {
520 "backtrace",
521 {backtrace_mark, backtrace_free, backtrace_memsize, backtrace_update},
522 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
526 rb_backtrace_p(VALUE obj)
528 return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
531 static VALUE
532 backtrace_alloc(VALUE klass)
534 rb_backtrace_t *bt;
535 VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
536 return obj;
539 static long
540 backtrace_size(const rb_execution_context_t *ec)
542 const rb_control_frame_t *last_cfp = ec->cfp;
543 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
545 if (start_cfp == NULL) {
546 return -1;
549 start_cfp =
550 RUBY_VM_NEXT_CONTROL_FRAME(
551 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
553 if (start_cfp < last_cfp) {
554 return 0;
557 return start_cfp - last_cfp + 1;
560 static bool
561 is_internal_location(const rb_control_frame_t *cfp)
563 static const char prefix[] = "<internal:";
564 const size_t prefix_len = sizeof(prefix) - 1;
565 VALUE file = rb_iseq_path(cfp->iseq);
566 return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0;
569 static void
570 bt_update_cfunc_loc(unsigned long cfunc_counter, rb_backtrace_location_t *cfunc_loc, const rb_iseq_t *iseq, const VALUE *pc)
572 for (; cfunc_counter > 0; cfunc_counter--, cfunc_loc--) {
573 cfunc_loc->iseq = iseq;
574 cfunc_loc->pc = pc;
578 static VALUE location_create(rb_backtrace_location_t *srcloc, void *btobj);
580 static void
581 bt_yield_loc(rb_backtrace_location_t *loc, long num_frames, VALUE btobj)
583 for (; num_frames > 0; num_frames--, loc++) {
584 rb_yield(location_create(loc, (void *)btobj));
588 static VALUE
589 rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_frame, long num_frames, int* start_too_large, bool skip_internal, bool do_yield)
591 const rb_control_frame_t *cfp = ec->cfp;
592 const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
593 ptrdiff_t size;
594 rb_backtrace_t *bt;
595 VALUE btobj = backtrace_alloc(rb_cBacktrace);
596 rb_backtrace_location_t *loc = NULL;
597 unsigned long cfunc_counter = 0;
598 GetCoreDataFromValue(btobj, rb_backtrace_t, bt);
600 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
601 if (end_cfp == NULL) {
602 num_frames = 0;
604 else {
605 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
608 * top frame (dummy) <- RUBY_VM_END_CONTROL_FRAME
609 * top frame (dummy) <- end_cfp
610 * top frame <- main script
611 * top frame
612 * ...
613 * 2nd frame <- lev:0
614 * current frame <- ec->cfp
617 size = end_cfp - cfp + 1;
618 if (size < 0) {
619 num_frames = 0;
621 else if (num_frames < 0 || num_frames > size) {
622 num_frames = size;
626 bt->backtrace = ZALLOC_N(rb_backtrace_location_t, num_frames);
627 bt->backtrace_size = 0;
628 if (num_frames == 0) {
629 if (start_too_large) *start_too_large = 0;
630 return btobj;
633 for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
634 if (cfp->iseq) {
635 if (cfp->pc) {
636 if (start_frame > 0) {
637 start_frame--;
639 else if (!skip_internal || !is_internal_location(cfp)) {
640 const rb_iseq_t *iseq = cfp->iseq;
641 const VALUE *pc = cfp->pc;
642 loc = &bt->backtrace[bt->backtrace_size++];
643 loc->type = LOCATION_TYPE_ISEQ;
644 RB_OBJ_WRITE(btobj, &loc->iseq, iseq);
645 loc->pc = pc;
646 bt_update_cfunc_loc(cfunc_counter, loc-1, iseq, pc);
647 if (do_yield) {
648 bt_yield_loc(loc - cfunc_counter, cfunc_counter+1, btobj);
650 cfunc_counter = 0;
654 else {
655 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
656 if (start_frame > 0) {
657 start_frame--;
659 else {
660 loc = &bt->backtrace[bt->backtrace_size++];
661 loc->type = LOCATION_TYPE_CFUNC;
662 loc->iseq = NULL;
663 loc->pc = NULL;
664 loc->mid = rb_vm_frame_method_entry(cfp)->def->original_id;
665 cfunc_counter++;
670 if (cfunc_counter > 0) {
671 for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
672 if (cfp->iseq && cfp->pc && (!skip_internal || !is_internal_location(cfp))) {
673 bt_update_cfunc_loc(cfunc_counter, loc, cfp->iseq, cfp->pc);
674 RB_OBJ_WRITTEN(btobj, Qundef, cfp->iseq);
675 if (do_yield) {
676 bt_yield_loc(loc - cfunc_counter, cfunc_counter, btobj);
678 break;
683 if (start_too_large) *start_too_large = (start_frame > 0 ? -1 : 0);
684 return btobj;
687 VALUE
688 rb_ec_backtrace_object(const rb_execution_context_t *ec)
690 return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL, FALSE, FALSE);
693 static VALUE
694 backtrace_collect(rb_backtrace_t *bt, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
696 VALUE btary;
697 int i;
699 btary = rb_ary_new2(bt->backtrace_size);
701 for (i=0; i<bt->backtrace_size; i++) {
702 rb_backtrace_location_t *loc = &bt->backtrace[i];
703 rb_ary_push(btary, func(loc, arg));
706 return btary;
709 static VALUE
710 location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
712 return location_to_str(loc);
715 static VALUE
716 backtrace_to_str_ary(VALUE self)
718 VALUE r;
719 rb_backtrace_t *bt;
720 GetCoreDataFromValue(self, rb_backtrace_t, bt);
721 r = backtrace_collect(bt, location_to_str_dmyarg, 0);
722 RB_GC_GUARD(self);
723 return r;
726 VALUE
727 rb_backtrace_to_str_ary(VALUE self)
729 rb_backtrace_t *bt;
730 GetCoreDataFromValue(self, rb_backtrace_t, bt);
732 if (!bt->strary) {
733 RB_OBJ_WRITE(self, &bt->strary, backtrace_to_str_ary(self));
735 return bt->strary;
738 void
739 rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self)
741 const rb_backtrace_t *bt;
742 rb_backtrace_location_t *loc;
744 GetCoreDataFromValue(self, rb_backtrace_t, bt);
745 VM_ASSERT(bt->backtrace_size > 0);
747 loc = &bt->backtrace[0];
749 VM_ASSERT(loc->type == LOCATION_TYPE_ISEQ);
751 loc->pc = NULL; // means location.first_lineno
754 static VALUE
755 location_create(rb_backtrace_location_t *srcloc, void *btobj)
757 VALUE obj;
758 struct valued_frame_info *vloc;
759 obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
761 vloc->loc = srcloc;
762 RB_OBJ_WRITE(obj, &vloc->btobj, (VALUE)btobj);
764 return obj;
767 static VALUE
768 backtrace_to_location_ary(VALUE self)
770 VALUE r;
771 rb_backtrace_t *bt;
772 GetCoreDataFromValue(self, rb_backtrace_t, bt);
773 r = backtrace_collect(bt, location_create, (void *)self);
774 RB_GC_GUARD(self);
775 return r;
778 VALUE
779 rb_backtrace_to_location_ary(VALUE self)
781 rb_backtrace_t *bt;
782 GetCoreDataFromValue(self, rb_backtrace_t, bt);
784 if (!bt->locary) {
785 RB_OBJ_WRITE(self, &bt->locary, backtrace_to_location_ary(self));
787 return bt->locary;
790 static VALUE
791 backtrace_dump_data(VALUE self)
793 VALUE str = rb_backtrace_to_str_ary(self);
794 return str;
797 static VALUE
798 backtrace_load_data(VALUE self, VALUE str)
800 rb_backtrace_t *bt;
801 GetCoreDataFromValue(self, rb_backtrace_t, bt);
802 RB_OBJ_WRITE(self, &bt->strary, str);
803 return self;
807 * call-seq: Thread::Backtrace::limit -> integer
809 * Returns maximum backtrace length set by <tt>--backtrace-limit</tt>
810 * command-line option. The default is <tt>-1</tt> which means unlimited
811 * backtraces. If the value is zero or positive, the error backtraces,
812 * produced by Exception#full_message, are abbreviated and the extra lines
813 * are replaced by <tt>... 3 levels... </tt>
815 * $ ruby -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
816 * - 1
817 * .../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)
818 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
819 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
820 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
821 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
822 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
823 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
824 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
825 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
826 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
827 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
828 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
829 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
830 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
831 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
832 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
833 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
834 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
835 * from -e:1:in `<main>'
837 * $ ruby --backtrace-limit 2 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
839 * .../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)
840 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
841 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
842 * ... 7 levels...
843 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
844 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
845 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
846 * ... 7 levels...
848 * $ ruby --backtrace-limit 0 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
850 * .../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)
851 * ... 9 levels...
852 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
853 * ... 9 levels...
856 static VALUE
857 backtrace_limit(VALUE self)
859 return LONG2NUM(rb_backtrace_length_limit);
862 VALUE
863 rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n)
865 return rb_backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, FALSE));
868 VALUE
869 rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal)
871 return rb_backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal, FALSE));
874 /* make old style backtrace directly */
876 static void
877 backtrace_each(const rb_execution_context_t *ec,
878 void (*init)(void *arg, size_t size),
879 void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
880 void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
881 void *arg)
883 const rb_control_frame_t *last_cfp = ec->cfp;
884 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
885 const rb_control_frame_t *cfp;
886 ptrdiff_t size, i;
888 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
889 if (start_cfp == NULL) {
890 init(arg, 0);
891 return;
894 /* <- start_cfp (end control frame)
895 * top frame (dummy)
896 * top frame (dummy)
897 * top frame <- start_cfp
898 * top frame
899 * ...
900 * 2nd frame <- lev:0
901 * current frame <- ec->cfp
904 start_cfp =
905 RUBY_VM_NEXT_CONTROL_FRAME(
906 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
908 if (start_cfp < last_cfp) {
909 size = 0;
911 else {
912 size = start_cfp - last_cfp + 1;
915 init(arg, size);
917 /* SDR(); */
918 for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
919 /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
920 if (cfp->iseq) {
921 if (cfp->pc) {
922 iter_iseq(arg, cfp);
925 else {
926 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
927 const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
928 ID mid = me->def->original_id;
930 iter_cfunc(arg, cfp, mid);
935 struct oldbt_arg {
936 VALUE filename;
937 int lineno;
938 void (*func)(void *data, VALUE file, int lineno, VALUE name);
939 void *data; /* result */
942 static void
943 oldbt_init(void *ptr, size_t dmy)
945 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
946 arg->filename = GET_VM()->progname;
947 arg->lineno = 0;
950 static void
951 oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
953 const rb_iseq_t *iseq = cfp->iseq;
954 const VALUE *pc = cfp->pc;
955 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
956 VALUE file = arg->filename = rb_iseq_path(iseq);
957 VALUE name = ISEQ_BODY(iseq)->location.label;
958 int lineno = arg->lineno = calc_lineno(iseq, pc);
960 (arg->func)(arg->data, file, lineno, name);
963 static void
964 oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
966 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
967 VALUE file = arg->filename;
968 VALUE name = rb_id2str(mid);
969 int lineno = arg->lineno;
971 (arg->func)(arg->data, file, lineno, name);
974 static void
975 oldbt_print(void *data, VALUE file, int lineno, VALUE name)
977 FILE *fp = (FILE *)data;
979 if (NIL_P(name)) {
980 fprintf(fp, "\tfrom %s:%d:in unknown method\n",
981 RSTRING_PTR(file), lineno);
983 else {
984 fprintf(fp, "\tfrom %s:%d:in `%s'\n",
985 RSTRING_PTR(file), lineno, RSTRING_PTR(name));
989 static void
990 vm_backtrace_print(FILE *fp)
992 struct oldbt_arg arg;
994 arg.func = oldbt_print;
995 arg.data = (void *)fp;
996 backtrace_each(GET_EC(),
997 oldbt_init,
998 oldbt_iter_iseq,
999 oldbt_iter_cfunc,
1000 &arg);
1003 static void
1004 oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
1006 const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
1007 if (!*(int *)arg) {
1008 fprintf(stderr, "-- Ruby level backtrace information "
1009 "----------------------------------------\n");
1010 *(int *)arg = 1;
1012 if (NIL_P(method)) {
1013 fprintf(stderr, "%s:%d:in unknown method\n", filename, line);
1015 else {
1016 fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
1020 void
1021 rb_backtrace_print_as_bugreport(void)
1023 struct oldbt_arg arg;
1024 int i = 0;
1026 arg.func = oldbt_bugreport;
1027 arg.data = (int *)&i;
1029 backtrace_each(GET_EC(),
1030 oldbt_init,
1031 oldbt_iter_iseq,
1032 oldbt_iter_cfunc,
1033 &arg);
1036 void
1037 rb_backtrace(void)
1039 vm_backtrace_print(stderr);
1042 struct print_to_arg {
1043 VALUE (*iter)(VALUE recv, VALUE str);
1044 VALUE output;
1047 static void
1048 oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
1050 const struct print_to_arg *arg = data;
1051 VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
1053 if (NIL_P(name)) {
1054 rb_str_cat2(str, "unknown method\n");
1056 else {
1057 rb_str_catf(str, " `%"PRIsVALUE"'\n", name);
1059 (*arg->iter)(arg->output, str);
1062 void
1063 rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output)
1065 struct oldbt_arg arg;
1066 struct print_to_arg parg;
1068 parg.iter = iter;
1069 parg.output = output;
1070 arg.func = oldbt_print_to;
1071 arg.data = &parg;
1072 backtrace_each(GET_EC(),
1073 oldbt_init,
1074 oldbt_iter_iseq,
1075 oldbt_iter_cfunc,
1076 &arg);
1079 VALUE
1080 rb_make_backtrace(void)
1082 return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START, ALL_BACKTRACE_LINES);
1085 static VALUE
1086 ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str)
1088 VALUE level, vn;
1089 long lev, n;
1090 VALUE btval;
1091 VALUE r;
1092 int too_large;
1094 rb_scan_args(argc, argv, "02", &level, &vn);
1096 if (argc == 2 && NIL_P(vn)) argc--;
1098 switch (argc) {
1099 case 0:
1100 lev = lev_default + lev_plus;
1101 n = ALL_BACKTRACE_LINES;
1102 break;
1103 case 1:
1105 long beg, len, bt_size = backtrace_size(ec);
1106 switch (rb_range_beg_len(level, &beg, &len, bt_size - lev_plus, 0)) {
1107 case Qfalse:
1108 lev = NUM2LONG(level);
1109 if (lev < 0) {
1110 rb_raise(rb_eArgError, "negative level (%ld)", lev);
1112 lev += lev_plus;
1113 n = ALL_BACKTRACE_LINES;
1114 break;
1115 case Qnil:
1116 return Qnil;
1117 default:
1118 lev = beg + lev_plus;
1119 n = len;
1120 break;
1122 break;
1124 case 2:
1125 lev = NUM2LONG(level);
1126 n = NUM2LONG(vn);
1127 if (lev < 0) {
1128 rb_raise(rb_eArgError, "negative level (%ld)", lev);
1130 if (n < 0) {
1131 rb_raise(rb_eArgError, "negative size (%ld)", n);
1133 lev += lev_plus;
1134 break;
1135 default:
1136 lev = n = 0; /* to avoid warning */
1137 break;
1140 if (n == 0) {
1141 return rb_ary_new();
1144 btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE, FALSE);
1146 if (too_large) {
1147 return Qnil;
1150 if (to_str) {
1151 r = backtrace_to_str_ary(btval);
1153 else {
1154 r = backtrace_to_location_ary(btval);
1156 RB_GC_GUARD(btval);
1157 return r;
1160 static VALUE
1161 thread_backtrace_to_ary(int argc, const VALUE *argv, VALUE thval, int to_str)
1163 rb_thread_t *target_th = rb_thread_ptr(thval);
1165 if (target_th->to_kill || target_th->status == THREAD_KILLED)
1166 return Qnil;
1168 return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1171 VALUE
1172 rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval)
1174 return thread_backtrace_to_ary(argc, argv, thval, 1);
1177 VALUE
1178 rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval)
1180 return thread_backtrace_to_ary(argc, argv, thval, 0);
1183 VALUE
1184 rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1186 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1189 VALUE
1190 rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1192 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1196 * call-seq:
1197 * caller(start=1, length=nil) -> array or nil
1198 * caller(range) -> array or nil
1200 * Returns the current execution stack---an array containing strings in
1201 * the form <code>file:line</code> or <code>file:line: in
1202 * `method'</code>.
1204 * The optional _start_ parameter determines the number of initial stack
1205 * entries to omit from the top of the stack.
1207 * A second optional +length+ parameter can be used to limit how many entries
1208 * are returned from the stack.
1210 * Returns +nil+ if _start_ is greater than the size of
1211 * current execution stack.
1213 * Optionally you can pass a range, which will return an array containing the
1214 * entries within the specified range.
1216 * def a(skip)
1217 * caller(skip)
1218 * end
1219 * def b(skip)
1220 * a(skip)
1221 * end
1222 * def c(skip)
1223 * b(skip)
1224 * end
1225 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1226 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1227 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1228 * c(3) #=> ["prog:13:in `<main>'"]
1229 * c(4) #=> []
1230 * c(5) #=> nil
1233 static VALUE
1234 rb_f_caller(int argc, VALUE *argv, VALUE _)
1236 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1240 * call-seq:
1241 * caller_locations(start=1, length=nil) -> array or nil
1242 * caller_locations(range) -> array or nil
1244 * Returns the current execution stack---an array containing
1245 * backtrace location objects.
1247 * See Thread::Backtrace::Location for more information.
1249 * The optional _start_ parameter determines the number of initial stack
1250 * entries to omit from the top of the stack.
1252 * A second optional +length+ parameter can be used to limit how many entries
1253 * are returned from the stack.
1255 * Returns +nil+ if _start_ is greater than the size of
1256 * current execution stack.
1258 * Optionally you can pass a range, which will return an array containing the
1259 * entries within the specified range.
1261 static VALUE
1262 rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
1264 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1268 * call-seq:
1269 * Thread.each_caller_location{ |loc| ... } -> nil
1271 * Yields each frame of the current execution stack as a
1272 * backtrace location object.
1274 static VALUE
1275 each_caller_location(VALUE unused)
1277 rb_ec_partial_backtrace_object(GET_EC(), 2, ALL_BACKTRACE_LINES, NULL, FALSE, TRUE);
1278 return Qnil;
1281 /* called from Init_vm() in vm.c */
1282 void
1283 Init_vm_backtrace(void)
1286 * An internal representation of the backtrace. The user will never interact with
1287 * objects of this class directly, but class methods can be used to get backtrace
1288 * settings of the current session.
1290 rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
1291 rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
1292 rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
1293 rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
1294 rb_define_singleton_method(rb_cBacktrace, "limit", backtrace_limit, 0);
1297 * An object representation of a stack frame, initialized by
1298 * Kernel#caller_locations.
1300 * For example:
1302 * # caller_locations.rb
1303 * def a(skip)
1304 * caller_locations(skip)
1305 * end
1306 * def b(skip)
1307 * a(skip)
1308 * end
1309 * def c(skip)
1310 * b(skip)
1311 * end
1313 * c(0..2).map do |call|
1314 * puts call.to_s
1315 * end
1317 * Running <code>ruby caller_locations.rb</code> will produce:
1319 * caller_locations.rb:2:in `a'
1320 * caller_locations.rb:5:in `b'
1321 * caller_locations.rb:8:in `c'
1323 * Here's another example with a slightly different result:
1325 * # foo.rb
1326 * class Foo
1327 * attr_accessor :locations
1328 * def initialize(skip)
1329 * @locations = caller_locations(skip)
1330 * end
1331 * end
1333 * Foo.new(0..2).locations.map do |call|
1334 * puts call.to_s
1335 * end
1337 * Now run <code>ruby foo.rb</code> and you should see:
1339 * init.rb:4:in `initialize'
1340 * init.rb:8:in `new'
1341 * init.rb:8:in `<main>'
1343 rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
1344 rb_undef_alloc_func(rb_cBacktraceLocation);
1345 rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
1346 rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
1347 rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
1348 rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
1349 rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
1350 rb_define_method(rb_cBacktraceLocation, "absolute_path", location_absolute_path_m, 0);
1351 rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
1352 rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
1354 rb_define_global_function("caller", rb_f_caller, -1);
1355 rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1357 rb_define_singleton_method(rb_cThread, "each_caller_location", each_caller_location, 0);
1360 /* debugger API */
1362 RUBY_SYMBOL_EXPORT_BEGIN
1364 RUBY_SYMBOL_EXPORT_END
1366 struct rb_debug_inspector_struct {
1367 rb_execution_context_t *ec;
1368 rb_control_frame_t *cfp;
1369 VALUE backtrace;
1370 VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1371 long backtrace_size;
1374 enum {
1375 CALLER_BINDING_SELF,
1376 CALLER_BINDING_CLASS,
1377 CALLER_BINDING_BINDING,
1378 CALLER_BINDING_ISEQ,
1379 CALLER_BINDING_CFP,
1380 CALLER_BINDING_DEPTH,
1383 struct collect_caller_bindings_data {
1384 VALUE ary;
1385 const rb_execution_context_t *ec;
1388 static void
1389 collect_caller_bindings_init(void *arg, size_t size)
1391 /* */
1394 static VALUE
1395 get_klass(const rb_control_frame_t *cfp)
1397 VALUE klass;
1398 if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
1399 if (RB_TYPE_P(klass, T_ICLASS)) {
1400 return RBASIC(klass)->klass;
1402 else {
1403 return klass;
1406 else {
1407 return Qnil;
1411 static int
1412 frame_depth(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
1414 VM_ASSERT(RUBY_VM_END_CONTROL_FRAME(ec) >= cfp);
1415 return (int)(RUBY_VM_END_CONTROL_FRAME(ec) - cfp);
1418 static void
1419 collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
1421 struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1422 VALUE frame = rb_ary_new2(6);
1424 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1425 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1426 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
1427 rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? (VALUE)cfp->iseq : Qnil);
1428 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1429 rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
1431 rb_ary_push(data->ary, frame);
1434 static void
1435 collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
1437 struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1438 VALUE frame = rb_ary_new2(6);
1440 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1441 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1442 rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
1443 rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
1444 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1445 rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
1447 rb_ary_push(data->ary, frame);
1450 static VALUE
1451 collect_caller_bindings(const rb_execution_context_t *ec)
1453 int i;
1454 VALUE result;
1455 struct collect_caller_bindings_data data = {
1456 rb_ary_new(), ec
1459 backtrace_each(ec,
1460 collect_caller_bindings_init,
1461 collect_caller_bindings_iseq,
1462 collect_caller_bindings_cfunc,
1463 &data);
1465 result = rb_ary_reverse(data.ary);
1467 /* bindings should be created from top of frame */
1468 for (i=0; i<RARRAY_LEN(result); i++) {
1469 VALUE entry = rb_ary_entry(result, i);
1470 VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
1472 if (!NIL_P(cfp_val)) {
1473 rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
1474 rb_ary_store(entry, CALLER_BINDING_BINDING, rb_vm_make_binding(ec, cfp));
1478 return result;
1482 * Note that the passed `rb_debug_inspector_t' will be disabled
1483 * after `rb_debug_inspector_open'.
1486 VALUE
1487 rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
1489 rb_debug_inspector_t dbg_context;
1490 rb_execution_context_t *ec = GET_EC();
1491 enum ruby_tag_type state;
1492 volatile VALUE MAYBE_UNUSED(result);
1494 /* escape all env to heap */
1495 rb_vm_stack_to_heap(ec);
1497 dbg_context.ec = ec;
1498 dbg_context.cfp = dbg_context.ec->cfp;
1499 dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, FALSE);
1500 dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
1501 dbg_context.contexts = collect_caller_bindings(ec);
1503 EC_PUSH_TAG(ec);
1504 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1505 result = (*func)(&dbg_context, data);
1507 EC_POP_TAG();
1509 /* invalidate bindings? */
1511 if (state) {
1512 EC_JUMP_TAG(ec, state);
1515 return result;
1518 static VALUE
1519 frame_get(const rb_debug_inspector_t *dc, long index)
1521 if (index < 0 || index >= dc->backtrace_size) {
1522 rb_raise(rb_eArgError, "no such frame");
1524 return rb_ary_entry(dc->contexts, index);
1527 VALUE
1528 rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
1530 VALUE frame = frame_get(dc, index);
1531 return rb_ary_entry(frame, CALLER_BINDING_SELF);
1534 VALUE
1535 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
1537 VALUE frame = frame_get(dc, index);
1538 return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1541 VALUE
1542 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
1544 VALUE frame = frame_get(dc, index);
1545 return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1548 VALUE
1549 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
1551 VALUE frame = frame_get(dc, index);
1552 VALUE iseq = rb_ary_entry(frame, CALLER_BINDING_ISEQ);
1554 return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) : Qnil;
1557 VALUE
1558 rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index)
1560 VALUE frame = frame_get(dc, index);
1561 return rb_ary_entry(frame, CALLER_BINDING_DEPTH);
1564 VALUE
1565 rb_debug_inspector_current_depth(void)
1567 rb_execution_context_t *ec = GET_EC();
1568 return INT2FIX(frame_depth(ec, ec->cfp));
1571 VALUE
1572 rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
1574 return dc->backtrace;
1578 rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
1580 int i;
1581 const rb_execution_context_t *ec = GET_EC();
1582 const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
1583 const rb_callable_method_entry_t *cme;
1585 // If this function is called inside a thread after thread creation, but
1586 // before the CFP has been created, just return 0. This can happen when
1587 // sampling via signals. Threads can be interrupted randomly by the
1588 // signal, including during the time after the thread has been created, but
1589 // before the CFP has been allocated
1590 if (!cfp) {
1591 return 0;
1594 // Skip dummy frame; see `rb_ec_partial_backtrace_object` for details
1595 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
1597 for (i=0; i<limit && cfp != end_cfp;) {
1598 if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->pc != 0) {
1599 if (start > 0) {
1600 start--;
1601 continue;
1604 /* record frame info */
1605 cme = rb_vm_frame_method_entry(cfp);
1606 if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
1607 buff[i] = (VALUE)cme;
1609 else {
1610 buff[i] = (VALUE)cfp->iseq;
1613 if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc);
1615 i++;
1617 else {
1618 cme = rb_vm_frame_method_entry(cfp);
1619 if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
1620 buff[i] = (VALUE)cme;
1621 if (lines) lines[i] = 0;
1622 i++;
1625 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
1628 return i;
1631 static const rb_iseq_t *
1632 frame2iseq(VALUE frame)
1634 if (NIL_P(frame)) return NULL;
1636 if (RB_TYPE_P(frame, T_IMEMO)) {
1637 switch (imemo_type(frame)) {
1638 case imemo_iseq:
1639 return (const rb_iseq_t *)frame;
1640 case imemo_ment:
1642 const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
1643 switch (cme->def->type) {
1644 case VM_METHOD_TYPE_ISEQ:
1645 return cme->def->body.iseq.iseqptr;
1646 default:
1647 return NULL;
1650 default:
1651 break;
1654 rb_bug("frame2iseq: unreachable");
1657 VALUE
1658 rb_profile_frame_path(VALUE frame)
1660 const rb_iseq_t *iseq = frame2iseq(frame);
1661 return iseq ? rb_iseq_path(iseq) : Qnil;
1664 static const rb_callable_method_entry_t *
1665 cframe(VALUE frame)
1667 if (NIL_P(frame)) return NULL;
1669 if (RB_TYPE_P(frame, T_IMEMO)) {
1670 switch (imemo_type(frame)) {
1671 case imemo_ment:
1673 const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
1674 switch (cme->def->type) {
1675 case VM_METHOD_TYPE_CFUNC:
1676 return cme;
1677 default:
1678 return NULL;
1681 default:
1682 return NULL;
1686 return NULL;
1689 VALUE
1690 rb_profile_frame_absolute_path(VALUE frame)
1692 if (cframe(frame)) {
1693 static VALUE cfunc_str = Qfalse;
1694 if (!cfunc_str) {
1695 cfunc_str = rb_str_new_literal("<cfunc>");
1696 rb_gc_register_mark_object(cfunc_str);
1698 return cfunc_str;
1700 const rb_iseq_t *iseq = frame2iseq(frame);
1701 return iseq ? rb_iseq_realpath(iseq) : Qnil;
1704 VALUE
1705 rb_profile_frame_label(VALUE frame)
1707 const rb_iseq_t *iseq = frame2iseq(frame);
1708 return iseq ? rb_iseq_label(iseq) : Qnil;
1711 VALUE
1712 rb_profile_frame_base_label(VALUE frame)
1714 const rb_iseq_t *iseq = frame2iseq(frame);
1715 return iseq ? rb_iseq_base_label(iseq) : Qnil;
1718 VALUE
1719 rb_profile_frame_first_lineno(VALUE frame)
1721 const rb_iseq_t *iseq = frame2iseq(frame);
1722 return iseq ? rb_iseq_first_lineno(iseq) : Qnil;
1725 static VALUE
1726 frame2klass(VALUE frame)
1728 if (NIL_P(frame)) return Qnil;
1730 if (RB_TYPE_P(frame, T_IMEMO)) {
1731 const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
1733 if (imemo_type(frame) == imemo_ment) {
1734 return cme->defined_class;
1737 return Qnil;
1740 VALUE
1741 rb_profile_frame_classpath(VALUE frame)
1743 VALUE klass = frame2klass(frame);
1745 if (klass && !NIL_P(klass)) {
1746 if (RB_TYPE_P(klass, T_ICLASS)) {
1747 klass = RBASIC(klass)->klass;
1749 else if (FL_TEST(klass, FL_SINGLETON)) {
1750 klass = RCLASS_ATTACHED_OBJECT(klass);
1751 if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE))
1752 return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass);
1754 return rb_class_path(klass);
1756 else {
1757 return Qnil;
1761 VALUE
1762 rb_profile_frame_singleton_method_p(VALUE frame)
1764 VALUE klass = frame2klass(frame);
1766 return RBOOL(klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON));
1769 VALUE
1770 rb_profile_frame_method_name(VALUE frame)
1772 const rb_callable_method_entry_t *cme = cframe(frame);
1773 if (cme) {
1774 ID mid = cme->def->original_id;
1775 return id2str(mid);
1777 const rb_iseq_t *iseq = frame2iseq(frame);
1778 return iseq ? rb_iseq_method_name(iseq) : Qnil;
1781 static VALUE
1782 qualified_method_name(VALUE frame, VALUE method_name)
1784 if (method_name != Qnil) {
1785 VALUE classpath = rb_profile_frame_classpath(frame);
1786 VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
1788 if (classpath != Qnil) {
1789 return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
1790 classpath, singleton_p == Qtrue ? "." : "#", method_name);
1792 else {
1793 return method_name;
1796 else {
1797 return Qnil;
1801 VALUE
1802 rb_profile_frame_qualified_method_name(VALUE frame)
1804 VALUE method_name = rb_profile_frame_method_name(frame);
1806 return qualified_method_name(frame, method_name);
1809 VALUE
1810 rb_profile_frame_full_label(VALUE frame)
1812 const rb_callable_method_entry_t *cme = cframe(frame);
1813 if (cme) {
1814 ID mid = cme->def->original_id;
1815 VALUE method_name = id2str(mid);
1816 return qualified_method_name(frame, method_name);
1819 VALUE label = rb_profile_frame_label(frame);
1820 VALUE base_label = rb_profile_frame_base_label(frame);
1821 VALUE qualified_method_name = rb_profile_frame_qualified_method_name(frame);
1823 if (NIL_P(qualified_method_name) || base_label == qualified_method_name) {
1824 return label;
1826 else {
1827 long label_length = RSTRING_LEN(label);
1828 long base_label_length = RSTRING_LEN(base_label);
1829 int prefix_len = rb_long2int(label_length - base_label_length);
1831 return rb_sprintf("%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);