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
;
61 #if SIZEOF_PTRDIFF_T > SIZEOF_INT
62 VM_ASSERT(n
<= (ptrdiff_t)UINT_MAX
);
64 VM_ASSERT((unsigned int)n
<= ISEQ_BODY(iseq
)->iseq_size
);
66 size_t pos
= n
; /* no overflow */
68 /* use pos-1 because PC points next instruction at the beginning of instruction */
71 #if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
73 /* SDR() is not possible; that causes infinite loop. */
74 rb_print_backtrace(stderr
);
78 if (lineno
) *lineno
= rb_iseq_line_no(iseq
, pos
);
79 #ifdef USE_ISEQ_NODE_ID
80 if (node_id
) *node_id
= rb_iseq_node_id(iseq
, pos
);
87 calc_lineno(const rb_iseq_t
*iseq
, const VALUE
*pc
)
90 if (calc_pos(iseq
, pc
, &lineno
, NULL
)) return lineno
;
94 #ifdef USE_ISEQ_NODE_ID
96 calc_node_id(const rb_iseq_t
*iseq
, const VALUE
*pc
)
99 if (calc_pos(iseq
, pc
, NULL
, &node_id
)) return node_id
;
105 rb_vm_get_sourceline(const rb_control_frame_t
*cfp
)
107 if (VM_FRAME_RUBYFRAME_P(cfp
) && cfp
->iseq
) {
108 const rb_iseq_t
*iseq
= cfp
->iseq
;
109 int line
= calc_lineno(iseq
, cfp
->pc
);
114 return ISEQ_BODY(iseq
)->location
.first_lineno
;
122 typedef struct rb_backtrace_location_struct
{
123 const rb_callable_method_entry_t
*cme
;
124 const rb_iseq_t
*iseq
;
126 } rb_backtrace_location_t
;
128 struct valued_frame_info
{
129 rb_backtrace_location_t
*loc
;
134 location_mark(void *ptr
)
136 struct valued_frame_info
*vfi
= (struct valued_frame_info
*)ptr
;
137 rb_gc_mark_movable(vfi
->btobj
);
141 location_ref_update(void *ptr
)
143 struct valued_frame_info
*vfi
= ptr
;
144 vfi
->btobj
= rb_gc_location(vfi
->btobj
);
148 location_mark_entry(rb_backtrace_location_t
*fi
)
150 rb_gc_mark((VALUE
)fi
->cme
);
151 if (fi
->iseq
) rb_gc_mark_movable((VALUE
)fi
->iseq
);
154 static const rb_data_type_t location_data_type
= {
158 RUBY_TYPED_DEFAULT_FREE
,
159 NULL
, // No external memory to report,
162 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
| RUBY_TYPED_WB_PROTECTED
| RUBY_TYPED_EMBEDDABLE
166 rb_frame_info_p(VALUE obj
)
168 return rb_typeddata_is_kind_of(obj
, &location_data_type
);
171 static inline rb_backtrace_location_t
*
172 location_ptr(VALUE locobj
)
174 struct valued_frame_info
*vloc
;
175 TypedData_Get_Struct(locobj
, struct valued_frame_info
, &location_data_type
, vloc
);
180 location_lineno(rb_backtrace_location_t
*loc
)
183 return calc_lineno(loc
->iseq
, loc
->pc
);
189 * Returns the line number of this frame.
191 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
193 * loc = c(0..1).first
197 location_lineno_m(VALUE self
)
199 return INT2FIX(location_lineno(location_ptr(self
)));
202 VALUE
rb_mod_name0(VALUE klass
, bool *permanent
);
205 rb_gen_method_name(VALUE owner
, VALUE name
)
208 if (RB_TYPE_P(owner
, T_CLASS
) || RB_TYPE_P(owner
, T_MODULE
)) {
209 if (RCLASS_SINGLETON_P(owner
)) {
210 VALUE v
= RCLASS_ATTACHED_OBJECT(owner
);
211 if (RB_TYPE_P(v
, T_CLASS
) || RB_TYPE_P(v
, T_MODULE
)) {
212 v
= rb_mod_name0(v
, &permanent
);
213 if (permanent
&& !NIL_P(v
)) {
214 return rb_sprintf("%"PRIsVALUE
".%"PRIsVALUE
, v
, name
);
219 owner
= rb_mod_name0(owner
, &permanent
);
220 if (permanent
&& !NIL_P(owner
)) {
221 return rb_sprintf("%"PRIsVALUE
"#%"PRIsVALUE
, owner
, name
);
229 calculate_iseq_label(VALUE owner
, const rb_iseq_t
*iseq
)
232 switch (ISEQ_BODY(iseq
)->type
) {
234 case ISEQ_TYPE_CLASS
:
236 return ISEQ_BODY(iseq
)->location
.label
;
237 case ISEQ_TYPE_METHOD
:
238 return rb_gen_method_name(owner
, ISEQ_BODY(iseq
)->location
.label
);
239 case ISEQ_TYPE_BLOCK
:
240 case ISEQ_TYPE_PLAIN
: {
242 const rb_iseq_t
*orig_iseq
= iseq
;
243 if (ISEQ_BODY(orig_iseq
)->parent_iseq
!= 0) {
244 while (ISEQ_BODY(orig_iseq
)->local_iseq
!= iseq
) {
245 if (ISEQ_BODY(iseq
)->type
== ISEQ_TYPE_BLOCK
) {
248 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
252 return rb_sprintf("block in %"PRIsVALUE
, calculate_iseq_label(owner
, iseq
));
255 return rb_sprintf("block (%d levels) in %"PRIsVALUE
, level
, calculate_iseq_label(owner
, iseq
));
258 case ISEQ_TYPE_RESCUE
:
259 case ISEQ_TYPE_ENSURE
:
261 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
264 rb_bug("calculate_iseq_label: unreachable");
269 location_label(rb_backtrace_location_t
*loc
)
271 if (loc
->cme
&& loc
->cme
->def
->type
== VM_METHOD_TYPE_CFUNC
) {
272 return rb_gen_method_name(loc
->cme
->owner
, rb_id2str(loc
->cme
->def
->original_id
));
277 owner
= loc
->cme
->owner
;
279 return calculate_iseq_label(owner
, loc
->iseq
);
283 * Returns the label of this frame.
285 * Usually consists of method, class, module, etc names with decoration.
287 * Consider the following example:
290 * puts caller_locations(0).first.label
293 * puts caller_locations(0).first.label
296 * puts caller_locations(0).first.label
301 * The result of calling +foo+ is this:
305 * block (2 levels) in foo
309 location_label_m(VALUE self
)
311 return location_label(location_ptr(self
));
315 location_base_label(rb_backtrace_location_t
*loc
)
317 if (loc
->cme
&& loc
->cme
->def
->type
== VM_METHOD_TYPE_CFUNC
) {
318 return rb_id2str(loc
->cme
->def
->original_id
);
321 return ISEQ_BODY(loc
->iseq
)->location
.base_label
;
325 * Returns the base label of this frame, which is usually equal to the label,
326 * without decoration.
328 * Consider the following example:
331 * puts caller_locations(0).first.base_label
334 * puts caller_locations(0).first.base_label
337 * puts caller_locations(0).first.base_label
342 * The result of calling +foo+ is this:
349 location_base_label_m(VALUE self
)
351 return location_base_label(location_ptr(self
));
354 static const rb_iseq_t
*
355 location_iseq(rb_backtrace_location_t
*loc
)
361 * Returns the file name of this frame. This will generally be an absolute
362 * path, unless the frame is in the main script, in which case it will be the
363 * script location passed on the command line.
365 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
367 * loc = c(0..1).first
368 * loc.path #=> caller_locations.rb
371 location_path_m(VALUE self
)
373 const rb_iseq_t
*iseq
= location_iseq(location_ptr(self
));
374 return iseq
? rb_iseq_path(iseq
) : Qnil
;
377 #ifdef USE_ISEQ_NODE_ID
379 location_node_id(rb_backtrace_location_t
*loc
)
381 if (loc
->iseq
&& loc
->pc
) {
382 return calc_node_id(loc
->iseq
, loc
->pc
);
389 rb_get_node_id_from_frame_info(VALUE obj
)
391 #ifdef USE_ISEQ_NODE_ID
392 rb_backtrace_location_t
*loc
= location_ptr(obj
);
393 return location_node_id(loc
);
400 rb_get_iseq_from_frame_info(VALUE obj
)
402 rb_backtrace_location_t
*loc
= location_ptr(obj
);
403 const rb_iseq_t
*iseq
= location_iseq(loc
);
408 location_realpath(rb_backtrace_location_t
*loc
)
411 return rb_iseq_realpath(loc
->iseq
);
417 * Returns the full file path of this frame.
419 * Same as #path, except that it will return absolute path
420 * even if the frame is in the main script.
423 location_absolute_path_m(VALUE self
)
425 return location_realpath(location_ptr(self
));
429 location_format(VALUE file
, int lineno
, VALUE name
)
431 VALUE s
= rb_enc_sprintf(rb_enc_compatible(file
, name
), "%s", RSTRING_PTR(file
));
433 rb_str_catf(s
, ":%d", lineno
);
435 rb_str_cat_cstr(s
, ":in ");
437 rb_str_cat_cstr(s
, "unknown method");
440 rb_str_catf(s
, "'%s'", RSTRING_PTR(name
));
446 location_to_str(rb_backtrace_location_t
*loc
)
448 VALUE file
, owner
= Qnil
, name
;
451 if (loc
->cme
&& loc
->cme
->def
->type
== VM_METHOD_TYPE_CFUNC
) {
452 if (loc
->iseq
&& loc
->pc
) {
453 file
= rb_iseq_path(loc
->iseq
);
454 lineno
= calc_lineno(loc
->iseq
, loc
->pc
);
457 file
= GET_VM()->progname
;
460 name
= rb_gen_method_name(loc
->cme
->owner
, rb_id2str(loc
->cme
->def
->original_id
));
463 file
= rb_iseq_path(loc
->iseq
);
464 lineno
= calc_lineno(loc
->iseq
, loc
->pc
);
466 owner
= loc
->cme
->owner
;
468 name
= calculate_iseq_label(owner
, loc
->iseq
);
471 return location_format(file
, lineno
, name
);
475 * Returns a Kernel#caller style string representing this frame.
478 location_to_str_m(VALUE self
)
480 return location_to_str(location_ptr(self
));
484 * Returns the same as calling +inspect+ on the string representation of
488 location_inspect_m(VALUE self
)
490 return rb_str_inspect(location_to_str(location_ptr(self
)));
493 typedef struct rb_backtrace_struct
{
497 rb_backtrace_location_t backtrace
[1];
501 backtrace_mark(void *ptr
)
503 rb_backtrace_t
*bt
= (rb_backtrace_t
*)ptr
;
504 size_t i
, s
= bt
->backtrace_size
;
506 for (i
=0; i
<s
; i
++) {
507 location_mark_entry(&bt
->backtrace
[i
]);
509 rb_gc_mark_movable(bt
->strary
);
510 rb_gc_mark_movable(bt
->locary
);
514 location_update_entry(rb_backtrace_location_t
*fi
)
516 fi
->cme
= (rb_callable_method_entry_t
*)rb_gc_location((VALUE
)fi
->cme
);
518 fi
->iseq
= (rb_iseq_t
*)rb_gc_location((VALUE
)fi
->iseq
);
523 backtrace_update(void *ptr
)
525 rb_backtrace_t
*bt
= (rb_backtrace_t
*)ptr
;
526 size_t i
, s
= bt
->backtrace_size
;
528 for (i
=0; i
<s
; i
++) {
529 location_update_entry(&bt
->backtrace
[i
]);
531 bt
->strary
= rb_gc_location(bt
->strary
);
532 bt
->locary
= rb_gc_location(bt
->locary
);
535 static const rb_data_type_t backtrace_data_type
= {
540 NULL
, // No external memory to report,
543 /* Cannot set the RUBY_TYPED_EMBEDDABLE flag because the loc of frame_info
544 * points elements in the backtrace array. This can cause the loc to become
545 * incorrect if this backtrace object is moved by compaction. */
546 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
| RUBY_TYPED_WB_PROTECTED
550 rb_backtrace_p(VALUE obj
)
552 return rb_typeddata_is_kind_of(obj
, &backtrace_data_type
);
556 backtrace_alloc(VALUE klass
)
559 VALUE obj
= TypedData_Make_Struct(klass
, rb_backtrace_t
, &backtrace_data_type
, bt
);
564 backtrace_alloc_capa(long num_frames
, rb_backtrace_t
**backtrace
)
566 size_t memsize
= offsetof(rb_backtrace_t
, backtrace
) + num_frames
* sizeof(rb_backtrace_location_t
);
567 VALUE btobj
= rb_data_typed_object_zalloc(rb_cBacktrace
, memsize
, &backtrace_data_type
);
568 TypedData_Get_Struct(btobj
, rb_backtrace_t
, &backtrace_data_type
, *backtrace
);
574 backtrace_size(const rb_execution_context_t
*ec
)
576 const rb_control_frame_t
*last_cfp
= ec
->cfp
;
577 const rb_control_frame_t
*start_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
579 if (start_cfp
== NULL
) {
584 RUBY_VM_NEXT_CONTROL_FRAME(
585 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp
)); /* skip top frames */
587 if (start_cfp
< last_cfp
) {
591 return start_cfp
- last_cfp
+ 1;
595 is_internal_location(const rb_control_frame_t
*cfp
)
597 static const char prefix
[] = "<internal:";
598 const size_t prefix_len
= sizeof(prefix
) - 1;
599 VALUE file
= rb_iseq_path(cfp
->iseq
);
600 return strncmp(prefix
, RSTRING_PTR(file
), prefix_len
) == 0;
604 is_rescue_or_ensure_frame(const rb_control_frame_t
*cfp
)
606 enum rb_iseq_type type
= ISEQ_BODY(cfp
->iseq
)->type
;
607 return type
== ISEQ_TYPE_RESCUE
|| type
== ISEQ_TYPE_ENSURE
;
611 bt_update_cfunc_loc(unsigned long cfunc_counter
, rb_backtrace_location_t
*cfunc_loc
, const rb_iseq_t
*iseq
, const VALUE
*pc
)
613 for (; cfunc_counter
> 0; cfunc_counter
--, cfunc_loc
--) {
614 cfunc_loc
->iseq
= iseq
;
619 static VALUE
location_create(rb_backtrace_location_t
*srcloc
, void *btobj
);
622 bt_yield_loc(rb_backtrace_location_t
*loc
, long num_frames
, VALUE btobj
)
624 for (; num_frames
> 0; num_frames
--, loc
++) {
625 rb_yield(location_create(loc
, (void *)btobj
));
630 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
)
632 const rb_control_frame_t
*cfp
= ec
->cfp
;
633 const rb_control_frame_t
*end_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
635 rb_backtrace_t
*bt
= NULL
;
637 rb_backtrace_location_t
*loc
= NULL
;
638 unsigned long cfunc_counter
= 0;
639 bool skip_next_frame
= FALSE
;
641 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
642 if (end_cfp
== NULL
) {
646 end_cfp
= RUBY_VM_NEXT_CONTROL_FRAME(end_cfp
);
649 * top frame (dummy) <- RUBY_VM_END_CONTROL_FRAME
650 * top frame (dummy) <- end_cfp
651 * top frame <- main script
655 * current frame <- ec->cfp
658 size
= end_cfp
- cfp
+ 1;
662 else if (num_frames
< 0 || num_frames
> size
) {
667 btobj
= backtrace_alloc_capa(num_frames
, &bt
);
669 bt
->backtrace_size
= 0;
670 if (num_frames
== 0) {
671 if (start_too_large
) *start_too_large
= 0;
675 for (; cfp
!= end_cfp
&& (bt
->backtrace_size
< num_frames
); cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
)) {
678 if (start_frame
> 0) {
681 else if (!(skip_internal
&& is_internal_location(cfp
))) {
682 if (!skip_next_frame
) {
683 const rb_iseq_t
*iseq
= cfp
->iseq
;
684 const VALUE
*pc
= cfp
->pc
;
685 loc
= &bt
->backtrace
[bt
->backtrace_size
++];
686 RB_OBJ_WRITE(btobj
, &loc
->cme
, rb_vm_frame_method_entry(cfp
));
687 RB_OBJ_WRITE(btobj
, &loc
->iseq
, iseq
);
689 bt_update_cfunc_loc(cfunc_counter
, loc
-1, iseq
, pc
);
691 bt_yield_loc(loc
- cfunc_counter
, cfunc_counter
+1, btobj
);
695 skip_next_frame
= is_rescue_or_ensure_frame(cfp
);
700 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp
));
701 if (start_frame
> 0) {
705 loc
= &bt
->backtrace
[bt
->backtrace_size
++];
706 RB_OBJ_WRITE(btobj
, &loc
->cme
, rb_vm_frame_method_entry(cfp
));
714 // When a backtrace entry corresponds to a method defined in C (e.g. rb_define_method), the reported file:line
715 // is the one of the caller Ruby frame, so if the last entry is a C frame we find the caller Ruby frame here.
716 if (cfunc_counter
> 0) {
717 for (; cfp
!= end_cfp
; cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
)) {
718 if (cfp
->iseq
&& cfp
->pc
&& !(skip_internal
&& is_internal_location(cfp
))) {
719 VM_ASSERT(!skip_next_frame
); // ISEQ_TYPE_RESCUE/ISEQ_TYPE_ENSURE should have a caller Ruby ISEQ, not a cfunc
720 bt_update_cfunc_loc(cfunc_counter
, loc
, cfp
->iseq
, cfp
->pc
);
721 RB_OBJ_WRITTEN(btobj
, Qundef
, cfp
->iseq
);
723 bt_yield_loc(loc
- cfunc_counter
, cfunc_counter
, btobj
);
730 if (start_too_large
) *start_too_large
= (start_frame
> 0 ? -1 : 0);
735 rb_ec_backtrace_object(const rb_execution_context_t
*ec
)
737 return rb_ec_partial_backtrace_object(ec
, BACKTRACE_START
, ALL_BACKTRACE_LINES
, NULL
, FALSE
, FALSE
);
741 backtrace_collect(rb_backtrace_t
*bt
, VALUE (*func
)(rb_backtrace_location_t
*, void *arg
), void *arg
)
746 btary
= rb_ary_new2(bt
->backtrace_size
);
748 for (i
=0; i
<bt
->backtrace_size
; i
++) {
749 rb_backtrace_location_t
*loc
= &bt
->backtrace
[i
];
750 rb_ary_push(btary
, func(loc
, arg
));
757 location_to_str_dmyarg(rb_backtrace_location_t
*loc
, void *dmy
)
759 return location_to_str(loc
);
763 backtrace_to_str_ary(VALUE self
)
767 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
768 r
= backtrace_collect(bt
, location_to_str_dmyarg
, 0);
774 rb_backtrace_to_str_ary(VALUE self
)
777 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
780 RB_OBJ_WRITE(self
, &bt
->strary
, backtrace_to_str_ary(self
));
786 rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self
)
789 rb_backtrace_location_t
*loc
;
791 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
792 VM_ASSERT(bt
->backtrace_size
> 0);
794 loc
= &bt
->backtrace
[0];
796 VM_ASSERT(!loc
->cme
|| loc
->cme
->def
->type
== VM_METHOD_TYPE_ISEQ
);
798 loc
->pc
= NULL
; // means location.first_lineno
802 location_create(rb_backtrace_location_t
*srcloc
, void *btobj
)
805 struct valued_frame_info
*vloc
;
806 obj
= TypedData_Make_Struct(rb_cBacktraceLocation
, struct valued_frame_info
, &location_data_type
, vloc
);
809 RB_OBJ_WRITE(obj
, &vloc
->btobj
, (VALUE
)btobj
);
815 backtrace_to_location_ary(VALUE self
)
819 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
820 r
= backtrace_collect(bt
, location_create
, (void *)self
);
826 rb_backtrace_to_location_ary(VALUE self
)
829 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
832 RB_OBJ_WRITE(self
, &bt
->locary
, backtrace_to_location_ary(self
));
838 rb_location_ary_to_backtrace(VALUE ary
)
840 if (!RB_TYPE_P(ary
, T_ARRAY
) || !rb_frame_info_p(RARRAY_AREF(ary
, 0))) {
844 rb_backtrace_t
*new_backtrace
;
845 long num_frames
= RARRAY_LEN(ary
);
846 VALUE btobj
= backtrace_alloc_capa(num_frames
, &new_backtrace
);
848 for (long index
= 0; index
< RARRAY_LEN(ary
); index
++) {
849 VALUE locobj
= RARRAY_AREF(ary
, index
);
851 if (!rb_frame_info_p(locobj
)) {
855 struct valued_frame_info
*src_vloc
;
856 TypedData_Get_Struct(locobj
, struct valued_frame_info
, &location_data_type
, src_vloc
);
858 rb_backtrace_location_t
*dst_location
= &new_backtrace
->backtrace
[index
];
859 RB_OBJ_WRITE(btobj
, &dst_location
->cme
, src_vloc
->loc
->cme
);
860 RB_OBJ_WRITE(btobj
, &dst_location
->iseq
, src_vloc
->loc
->iseq
);
861 dst_location
->pc
= src_vloc
->loc
->pc
;
863 new_backtrace
->backtrace_size
++;
872 backtrace_dump_data(VALUE self
)
874 VALUE str
= rb_backtrace_to_str_ary(self
);
879 backtrace_load_data(VALUE self
, VALUE str
)
882 TypedData_Get_Struct(self
, rb_backtrace_t
, &backtrace_data_type
, bt
);
883 RB_OBJ_WRITE(self
, &bt
->strary
, str
);
888 * call-seq: Thread::Backtrace::limit -> integer
890 * Returns maximum backtrace length set by <tt>--backtrace-limit</tt>
891 * command-line option. The default is <tt>-1</tt> which means unlimited
892 * backtraces. If the value is zero or positive, the error backtraces,
893 * produced by Exception#full_message, are abbreviated and the extra lines
894 * are replaced by <tt>... 3 levels... </tt>
896 * $ ruby -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
898 * .../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)
899 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
900 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
901 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
902 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
903 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
904 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
905 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
906 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
907 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
908 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
909 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
910 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
911 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
912 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
913 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
914 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
915 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
916 * from -e:1:in `<main>'
918 * $ ruby --backtrace-limit 2 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
920 * .../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)
921 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
922 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
924 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
925 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
926 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
929 * $ ruby --backtrace-limit 0 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
931 * .../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)
933 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
938 backtrace_limit(VALUE self
)
940 return LONG2NUM(rb_backtrace_length_limit
);
944 rb_ec_backtrace_str_ary(const rb_execution_context_t
*ec
, long lev
, long n
)
946 return rb_backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec
, lev
, n
, NULL
, FALSE
, FALSE
));
950 rb_ec_backtrace_location_ary(const rb_execution_context_t
*ec
, long lev
, long n
, bool skip_internal
)
952 return rb_backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec
, lev
, n
, NULL
, skip_internal
, FALSE
));
955 /* make old style backtrace directly */
958 backtrace_each(const rb_execution_context_t
*ec
,
959 void (*init
)(void *arg
, size_t size
),
960 void (*iter_iseq
)(void *arg
, const rb_control_frame_t
*cfp
),
961 void (*iter_cfunc
)(void *arg
, const rb_control_frame_t
*cfp
, ID mid
),
964 const rb_control_frame_t
*last_cfp
= ec
->cfp
;
965 const rb_control_frame_t
*start_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
966 const rb_control_frame_t
*cfp
;
969 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
970 if (start_cfp
== NULL
) {
975 /* <- start_cfp (end control frame)
978 * top frame <- start_cfp
982 * current frame <- ec->cfp
986 RUBY_VM_NEXT_CONTROL_FRAME(
987 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp
)); /* skip top frames */
989 if (start_cfp
< last_cfp
) {
993 size
= start_cfp
- last_cfp
+ 1;
999 for (i
=0, cfp
= start_cfp
; i
<size
; i
++, cfp
= RUBY_VM_NEXT_CONTROL_FRAME(cfp
)) {
1000 /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
1003 iter_iseq(arg
, cfp
);
1007 VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp
));
1008 const rb_callable_method_entry_t
*me
= rb_vm_frame_method_entry(cfp
);
1009 ID mid
= me
->def
->original_id
;
1011 iter_cfunc(arg
, cfp
, mid
);
1019 void (*func
)(void *data
, VALUE file
, int lineno
, VALUE name
);
1020 void *data
; /* result */
1024 oldbt_init(void *ptr
, size_t dmy
)
1026 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
1027 arg
->filename
= GET_VM()->progname
;
1032 oldbt_iter_iseq(void *ptr
, const rb_control_frame_t
*cfp
)
1034 const rb_iseq_t
*iseq
= cfp
->iseq
;
1035 const VALUE
*pc
= cfp
->pc
;
1036 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
1037 VALUE file
= arg
->filename
= rb_iseq_path(iseq
);
1038 VALUE name
= ISEQ_BODY(iseq
)->location
.label
;
1039 int lineno
= arg
->lineno
= calc_lineno(iseq
, pc
);
1041 (arg
->func
)(arg
->data
, file
, lineno
, name
);
1045 oldbt_iter_cfunc(void *ptr
, const rb_control_frame_t
*cfp
, ID mid
)
1047 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
1048 VALUE file
= arg
->filename
;
1049 VALUE name
= rb_id2str(mid
);
1050 int lineno
= arg
->lineno
;
1052 (arg
->func
)(arg
->data
, file
, lineno
, name
);
1056 oldbt_print(void *data
, VALUE file
, int lineno
, VALUE name
)
1058 FILE *fp
= (FILE *)data
;
1061 fprintf(fp
, "\tfrom %s:%d:in unknown method\n",
1062 RSTRING_PTR(file
), lineno
);
1065 fprintf(fp
, "\tfrom %s:%d:in '%s'\n",
1066 RSTRING_PTR(file
), lineno
, RSTRING_PTR(name
));
1071 vm_backtrace_print(FILE *fp
)
1073 struct oldbt_arg arg
;
1075 arg
.func
= oldbt_print
;
1076 arg
.data
= (void *)fp
;
1077 backtrace_each(GET_EC(),
1084 struct oldbt_bugreport_arg
{
1090 oldbt_bugreport(void *arg
, VALUE file
, int line
, VALUE method
)
1092 struct oldbt_bugreport_arg
*p
= arg
;
1094 const char *filename
= NIL_P(file
) ? "ruby" : RSTRING_PTR(file
);
1096 fprintf(fp
, "-- Ruby level backtrace information "
1097 "----------------------------------------\n");
1100 if (NIL_P(method
)) {
1101 fprintf(fp
, "%s:%d:in unknown method\n", filename
, line
);
1104 fprintf(fp
, "%s:%d:in '%s'\n", filename
, line
, RSTRING_PTR(method
));
1109 rb_backtrace_print_as_bugreport(FILE *fp
)
1111 struct oldbt_arg arg
;
1112 struct oldbt_bugreport_arg barg
= {fp
, 0};
1114 arg
.func
= oldbt_bugreport
;
1117 backtrace_each(GET_EC(),
1127 vm_backtrace_print(stderr
);
1130 struct print_to_arg
{
1131 VALUE (*iter
)(VALUE recv
, VALUE str
);
1136 oldbt_print_to(void *data
, VALUE file
, int lineno
, VALUE name
)
1138 const struct print_to_arg
*arg
= data
;
1139 VALUE str
= rb_sprintf("\tfrom %"PRIsVALUE
":%d:in ", file
, lineno
);
1142 rb_str_cat2(str
, "unknown method\n");
1145 rb_str_catf(str
, " '%"PRIsVALUE
"'\n", name
);
1147 (*arg
->iter
)(arg
->output
, str
);
1151 rb_backtrace_each(VALUE (*iter
)(VALUE recv
, VALUE str
), VALUE output
)
1153 struct oldbt_arg arg
;
1154 struct print_to_arg parg
;
1157 parg
.output
= output
;
1158 arg
.func
= oldbt_print_to
;
1160 backtrace_each(GET_EC(),
1168 rb_make_backtrace(void)
1170 return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START
, ALL_BACKTRACE_LINES
);
1174 ec_backtrace_range(const rb_execution_context_t
*ec
, int argc
, const VALUE
*argv
, int lev_default
, int lev_plus
, long *len_ptr
)
1176 VALUE level
, vn
, opts
;
1179 rb_scan_args(argc
, argv
, "02:", &level
, &vn
, &opts
);
1182 rb_get_kwargs(opts
, (ID
[]){0}, 0, 0, NULL
);
1184 if (argc
== 2 && NIL_P(vn
)) argc
--;
1188 lev
= lev_default
+ lev_plus
;
1189 n
= ALL_BACKTRACE_LINES
;
1193 long beg
, len
, bt_size
= backtrace_size(ec
);
1194 switch (rb_range_beg_len(level
, &beg
, &len
, bt_size
- lev_plus
, 0)) {
1196 lev
= NUM2LONG(level
);
1198 rb_raise(rb_eArgError
, "negative level (%ld)", lev
);
1201 n
= ALL_BACKTRACE_LINES
;
1206 lev
= beg
+ lev_plus
;
1213 lev
= NUM2LONG(level
);
1216 rb_raise(rb_eArgError
, "negative level (%ld)", lev
);
1219 rb_raise(rb_eArgError
, "negative size (%ld)", n
);
1224 lev
= n
= 0; /* to avoid warning */
1233 ec_backtrace_to_ary(const rb_execution_context_t
*ec
, int argc
, const VALUE
*argv
, int lev_default
, int lev_plus
, int to_str
)
1239 lev
= ec_backtrace_range(ec
, argc
, argv
, lev_default
, lev_plus
, &n
);
1240 if (lev
< 0) return Qnil
;
1243 return rb_ary_new();
1246 btval
= rb_ec_partial_backtrace_object(ec
, lev
, n
, &too_large
, FALSE
, FALSE
);
1253 r
= backtrace_to_str_ary(btval
);
1256 r
= backtrace_to_location_ary(btval
);
1263 thread_backtrace_to_ary(int argc
, const VALUE
*argv
, VALUE thval
, int to_str
)
1265 rb_thread_t
*target_th
= rb_thread_ptr(thval
);
1267 if (target_th
->to_kill
|| target_th
->status
== THREAD_KILLED
)
1270 return ec_backtrace_to_ary(target_th
->ec
, argc
, argv
, 0, 0, to_str
);
1274 rb_vm_thread_backtrace(int argc
, const VALUE
*argv
, VALUE thval
)
1276 return thread_backtrace_to_ary(argc
, argv
, thval
, 1);
1280 rb_vm_thread_backtrace_locations(int argc
, const VALUE
*argv
, VALUE thval
)
1282 return thread_backtrace_to_ary(argc
, argv
, thval
, 0);
1286 rb_vm_backtrace(int argc
, const VALUE
* argv
, struct rb_execution_context_struct
* ec
)
1288 return ec_backtrace_to_ary(ec
, argc
, argv
, 0, 0, 1);
1292 rb_vm_backtrace_locations(int argc
, const VALUE
* argv
, struct rb_execution_context_struct
* ec
)
1294 return ec_backtrace_to_ary(ec
, argc
, argv
, 0, 0, 0);
1299 * caller(start=1, length=nil) -> array or nil
1300 * caller(range) -> array or nil
1302 * Returns the current execution stack---an array containing strings in
1303 * the form <code>file:line</code> or <code>file:line: in
1306 * The optional _start_ parameter determines the number of initial stack
1307 * entries to omit from the top of the stack.
1309 * A second optional +length+ parameter can be used to limit how many entries
1310 * are returned from the stack.
1312 * Returns +nil+ if _start_ is greater than the size of
1313 * current execution stack.
1315 * Optionally you can pass a range, which will return an array containing the
1316 * entries within the specified range.
1327 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1328 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1329 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1330 * c(3) #=> ["prog:13:in `<main>'"]
1336 rb_f_caller(int argc
, VALUE
*argv
, VALUE _
)
1338 return ec_backtrace_to_ary(GET_EC(), argc
, argv
, 1, 1, 1);
1343 * caller_locations(start=1, length=nil) -> array or nil
1344 * caller_locations(range) -> array or nil
1346 * Returns the current execution stack---an array containing
1347 * backtrace location objects.
1349 * See Thread::Backtrace::Location for more information.
1351 * The optional _start_ parameter determines the number of initial stack
1352 * entries to omit from the top of the stack.
1354 * A second optional +length+ parameter can be used to limit how many entries
1355 * are returned from the stack.
1357 * Returns +nil+ if _start_ is greater than the size of
1358 * current execution stack.
1360 * Optionally you can pass a range, which will return an array containing the
1361 * entries within the specified range.
1364 rb_f_caller_locations(int argc
, VALUE
*argv
, VALUE _
)
1366 return ec_backtrace_to_ary(GET_EC(), argc
, argv
, 1, 1, 0);
1371 * Thread.each_caller_location(...) { |loc| ... } -> nil
1373 * Yields each frame of the current execution stack as a
1374 * backtrace location object.
1377 each_caller_location(int argc
, VALUE
*argv
, VALUE _
)
1379 rb_execution_context_t
*ec
= GET_EC();
1380 long n
, lev
= ec_backtrace_range(ec
, argc
, argv
, 1, 1, &n
);
1381 if (lev
>= 0 && n
!= 0) {
1382 rb_ec_partial_backtrace_object(ec
, lev
, n
, NULL
, FALSE
, TRUE
);
1387 /* called from Init_vm() in vm.c */
1389 Init_vm_backtrace(void)
1392 * An internal representation of the backtrace. The user will never interact with
1393 * objects of this class directly, but class methods can be used to get backtrace
1394 * settings of the current session.
1396 rb_cBacktrace
= rb_define_class_under(rb_cThread
, "Backtrace", rb_cObject
);
1397 rb_define_alloc_func(rb_cBacktrace
, backtrace_alloc
);
1398 rb_undef_method(CLASS_OF(rb_cBacktrace
), "new");
1399 rb_marshal_define_compat(rb_cBacktrace
, rb_cArray
, backtrace_dump_data
, backtrace_load_data
);
1400 rb_define_singleton_method(rb_cBacktrace
, "limit", backtrace_limit
, 0);
1403 * An object representation of a stack frame, initialized by
1404 * Kernel#caller_locations.
1408 * # caller_locations.rb
1410 * caller_locations(skip)
1419 * c(0..2).map do |call|
1423 * Running <code>ruby caller_locations.rb</code> will produce:
1425 * caller_locations.rb:2:in `a'
1426 * caller_locations.rb:5:in `b'
1427 * caller_locations.rb:8:in `c'
1429 * Here's another example with a slightly different result:
1433 * attr_accessor :locations
1434 * def initialize(skip)
1435 * @locations = caller_locations(skip)
1439 * Foo.new(0..2).locations.map do |call|
1443 * Now run <code>ruby foo.rb</code> and you should see:
1445 * init.rb:4:in `initialize'
1446 * init.rb:8:in `new'
1447 * init.rb:8:in `<main>'
1449 rb_cBacktraceLocation
= rb_define_class_under(rb_cBacktrace
, "Location", rb_cObject
);
1450 rb_undef_alloc_func(rb_cBacktraceLocation
);
1451 rb_undef_method(CLASS_OF(rb_cBacktraceLocation
), "new");
1452 rb_define_method(rb_cBacktraceLocation
, "lineno", location_lineno_m
, 0);
1453 rb_define_method(rb_cBacktraceLocation
, "label", location_label_m
, 0);
1454 rb_define_method(rb_cBacktraceLocation
, "base_label", location_base_label_m
, 0);
1455 rb_define_method(rb_cBacktraceLocation
, "path", location_path_m
, 0);
1456 rb_define_method(rb_cBacktraceLocation
, "absolute_path", location_absolute_path_m
, 0);
1457 rb_define_method(rb_cBacktraceLocation
, "to_s", location_to_str_m
, 0);
1458 rb_define_method(rb_cBacktraceLocation
, "inspect", location_inspect_m
, 0);
1460 rb_define_global_function("caller", rb_f_caller
, -1);
1461 rb_define_global_function("caller_locations", rb_f_caller_locations
, -1);
1463 rb_define_singleton_method(rb_cThread
, "each_caller_location", each_caller_location
, -1);
1468 RUBY_SYMBOL_EXPORT_BEGIN
1470 RUBY_SYMBOL_EXPORT_END
1472 struct rb_debug_inspector_struct
{
1473 rb_execution_context_t
*ec
;
1474 rb_control_frame_t
*cfp
;
1476 VALUE contexts
; /* [[klass, binding, iseq, cfp], ...] */
1477 long backtrace_size
;
1481 CALLER_BINDING_SELF
,
1482 CALLER_BINDING_CLASS
,
1483 CALLER_BINDING_BINDING
,
1484 CALLER_BINDING_ISEQ
,
1486 CALLER_BINDING_DEPTH
,
1489 struct collect_caller_bindings_data
{
1491 const rb_execution_context_t
*ec
;
1495 collect_caller_bindings_init(void *arg
, size_t size
)
1501 get_klass(const rb_control_frame_t
*cfp
)
1504 if (rb_vm_control_frame_id_and_class(cfp
, 0, 0, &klass
)) {
1505 if (RB_TYPE_P(klass
, T_ICLASS
)) {
1506 return RBASIC(klass
)->klass
;
1518 frame_depth(const rb_execution_context_t
*ec
, const rb_control_frame_t
*cfp
)
1520 VM_ASSERT(RUBY_VM_END_CONTROL_FRAME(ec
) >= cfp
);
1521 return (int)(RUBY_VM_END_CONTROL_FRAME(ec
) - cfp
);
1525 collect_caller_bindings_iseq(void *arg
, const rb_control_frame_t
*cfp
)
1527 struct collect_caller_bindings_data
*data
= (struct collect_caller_bindings_data
*)arg
;
1528 VALUE frame
= rb_ary_new2(6);
1530 rb_ary_store(frame
, CALLER_BINDING_SELF
, cfp
->self
);
1531 rb_ary_store(frame
, CALLER_BINDING_CLASS
, get_klass(cfp
));
1532 rb_ary_store(frame
, CALLER_BINDING_BINDING
, GC_GUARDED_PTR(cfp
)); /* create later */
1533 rb_ary_store(frame
, CALLER_BINDING_ISEQ
, cfp
->iseq
? (VALUE
)cfp
->iseq
: Qnil
);
1534 rb_ary_store(frame
, CALLER_BINDING_CFP
, GC_GUARDED_PTR(cfp
));
1535 rb_ary_store(frame
, CALLER_BINDING_DEPTH
, INT2FIX(frame_depth(data
->ec
, cfp
)));
1537 rb_ary_push(data
->ary
, frame
);
1541 collect_caller_bindings_cfunc(void *arg
, const rb_control_frame_t
*cfp
, ID mid
)
1543 struct collect_caller_bindings_data
*data
= (struct collect_caller_bindings_data
*)arg
;
1544 VALUE frame
= rb_ary_new2(6);
1546 rb_ary_store(frame
, CALLER_BINDING_SELF
, cfp
->self
);
1547 rb_ary_store(frame
, CALLER_BINDING_CLASS
, get_klass(cfp
));
1548 rb_ary_store(frame
, CALLER_BINDING_BINDING
, Qnil
); /* not available */
1549 rb_ary_store(frame
, CALLER_BINDING_ISEQ
, Qnil
); /* not available */
1550 rb_ary_store(frame
, CALLER_BINDING_CFP
, GC_GUARDED_PTR(cfp
));
1551 rb_ary_store(frame
, CALLER_BINDING_DEPTH
, INT2FIX(frame_depth(data
->ec
, cfp
)));
1553 rb_ary_push(data
->ary
, frame
);
1557 collect_caller_bindings(const rb_execution_context_t
*ec
)
1561 struct collect_caller_bindings_data data
= {
1566 collect_caller_bindings_init
,
1567 collect_caller_bindings_iseq
,
1568 collect_caller_bindings_cfunc
,
1571 result
= rb_ary_reverse(data
.ary
);
1573 /* bindings should be created from top of frame */
1574 for (i
=0; i
<RARRAY_LEN(result
); i
++) {
1575 VALUE entry
= rb_ary_entry(result
, i
);
1576 VALUE cfp_val
= rb_ary_entry(entry
, CALLER_BINDING_BINDING
);
1578 if (!NIL_P(cfp_val
)) {
1579 rb_control_frame_t
*cfp
= GC_GUARDED_PTR_REF(cfp_val
);
1580 rb_ary_store(entry
, CALLER_BINDING_BINDING
, rb_vm_make_binding(ec
, cfp
));
1588 * Note that the passed `rb_debug_inspector_t' will be disabled
1589 * after `rb_debug_inspector_open'.
1593 rb_debug_inspector_open(rb_debug_inspector_func_t func
, void *data
)
1595 rb_debug_inspector_t dbg_context
;
1596 rb_execution_context_t
*ec
= GET_EC();
1597 enum ruby_tag_type state
;
1598 volatile VALUE
MAYBE_UNUSED(result
);
1600 /* escape all env to heap */
1601 rb_vm_stack_to_heap(ec
);
1603 dbg_context
.ec
= ec
;
1604 dbg_context
.cfp
= dbg_context
.ec
->cfp
;
1605 dbg_context
.backtrace
= rb_ec_backtrace_location_ary(ec
, BACKTRACE_START
, ALL_BACKTRACE_LINES
, FALSE
);
1606 dbg_context
.backtrace_size
= RARRAY_LEN(dbg_context
.backtrace
);
1607 dbg_context
.contexts
= collect_caller_bindings(ec
);
1610 if ((state
= EC_EXEC_TAG()) == TAG_NONE
) {
1611 result
= (*func
)(&dbg_context
, data
);
1615 /* invalidate bindings? */
1618 EC_JUMP_TAG(ec
, state
);
1625 frame_get(const rb_debug_inspector_t
*dc
, long index
)
1627 if (index
< 0 || index
>= dc
->backtrace_size
) {
1628 rb_raise(rb_eArgError
, "no such frame");
1630 return rb_ary_entry(dc
->contexts
, index
);
1634 rb_debug_inspector_frame_self_get(const rb_debug_inspector_t
*dc
, long index
)
1636 VALUE frame
= frame_get(dc
, index
);
1637 return rb_ary_entry(frame
, CALLER_BINDING_SELF
);
1641 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t
*dc
, long index
)
1643 VALUE frame
= frame_get(dc
, index
);
1644 return rb_ary_entry(frame
, CALLER_BINDING_CLASS
);
1648 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t
*dc
, long index
)
1650 VALUE frame
= frame_get(dc
, index
);
1651 return rb_ary_entry(frame
, CALLER_BINDING_BINDING
);
1655 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t
*dc
, long index
)
1657 VALUE frame
= frame_get(dc
, index
);
1658 VALUE iseq
= rb_ary_entry(frame
, CALLER_BINDING_ISEQ
);
1660 return RTEST(iseq
) ? rb_iseqw_new((rb_iseq_t
*)iseq
) : Qnil
;
1664 rb_debug_inspector_frame_depth(const rb_debug_inspector_t
*dc
, long index
)
1666 VALUE frame
= frame_get(dc
, index
);
1667 return rb_ary_entry(frame
, CALLER_BINDING_DEPTH
);
1671 rb_debug_inspector_current_depth(void)
1673 rb_execution_context_t
*ec
= GET_EC();
1674 return INT2FIX(frame_depth(ec
, ec
->cfp
));
1678 rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t
*dc
)
1680 return dc
->backtrace
;
1684 thread_profile_frames(rb_execution_context_t
*ec
, int start
, int limit
, VALUE
*buff
, int *lines
)
1687 const rb_control_frame_t
*cfp
= ec
->cfp
, *end_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
1688 const rb_control_frame_t
*top
= cfp
;
1689 const rb_callable_method_entry_t
*cme
;
1691 // If this function is called inside a thread after thread creation, but
1692 // before the CFP has been created, just return 0. This can happen when
1693 // sampling via signals. Threads can be interrupted randomly by the
1694 // signal, including during the time after the thread has been created, but
1695 // before the CFP has been allocated
1700 // Skip dummy frame; see `rb_ec_partial_backtrace_object` for details
1701 end_cfp
= RUBY_VM_NEXT_CONTROL_FRAME(end_cfp
);
1703 for (i
=0; i
<limit
&& cfp
!= end_cfp
; cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
)) {
1704 if (VM_FRAME_RUBYFRAME_P(cfp
) && cfp
->pc
!= 0) {
1710 /* record frame info */
1711 cme
= rb_vm_frame_method_entry(cfp
);
1712 if (cme
&& cme
->def
->type
== VM_METHOD_TYPE_ISEQ
) {
1713 buff
[i
] = (VALUE
)cme
;
1716 buff
[i
] = (VALUE
)cfp
->iseq
;
1720 // The topmost frame may not have an updated PC because the JIT
1721 // may not have set one. The JIT compiler will update the PC
1722 // before entering a new function (so that `caller` will work),
1723 // so only the topmost frame could possibly have an out of date PC
1724 if (cfp
== top
&& cfp
->jit_return
) {
1728 lines
[i
] = calc_lineno(cfp
->iseq
, cfp
->pc
);
1735 cme
= rb_vm_frame_method_entry(cfp
);
1736 if (cme
&& cme
->def
->type
== VM_METHOD_TYPE_CFUNC
) {
1741 buff
[i
] = (VALUE
)cme
;
1742 if (lines
) lines
[i
] = 0;
1752 rb_profile_frames(int start
, int limit
, VALUE
*buff
, int *lines
)
1754 rb_execution_context_t
*ec
= rb_current_execution_context(false);
1756 // If there is no EC, we may be attempting to profile a non-Ruby thread or a
1757 // M:N shared native thread which has no active Ruby thread.
1762 return thread_profile_frames(ec
, start
, limit
, buff
, lines
);
1766 rb_profile_thread_frames(VALUE thread
, int start
, int limit
, VALUE
*buff
, int *lines
)
1768 rb_thread_t
*th
= rb_thread_ptr(thread
);
1769 return thread_profile_frames(th
->ec
, start
, limit
, buff
, lines
);
1772 static const rb_iseq_t
*
1773 frame2iseq(VALUE frame
)
1775 if (NIL_P(frame
)) return NULL
;
1777 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1778 switch (imemo_type(frame
)) {
1780 return (const rb_iseq_t
*)frame
;
1783 const rb_callable_method_entry_t
*cme
= (rb_callable_method_entry_t
*)frame
;
1784 switch (cme
->def
->type
) {
1785 case VM_METHOD_TYPE_ISEQ
:
1786 return cme
->def
->body
.iseq
.iseqptr
;
1795 rb_bug("frame2iseq: unreachable");
1799 rb_profile_frame_path(VALUE frame
)
1801 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1802 return iseq
? rb_iseq_path(iseq
) : Qnil
;
1805 static const rb_callable_method_entry_t
*
1808 if (NIL_P(frame
)) return NULL
;
1810 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1811 switch (imemo_type(frame
)) {
1814 const rb_callable_method_entry_t
*cme
= (rb_callable_method_entry_t
*)frame
;
1815 switch (cme
->def
->type
) {
1816 case VM_METHOD_TYPE_CFUNC
:
1831 rb_profile_frame_absolute_path(VALUE frame
)
1833 if (cframe(frame
)) {
1834 static VALUE cfunc_str
= Qfalse
;
1836 cfunc_str
= rb_str_new_literal("<cfunc>");
1837 rb_vm_register_global_object(cfunc_str
);
1841 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1842 return iseq
? rb_iseq_realpath(iseq
) : Qnil
;
1846 rb_profile_frame_label(VALUE frame
)
1848 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1849 return iseq
? rb_iseq_label(iseq
) : Qnil
;
1853 rb_profile_frame_base_label(VALUE frame
)
1855 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1856 return iseq
? rb_iseq_base_label(iseq
) : Qnil
;
1860 rb_profile_frame_first_lineno(VALUE frame
)
1862 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1863 return iseq
? rb_iseq_first_lineno(iseq
) : Qnil
;
1867 frame2klass(VALUE frame
)
1869 if (NIL_P(frame
)) return Qnil
;
1871 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1872 const rb_callable_method_entry_t
*cme
= (rb_callable_method_entry_t
*)frame
;
1874 if (imemo_type(frame
) == imemo_ment
) {
1875 return cme
->defined_class
;
1882 rb_profile_frame_classpath(VALUE frame
)
1884 VALUE klass
= frame2klass(frame
);
1886 if (klass
&& !NIL_P(klass
)) {
1887 if (RB_TYPE_P(klass
, T_ICLASS
)) {
1888 klass
= RBASIC(klass
)->klass
;
1890 else if (RCLASS_SINGLETON_P(klass
)) {
1891 klass
= RCLASS_ATTACHED_OBJECT(klass
);
1892 if (!RB_TYPE_P(klass
, T_CLASS
) && !RB_TYPE_P(klass
, T_MODULE
))
1893 return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass
)), (void*)klass
);
1895 return rb_class_path(klass
);
1903 rb_profile_frame_singleton_method_p(VALUE frame
)
1905 VALUE klass
= frame2klass(frame
);
1907 return RBOOL(klass
&& !NIL_P(klass
) && RCLASS_SINGLETON_P(klass
));
1911 rb_profile_frame_method_name(VALUE frame
)
1913 const rb_callable_method_entry_t
*cme
= cframe(frame
);
1915 ID mid
= cme
->def
->original_id
;
1918 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1919 return iseq
? rb_iseq_method_name(iseq
) : Qnil
;
1923 qualified_method_name(VALUE frame
, VALUE method_name
)
1925 if (method_name
!= Qnil
) {
1926 VALUE classpath
= rb_profile_frame_classpath(frame
);
1927 VALUE singleton_p
= rb_profile_frame_singleton_method_p(frame
);
1929 if (classpath
!= Qnil
) {
1930 return rb_sprintf("%"PRIsVALUE
"%s%"PRIsVALUE
,
1931 classpath
, singleton_p
== Qtrue
? "." : "#", method_name
);
1943 rb_profile_frame_qualified_method_name(VALUE frame
)
1945 VALUE method_name
= rb_profile_frame_method_name(frame
);
1947 return qualified_method_name(frame
, method_name
);
1951 rb_profile_frame_full_label(VALUE frame
)
1953 const rb_callable_method_entry_t
*cme
= cframe(frame
);
1955 ID mid
= cme
->def
->original_id
;
1956 VALUE method_name
= id2str(mid
);
1957 return qualified_method_name(frame
, method_name
);
1960 VALUE label
= rb_profile_frame_label(frame
);
1961 VALUE base_label
= rb_profile_frame_base_label(frame
);
1962 VALUE qualified_method_name
= rb_profile_frame_qualified_method_name(frame
);
1964 if (NIL_P(qualified_method_name
) || base_label
== qualified_method_name
) {
1968 long label_length
= RSTRING_LEN(label
);
1969 long base_label_length
= RSTRING_LEN(base_label
);
1970 int prefix_len
= rb_long2int(label_length
- base_label_length
);
1972 return rb_sprintf("%.*s%"PRIsVALUE
, prefix_len
, RSTRING_PTR(label
), qualified_method_name
);