1 /**********************************************************************
6 created at: Sun Jun 03 00:14:20 2012
8 Copyright (C) 1993-2012 Yukihiro Matsumoto
10 **********************************************************************/
12 #include "eval_intern.h"
14 #include "internal/class.h"
15 #include "internal/error.h"
16 #include "internal/vm.h"
18 #include "ruby/debug.h"
19 #include "ruby/encoding.h"
22 static VALUE rb_cBacktrace
;
23 static VALUE rb_cBacktraceLocation
;
28 VALUE str
= rb_id2str(id
);
29 if (!str
) return Qnil
;
32 #define rb_id2str(id) id2str(id)
34 #define BACKTRACE_START 0
35 #define ALL_BACKTRACE_LINES -1
38 calc_pos(const rb_iseq_t
*iseq
, const VALUE
*pc
, int *lineno
, int *node_id
)
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
);
48 if (lineno
) *lineno
= ISEQ_BODY(iseq
)->location
.first_lineno
;
49 #ifdef USE_ISEQ_NODE_ID
50 if (node_id
) *node_id
= -1;
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
);
63 size_t pos
= n
; /* no overflow */
65 /* use pos-1 because PC points next instruction at the beginning of instruction */
68 #if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
70 /* SDR() is not possible; that causes infinite loop. */
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
);
84 calc_lineno(const rb_iseq_t
*iseq
, const VALUE
*pc
)
87 if (calc_pos(iseq
, pc
, &lineno
, NULL
)) return lineno
;
91 #ifdef USE_ISEQ_NODE_ID
93 calc_node_id(const rb_iseq_t
*iseq
, const VALUE
*pc
)
96 if (calc_pos(iseq
, pc
, NULL
, &node_id
)) return node_id
;
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
);
111 return ISEQ_BODY(iseq
)->location
.first_lineno
;
119 typedef struct rb_backtrace_location_struct
{
121 LOCATION_TYPE_ISEQ
= 1,
125 const rb_iseq_t
*iseq
;
128 } rb_backtrace_location_t
;
130 struct valued_frame_info
{
131 rb_backtrace_location_t
*loc
;
136 location_mark(void *ptr
)
138 struct valued_frame_info
*vfi
= (struct valued_frame_info
*)ptr
;
139 rb_gc_mark(vfi
->btobj
);
143 location_mark_entry(rb_backtrace_location_t
*fi
)
146 case LOCATION_TYPE_ISEQ
:
147 rb_gc_mark_movable((VALUE
)fi
->iseq
);
149 case LOCATION_TYPE_CFUNC
:
151 rb_gc_mark_movable((VALUE
)fi
->iseq
);
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
= {
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
);
187 location_lineno(rb_backtrace_location_t
*loc
)
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
);
198 rb_bug("location_lineno: 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
212 location_lineno_m(VALUE self
)
214 return INT2FIX(location_lineno(location_ptr(self
)));
218 location_label(rb_backtrace_location_t
*loc
)
221 case LOCATION_TYPE_ISEQ
:
222 return ISEQ_BODY(loc
->iseq
)->location
.label
;
223 case LOCATION_TYPE_CFUNC
:
224 return rb_id2str(loc
->mid
);
226 rb_bug("location_label: unreachable");
232 * Returns the label of this frame.
234 * Usually consists of method, class, module, etc names with decoration.
236 * Consider the following example:
239 * puts caller_locations(0).first.label
242 * puts caller_locations(0).first.label
245 * puts caller_locations(0).first.label
251 * The result of calling +foo+ is this:
254 * label: block in foo
255 * label: block (2 levels) in foo
259 location_label_m(VALUE self
)
261 return location_label(location_ptr(self
));
265 location_base_label(rb_backtrace_location_t
*loc
)
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
);
273 rb_bug("location_base_label: unreachable");
279 * Returns the base label of this frame.
281 * Usually same as #label, without decoration.
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
)
293 case LOCATION_TYPE_ISEQ
:
295 case LOCATION_TYPE_CFUNC
:
298 rb_bug("location_iseq: 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
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
322 location_node_id(rb_backtrace_location_t
*loc
)
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
);
333 rb_bug("location_node_id: unreachable");
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
);
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
);
359 location_realpath(rb_backtrace_location_t
*loc
)
362 case LOCATION_TYPE_ISEQ
:
363 return rb_iseq_realpath(loc
->iseq
);
364 case LOCATION_TYPE_CFUNC
:
366 return rb_iseq_realpath(loc
->iseq
);
370 rb_bug("location_realpath: 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.
382 location_absolute_path_m(VALUE self
)
384 return location_realpath(location_ptr(self
));
388 location_format(VALUE file
, int lineno
, VALUE name
)
390 VALUE s
= rb_enc_sprintf(rb_enc_compatible(file
, name
), "%s", RSTRING_PTR(file
));
392 rb_str_catf(s
, ":%d", lineno
);
394 rb_str_cat_cstr(s
, ":in ");
396 rb_str_cat_cstr(s
, "unknown method");
399 rb_str_catf(s
, "`%s'", RSTRING_PTR(name
));
405 location_to_str(rb_backtrace_location_t
*loc
)
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
);
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
);
423 file
= GET_VM()->progname
;
426 name
= rb_id2str(loc
->mid
);
429 rb_bug("location_to_str: unreachable");
432 return location_format(file
, lineno
, name
);
436 * Returns a Kernel#caller style string representing this frame.
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
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
;
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
);
475 backtrace_free(void *ptr
)
477 rb_backtrace_t
*bt
= (rb_backtrace_t
*)ptr
;
478 if (bt
->backtrace
) ruby_xfree(bt
->backtrace
);
483 location_update_entry(rb_backtrace_location_t
*fi
)
486 case LOCATION_TYPE_ISEQ
:
487 fi
->iseq
= (rb_iseq_t
*)rb_gc_location((VALUE
)fi
->iseq
);
489 case LOCATION_TYPE_CFUNC
:
491 fi
->iseq
= (rb_iseq_t
*)rb_gc_location((VALUE
)fi
->iseq
);
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
);
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
= {
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
);
532 backtrace_alloc(VALUE klass
)
535 VALUE obj
= TypedData_Make_Struct(klass
, rb_backtrace_t
, &backtrace_data_type
, bt
);
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
) {
550 RUBY_VM_NEXT_CONTROL_FRAME(
551 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp
)); /* skip top frames */
553 if (start_cfp
< last_cfp
) {
557 return start_cfp
- last_cfp
+ 1;
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;
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
;
578 static VALUE
location_create(rb_backtrace_location_t
*srcloc
, void *btobj
);
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
));
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
);
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
) {
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
614 * current frame <- ec->cfp
617 size
= end_cfp
- cfp
+ 1;
621 else if (num_frames
< 0 || 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;
633 for (; cfp
!= end_cfp
&& (bt
->backtrace_size
< num_frames
); cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
)) {
636 if (start_frame
> 0) {
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
);
646 bt_update_cfunc_loc(cfunc_counter
, loc
-1, iseq
, pc
);
648 bt_yield_loc(loc
- cfunc_counter
, cfunc_counter
+1, btobj
);
655 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp
));
656 if (start_frame
> 0) {
660 loc
= &bt
->backtrace
[bt
->backtrace_size
++];
661 loc
->type
= LOCATION_TYPE_CFUNC
;
664 loc
->mid
= rb_vm_frame_method_entry(cfp
)->def
->original_id
;
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
);
676 bt_yield_loc(loc
- cfunc_counter
, cfunc_counter
, btobj
);
683 if (start_too_large
) *start_too_large
= (start_frame
> 0 ? -1 : 0);
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
);
694 backtrace_collect(rb_backtrace_t
*bt
, VALUE (*func
)(rb_backtrace_location_t
*, void *arg
), void *arg
)
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
));
710 location_to_str_dmyarg(rb_backtrace_location_t
*loc
, void *dmy
)
712 return location_to_str(loc
);
716 backtrace_to_str_ary(VALUE self
)
720 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
721 r
= backtrace_collect(bt
, location_to_str_dmyarg
, 0);
727 rb_backtrace_to_str_ary(VALUE self
)
730 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
733 RB_OBJ_WRITE(self
, &bt
->strary
, backtrace_to_str_ary(self
));
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
755 location_create(rb_backtrace_location_t
*srcloc
, void *btobj
)
758 struct valued_frame_info
*vloc
;
759 obj
= TypedData_Make_Struct(rb_cBacktraceLocation
, struct valued_frame_info
, &location_data_type
, vloc
);
762 RB_OBJ_WRITE(obj
, &vloc
->btobj
, (VALUE
)btobj
);
768 backtrace_to_location_ary(VALUE self
)
772 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
773 r
= backtrace_collect(bt
, location_create
, (void *)self
);
779 rb_backtrace_to_location_ary(VALUE self
)
782 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
785 RB_OBJ_WRITE(self
, &bt
->locary
, backtrace_to_location_ary(self
));
791 backtrace_dump_data(VALUE self
)
793 VALUE str
= rb_backtrace_to_str_ary(self
);
798 backtrace_load_data(VALUE self
, VALUE str
)
801 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
802 RB_OBJ_WRITE(self
, &bt
->strary
, str
);
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'))"
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'
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'
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)
852 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
857 backtrace_limit(VALUE self
)
859 return LONG2NUM(rb_backtrace_length_limit
);
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
));
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 */
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
),
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
;
888 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
889 if (start_cfp
== NULL
) {
894 /* <- start_cfp (end control frame)
897 * top frame <- start_cfp
901 * current frame <- ec->cfp
905 RUBY_VM_NEXT_CONTROL_FRAME(
906 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp
)); /* skip top frames */
908 if (start_cfp
< last_cfp
) {
912 size
= start_cfp
- last_cfp
+ 1;
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); */
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
);
938 void (*func
)(void *data
, VALUE file
, int lineno
, VALUE name
);
939 void *data
; /* result */
943 oldbt_init(void *ptr
, size_t dmy
)
945 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
946 arg
->filename
= GET_VM()->progname
;
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
);
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
);
975 oldbt_print(void *data
, VALUE file
, int lineno
, VALUE name
)
977 FILE *fp
= (FILE *)data
;
980 fprintf(fp
, "\tfrom %s:%d:in unknown method\n",
981 RSTRING_PTR(file
), lineno
);
984 fprintf(fp
, "\tfrom %s:%d:in `%s'\n",
985 RSTRING_PTR(file
), lineno
, RSTRING_PTR(name
));
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(),
1004 oldbt_bugreport(void *arg
, VALUE file
, int line
, VALUE method
)
1006 const char *filename
= NIL_P(file
) ? "ruby" : RSTRING_PTR(file
);
1008 fprintf(stderr
, "-- Ruby level backtrace information "
1009 "----------------------------------------\n");
1012 if (NIL_P(method
)) {
1013 fprintf(stderr
, "%s:%d:in unknown method\n", filename
, line
);
1016 fprintf(stderr
, "%s:%d:in `%s'\n", filename
, line
, RSTRING_PTR(method
));
1021 rb_backtrace_print_as_bugreport(void)
1023 struct oldbt_arg arg
;
1026 arg
.func
= oldbt_bugreport
;
1027 arg
.data
= (int *)&i
;
1029 backtrace_each(GET_EC(),
1039 vm_backtrace_print(stderr
);
1042 struct print_to_arg
{
1043 VALUE (*iter
)(VALUE recv
, VALUE str
);
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
);
1054 rb_str_cat2(str
, "unknown method\n");
1057 rb_str_catf(str
, " `%"PRIsVALUE
"'\n", name
);
1059 (*arg
->iter
)(arg
->output
, str
);
1063 rb_backtrace_each(VALUE (*iter
)(VALUE recv
, VALUE str
), VALUE output
)
1065 struct oldbt_arg arg
;
1066 struct print_to_arg parg
;
1069 parg
.output
= output
;
1070 arg
.func
= oldbt_print_to
;
1072 backtrace_each(GET_EC(),
1080 rb_make_backtrace(void)
1082 return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START
, ALL_BACKTRACE_LINES
);
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
)
1094 rb_scan_args(argc
, argv
, "02", &level
, &vn
);
1096 if (argc
== 2 && NIL_P(vn
)) argc
--;
1100 lev
= lev_default
+ lev_plus
;
1101 n
= ALL_BACKTRACE_LINES
;
1105 long beg
, len
, bt_size
= backtrace_size(ec
);
1106 switch (rb_range_beg_len(level
, &beg
, &len
, bt_size
- lev_plus
, 0)) {
1108 lev
= NUM2LONG(level
);
1110 rb_raise(rb_eArgError
, "negative level (%ld)", lev
);
1113 n
= ALL_BACKTRACE_LINES
;
1118 lev
= beg
+ lev_plus
;
1125 lev
= NUM2LONG(level
);
1128 rb_raise(rb_eArgError
, "negative level (%ld)", lev
);
1131 rb_raise(rb_eArgError
, "negative size (%ld)", n
);
1136 lev
= n
= 0; /* to avoid warning */
1141 return rb_ary_new();
1144 btval
= rb_ec_partial_backtrace_object(ec
, lev
, n
, &too_large
, FALSE
, FALSE
);
1151 r
= backtrace_to_str_ary(btval
);
1154 r
= backtrace_to_location_ary(btval
);
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
)
1168 return ec_backtrace_to_ary(target_th
->ec
, argc
, argv
, 0, 0, to_str
);
1172 rb_vm_thread_backtrace(int argc
, const VALUE
*argv
, VALUE thval
)
1174 return thread_backtrace_to_ary(argc
, argv
, thval
, 1);
1178 rb_vm_thread_backtrace_locations(int argc
, const VALUE
*argv
, VALUE thval
)
1180 return thread_backtrace_to_ary(argc
, argv
, thval
, 0);
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);
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);
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
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.
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>'"]
1234 rb_f_caller(int argc
, VALUE
*argv
, VALUE _
)
1236 return ec_backtrace_to_ary(GET_EC(), argc
, argv
, 1, 1, 1);
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.
1262 rb_f_caller_locations(int argc
, VALUE
*argv
, VALUE _
)
1264 return ec_backtrace_to_ary(GET_EC(), argc
, argv
, 1, 1, 0);
1269 * Thread.each_caller_location{ |loc| ... } -> nil
1271 * Yields each frame of the current execution stack as a
1272 * backtrace location object.
1275 each_caller_location(VALUE unused
)
1277 rb_ec_partial_backtrace_object(GET_EC(), 2, ALL_BACKTRACE_LINES
, NULL
, FALSE
, TRUE
);
1281 /* called from Init_vm() in vm.c */
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.
1302 * # caller_locations.rb
1304 * caller_locations(skip)
1313 * c(0..2).map do |call|
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:
1327 * attr_accessor :locations
1328 * def initialize(skip)
1329 * @locations = caller_locations(skip)
1333 * Foo.new(0..2).locations.map do |call|
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);
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
;
1370 VALUE contexts
; /* [[klass, binding, iseq, cfp], ...] */
1371 long backtrace_size
;
1375 CALLER_BINDING_SELF
,
1376 CALLER_BINDING_CLASS
,
1377 CALLER_BINDING_BINDING
,
1378 CALLER_BINDING_ISEQ
,
1380 CALLER_BINDING_DEPTH
,
1383 struct collect_caller_bindings_data
{
1385 const rb_execution_context_t
*ec
;
1389 collect_caller_bindings_init(void *arg
, size_t size
)
1395 get_klass(const rb_control_frame_t
*cfp
)
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
;
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
);
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
);
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
);
1451 collect_caller_bindings(const rb_execution_context_t
*ec
)
1455 struct collect_caller_bindings_data data
= {
1460 collect_caller_bindings_init
,
1461 collect_caller_bindings_iseq
,
1462 collect_caller_bindings_cfunc
,
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
));
1482 * Note that the passed `rb_debug_inspector_t' will be disabled
1483 * after `rb_debug_inspector_open'.
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
);
1504 if ((state
= EC_EXEC_TAG()) == TAG_NONE
) {
1505 result
= (*func
)(&dbg_context
, data
);
1509 /* invalidate bindings? */
1512 EC_JUMP_TAG(ec
, state
);
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
);
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
);
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
);
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
);
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
;
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
);
1565 rb_debug_inspector_current_depth(void)
1567 rb_execution_context_t
*ec
= GET_EC();
1568 return INT2FIX(frame_depth(ec
, ec
->cfp
));
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
)
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
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) {
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
;
1610 buff
[i
] = (VALUE
)cfp
->iseq
;
1613 if (lines
) lines
[i
] = calc_lineno(cfp
->iseq
, cfp
->pc
);
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;
1625 cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
);
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
)) {
1639 return (const rb_iseq_t
*)frame
;
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
;
1654 rb_bug("frame2iseq: unreachable");
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
*
1667 if (NIL_P(frame
)) return NULL
;
1669 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1670 switch (imemo_type(frame
)) {
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
:
1690 rb_profile_frame_absolute_path(VALUE frame
)
1692 if (cframe(frame
)) {
1693 static VALUE cfunc_str
= Qfalse
;
1695 cfunc_str
= rb_str_new_literal("<cfunc>");
1696 rb_gc_register_mark_object(cfunc_str
);
1700 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1701 return iseq
? rb_iseq_realpath(iseq
) : Qnil
;
1705 rb_profile_frame_label(VALUE frame
)
1707 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1708 return iseq
? rb_iseq_label(iseq
) : Qnil
;
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
;
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
;
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
;
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
);
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
));
1770 rb_profile_frame_method_name(VALUE frame
)
1772 const rb_callable_method_entry_t
*cme
= cframe(frame
);
1774 ID mid
= cme
->def
->original_id
;
1777 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1778 return iseq
? rb_iseq_method_name(iseq
) : Qnil
;
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
);
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
);
1810 rb_profile_frame_full_label(VALUE frame
)
1812 const rb_callable_method_entry_t
*cme
= cframe(frame
);
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
) {
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
);