[ruby/win32ole] Undefine allocator of WIN32OLE_VARIABLE to get rid of warning
[ruby-80x24.org.git] / vm_backtrace.c
blob9f5fcc8da2b4092c169f0d16d2bfe6a20ebf59bf
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/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"
21 static VALUE rb_cBacktrace;
22 static VALUE rb_cBacktraceLocation;
24 static VALUE
25 id2str(ID id)
27 VALUE str = rb_id2str(id);
28 if (!str) return Qnil;
29 return str;
31 #define rb_id2str(id) id2str(id)
33 #define BACKTRACE_START 0
34 #define ALL_BACKTRACE_LINES -1
36 inline static int
37 calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
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;
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;
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--;
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();
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;
80 inline static int
81 calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
83 int lineno;
84 if (calc_pos(iseq, pc, &lineno, NULL)) return lineno;
85 return 0;
88 #ifdef USE_ISEQ_NODE_ID
89 inline static int
90 calc_node_id(const rb_iseq_t *iseq, const VALUE *pc)
92 int node_id;
93 if (calc_pos(iseq, pc, NULL, &node_id)) return node_id;
94 return -1;
96 #endif
98 int
99 rb_vm_get_sourceline(const rb_control_frame_t *cfp)
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;
107 else {
108 return FIX2INT(rb_iseq_first_lineno(iseq));
111 else {
112 return 0;
116 typedef struct rb_backtrace_location_struct {
117 enum LOCATION_TYPE {
118 LOCATION_TYPE_ISEQ = 1,
119 LOCATION_TYPE_CFUNC,
120 } type;
122 const rb_iseq_t *iseq;
123 const VALUE *pc;
124 ID mid;
125 } rb_backtrace_location_t;
127 struct valued_frame_info {
128 rb_backtrace_location_t *loc;
129 VALUE btobj;
132 static void
133 location_mark(void *ptr)
135 struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
136 rb_gc_mark(vfi->btobj);
139 static void
140 location_mark_entry(rb_backtrace_location_t *fi)
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);
150 break;
151 default:
152 break;
156 static size_t
157 location_memsize(const void *ptr)
159 /* rb_backtrace_location_t *fi = (rb_backtrace_location_t *)ptr; */
160 return sizeof(rb_backtrace_location_t);
163 static 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
170 rb_frame_info_p(VALUE obj)
172 return rb_typeddata_is_kind_of(obj, &location_data_type);
175 static inline rb_backtrace_location_t *
176 location_ptr(VALUE locobj)
178 struct valued_frame_info *vloc;
179 GetCoreDataFromValue(locobj, struct valued_frame_info, vloc);
180 return vloc->loc;
183 static int
184 location_lineno(rb_backtrace_location_t *loc)
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);
193 return 0;
194 default:
195 rb_bug("location_lineno: unreachable");
196 UNREACHABLE;
201 * Returns the line number of this frame.
203 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
205 * loc = c(0..1).first
206 * loc.lineno #=> 2
208 static VALUE
209 location_lineno_m(VALUE self)
211 return INT2FIX(location_lineno(location_ptr(self)));
214 static VALUE
215 location_label(rb_backtrace_location_t *loc)
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");
224 UNREACHABLE;
229 * Returns the label of this frame.
231 * Usually consists of method, class, module, etc names with decoration.
233 * Consider the following example:
235 * def foo
236 * puts caller_locations(0).first.label
238 * 1.times do
239 * puts caller_locations(0).first.label
241 * 1.times do
242 * puts caller_locations(0).first.label
243 * end
245 * end
246 * end
248 * The result of calling +foo+ is this:
250 * label: foo
251 * label: block in foo
252 * label: block (2 levels) in foo
255 static VALUE
256 location_label_m(VALUE self)
258 return location_label(location_ptr(self));
261 static VALUE
262 location_base_label(rb_backtrace_location_t *loc)
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");
271 UNREACHABLE;
276 * Returns the base label of this frame.
278 * Usually same as #label, without decoration.
280 static VALUE
281 location_base_label_m(VALUE self)
283 return location_base_label(location_ptr(self));
286 static const rb_iseq_t *
287 location_iseq(rb_backtrace_location_t *loc)
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");
296 UNREACHABLE;
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.
305 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
307 * loc = c(0..1).first
308 * loc.path #=> caller_locations.rb
310 static VALUE
311 location_path_m(VALUE self)
313 const rb_iseq_t *iseq = location_iseq(location_ptr(self));
314 return iseq ? rb_iseq_path(iseq) : Qnil;
317 #ifdef USE_ISEQ_NODE_ID
318 static int
319 location_node_id(rb_backtrace_location_t *loc)
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);
328 return -1;
329 default:
330 rb_bug("location_node_id: unreachable");
331 UNREACHABLE;
334 #endif
337 rb_get_node_id_from_frame_info(VALUE obj)
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
347 const rb_iseq_t *
348 rb_get_iseq_from_frame_info(VALUE obj)
350 rb_backtrace_location_t *loc = location_ptr(obj);
351 const rb_iseq_t *iseq = location_iseq(loc);
352 return iseq;
355 static VALUE
356 location_realpath(rb_backtrace_location_t *loc)
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);
365 return Qnil;
366 default:
367 rb_bug("location_realpath: unreachable");
368 UNREACHABLE;
373 * Returns the full file path of this frame.
375 * Same as #path, except that it will return absolute path
376 * even if the frame is in the main script.
378 static VALUE
379 location_absolute_path_m(VALUE self)
381 return location_realpath(location_ptr(self));
384 static VALUE
385 location_format(VALUE file, int lineno, VALUE name)
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);
391 rb_str_cat_cstr(s, ":in ");
392 if (NIL_P(name)) {
393 rb_str_cat_cstr(s, "unknown method");
395 else {
396 rb_str_catf(s, "`%s'", RSTRING_PTR(name));
398 return s;
401 static VALUE
402 location_to_str(rb_backtrace_location_t *loc)
404 VALUE file, name;
405 int lineno;
407 switch (loc->type) {
408 case LOCATION_TYPE_ISEQ:
409 file = rb_iseq_path(loc->iseq);
410 name = loc->iseq->body->location.label;
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);
419 else {
420 file = GET_VM()->progname;
421 lineno = 0;
423 name = rb_id2str(loc->mid);
424 break;
425 default:
426 rb_bug("location_to_str: unreachable");
429 return location_format(file, lineno, name);
433 * Returns a Kernel#caller style string representing this frame.
435 static VALUE
436 location_to_str_m(VALUE self)
438 return location_to_str(location_ptr(self));
442 * Returns the same as calling +inspect+ on the string representation of
443 * #to_str
445 static VALUE
446 location_inspect_m(VALUE self)
448 return rb_str_inspect(location_to_str(location_ptr(self)));
451 typedef struct rb_backtrace_struct {
452 rb_backtrace_location_t *backtrace;
453 int backtrace_size;
454 VALUE strary;
455 VALUE locary;
456 } rb_backtrace_t;
458 static void
459 backtrace_mark(void *ptr)
461 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
462 size_t i, s = bt->backtrace_size;
464 for (i=0; i<s; i++) {
465 location_mark_entry(&bt->backtrace[i]);
467 rb_gc_mark_movable(bt->strary);
468 rb_gc_mark_movable(bt->locary);
471 static void
472 backtrace_free(void *ptr)
474 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
475 if (bt->backtrace) ruby_xfree(bt->backtrace);
476 ruby_xfree(bt);
479 static void
480 location_update_entry(rb_backtrace_location_t *fi)
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);
490 break;
491 default:
492 break;
496 static void
497 backtrace_update(void *ptr)
499 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
500 size_t i, s = bt->backtrace_size;
502 for (i=0; i<s; i++) {
503 location_update_entry(&bt->backtrace[i]);
505 bt->strary = rb_gc_location(bt->strary);
506 bt->locary = rb_gc_location(bt->locary);
509 static size_t
510 backtrace_memsize(const void *ptr)
512 rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
513 return sizeof(rb_backtrace_t) + sizeof(rb_backtrace_location_t) * bt->backtrace_size;
516 static 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
523 rb_backtrace_p(VALUE obj)
525 return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
528 static VALUE
529 backtrace_alloc(VALUE klass)
531 rb_backtrace_t *bt;
532 VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
533 return obj;
536 static long
537 backtrace_size(const rb_execution_context_t *ec)
539 const rb_control_frame_t *last_cfp = ec->cfp;
540 const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
542 if (start_cfp == NULL) {
543 return -1;
546 start_cfp =
547 RUBY_VM_NEXT_CONTROL_FRAME(
548 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
550 if (start_cfp < last_cfp) {
551 return 0;
554 return start_cfp - last_cfp + 1;
557 static bool
558 is_internal_location(const rb_control_frame_t *cfp)
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;
566 static void
567 bt_update_cfunc_loc(unsigned long cfunc_counter, rb_backtrace_location_t *cfunc_loc, const rb_iseq_t *iseq, const VALUE *pc)
569 for (; cfunc_counter > 0; cfunc_counter--, cfunc_loc--) {
570 cfunc_loc->iseq = iseq;
571 cfunc_loc->pc = pc;
575 static VALUE
576 rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_frame, long num_frames, int* start_too_large, bool skip_internal)
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);
583 rb_backtrace_location_t *loc;
584 unsigned long cfunc_counter = 0;
585 GetCoreDataFromValue(btobj, rb_backtrace_t, bt);
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;
591 else {
592 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
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
604 size = end_cfp - cfp + 1;
605 if (size < 0) {
606 num_frames = 0;
608 else if (num_frames < 0 || num_frames > size) {
609 num_frames = size;
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;
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--;
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;
638 else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
639 if (start_frame > 0) {
640 start_frame--;
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++;
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;
662 if (start_too_large) *start_too_large = (start_frame > 0 ? -1 : 0);
663 return btobj;
666 MJIT_FUNC_EXPORTED VALUE
667 rb_ec_backtrace_object(const rb_execution_context_t *ec)
669 return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL, FALSE);
672 static VALUE
673 backtrace_collect(rb_backtrace_t *bt, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
675 VALUE btary;
676 int i;
678 btary = rb_ary_new2(bt->backtrace_size);
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));
685 return btary;
688 static VALUE
689 location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
691 return location_to_str(loc);
694 static VALUE
695 backtrace_to_str_ary(VALUE self)
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;
705 VALUE
706 rb_backtrace_to_str_ary(VALUE self)
708 rb_backtrace_t *bt;
709 GetCoreDataFromValue(self, rb_backtrace_t, bt);
711 if (!bt->strary) {
712 bt->strary = backtrace_to_str_ary(self);
714 return bt->strary;
717 MJIT_FUNC_EXPORTED void
718 rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self)
720 const rb_backtrace_t *bt;
721 rb_backtrace_location_t *loc;
723 GetCoreDataFromValue(self, rb_backtrace_t, bt);
724 VM_ASSERT(bt->backtrace_size > 0);
726 loc = &bt->backtrace[0];
728 VM_ASSERT(loc->type == LOCATION_TYPE_ISEQ);
730 loc->pc = NULL; // means location.first_lineno
733 static VALUE
734 location_create(rb_backtrace_location_t *srcloc, void *btobj)
736 VALUE obj;
737 struct valued_frame_info *vloc;
738 obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
740 vloc->loc = srcloc;
741 vloc->btobj = (VALUE)btobj;
743 return obj;
746 static VALUE
747 backtrace_to_location_ary(VALUE self)
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;
757 VALUE
758 rb_backtrace_to_location_ary(VALUE self)
760 rb_backtrace_t *bt;
761 GetCoreDataFromValue(self, rb_backtrace_t, bt);
763 if (!bt->locary) {
764 bt->locary = backtrace_to_location_ary(self);
766 return bt->locary;
769 static VALUE
770 backtrace_dump_data(VALUE self)
772 VALUE str = rb_backtrace_to_str_ary(self);
773 return str;
776 static VALUE
777 backtrace_load_data(VALUE self, VALUE str)
779 rb_backtrace_t *bt;
780 GetCoreDataFromValue(self, rb_backtrace_t, bt);
781 bt->strary = str;
782 return self;
786 * call-seq: Threade::Backtrace::limit -> integer
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>
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>'
816 * $ ruby --backtrace-limit 2 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
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...
827 * $ ruby --backtrace-limit 0 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
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...
835 static VALUE
836 backtrace_limit(VALUE self)
838 return LONG2NUM(rb_backtrace_length_limit);
841 VALUE
842 rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n)
844 return backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE));
847 VALUE
848 rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal)
850 return backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal));
853 /* make old style backtrace directly */
855 static void
856 backtrace_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)
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;
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;
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
883 start_cfp =
884 RUBY_VM_NEXT_CONTROL_FRAME(
885 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
887 if (start_cfp < last_cfp) {
888 size = 0;
890 else {
891 size = start_cfp - last_cfp + 1;
894 init(arg, size);
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);
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;
908 iter_cfunc(arg, cfp, mid);
913 struct oldbt_arg {
914 VALUE filename;
915 int lineno;
916 void (*func)(void *data, VALUE file, int lineno, VALUE name);
917 void *data; /* result */
920 static void
921 oldbt_init(void *ptr, size_t dmy)
923 struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
924 arg->filename = GET_VM()->progname;
925 arg->lineno = 0;
928 static void
929 oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
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);
938 (arg->func)(arg->data, file, lineno, name);
941 static void
942 oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
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;
949 (arg->func)(arg->data, file, lineno, name);
952 static void
953 oldbt_print(void *data, VALUE file, int lineno, VALUE name)
955 FILE *fp = (FILE *)data;
957 if (NIL_P(name)) {
958 fprintf(fp, "\tfrom %s:%d:in unknown method\n",
959 RSTRING_PTR(file), lineno);
961 else {
962 fprintf(fp, "\tfrom %s:%d:in `%s'\n",
963 RSTRING_PTR(file), lineno, RSTRING_PTR(name));
967 static void
968 vm_backtrace_print(FILE *fp)
970 struct oldbt_arg arg;
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);
981 static void
982 oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
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;
990 if (NIL_P(method)) {
991 fprintf(stderr, "%s:%d:in unknown method\n", filename, line);
993 else {
994 fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
998 void
999 rb_backtrace_print_as_bugreport(void)
1001 struct oldbt_arg arg;
1002 int i = 0;
1004 arg.func = oldbt_bugreport;
1005 arg.data = (int *)&i;
1007 backtrace_each(GET_EC(),
1008 oldbt_init,
1009 oldbt_iter_iseq,
1010 oldbt_iter_cfunc,
1011 &arg);
1014 void
1015 rb_backtrace(void)
1017 vm_backtrace_print(stderr);
1020 struct print_to_arg {
1021 VALUE (*iter)(VALUE recv, VALUE str);
1022 VALUE output;
1025 static void
1026 oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
1028 const struct print_to_arg *arg = data;
1029 VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
1031 if (NIL_P(name)) {
1032 rb_str_cat2(str, "unknown method\n");
1034 else {
1035 rb_str_catf(str, " `%"PRIsVALUE"'\n", name);
1037 (*arg->iter)(arg->output, str);
1040 void
1041 rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output)
1043 struct oldbt_arg arg;
1044 struct print_to_arg parg;
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);
1057 VALUE
1058 rb_make_backtrace(void)
1060 return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START, ALL_BACKTRACE_LINES);
1063 static VALUE
1064 ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str)
1066 VALUE level, vn;
1067 long lev, n;
1068 VALUE btval;
1069 VALUE r;
1070 int too_large;
1072 rb_scan_args(argc, argv, "02", &level, &vn);
1074 if (argc == 2 && NIL_P(vn)) argc--;
1076 switch (argc) {
1077 case 0:
1078 lev = lev_default + lev_plus;
1079 n = ALL_BACKTRACE_LINES;
1080 break;
1081 case 1:
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);
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;
1100 break;
1102 case 2:
1103 lev = NUM2LONG(level);
1104 n = NUM2LONG(vn);
1105 if (lev < 0) {
1106 rb_raise(rb_eArgError, "negative level (%ld)", lev);
1108 if (n < 0) {
1109 rb_raise(rb_eArgError, "negative size (%ld)", n);
1111 lev += lev_plus;
1112 break;
1113 default:
1114 lev = n = 0; /* to avoid warning */
1115 break;
1118 if (n == 0) {
1119 return rb_ary_new();
1122 btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE);
1124 if (too_large) {
1125 return Qnil;
1128 if (to_str) {
1129 r = backtrace_to_str_ary(btval);
1131 else {
1132 r = backtrace_to_location_ary(btval);
1134 RB_GC_GUARD(btval);
1135 return r;
1138 static VALUE
1139 thread_backtrace_to_ary(int argc, const VALUE *argv, VALUE thval, int to_str)
1141 rb_thread_t *target_th = rb_thread_ptr(thval);
1143 if (target_th->to_kill || target_th->status == THREAD_KILLED)
1144 return Qnil;
1146 return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1149 VALUE
1150 rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval)
1152 return thread_backtrace_to_ary(argc, argv, thval, 1);
1155 VALUE
1156 rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval)
1158 return thread_backtrace_to_ary(argc, argv, thval, 0);
1161 VALUE rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1163 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1166 VALUE rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1168 return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1172 * call-seq:
1173 * caller(start=1, length=nil) -> array or nil
1174 * caller(range) -> array or nil
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>.
1180 * The optional _start_ parameter determines the number of initial stack
1181 * entries to omit from the top of the stack.
1183 * A second optional +length+ parameter can be used to limit how many entries
1184 * are returned from the stack.
1186 * Returns +nil+ if _start_ is greater than the size of
1187 * current execution stack.
1189 * Optionally you can pass a range, which will return an array containing the
1190 * entries within the specified range.
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
1209 static VALUE
1210 rb_f_caller(int argc, VALUE *argv, VALUE _)
1212 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1216 * call-seq:
1217 * caller_locations(start=1, length=nil) -> array or nil
1218 * caller_locations(range) -> array or nil
1220 * Returns the current execution stack---an array containing
1221 * backtrace location objects.
1223 * See Thread::Backtrace::Location for more information.
1225 * The optional _start_ parameter determines the number of initial stack
1226 * entries to omit from the top of the stack.
1228 * A second optional +length+ parameter can be used to limit how many entries
1229 * are returned from the stack.
1231 * Returns +nil+ if _start_ is greater than the size of
1232 * current execution stack.
1234 * Optionally you can pass a range, which will return an array containing the
1235 * entries within the specified range.
1237 static VALUE
1238 rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
1240 return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1243 /* called from Init_vm() in vm.c */
1244 void
1245 Init_vm_backtrace(void)
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.
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);
1259 * An object representation of a stack frame, initialized by
1260 * Kernel#caller_locations.
1262 * For example:
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
1275 * c(0..2).map do |call|
1276 * puts call.to_s
1277 * end
1279 * Running <code>ruby caller_locations.rb</code> will produce:
1281 * caller_locations.rb:2:in `a'
1282 * caller_locations.rb:5:in `b'
1283 * caller_locations.rb:8:in `c'
1285 * Here's another example with a slightly different result:
1287 * # foo.rb
1288 * class Foo
1289 * attr_accessor :locations
1290 * def initialize(skip)
1291 * @locations = caller_locations(skip)
1292 * end
1293 * end
1295 * Foo.new(0..2).locations.map do |call|
1296 * puts call.to_s
1297 * end
1299 * Now run <code>ruby foo.rb</code> and you should see:
1301 * init.rb:4:in `initialize'
1302 * init.rb:8:in `new'
1303 * init.rb:8:in `<main>'
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);
1316 rb_define_global_function("caller", rb_f_caller, -1);
1317 rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1320 /* debugger API */
1322 RUBY_SYMBOL_EXPORT_BEGIN
1324 RUBY_SYMBOL_EXPORT_END
1326 struct rb_debug_inspector_struct {
1327 rb_execution_context_t *ec;
1328 rb_control_frame_t *cfp;
1329 VALUE backtrace;
1330 VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1331 long backtrace_size;
1334 enum {
1335 CALLER_BINDING_SELF,
1336 CALLER_BINDING_CLASS,
1337 CALLER_BINDING_BINDING,
1338 CALLER_BINDING_ISEQ,
1339 CALLER_BINDING_CFP
1342 struct collect_caller_bindings_data {
1343 VALUE ary;
1346 static void
1347 collect_caller_bindings_init(void *arg, size_t size)
1349 /* */
1352 static VALUE
1353 get_klass(const rb_control_frame_t *cfp)
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;
1360 else {
1361 return klass;
1364 else {
1365 return Qnil;
1369 static void
1370 collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
1372 struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1373 VALUE frame = rb_ary_new2(5);
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));
1381 rb_ary_push(data->ary, frame);
1384 static void
1385 collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
1387 struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1388 VALUE frame = rb_ary_new2(5);
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));
1396 rb_ary_push(data->ary, frame);
1399 static VALUE
1400 collect_caller_bindings(const rb_execution_context_t *ec)
1402 struct collect_caller_bindings_data data;
1403 VALUE result;
1404 int i;
1406 data.ary = rb_ary_new();
1408 backtrace_each(ec,
1409 collect_caller_bindings_init,
1410 collect_caller_bindings_iseq,
1411 collect_caller_bindings_cfunc,
1412 &data);
1414 result = rb_ary_reverse(data.ary);
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);
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));
1427 return result;
1431 * Note that the passed `rb_debug_inspector_t' will be disabled
1432 * after `rb_debug_inspector_open'.
1435 VALUE
1436 rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
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);
1443 /* escape all env to heap */
1444 rb_vm_stack_to_heap(ec);
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);
1452 EC_PUSH_TAG(ec);
1453 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1454 result = (*func)(&dbg_context, data);
1456 EC_POP_TAG();
1458 /* invalidate bindings? */
1460 if (state) {
1461 EC_JUMP_TAG(ec, state);
1464 return result;
1467 static VALUE
1468 frame_get(const rb_debug_inspector_t *dc, long index)
1470 if (index < 0 || index >= dc->backtrace_size) {
1471 rb_raise(rb_eArgError, "no such frame");
1473 return rb_ary_entry(dc->contexts, index);
1476 VALUE
1477 rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
1479 VALUE frame = frame_get(dc, index);
1480 return rb_ary_entry(frame, CALLER_BINDING_SELF);
1483 VALUE
1484 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
1486 VALUE frame = frame_get(dc, index);
1487 return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1490 VALUE
1491 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
1493 VALUE frame = frame_get(dc, index);
1494 return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1497 VALUE
1498 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
1500 VALUE frame = frame_get(dc, index);
1501 VALUE iseq = rb_ary_entry(frame, CALLER_BINDING_ISEQ);
1503 return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) : Qnil;
1506 VALUE
1507 rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
1509 return dc->backtrace;
1513 rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
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;
1520 for (i=0; i<limit && cfp != end_cfp;) {
1521 if (VM_FRAME_RUBYFRAME_P(cfp)) {
1522 if (start > 0) {
1523 start--;
1524 continue;
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;
1532 else {
1533 buff[i] = (VALUE)cfp->iseq;
1536 if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc);
1538 i++;
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++;
1548 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
1551 return i;
1554 static const rb_iseq_t *
1555 frame2iseq(VALUE frame)
1557 if (NIL_P(frame)) return NULL;
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:
1565 const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
1566 switch (cme->def->type) {
1567 case VM_METHOD_TYPE_ISEQ:
1568 return cme->def->body.iseq.iseqptr;
1569 default:
1570 return NULL;
1573 default:
1574 break;
1577 rb_bug("frame2iseq: unreachable");
1580 VALUE
1581 rb_profile_frame_path(VALUE frame)
1583 const rb_iseq_t *iseq = frame2iseq(frame);
1584 return iseq ? rb_iseq_path(iseq) : Qnil;
1587 static const rb_callable_method_entry_t *
1588 cframe(VALUE frame)
1590 if (NIL_P(frame)) return NULL;
1592 if (RB_TYPE_P(frame, T_IMEMO)) {
1593 switch (imemo_type(frame)) {
1594 case imemo_ment:
1596 const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
1597 switch (cme->def->type) {
1598 case VM_METHOD_TYPE_CFUNC:
1599 return cme;
1600 default:
1601 return NULL;
1604 default:
1605 return NULL;
1609 return NULL;
1612 VALUE
1613 rb_profile_frame_absolute_path(VALUE frame)
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);
1621 return cfunc_str;
1623 const rb_iseq_t *iseq = frame2iseq(frame);
1624 return iseq ? rb_iseq_realpath(iseq) : Qnil;
1627 VALUE
1628 rb_profile_frame_label(VALUE frame)
1630 const rb_iseq_t *iseq = frame2iseq(frame);
1631 return iseq ? rb_iseq_label(iseq) : Qnil;
1634 VALUE
1635 rb_profile_frame_base_label(VALUE frame)
1637 const rb_iseq_t *iseq = frame2iseq(frame);
1638 return iseq ? rb_iseq_base_label(iseq) : Qnil;
1641 VALUE
1642 rb_profile_frame_first_lineno(VALUE frame)
1644 const rb_iseq_t *iseq = frame2iseq(frame);
1645 return iseq ? rb_iseq_first_lineno(iseq) : Qnil;
1648 static VALUE
1649 frame2klass(VALUE frame)
1651 if (NIL_P(frame)) return Qnil;
1653 if (RB_TYPE_P(frame, T_IMEMO)) {
1654 const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
1656 if (imemo_type(frame) == imemo_ment) {
1657 return cme->defined_class;
1660 return Qnil;
1663 VALUE
1664 rb_profile_frame_classpath(VALUE frame)
1666 VALUE klass = frame2klass(frame);
1668 if (klass && !NIL_P(klass)) {
1669 if (RB_TYPE_P(klass, T_ICLASS)) {
1670 klass = RBASIC(klass)->klass;
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);
1677 return rb_class_path(klass);
1679 else {
1680 return Qnil;
1684 VALUE
1685 rb_profile_frame_singleton_method_p(VALUE frame)
1687 VALUE klass = frame2klass(frame);
1689 return RBOOL(klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON));
1692 VALUE
1693 rb_profile_frame_method_name(VALUE frame)
1695 const rb_callable_method_entry_t *cme = cframe(frame);
1696 if (cme) {
1697 ID mid = cme->def->original_id;
1698 return id2str(mid);
1700 const rb_iseq_t *iseq = frame2iseq(frame);
1701 return iseq ? rb_iseq_method_name(iseq) : Qnil;
1704 static VALUE
1705 qualified_method_name(VALUE frame, VALUE method_name)
1707 if (method_name != Qnil) {
1708 VALUE classpath = rb_profile_frame_classpath(frame);
1709 VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
1711 if (classpath != Qnil) {
1712 return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
1713 classpath, singleton_p == Qtrue ? "." : "#", method_name);
1715 else {
1716 return method_name;
1719 else {
1720 return Qnil;
1724 VALUE
1725 rb_profile_frame_qualified_method_name(VALUE frame)
1727 VALUE method_name = rb_profile_frame_method_name(frame);
1729 return qualified_method_name(frame, method_name);
1732 VALUE
1733 rb_profile_frame_full_label(VALUE frame)
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);
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);
1746 if (NIL_P(qualified_method_name) || base_label == qualified_method_name) {
1747 return label;
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);
1754 return rb_sprintf("%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);