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)
35 calc_pos(const rb_iseq_t
*iseq
, const VALUE
*pc
, int *lineno
, int *node_id
)
40 if (ISEQ_BODY(iseq
)->type
== ISEQ_TYPE_TOP
) {
41 VM_ASSERT(! ISEQ_BODY(iseq
)->local_table
);
42 VM_ASSERT(! ISEQ_BODY(iseq
)->local_table_size
);
45 if (lineno
) *lineno
= ISEQ_BODY(iseq
)->location
.first_lineno
;
46 #ifdef USE_ISEQ_NODE_ID
47 if (node_id
) *node_id
= -1;
52 VM_ASSERT(ISEQ_BODY(iseq
));
53 VM_ASSERT(ISEQ_BODY(iseq
)->iseq_encoded
);
54 VM_ASSERT(ISEQ_BODY(iseq
)->iseq_size
);
56 ptrdiff_t n
= pc
- ISEQ_BODY(iseq
)->iseq_encoded
;
58 #if SIZEOF_PTRDIFF_T > SIZEOF_INT
59 VM_ASSERT(n
<= (ptrdiff_t)UINT_MAX
);
61 VM_ASSERT((unsigned int)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. */
71 rb_print_backtrace(stderr
);
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
{
120 const rb_callable_method_entry_t
*cme
;
121 const rb_iseq_t
*iseq
;
123 } rb_backtrace_location_t
;
125 struct valued_frame_info
{
126 rb_backtrace_location_t
*loc
;
131 location_mark(void *ptr
)
133 struct valued_frame_info
*vfi
= (struct valued_frame_info
*)ptr
;
134 rb_gc_mark_movable(vfi
->btobj
);
138 location_ref_update(void *ptr
)
140 struct valued_frame_info
*vfi
= ptr
;
141 vfi
->btobj
= rb_gc_location(vfi
->btobj
);
145 location_mark_entry(rb_backtrace_location_t
*fi
)
147 rb_gc_mark((VALUE
)fi
->cme
);
148 if (fi
->iseq
) rb_gc_mark_movable((VALUE
)fi
->iseq
);
151 static const rb_data_type_t location_data_type
= {
155 RUBY_TYPED_DEFAULT_FREE
,
156 NULL
, // No external memory to report,
159 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
| RUBY_TYPED_WB_PROTECTED
| RUBY_TYPED_EMBEDDABLE
163 rb_frame_info_p(VALUE obj
)
165 return rb_typeddata_is_kind_of(obj
, &location_data_type
);
168 static inline rb_backtrace_location_t
*
169 location_ptr(VALUE locobj
)
171 struct valued_frame_info
*vloc
;
172 TypedData_Get_Struct(locobj
, struct valued_frame_info
, &location_data_type
, vloc
);
177 location_lineno(rb_backtrace_location_t
*loc
)
180 return calc_lineno(loc
->iseq
, loc
->pc
);
186 * Returns the line number of this frame.
188 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
190 * loc = c(0..1).first
194 location_lineno_m(VALUE self
)
196 return INT2FIX(location_lineno(location_ptr(self
)));
199 VALUE
rb_mod_name0(VALUE klass
, bool *permanent
);
202 rb_gen_method_name(VALUE owner
, VALUE name
)
205 if (RB_TYPE_P(owner
, T_CLASS
) || RB_TYPE_P(owner
, T_MODULE
)) {
206 if (RCLASS_SINGLETON_P(owner
)) {
207 VALUE v
= RCLASS_ATTACHED_OBJECT(owner
);
208 if (RB_TYPE_P(v
, T_CLASS
) || RB_TYPE_P(v
, T_MODULE
)) {
209 v
= rb_mod_name0(v
, &permanent
);
210 if (permanent
&& !NIL_P(v
)) {
211 return rb_sprintf("%"PRIsVALUE
".%"PRIsVALUE
, v
, name
);
216 owner
= rb_mod_name0(owner
, &permanent
);
217 if (permanent
&& !NIL_P(owner
)) {
218 return rb_sprintf("%"PRIsVALUE
"#%"PRIsVALUE
, owner
, name
);
226 calculate_iseq_label(VALUE owner
, const rb_iseq_t
*iseq
)
229 switch (ISEQ_BODY(iseq
)->type
) {
231 case ISEQ_TYPE_CLASS
:
233 return ISEQ_BODY(iseq
)->location
.label
;
234 case ISEQ_TYPE_METHOD
:
235 return rb_gen_method_name(owner
, ISEQ_BODY(iseq
)->location
.label
);
236 case ISEQ_TYPE_BLOCK
:
237 case ISEQ_TYPE_PLAIN
: {
239 const rb_iseq_t
*orig_iseq
= iseq
;
240 if (ISEQ_BODY(orig_iseq
)->parent_iseq
!= 0) {
241 while (ISEQ_BODY(orig_iseq
)->local_iseq
!= iseq
) {
242 if (ISEQ_BODY(iseq
)->type
== ISEQ_TYPE_BLOCK
) {
245 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
249 return rb_sprintf("block in %"PRIsVALUE
, calculate_iseq_label(owner
, iseq
));
252 return rb_sprintf("block (%d levels) in %"PRIsVALUE
, level
, calculate_iseq_label(owner
, iseq
));
255 case ISEQ_TYPE_RESCUE
:
256 case ISEQ_TYPE_ENSURE
:
258 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
261 rb_bug("calculate_iseq_label: unreachable");
265 // Return true if a given location is a C method or supposed to behave like one.
267 location_cfunc_p(rb_backtrace_location_t
*loc
)
269 if (!loc
->cme
) return false;
271 switch (loc
->cme
->def
->type
) {
272 case VM_METHOD_TYPE_CFUNC
:
274 case VM_METHOD_TYPE_ISEQ
:
275 return rb_iseq_attr_p(loc
->cme
->def
->body
.iseq
.iseqptr
, BUILTIN_ATTR_C_TRACE
);
282 location_label(rb_backtrace_location_t
*loc
)
284 if (location_cfunc_p(loc
)) {
285 return rb_gen_method_name(loc
->cme
->owner
, rb_id2str(loc
->cme
->def
->original_id
));
290 owner
= loc
->cme
->owner
;
292 return calculate_iseq_label(owner
, loc
->iseq
);
296 * Returns the label of this frame.
298 * Usually consists of method, class, module, etc names with decoration.
300 * Consider the following example:
303 * puts caller_locations(0).first.label
306 * puts caller_locations(0).first.label
309 * puts caller_locations(0).first.label
314 * The result of calling +foo+ is this:
318 * block (2 levels) in foo
322 location_label_m(VALUE self
)
324 return location_label(location_ptr(self
));
328 location_base_label(rb_backtrace_location_t
*loc
)
330 if (location_cfunc_p(loc
)) {
331 return rb_id2str(loc
->cme
->def
->original_id
);
334 return ISEQ_BODY(loc
->iseq
)->location
.base_label
;
338 * Returns the base label of this frame, which is usually equal to the label,
339 * without decoration.
341 * Consider the following example:
344 * puts caller_locations(0).first.base_label
347 * puts caller_locations(0).first.base_label
350 * puts caller_locations(0).first.base_label
355 * The result of calling +foo+ is this:
362 location_base_label_m(VALUE self
)
364 return location_base_label(location_ptr(self
));
367 static const rb_iseq_t
*
368 location_iseq(rb_backtrace_location_t
*loc
)
374 * Returns the file name of this frame. This will generally be an absolute
375 * path, unless the frame is in the main script, in which case it will be the
376 * script location passed on the command line.
378 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
380 * loc = c(0..1).first
381 * loc.path #=> caller_locations.rb
384 location_path_m(VALUE self
)
386 const rb_iseq_t
*iseq
= location_iseq(location_ptr(self
));
387 return iseq
? rb_iseq_path(iseq
) : Qnil
;
390 #ifdef USE_ISEQ_NODE_ID
392 location_node_id(rb_backtrace_location_t
*loc
)
394 if (loc
->iseq
&& loc
->pc
) {
395 return calc_node_id(loc
->iseq
, loc
->pc
);
402 rb_get_node_id_from_frame_info(VALUE obj
)
404 #ifdef USE_ISEQ_NODE_ID
405 rb_backtrace_location_t
*loc
= location_ptr(obj
);
406 return location_node_id(loc
);
413 rb_get_iseq_from_frame_info(VALUE obj
)
415 rb_backtrace_location_t
*loc
= location_ptr(obj
);
416 const rb_iseq_t
*iseq
= location_iseq(loc
);
421 location_realpath(rb_backtrace_location_t
*loc
)
424 return rb_iseq_realpath(loc
->iseq
);
430 * Returns the full file path of this frame.
432 * Same as #path, except that it will return absolute path
433 * even if the frame is in the main script.
436 location_absolute_path_m(VALUE self
)
438 return location_realpath(location_ptr(self
));
442 location_format(VALUE file
, int lineno
, VALUE name
)
444 VALUE s
= rb_enc_sprintf(rb_enc_compatible(file
, name
), "%s", RSTRING_PTR(file
));
446 rb_str_catf(s
, ":%d", lineno
);
448 rb_str_cat_cstr(s
, ":in ");
450 rb_str_cat_cstr(s
, "unknown method");
453 rb_str_catf(s
, "'%s'", RSTRING_PTR(name
));
459 location_to_str(rb_backtrace_location_t
*loc
)
461 VALUE file
, owner
= Qnil
, name
;
464 if (location_cfunc_p(loc
)) {
465 if (loc
->iseq
&& loc
->pc
) {
466 file
= rb_iseq_path(loc
->iseq
);
467 lineno
= calc_lineno(loc
->iseq
, loc
->pc
);
470 file
= GET_VM()->progname
;
473 name
= rb_gen_method_name(loc
->cme
->owner
, rb_id2str(loc
->cme
->def
->original_id
));
476 file
= rb_iseq_path(loc
->iseq
);
477 lineno
= calc_lineno(loc
->iseq
, loc
->pc
);
479 owner
= loc
->cme
->owner
;
481 name
= calculate_iseq_label(owner
, loc
->iseq
);
484 return location_format(file
, lineno
, name
);
488 * Returns a Kernel#caller style string representing this frame.
491 location_to_str_m(VALUE self
)
493 return location_to_str(location_ptr(self
));
497 * Returns the same as calling +inspect+ on the string representation of
501 location_inspect_m(VALUE self
)
503 return rb_str_inspect(location_to_str(location_ptr(self
)));
506 typedef struct rb_backtrace_struct
{
510 rb_backtrace_location_t backtrace
[1];
514 backtrace_mark(void *ptr
)
516 rb_backtrace_t
*bt
= (rb_backtrace_t
*)ptr
;
517 size_t i
, s
= bt
->backtrace_size
;
519 for (i
=0; i
<s
; i
++) {
520 location_mark_entry(&bt
->backtrace
[i
]);
522 rb_gc_mark_movable(bt
->strary
);
523 rb_gc_mark_movable(bt
->locary
);
527 location_update_entry(rb_backtrace_location_t
*fi
)
529 fi
->cme
= (rb_callable_method_entry_t
*)rb_gc_location((VALUE
)fi
->cme
);
531 fi
->iseq
= (rb_iseq_t
*)rb_gc_location((VALUE
)fi
->iseq
);
536 backtrace_update(void *ptr
)
538 rb_backtrace_t
*bt
= (rb_backtrace_t
*)ptr
;
539 size_t i
, s
= bt
->backtrace_size
;
541 for (i
=0; i
<s
; i
++) {
542 location_update_entry(&bt
->backtrace
[i
]);
544 bt
->strary
= rb_gc_location(bt
->strary
);
545 bt
->locary
= rb_gc_location(bt
->locary
);
548 static const rb_data_type_t backtrace_data_type
= {
553 NULL
, // No external memory to report,
556 /* Cannot set the RUBY_TYPED_EMBEDDABLE flag because the loc of frame_info
557 * points elements in the backtrace array. This can cause the loc to become
558 * incorrect if this backtrace object is moved by compaction. */
559 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
| RUBY_TYPED_WB_PROTECTED
563 rb_backtrace_p(VALUE obj
)
565 return rb_typeddata_is_kind_of(obj
, &backtrace_data_type
);
569 backtrace_alloc(VALUE klass
)
572 VALUE obj
= TypedData_Make_Struct(klass
, rb_backtrace_t
, &backtrace_data_type
, bt
);
577 backtrace_alloc_capa(long num_frames
, rb_backtrace_t
**backtrace
)
579 size_t memsize
= offsetof(rb_backtrace_t
, backtrace
) + num_frames
* sizeof(rb_backtrace_location_t
);
580 VALUE btobj
= rb_data_typed_object_zalloc(rb_cBacktrace
, memsize
, &backtrace_data_type
);
581 TypedData_Get_Struct(btobj
, rb_backtrace_t
, &backtrace_data_type
, *backtrace
);
587 backtrace_size(const rb_execution_context_t
*ec
)
589 const rb_control_frame_t
*last_cfp
= ec
->cfp
;
590 const rb_control_frame_t
*start_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
592 if (start_cfp
== NULL
) {
597 RUBY_VM_NEXT_CONTROL_FRAME(
598 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp
)); /* skip top frames */
600 if (start_cfp
< last_cfp
) {
604 return start_cfp
- last_cfp
+ 1;
608 is_internal_location(const rb_control_frame_t
*cfp
)
610 static const char prefix
[] = "<internal:";
611 const size_t prefix_len
= sizeof(prefix
) - 1;
612 VALUE file
= rb_iseq_path(cfp
->iseq
);
613 return strncmp(prefix
, RSTRING_PTR(file
), prefix_len
) == 0;
617 is_rescue_or_ensure_frame(const rb_control_frame_t
*cfp
)
619 enum rb_iseq_type type
= ISEQ_BODY(cfp
->iseq
)->type
;
620 return type
== ISEQ_TYPE_RESCUE
|| type
== ISEQ_TYPE_ENSURE
;
624 bt_update_cfunc_loc(unsigned long cfunc_counter
, rb_backtrace_location_t
*cfunc_loc
, const rb_iseq_t
*iseq
, const VALUE
*pc
)
626 for (; cfunc_counter
> 0; cfunc_counter
--, cfunc_loc
--) {
627 cfunc_loc
->iseq
= iseq
;
632 static VALUE
location_create(rb_backtrace_location_t
*srcloc
, void *btobj
);
635 bt_yield_loc(rb_backtrace_location_t
*loc
, long num_frames
, VALUE btobj
)
637 for (; num_frames
> 0; num_frames
--, loc
++) {
638 rb_yield(location_create(loc
, (void *)btobj
));
643 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
)
645 const rb_control_frame_t
*cfp
= ec
->cfp
;
646 const rb_control_frame_t
*end_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
648 rb_backtrace_t
*bt
= NULL
;
650 rb_backtrace_location_t
*loc
= NULL
;
651 unsigned long cfunc_counter
= 0;
652 bool skip_next_frame
= FALSE
;
654 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
655 if (end_cfp
== NULL
) {
659 end_cfp
= RUBY_VM_NEXT_CONTROL_FRAME(end_cfp
);
662 * top frame (dummy) <- RUBY_VM_END_CONTROL_FRAME
663 * top frame (dummy) <- end_cfp
664 * top frame <- main script
668 * current frame <- ec->cfp
671 size
= end_cfp
- cfp
+ 1;
675 else if (num_frames
< 0 || num_frames
> size
) {
680 btobj
= backtrace_alloc_capa(num_frames
, &bt
);
682 bt
->backtrace_size
= 0;
683 if (num_frames
== 0) {
684 if (start_too_large
) *start_too_large
= 0;
688 for (; cfp
!= end_cfp
&& (bt
->backtrace_size
< num_frames
); cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
)) {
691 if (start_frame
> 0) {
694 else if (!(skip_internal
&& is_internal_location(cfp
))) {
695 if (!skip_next_frame
) {
696 const rb_iseq_t
*iseq
= cfp
->iseq
;
697 const VALUE
*pc
= cfp
->pc
;
698 loc
= &bt
->backtrace
[bt
->backtrace_size
++];
699 RB_OBJ_WRITE(btobj
, &loc
->cme
, rb_vm_frame_method_entry(cfp
));
700 // Ruby methods with `Primitive.attr! :c_trace` should behave like C methods
701 if (rb_iseq_attr_p(cfp
->iseq
, BUILTIN_ATTR_C_TRACE
)) {
707 RB_OBJ_WRITE(btobj
, &loc
->iseq
, iseq
);
709 bt_update_cfunc_loc(cfunc_counter
, loc
-1, iseq
, pc
);
711 bt_yield_loc(loc
- cfunc_counter
, cfunc_counter
+1, btobj
);
716 skip_next_frame
= is_rescue_or_ensure_frame(cfp
);
721 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp
));
722 if (start_frame
> 0) {
726 loc
= &bt
->backtrace
[bt
->backtrace_size
++];
727 RB_OBJ_WRITE(btobj
, &loc
->cme
, rb_vm_frame_method_entry(cfp
));
735 // When a backtrace entry corresponds to a method defined in C (e.g. rb_define_method), the reported file:line
736 // is the one of the caller Ruby frame, so if the last entry is a C frame we find the caller Ruby frame here.
737 if (cfunc_counter
> 0) {
738 for (; cfp
!= end_cfp
; cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
)) {
739 if (cfp
->iseq
&& cfp
->pc
&& !(skip_internal
&& is_internal_location(cfp
))) {
740 VM_ASSERT(!skip_next_frame
); // ISEQ_TYPE_RESCUE/ISEQ_TYPE_ENSURE should have a caller Ruby ISEQ, not a cfunc
741 bt_update_cfunc_loc(cfunc_counter
, loc
, cfp
->iseq
, cfp
->pc
);
742 RB_OBJ_WRITTEN(btobj
, Qundef
, cfp
->iseq
);
744 bt_yield_loc(loc
- cfunc_counter
, cfunc_counter
, btobj
);
751 if (start_too_large
) *start_too_large
= (start_frame
> 0 ? -1 : 0);
756 rb_ec_backtrace_object(const rb_execution_context_t
*ec
)
758 return rb_ec_partial_backtrace_object(ec
, RUBY_BACKTRACE_START
, RUBY_ALL_BACKTRACE_LINES
, NULL
, FALSE
, FALSE
);
762 backtrace_collect(rb_backtrace_t
*bt
, VALUE (*func
)(rb_backtrace_location_t
*, void *arg
), void *arg
)
767 btary
= rb_ary_new2(bt
->backtrace_size
);
769 for (i
=0; i
<bt
->backtrace_size
; i
++) {
770 rb_backtrace_location_t
*loc
= &bt
->backtrace
[i
];
771 rb_ary_push(btary
, func(loc
, arg
));
778 location_to_str_dmyarg(rb_backtrace_location_t
*loc
, void *dmy
)
780 return location_to_str(loc
);
784 backtrace_to_str_ary(VALUE self
)
788 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
789 r
= backtrace_collect(bt
, location_to_str_dmyarg
, 0);
795 rb_backtrace_to_str_ary(VALUE self
)
798 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
801 RB_OBJ_WRITE(self
, &bt
->strary
, backtrace_to_str_ary(self
));
807 rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self
)
810 rb_backtrace_location_t
*loc
;
812 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
813 VM_ASSERT(bt
->backtrace_size
> 0);
815 loc
= &bt
->backtrace
[0];
817 VM_ASSERT(!loc
->cme
|| loc
->cme
->def
->type
== VM_METHOD_TYPE_ISEQ
);
819 loc
->pc
= NULL
; // means location.first_lineno
823 location_create(rb_backtrace_location_t
*srcloc
, void *btobj
)
826 struct valued_frame_info
*vloc
;
827 obj
= TypedData_Make_Struct(rb_cBacktraceLocation
, struct valued_frame_info
, &location_data_type
, vloc
);
830 RB_OBJ_WRITE(obj
, &vloc
->btobj
, (VALUE
)btobj
);
836 backtrace_to_location_ary(VALUE self
)
840 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
841 r
= backtrace_collect(bt
, location_create
, (void *)self
);
847 rb_backtrace_to_location_ary(VALUE self
)
850 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
853 RB_OBJ_WRITE(self
, &bt
->locary
, backtrace_to_location_ary(self
));
859 rb_location_ary_to_backtrace(VALUE ary
)
861 if (!RB_TYPE_P(ary
, T_ARRAY
) || !rb_frame_info_p(RARRAY_AREF(ary
, 0))) {
865 rb_backtrace_t
*new_backtrace
;
866 long num_frames
= RARRAY_LEN(ary
);
867 VALUE btobj
= backtrace_alloc_capa(num_frames
, &new_backtrace
);
869 for (long index
= 0; index
< RARRAY_LEN(ary
); index
++) {
870 VALUE locobj
= RARRAY_AREF(ary
, index
);
872 if (!rb_frame_info_p(locobj
)) {
876 struct valued_frame_info
*src_vloc
;
877 TypedData_Get_Struct(locobj
, struct valued_frame_info
, &location_data_type
, src_vloc
);
879 rb_backtrace_location_t
*dst_location
= &new_backtrace
->backtrace
[index
];
880 RB_OBJ_WRITE(btobj
, &dst_location
->cme
, src_vloc
->loc
->cme
);
881 RB_OBJ_WRITE(btobj
, &dst_location
->iseq
, src_vloc
->loc
->iseq
);
882 dst_location
->pc
= src_vloc
->loc
->pc
;
884 new_backtrace
->backtrace_size
++;
893 backtrace_dump_data(VALUE self
)
895 VALUE str
= rb_backtrace_to_str_ary(self
);
900 backtrace_load_data(VALUE self
, VALUE str
)
903 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
904 RB_OBJ_WRITE(self
, &bt
->strary
, str
);
909 * call-seq: Thread::Backtrace::limit -> integer
911 * Returns maximum backtrace length set by <tt>--backtrace-limit</tt>
912 * command-line option. The default is <tt>-1</tt> which means unlimited
913 * backtraces. If the value is zero or positive, the error backtraces,
914 * produced by Exception#full_message, are abbreviated and the extra lines
915 * are replaced by <tt>... 3 levels... </tt>
917 * $ ruby -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
919 * .../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)
920 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
921 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
922 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
923 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
924 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
925 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
926 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
927 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
928 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
929 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
930 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
931 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
932 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
933 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
934 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
935 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
936 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
937 * from -e:1:in `<main>'
939 * $ ruby --backtrace-limit 2 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
941 * .../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)
942 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
943 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
945 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
946 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
947 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
950 * $ ruby --backtrace-limit 0 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
952 * .../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)
954 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
959 backtrace_limit(VALUE self
)
961 return LONG2NUM(rb_backtrace_length_limit
);
965 rb_ec_backtrace_str_ary(const rb_execution_context_t
*ec
, long lev
, long n
)
967 return rb_backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec
, lev
, n
, NULL
, FALSE
, FALSE
));
971 rb_ec_backtrace_location_ary(const rb_execution_context_t
*ec
, long lev
, long n
, bool skip_internal
)
973 return rb_backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec
, lev
, n
, NULL
, skip_internal
, FALSE
));
976 /* make old style backtrace directly */
979 backtrace_each(const rb_execution_context_t
*ec
,
980 void (*init
)(void *arg
, size_t size
),
981 void (*iter_iseq
)(void *arg
, const rb_control_frame_t
*cfp
),
982 void (*iter_cfunc
)(void *arg
, const rb_control_frame_t
*cfp
, ID mid
),
985 const rb_control_frame_t
*last_cfp
= ec
->cfp
;
986 const rb_control_frame_t
*start_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
987 const rb_control_frame_t
*cfp
;
990 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
991 if (start_cfp
== NULL
) {
996 /* <- start_cfp (end control frame)
999 * top frame <- start_cfp
1002 * 2nd frame <- lev:0
1003 * current frame <- ec->cfp
1007 RUBY_VM_NEXT_CONTROL_FRAME(
1008 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp
)); /* skip top frames */
1010 if (start_cfp
< last_cfp
) {
1014 size
= start_cfp
- last_cfp
+ 1;
1020 for (i
=0, cfp
= start_cfp
; i
<size
; i
++, cfp
= RUBY_VM_NEXT_CONTROL_FRAME(cfp
)) {
1021 /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
1024 iter_iseq(arg
, cfp
);
1028 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp
));
1029 const rb_callable_method_entry_t
*me
= rb_vm_frame_method_entry(cfp
);
1030 ID mid
= me
->def
->original_id
;
1032 iter_cfunc(arg
, cfp
, mid
);
1040 void (*func
)(void *data
, VALUE file
, int lineno
, VALUE name
);
1041 void *data
; /* result */
1045 oldbt_init(void *ptr
, size_t dmy
)
1047 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
1048 arg
->filename
= GET_VM()->progname
;
1053 oldbt_iter_iseq(void *ptr
, const rb_control_frame_t
*cfp
)
1055 const rb_iseq_t
*iseq
= cfp
->iseq
;
1056 const VALUE
*pc
= cfp
->pc
;
1057 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
1058 VALUE file
= arg
->filename
= rb_iseq_path(iseq
);
1059 VALUE name
= ISEQ_BODY(iseq
)->location
.label
;
1060 int lineno
= arg
->lineno
= calc_lineno(iseq
, pc
);
1062 (arg
->func
)(arg
->data
, file
, lineno
, name
);
1066 oldbt_iter_cfunc(void *ptr
, const rb_control_frame_t
*cfp
, ID mid
)
1068 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
1069 VALUE file
= arg
->filename
;
1070 VALUE name
= rb_id2str(mid
);
1071 int lineno
= arg
->lineno
;
1073 (arg
->func
)(arg
->data
, file
, lineno
, name
);
1077 oldbt_print(void *data
, VALUE file
, int lineno
, VALUE name
)
1079 FILE *fp
= (FILE *)data
;
1082 fprintf(fp
, "\tfrom %s:%d:in unknown method\n",
1083 RSTRING_PTR(file
), lineno
);
1086 fprintf(fp
, "\tfrom %s:%d:in '%s'\n",
1087 RSTRING_PTR(file
), lineno
, RSTRING_PTR(name
));
1092 vm_backtrace_print(FILE *fp
)
1094 struct oldbt_arg arg
;
1096 arg
.func
= oldbt_print
;
1097 arg
.data
= (void *)fp
;
1098 backtrace_each(GET_EC(),
1105 struct oldbt_bugreport_arg
{
1111 oldbt_bugreport(void *arg
, VALUE file
, int line
, VALUE method
)
1113 struct oldbt_bugreport_arg
*p
= arg
;
1115 const char *filename
= NIL_P(file
) ? "ruby" : RSTRING_PTR(file
);
1117 fprintf(fp
, "-- Ruby level backtrace information "
1118 "----------------------------------------\n");
1121 if (NIL_P(method
)) {
1122 fprintf(fp
, "%s:%d:in unknown method\n", filename
, line
);
1125 fprintf(fp
, "%s:%d:in '%s'\n", filename
, line
, RSTRING_PTR(method
));
1130 rb_backtrace_print_as_bugreport(FILE *fp
)
1132 struct oldbt_arg arg
;
1133 struct oldbt_bugreport_arg barg
= {fp
, 0};
1135 arg
.func
= oldbt_bugreport
;
1138 backtrace_each(GET_EC(),
1148 vm_backtrace_print(stderr
);
1151 struct print_to_arg
{
1152 VALUE (*iter
)(VALUE recv
, VALUE str
);
1157 oldbt_print_to(void *data
, VALUE file
, int lineno
, VALUE name
)
1159 const struct print_to_arg
*arg
= data
;
1160 VALUE str
= rb_sprintf("\tfrom %"PRIsVALUE
":%d:in ", file
, lineno
);
1163 rb_str_cat2(str
, "unknown method\n");
1166 rb_str_catf(str
, " '%"PRIsVALUE
"'\n", name
);
1168 (*arg
->iter
)(arg
->output
, str
);
1172 rb_backtrace_each(VALUE (*iter
)(VALUE recv
, VALUE str
), VALUE output
)
1174 struct oldbt_arg arg
;
1175 struct print_to_arg parg
;
1178 parg
.output
= output
;
1179 arg
.func
= oldbt_print_to
;
1181 backtrace_each(GET_EC(),
1189 rb_make_backtrace(void)
1191 return rb_ec_backtrace_str_ary(GET_EC(), RUBY_BACKTRACE_START
, RUBY_ALL_BACKTRACE_LINES
);
1195 ec_backtrace_range(const rb_execution_context_t
*ec
, int argc
, const VALUE
*argv
, int lev_default
, int lev_plus
, long *len_ptr
)
1197 VALUE level
, vn
, opts
;
1200 rb_scan_args(argc
, argv
, "02:", &level
, &vn
, &opts
);
1203 rb_get_kwargs(opts
, (ID
[]){0}, 0, 0, NULL
);
1205 if (argc
== 2 && NIL_P(vn
)) argc
--;
1209 lev
= lev_default
+ lev_plus
;
1210 n
= RUBY_ALL_BACKTRACE_LINES
;
1214 long beg
, len
, bt_size
= backtrace_size(ec
);
1215 switch (rb_range_beg_len(level
, &beg
, &len
, bt_size
- lev_plus
, 0)) {
1217 lev
= NUM2LONG(level
);
1219 rb_raise(rb_eArgError
, "negative level (%ld)", lev
);
1222 n
= RUBY_ALL_BACKTRACE_LINES
;
1227 lev
= beg
+ lev_plus
;
1234 lev
= NUM2LONG(level
);
1237 rb_raise(rb_eArgError
, "negative level (%ld)", lev
);
1240 rb_raise(rb_eArgError
, "negative size (%ld)", n
);
1245 lev
= n
= 0; /* to avoid warning */
1254 ec_backtrace_to_ary(const rb_execution_context_t
*ec
, int argc
, const VALUE
*argv
, int lev_default
, int lev_plus
, int to_str
)
1260 lev
= ec_backtrace_range(ec
, argc
, argv
, lev_default
, lev_plus
, &n
);
1261 if (lev
< 0) return Qnil
;
1264 return rb_ary_new();
1267 btval
= rb_ec_partial_backtrace_object(ec
, lev
, n
, &too_large
, FALSE
, FALSE
);
1274 r
= backtrace_to_str_ary(btval
);
1277 r
= backtrace_to_location_ary(btval
);
1284 thread_backtrace_to_ary(int argc
, const VALUE
*argv
, VALUE thval
, int to_str
)
1286 rb_thread_t
*target_th
= rb_thread_ptr(thval
);
1288 if (target_th
->to_kill
|| target_th
->status
== THREAD_KILLED
)
1291 return ec_backtrace_to_ary(target_th
->ec
, argc
, argv
, 0, 0, to_str
);
1295 rb_vm_thread_backtrace(int argc
, const VALUE
*argv
, VALUE thval
)
1297 return thread_backtrace_to_ary(argc
, argv
, thval
, 1);
1301 rb_vm_thread_backtrace_locations(int argc
, const VALUE
*argv
, VALUE thval
)
1303 return thread_backtrace_to_ary(argc
, argv
, thval
, 0);
1307 rb_vm_backtrace(int argc
, const VALUE
* argv
, struct rb_execution_context_struct
* ec
)
1309 return ec_backtrace_to_ary(ec
, argc
, argv
, 0, 0, 1);
1313 rb_vm_backtrace_locations(int argc
, const VALUE
* argv
, struct rb_execution_context_struct
* ec
)
1315 return ec_backtrace_to_ary(ec
, argc
, argv
, 0, 0, 0);
1320 * caller(start=1, length=nil) -> array or nil
1321 * caller(range) -> array or nil
1323 * Returns the current execution stack---an array containing strings in
1324 * the form <code>file:line</code> or <code>file:line: in
1327 * The optional _start_ parameter determines the number of initial stack
1328 * entries to omit from the top of the stack.
1330 * A second optional +length+ parameter can be used to limit how many entries
1331 * are returned from the stack.
1333 * Returns +nil+ if _start_ is greater than the size of
1334 * current execution stack.
1336 * Optionally you can pass a range, which will return an array containing the
1337 * entries within the specified range.
1348 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1349 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1350 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1351 * c(3) #=> ["prog:13:in `<main>'"]
1357 rb_f_caller(int argc
, VALUE
*argv
, VALUE _
)
1359 return ec_backtrace_to_ary(GET_EC(), argc
, argv
, 1, 1, 1);
1364 * caller_locations(start=1, length=nil) -> array or nil
1365 * caller_locations(range) -> array or nil
1367 * Returns the current execution stack---an array containing
1368 * backtrace location objects.
1370 * See Thread::Backtrace::Location for more information.
1372 * The optional _start_ parameter determines the number of initial stack
1373 * entries to omit from the top of the stack.
1375 * A second optional +length+ parameter can be used to limit how many entries
1376 * are returned from the stack.
1378 * Returns +nil+ if _start_ is greater than the size of
1379 * current execution stack.
1381 * Optionally you can pass a range, which will return an array containing the
1382 * entries within the specified range.
1385 rb_f_caller_locations(int argc
, VALUE
*argv
, VALUE _
)
1387 return ec_backtrace_to_ary(GET_EC(), argc
, argv
, 1, 1, 0);
1392 * Thread.each_caller_location(...) { |loc| ... } -> nil
1394 * Yields each frame of the current execution stack as a
1395 * backtrace location object.
1398 each_caller_location(int argc
, VALUE
*argv
, VALUE _
)
1400 rb_execution_context_t
*ec
= GET_EC();
1401 long n
, lev
= ec_backtrace_range(ec
, argc
, argv
, 1, 1, &n
);
1402 if (lev
>= 0 && n
!= 0) {
1403 rb_ec_partial_backtrace_object(ec
, lev
, n
, NULL
, FALSE
, TRUE
);
1408 /* called from Init_vm() in vm.c */
1410 Init_vm_backtrace(void)
1413 * An internal representation of the backtrace. The user will never interact with
1414 * objects of this class directly, but class methods can be used to get backtrace
1415 * settings of the current session.
1417 rb_cBacktrace
= rb_define_class_under(rb_cThread
, "Backtrace", rb_cObject
);
1418 rb_define_alloc_func(rb_cBacktrace
, backtrace_alloc
);
1419 rb_undef_method(CLASS_OF(rb_cBacktrace
), "new");
1420 rb_marshal_define_compat(rb_cBacktrace
, rb_cArray
, backtrace_dump_data
, backtrace_load_data
);
1421 rb_define_singleton_method(rb_cBacktrace
, "limit", backtrace_limit
, 0);
1424 * An object representation of a stack frame, initialized by
1425 * Kernel#caller_locations.
1429 * # caller_locations.rb
1431 * caller_locations(skip)
1440 * c(0..2).map do |call|
1444 * Running <code>ruby caller_locations.rb</code> will produce:
1446 * caller_locations.rb:2:in `a'
1447 * caller_locations.rb:5:in `b'
1448 * caller_locations.rb:8:in `c'
1450 * Here's another example with a slightly different result:
1454 * attr_accessor :locations
1455 * def initialize(skip)
1456 * @locations = caller_locations(skip)
1460 * Foo.new(0..2).locations.map do |call|
1464 * Now run <code>ruby foo.rb</code> and you should see:
1466 * init.rb:4:in `initialize'
1467 * init.rb:8:in `new'
1468 * init.rb:8:in `<main>'
1470 rb_cBacktraceLocation
= rb_define_class_under(rb_cBacktrace
, "Location", rb_cObject
);
1471 rb_undef_alloc_func(rb_cBacktraceLocation
);
1472 rb_undef_method(CLASS_OF(rb_cBacktraceLocation
), "new");
1473 rb_define_method(rb_cBacktraceLocation
, "lineno", location_lineno_m
, 0);
1474 rb_define_method(rb_cBacktraceLocation
, "label", location_label_m
, 0);
1475 rb_define_method(rb_cBacktraceLocation
, "base_label", location_base_label_m
, 0);
1476 rb_define_method(rb_cBacktraceLocation
, "path", location_path_m
, 0);
1477 rb_define_method(rb_cBacktraceLocation
, "absolute_path", location_absolute_path_m
, 0);
1478 rb_define_method(rb_cBacktraceLocation
, "to_s", location_to_str_m
, 0);
1479 rb_define_method(rb_cBacktraceLocation
, "inspect", location_inspect_m
, 0);
1481 rb_define_global_function("caller", rb_f_caller
, -1);
1482 rb_define_global_function("caller_locations", rb_f_caller_locations
, -1);
1484 rb_define_singleton_method(rb_cThread
, "each_caller_location", each_caller_location
, -1);
1489 RUBY_SYMBOL_EXPORT_BEGIN
1491 RUBY_SYMBOL_EXPORT_END
1493 struct rb_debug_inspector_struct
{
1494 rb_execution_context_t
*ec
;
1495 rb_control_frame_t
*cfp
;
1497 VALUE contexts
; /* [[klass, binding, iseq, cfp], ...] */
1498 long backtrace_size
;
1502 CALLER_BINDING_SELF
,
1503 CALLER_BINDING_CLASS
,
1504 CALLER_BINDING_BINDING
,
1505 CALLER_BINDING_ISEQ
,
1507 CALLER_BINDING_DEPTH
,
1510 struct collect_caller_bindings_data
{
1512 const rb_execution_context_t
*ec
;
1516 collect_caller_bindings_init(void *arg
, size_t size
)
1522 get_klass(const rb_control_frame_t
*cfp
)
1525 if (rb_vm_control_frame_id_and_class(cfp
, 0, 0, &klass
)) {
1526 if (RB_TYPE_P(klass
, T_ICLASS
)) {
1527 return RBASIC(klass
)->klass
;
1539 frame_depth(const rb_execution_context_t
*ec
, const rb_control_frame_t
*cfp
)
1541 VM_ASSERT(RUBY_VM_END_CONTROL_FRAME(ec
) >= cfp
);
1542 return (int)(RUBY_VM_END_CONTROL_FRAME(ec
) - cfp
);
1546 collect_caller_bindings_iseq(void *arg
, const rb_control_frame_t
*cfp
)
1548 struct collect_caller_bindings_data
*data
= (struct collect_caller_bindings_data
*)arg
;
1549 VALUE frame
= rb_ary_new2(6);
1551 rb_ary_store(frame
, CALLER_BINDING_SELF
, cfp
->self
);
1552 rb_ary_store(frame
, CALLER_BINDING_CLASS
, get_klass(cfp
));
1553 rb_ary_store(frame
, CALLER_BINDING_BINDING
, GC_GUARDED_PTR(cfp
)); /* create later */
1554 rb_ary_store(frame
, CALLER_BINDING_ISEQ
, cfp
->iseq
? (VALUE
)cfp
->iseq
: Qnil
);
1555 rb_ary_store(frame
, CALLER_BINDING_CFP
, GC_GUARDED_PTR(cfp
));
1556 rb_ary_store(frame
, CALLER_BINDING_DEPTH
, INT2FIX(frame_depth(data
->ec
, cfp
)));
1558 rb_ary_push(data
->ary
, frame
);
1562 collect_caller_bindings_cfunc(void *arg
, const rb_control_frame_t
*cfp
, ID mid
)
1564 struct collect_caller_bindings_data
*data
= (struct collect_caller_bindings_data
*)arg
;
1565 VALUE frame
= rb_ary_new2(6);
1567 rb_ary_store(frame
, CALLER_BINDING_SELF
, cfp
->self
);
1568 rb_ary_store(frame
, CALLER_BINDING_CLASS
, get_klass(cfp
));
1569 rb_ary_store(frame
, CALLER_BINDING_BINDING
, Qnil
); /* not available */
1570 rb_ary_store(frame
, CALLER_BINDING_ISEQ
, Qnil
); /* not available */
1571 rb_ary_store(frame
, CALLER_BINDING_CFP
, GC_GUARDED_PTR(cfp
));
1572 rb_ary_store(frame
, CALLER_BINDING_DEPTH
, INT2FIX(frame_depth(data
->ec
, cfp
)));
1574 rb_ary_push(data
->ary
, frame
);
1578 collect_caller_bindings(const rb_execution_context_t
*ec
)
1582 struct collect_caller_bindings_data data
= {
1587 collect_caller_bindings_init
,
1588 collect_caller_bindings_iseq
,
1589 collect_caller_bindings_cfunc
,
1592 result
= rb_ary_reverse(data
.ary
);
1594 /* bindings should be created from top of frame */
1595 for (i
=0; i
<RARRAY_LEN(result
); i
++) {
1596 VALUE entry
= rb_ary_entry(result
, i
);
1597 VALUE cfp_val
= rb_ary_entry(entry
, CALLER_BINDING_BINDING
);
1599 if (!NIL_P(cfp_val
)) {
1600 rb_control_frame_t
*cfp
= GC_GUARDED_PTR_REF(cfp_val
);
1601 rb_ary_store(entry
, CALLER_BINDING_BINDING
, rb_vm_make_binding(ec
, cfp
));
1609 * Note that the passed `rb_debug_inspector_t' will be disabled
1610 * after `rb_debug_inspector_open'.
1614 rb_debug_inspector_open(rb_debug_inspector_func_t func
, void *data
)
1616 rb_debug_inspector_t dbg_context
;
1617 rb_execution_context_t
*ec
= GET_EC();
1618 enum ruby_tag_type state
;
1619 volatile VALUE
MAYBE_UNUSED(result
);
1621 /* escape all env to heap */
1622 rb_vm_stack_to_heap(ec
);
1624 dbg_context
.ec
= ec
;
1625 dbg_context
.cfp
= dbg_context
.ec
->cfp
;
1626 dbg_context
.backtrace
= rb_ec_backtrace_location_ary(ec
, RUBY_BACKTRACE_START
, RUBY_ALL_BACKTRACE_LINES
, FALSE
);
1627 dbg_context
.backtrace_size
= RARRAY_LEN(dbg_context
.backtrace
);
1628 dbg_context
.contexts
= collect_caller_bindings(ec
);
1631 if ((state
= EC_EXEC_TAG()) == TAG_NONE
) {
1632 result
= (*func
)(&dbg_context
, data
);
1636 /* invalidate bindings? */
1639 EC_JUMP_TAG(ec
, state
);
1646 frame_get(const rb_debug_inspector_t
*dc
, long index
)
1648 if (index
< 0 || index
>= dc
->backtrace_size
) {
1649 rb_raise(rb_eArgError
, "no such frame");
1651 return rb_ary_entry(dc
->contexts
, index
);
1655 rb_debug_inspector_frame_self_get(const rb_debug_inspector_t
*dc
, long index
)
1657 VALUE frame
= frame_get(dc
, index
);
1658 return rb_ary_entry(frame
, CALLER_BINDING_SELF
);
1662 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t
*dc
, long index
)
1664 VALUE frame
= frame_get(dc
, index
);
1665 return rb_ary_entry(frame
, CALLER_BINDING_CLASS
);
1669 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t
*dc
, long index
)
1671 VALUE frame
= frame_get(dc
, index
);
1672 return rb_ary_entry(frame
, CALLER_BINDING_BINDING
);
1676 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t
*dc
, long index
)
1678 VALUE frame
= frame_get(dc
, index
);
1679 VALUE iseq
= rb_ary_entry(frame
, CALLER_BINDING_ISEQ
);
1681 return RTEST(iseq
) ? rb_iseqw_new((rb_iseq_t
*)iseq
) : Qnil
;
1685 rb_debug_inspector_frame_depth(const rb_debug_inspector_t
*dc
, long index
)
1687 VALUE frame
= frame_get(dc
, index
);
1688 return rb_ary_entry(frame
, CALLER_BINDING_DEPTH
);
1692 rb_debug_inspector_current_depth(void)
1694 rb_execution_context_t
*ec
= GET_EC();
1695 return INT2FIX(frame_depth(ec
, ec
->cfp
));
1699 rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t
*dc
)
1701 return dc
->backtrace
;
1705 thread_profile_frames(rb_execution_context_t
*ec
, int start
, int limit
, VALUE
*buff
, int *lines
)
1708 const rb_control_frame_t
*cfp
= ec
->cfp
, *end_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
1709 const rb_control_frame_t
*top
= cfp
;
1710 const rb_callable_method_entry_t
*cme
;
1712 // If this function is called inside a thread after thread creation, but
1713 // before the CFP has been created, just return 0. This can happen when
1714 // sampling via signals. Threads can be interrupted randomly by the
1715 // signal, including during the time after the thread has been created, but
1716 // before the CFP has been allocated
1721 // Skip dummy frame; see `rb_ec_partial_backtrace_object` for details
1722 end_cfp
= RUBY_VM_NEXT_CONTROL_FRAME(end_cfp
);
1724 for (i
=0; i
<limit
&& cfp
!= end_cfp
; cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
)) {
1725 if (VM_FRAME_RUBYFRAME_P(cfp
) && cfp
->pc
!= 0) {
1731 /* record frame info */
1732 cme
= rb_vm_frame_method_entry(cfp
);
1733 if (cme
&& cme
->def
->type
== VM_METHOD_TYPE_ISEQ
) {
1734 buff
[i
] = (VALUE
)cme
;
1737 buff
[i
] = (VALUE
)cfp
->iseq
;
1741 // The topmost frame may not have an updated PC because the JIT
1742 // may not have set one. The JIT compiler will update the PC
1743 // before entering a new function (so that `caller` will work),
1744 // so only the topmost frame could possibly have an out of date PC
1745 if (cfp
== top
&& cfp
->jit_return
) {
1749 lines
[i
] = calc_lineno(cfp
->iseq
, cfp
->pc
);
1756 cme
= rb_vm_frame_method_entry(cfp
);
1757 if (cme
&& cme
->def
->type
== VM_METHOD_TYPE_CFUNC
) {
1762 buff
[i
] = (VALUE
)cme
;
1763 if (lines
) lines
[i
] = 0;
1773 rb_profile_frames(int start
, int limit
, VALUE
*buff
, int *lines
)
1775 rb_execution_context_t
*ec
= rb_current_execution_context(false);
1777 // If there is no EC, we may be attempting to profile a non-Ruby thread or a
1778 // M:N shared native thread which has no active Ruby thread.
1783 return thread_profile_frames(ec
, start
, limit
, buff
, lines
);
1787 rb_profile_thread_frames(VALUE thread
, int start
, int limit
, VALUE
*buff
, int *lines
)
1789 rb_thread_t
*th
= rb_thread_ptr(thread
);
1790 return thread_profile_frames(th
->ec
, start
, limit
, buff
, lines
);
1793 static const rb_iseq_t
*
1794 frame2iseq(VALUE frame
)
1796 if (NIL_P(frame
)) return NULL
;
1798 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1799 switch (imemo_type(frame
)) {
1801 return (const rb_iseq_t
*)frame
;
1804 const rb_callable_method_entry_t
*cme
= (rb_callable_method_entry_t
*)frame
;
1805 switch (cme
->def
->type
) {
1806 case VM_METHOD_TYPE_ISEQ
:
1807 return cme
->def
->body
.iseq
.iseqptr
;
1816 rb_bug("frame2iseq: unreachable");
1820 rb_profile_frame_path(VALUE frame
)
1822 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1823 return iseq
? rb_iseq_path(iseq
) : Qnil
;
1826 static const rb_callable_method_entry_t
*
1829 if (NIL_P(frame
)) return NULL
;
1831 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1832 switch (imemo_type(frame
)) {
1835 const rb_callable_method_entry_t
*cme
= (rb_callable_method_entry_t
*)frame
;
1836 switch (cme
->def
->type
) {
1837 case VM_METHOD_TYPE_CFUNC
:
1852 rb_profile_frame_absolute_path(VALUE frame
)
1854 if (cframe(frame
)) {
1855 static VALUE cfunc_str
= Qfalse
;
1857 cfunc_str
= rb_str_new_literal("<cfunc>");
1858 rb_vm_register_global_object(cfunc_str
);
1862 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1863 return iseq
? rb_iseq_realpath(iseq
) : Qnil
;
1867 rb_profile_frame_label(VALUE frame
)
1869 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1870 return iseq
? rb_iseq_label(iseq
) : Qnil
;
1874 rb_profile_frame_base_label(VALUE frame
)
1876 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1877 return iseq
? rb_iseq_base_label(iseq
) : Qnil
;
1881 rb_profile_frame_first_lineno(VALUE frame
)
1883 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1884 return iseq
? rb_iseq_first_lineno(iseq
) : Qnil
;
1888 frame2klass(VALUE frame
)
1890 if (NIL_P(frame
)) return Qnil
;
1892 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1893 const rb_callable_method_entry_t
*cme
= (rb_callable_method_entry_t
*)frame
;
1895 if (imemo_type(frame
) == imemo_ment
) {
1896 return cme
->defined_class
;
1903 rb_profile_frame_classpath(VALUE frame
)
1905 VALUE klass
= frame2klass(frame
);
1907 if (klass
&& !NIL_P(klass
)) {
1908 if (RB_TYPE_P(klass
, T_ICLASS
)) {
1909 klass
= RBASIC(klass
)->klass
;
1911 else if (RCLASS_SINGLETON_P(klass
)) {
1912 klass
= RCLASS_ATTACHED_OBJECT(klass
);
1913 if (!RB_TYPE_P(klass
, T_CLASS
) && !RB_TYPE_P(klass
, T_MODULE
))
1914 return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass
)), (void*)klass
);
1916 return rb_class_path(klass
);
1924 rb_profile_frame_singleton_method_p(VALUE frame
)
1926 VALUE klass
= frame2klass(frame
);
1928 return RBOOL(klass
&& !NIL_P(klass
) && RCLASS_SINGLETON_P(klass
));
1932 rb_profile_frame_method_name(VALUE frame
)
1934 const rb_callable_method_entry_t
*cme
= cframe(frame
);
1936 ID mid
= cme
->def
->original_id
;
1939 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1940 return iseq
? rb_iseq_method_name(iseq
) : Qnil
;
1944 qualified_method_name(VALUE frame
, VALUE method_name
)
1946 if (method_name
!= Qnil
) {
1947 VALUE classpath
= rb_profile_frame_classpath(frame
);
1948 VALUE singleton_p
= rb_profile_frame_singleton_method_p(frame
);
1950 if (classpath
!= Qnil
) {
1951 return rb_sprintf("%"PRIsVALUE
"%s%"PRIsVALUE
,
1952 classpath
, singleton_p
== Qtrue
? "." : "#", method_name
);
1964 rb_profile_frame_qualified_method_name(VALUE frame
)
1966 VALUE method_name
= rb_profile_frame_method_name(frame
);
1968 return qualified_method_name(frame
, method_name
);
1972 rb_profile_frame_full_label(VALUE frame
)
1974 const rb_callable_method_entry_t
*cme
= cframe(frame
);
1976 ID mid
= cme
->def
->original_id
;
1977 VALUE method_name
= id2str(mid
);
1978 return qualified_method_name(frame
, method_name
);
1981 VALUE label
= rb_profile_frame_label(frame
);
1982 VALUE base_label
= rb_profile_frame_base_label(frame
);
1983 VALUE qualified_method_name
= rb_profile_frame_qualified_method_name(frame
);
1985 if (NIL_P(qualified_method_name
) || base_label
== qualified_method_name
) {
1989 long label_length
= RSTRING_LEN(label
);
1990 long base_label_length
= RSTRING_LEN(base_label
);
1991 int prefix_len
= rb_long2int(label_length
- base_label_length
);
1993 return rb_sprintf("%.*s%"PRIsVALUE
, prefix_len
, RSTRING_PTR(label
), qualified_method_name
);