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/error.h"
15 #include "internal/vm.h"
17 #include "ruby/debug.h"
18 #include "ruby/encoding.h"
21 static VALUE rb_cBacktrace
;
22 static VALUE rb_cBacktraceLocation
;
27 VALUE str
= rb_id2str(id
);
28 if (!str
) return Qnil
;
31 #define rb_id2str(id) id2str(id)
33 #define BACKTRACE_START 0
34 #define ALL_BACKTRACE_LINES -1
37 calc_pos(const rb_iseq_t
*iseq
, const VALUE
*pc
, int *lineno
, int *node_id
)
40 VM_ASSERT(iseq
->body
);
41 VM_ASSERT(iseq
->body
->iseq_encoded
);
42 VM_ASSERT(iseq
->body
->iseq_size
);
44 if (iseq
->body
->type
== ISEQ_TYPE_TOP
) {
45 VM_ASSERT(! iseq
->body
->local_table
);
46 VM_ASSERT(! iseq
->body
->local_table_size
);
49 if (lineno
) *lineno
= FIX2INT(iseq
->body
->location
.first_lineno
);
50 #ifdef USE_ISEQ_NODE_ID
51 if (node_id
) *node_id
= -1;
56 ptrdiff_t n
= pc
- iseq
->body
->iseq_encoded
;
57 VM_ASSERT(n
<= iseq
->body
->iseq_size
);
60 size_t pos
= n
; /* no overflow */
62 /* use pos-1 because PC points next instruction at the beginning of instruction */
65 #if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
67 /* SDR() is not possible; that causes infinite loop. */
72 if (lineno
) *lineno
= rb_iseq_line_no(iseq
, pos
);
73 #ifdef USE_ISEQ_NODE_ID
74 if (node_id
) *node_id
= rb_iseq_node_id(iseq
, pos
);
81 calc_lineno(const rb_iseq_t
*iseq
, const VALUE
*pc
)
84 if (calc_pos(iseq
, pc
, &lineno
, NULL
)) return lineno
;
88 #ifdef USE_ISEQ_NODE_ID
90 calc_node_id(const rb_iseq_t
*iseq
, const VALUE
*pc
)
93 if (calc_pos(iseq
, pc
, NULL
, &node_id
)) return node_id
;
99 rb_vm_get_sourceline(const rb_control_frame_t
*cfp
)
101 if (VM_FRAME_RUBYFRAME_P(cfp
) && cfp
->iseq
) {
102 const rb_iseq_t
*iseq
= cfp
->iseq
;
103 int line
= calc_lineno(iseq
, cfp
->pc
);
108 return FIX2INT(rb_iseq_first_lineno(iseq
));
116 typedef struct rb_backtrace_location_struct
{
118 LOCATION_TYPE_ISEQ
= 1,
122 const rb_iseq_t
*iseq
;
125 } rb_backtrace_location_t
;
127 struct valued_frame_info
{
128 rb_backtrace_location_t
*loc
;
133 location_mark(void *ptr
)
135 struct valued_frame_info
*vfi
= (struct valued_frame_info
*)ptr
;
136 rb_gc_mark(vfi
->btobj
);
140 location_mark_entry(rb_backtrace_location_t
*fi
)
143 case LOCATION_TYPE_ISEQ
:
144 rb_gc_mark_movable((VALUE
)fi
->iseq
);
146 case LOCATION_TYPE_CFUNC
:
148 rb_gc_mark_movable((VALUE
)fi
->iseq
);
157 location_memsize(const void *ptr
)
159 /* rb_backtrace_location_t *fi = (rb_backtrace_location_t *)ptr; */
160 return sizeof(rb_backtrace_location_t
);
163 static const rb_data_type_t location_data_type
= {
165 {location_mark
, RUBY_TYPED_DEFAULT_FREE
, location_memsize
,},
166 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
170 rb_frame_info_p(VALUE obj
)
172 return rb_typeddata_is_kind_of(obj
, &location_data_type
);
175 static inline rb_backtrace_location_t
*
176 location_ptr(VALUE locobj
)
178 struct valued_frame_info
*vloc
;
179 GetCoreDataFromValue(locobj
, struct valued_frame_info
, vloc
);
184 location_lineno(rb_backtrace_location_t
*loc
)
187 case LOCATION_TYPE_ISEQ
:
188 return calc_lineno(loc
->iseq
, loc
->pc
);
189 case LOCATION_TYPE_CFUNC
:
190 if (loc
->iseq
&& loc
->pc
) {
191 return calc_lineno(loc
->iseq
, loc
->pc
);
195 rb_bug("location_lineno: unreachable");
201 * Returns the line number of this frame.
203 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
205 * loc = c(0..1).first
209 location_lineno_m(VALUE self
)
211 return INT2FIX(location_lineno(location_ptr(self
)));
215 location_label(rb_backtrace_location_t
*loc
)
218 case LOCATION_TYPE_ISEQ
:
219 return loc
->iseq
->body
->location
.label
;
220 case LOCATION_TYPE_CFUNC
:
221 return rb_id2str(loc
->mid
);
223 rb_bug("location_label: unreachable");
229 * Returns the label of this frame.
231 * Usually consists of method, class, module, etc names with decoration.
233 * Consider the following example:
236 * puts caller_locations(0).first.label
239 * puts caller_locations(0).first.label
242 * puts caller_locations(0).first.label
248 * The result of calling +foo+ is this:
251 * label: block in foo
252 * label: block (2 levels) in foo
256 location_label_m(VALUE self
)
258 return location_label(location_ptr(self
));
262 location_base_label(rb_backtrace_location_t
*loc
)
265 case LOCATION_TYPE_ISEQ
:
266 return loc
->iseq
->body
->location
.base_label
;
267 case LOCATION_TYPE_CFUNC
:
268 return rb_id2str(loc
->mid
);
270 rb_bug("location_base_label: unreachable");
276 * Returns the base label of this frame.
278 * Usually same as #label, without decoration.
281 location_base_label_m(VALUE self
)
283 return location_base_label(location_ptr(self
));
286 static const rb_iseq_t
*
287 location_iseq(rb_backtrace_location_t
*loc
)
290 case LOCATION_TYPE_ISEQ
:
292 case LOCATION_TYPE_CFUNC
:
295 rb_bug("location_iseq: unreachable");
301 * Returns the file name of this frame. This will generally be an absolute
302 * path, unless the frame is in the main script, in which case it will be the
303 * script location passed on the command line.
305 * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
307 * loc = c(0..1).first
308 * loc.path #=> caller_locations.rb
311 location_path_m(VALUE self
)
313 const rb_iseq_t
*iseq
= location_iseq(location_ptr(self
));
314 return iseq
? rb_iseq_path(iseq
) : Qnil
;
317 #ifdef USE_ISEQ_NODE_ID
319 location_node_id(rb_backtrace_location_t
*loc
)
322 case LOCATION_TYPE_ISEQ
:
323 return calc_node_id(loc
->iseq
, loc
->pc
);
324 case LOCATION_TYPE_CFUNC
:
325 if (loc
->iseq
&& loc
->pc
) {
326 return calc_node_id(loc
->iseq
, loc
->pc
);
330 rb_bug("location_node_id: unreachable");
337 rb_get_node_id_from_frame_info(VALUE obj
)
339 #ifdef USE_ISEQ_NODE_ID
340 rb_backtrace_location_t
*loc
= location_ptr(obj
);
341 return location_node_id(loc
);
348 rb_get_iseq_from_frame_info(VALUE obj
)
350 rb_backtrace_location_t
*loc
= location_ptr(obj
);
351 const rb_iseq_t
*iseq
= location_iseq(loc
);
356 location_realpath(rb_backtrace_location_t
*loc
)
359 case LOCATION_TYPE_ISEQ
:
360 return rb_iseq_realpath(loc
->iseq
);
361 case LOCATION_TYPE_CFUNC
:
363 return rb_iseq_realpath(loc
->iseq
);
367 rb_bug("location_realpath: unreachable");
373 * Returns the full file path of this frame.
375 * Same as #path, except that it will return absolute path
376 * even if the frame is in the main script.
379 location_absolute_path_m(VALUE self
)
381 return location_realpath(location_ptr(self
));
385 location_format(VALUE file
, int lineno
, VALUE name
)
387 VALUE s
= rb_enc_sprintf(rb_enc_compatible(file
, name
), "%s", RSTRING_PTR(file
));
389 rb_str_catf(s
, ":%d", lineno
);
391 rb_str_cat_cstr(s
, ":in ");
393 rb_str_cat_cstr(s
, "unknown method");
396 rb_str_catf(s
, "`%s'", RSTRING_PTR(name
));
402 location_to_str(rb_backtrace_location_t
*loc
)
408 case LOCATION_TYPE_ISEQ
:
409 file
= rb_iseq_path(loc
->iseq
);
410 name
= loc
->iseq
->body
->location
.label
;
412 lineno
= calc_lineno(loc
->iseq
, loc
->pc
);
414 case LOCATION_TYPE_CFUNC
:
415 if (loc
->iseq
&& loc
->pc
) {
416 file
= rb_iseq_path(loc
->iseq
);
417 lineno
= calc_lineno(loc
->iseq
, loc
->pc
);
420 file
= GET_VM()->progname
;
423 name
= rb_id2str(loc
->mid
);
426 rb_bug("location_to_str: unreachable");
429 return location_format(file
, lineno
, name
);
433 * Returns a Kernel#caller style string representing this frame.
436 location_to_str_m(VALUE self
)
438 return location_to_str(location_ptr(self
));
442 * Returns the same as calling +inspect+ on the string representation of
446 location_inspect_m(VALUE self
)
448 return rb_str_inspect(location_to_str(location_ptr(self
)));
451 typedef struct rb_backtrace_struct
{
452 rb_backtrace_location_t
*backtrace
;
459 backtrace_mark(void *ptr
)
461 rb_backtrace_t
*bt
= (rb_backtrace_t
*)ptr
;
462 size_t i
, s
= bt
->backtrace_size
;
464 for (i
=0; i
<s
; i
++) {
465 location_mark_entry(&bt
->backtrace
[i
]);
467 rb_gc_mark_movable(bt
->strary
);
468 rb_gc_mark_movable(bt
->locary
);
472 backtrace_free(void *ptr
)
474 rb_backtrace_t
*bt
= (rb_backtrace_t
*)ptr
;
475 if (bt
->backtrace
) ruby_xfree(bt
->backtrace
);
480 location_update_entry(rb_backtrace_location_t
*fi
)
483 case LOCATION_TYPE_ISEQ
:
484 fi
->iseq
= (rb_iseq_t
*)rb_gc_location((VALUE
)fi
->iseq
);
486 case LOCATION_TYPE_CFUNC
:
488 fi
->iseq
= (rb_iseq_t
*)rb_gc_location((VALUE
)fi
->iseq
);
497 backtrace_update(void *ptr
)
499 rb_backtrace_t
*bt
= (rb_backtrace_t
*)ptr
;
500 size_t i
, s
= bt
->backtrace_size
;
502 for (i
=0; i
<s
; i
++) {
503 location_update_entry(&bt
->backtrace
[i
]);
505 bt
->strary
= rb_gc_location(bt
->strary
);
506 bt
->locary
= rb_gc_location(bt
->locary
);
510 backtrace_memsize(const void *ptr
)
512 rb_backtrace_t
*bt
= (rb_backtrace_t
*)ptr
;
513 return sizeof(rb_backtrace_t
) + sizeof(rb_backtrace_location_t
) * bt
->backtrace_size
;
516 static const rb_data_type_t backtrace_data_type
= {
518 {backtrace_mark
, backtrace_free
, backtrace_memsize
, backtrace_update
},
519 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
523 rb_backtrace_p(VALUE obj
)
525 return rb_typeddata_is_kind_of(obj
, &backtrace_data_type
);
529 backtrace_alloc(VALUE klass
)
532 VALUE obj
= TypedData_Make_Struct(klass
, rb_backtrace_t
, &backtrace_data_type
, bt
);
537 backtrace_size(const rb_execution_context_t
*ec
)
539 const rb_control_frame_t
*last_cfp
= ec
->cfp
;
540 const rb_control_frame_t
*start_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
542 if (start_cfp
== NULL
) {
547 RUBY_VM_NEXT_CONTROL_FRAME(
548 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp
)); /* skip top frames */
550 if (start_cfp
< last_cfp
) {
554 return start_cfp
- last_cfp
+ 1;
558 is_internal_location(const rb_control_frame_t
*cfp
)
560 static const char prefix
[] = "<internal:";
561 const size_t prefix_len
= sizeof(prefix
) - 1;
562 VALUE file
= rb_iseq_path(cfp
->iseq
);
563 return strncmp(prefix
, RSTRING_PTR(file
), prefix_len
) == 0;
567 bt_update_cfunc_loc(unsigned long cfunc_counter
, rb_backtrace_location_t
*cfunc_loc
, const rb_iseq_t
*iseq
, const VALUE
*pc
)
569 for (; cfunc_counter
> 0; cfunc_counter
--, cfunc_loc
--) {
570 cfunc_loc
->iseq
= iseq
;
576 rb_ec_partial_backtrace_object(const rb_execution_context_t
*ec
, long start_frame
, long num_frames
, int* start_too_large
, bool skip_internal
)
578 const rb_control_frame_t
*cfp
= ec
->cfp
;
579 const rb_control_frame_t
*end_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
582 VALUE btobj
= backtrace_alloc(rb_cBacktrace
);
583 rb_backtrace_location_t
*loc
;
584 unsigned long cfunc_counter
= 0;
585 GetCoreDataFromValue(btobj
, rb_backtrace_t
, bt
);
587 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
588 if (end_cfp
== NULL
) {
592 end_cfp
= RUBY_VM_NEXT_CONTROL_FRAME(end_cfp
);
595 * top frame (dummy) <- RUBY_VM_END_CONTROL_FRAME
596 * top frame (dummy) <- end_cfp
597 * top frame <- main script
601 * current frame <- ec->cfp
604 size
= end_cfp
- cfp
+ 1;
608 else if (num_frames
< 0 || num_frames
> size
) {
613 bt
->backtrace
= ZALLOC_N(rb_backtrace_location_t
, num_frames
);
614 bt
->backtrace_size
= 0;
615 if (num_frames
== 0) {
616 if (start_too_large
) *start_too_large
= 0;
620 for (; cfp
!= end_cfp
&& (bt
->backtrace_size
< num_frames
); cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
)) {
623 if (start_frame
> 0) {
626 else if (!skip_internal
|| !is_internal_location(cfp
)) {
627 const rb_iseq_t
*iseq
= cfp
->iseq
;
628 const VALUE
*pc
= cfp
->pc
;
629 loc
= &bt
->backtrace
[bt
->backtrace_size
++];
630 loc
->type
= LOCATION_TYPE_ISEQ
;
633 bt_update_cfunc_loc(cfunc_counter
, loc
-1, iseq
, pc
);
638 else if (RUBYVM_CFUNC_FRAME_P(cfp
)) {
639 if (start_frame
> 0) {
643 loc
= &bt
->backtrace
[bt
->backtrace_size
++];
644 loc
->type
= LOCATION_TYPE_CFUNC
;
647 loc
->mid
= rb_vm_frame_method_entry(cfp
)->def
->original_id
;
653 if (cfunc_counter
> 0) {
654 for (; cfp
!= end_cfp
; cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
)) {
655 if (cfp
->iseq
&& cfp
->pc
&& (!skip_internal
|| !is_internal_location(cfp
))) {
656 bt_update_cfunc_loc(cfunc_counter
, loc
, cfp
->iseq
, cfp
->pc
);
662 if (start_too_large
) *start_too_large
= (start_frame
> 0 ? -1 : 0);
666 MJIT_FUNC_EXPORTED VALUE
667 rb_ec_backtrace_object(const rb_execution_context_t
*ec
)
669 return rb_ec_partial_backtrace_object(ec
, BACKTRACE_START
, ALL_BACKTRACE_LINES
, NULL
, FALSE
);
673 backtrace_collect(rb_backtrace_t
*bt
, VALUE (*func
)(rb_backtrace_location_t
*, void *arg
), void *arg
)
678 btary
= rb_ary_new2(bt
->backtrace_size
);
680 for (i
=0; i
<bt
->backtrace_size
; i
++) {
681 rb_backtrace_location_t
*loc
= &bt
->backtrace
[i
];
682 rb_ary_push(btary
, func(loc
, arg
));
689 location_to_str_dmyarg(rb_backtrace_location_t
*loc
, void *dmy
)
691 return location_to_str(loc
);
695 backtrace_to_str_ary(VALUE self
)
699 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
700 r
= backtrace_collect(bt
, location_to_str_dmyarg
, 0);
706 rb_backtrace_to_str_ary(VALUE self
)
709 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
712 bt
->strary
= backtrace_to_str_ary(self
);
717 MJIT_FUNC_EXPORTED
void
718 rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self
)
720 const rb_backtrace_t
*bt
;
721 rb_backtrace_location_t
*loc
;
723 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
724 VM_ASSERT(bt
->backtrace_size
> 0);
726 loc
= &bt
->backtrace
[0];
728 VM_ASSERT(loc
->type
== LOCATION_TYPE_ISEQ
);
730 loc
->pc
= NULL
; // means location.first_lineno
734 location_create(rb_backtrace_location_t
*srcloc
, void *btobj
)
737 struct valued_frame_info
*vloc
;
738 obj
= TypedData_Make_Struct(rb_cBacktraceLocation
, struct valued_frame_info
, &location_data_type
, vloc
);
741 vloc
->btobj
= (VALUE
)btobj
;
747 backtrace_to_location_ary(VALUE self
)
751 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
752 r
= backtrace_collect(bt
, location_create
, (void *)self
);
758 rb_backtrace_to_location_ary(VALUE self
)
761 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
764 bt
->locary
= backtrace_to_location_ary(self
);
770 backtrace_dump_data(VALUE self
)
772 VALUE str
= rb_backtrace_to_str_ary(self
);
777 backtrace_load_data(VALUE self
, VALUE str
)
780 GetCoreDataFromValue(self
, rb_backtrace_t
, bt
);
786 * call-seq: Threade::Backtrace::limit -> integer
788 * Returns maximum backtrace length set by <tt>--backtrace-limit</tt>
789 * command-line option. The defalt is <tt>-1</tt> which means unlimited
790 * backtraces. If the value is zero or positive, the error backtraces,
791 * produced by Exception#full_message, are abbreviated and the extra lines
792 * are replaced by <tt>... 3 levels... </tt>
794 * $ ruby -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
796 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': Failed to open TCP connection to wrong.address:80 (getaddrinfo: Name or service not known) (SocketError)
797 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
798 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
799 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
800 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
801 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
802 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
803 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
804 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
805 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
806 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
807 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
808 * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
809 * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
810 * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
811 * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
812 * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
813 * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
814 * from -e:1:in `<main>'
816 * $ ruby --backtrace-limit 2 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
818 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': Failed to open TCP connection to wrong.address:80 (getaddrinfo: Name or service not known) (SocketError)
819 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
820 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
822 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
823 * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
824 * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
827 * $ ruby --backtrace-limit 0 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
829 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': Failed to open TCP connection to wrong.address:80 (getaddrinfo: Name or service not known) (SocketError)
831 * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
836 backtrace_limit(VALUE self
)
838 return LONG2NUM(rb_backtrace_length_limit
);
842 rb_ec_backtrace_str_ary(const rb_execution_context_t
*ec
, long lev
, long n
)
844 return backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec
, lev
, n
, NULL
, FALSE
));
848 rb_ec_backtrace_location_ary(const rb_execution_context_t
*ec
, long lev
, long n
, bool skip_internal
)
850 return backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec
, lev
, n
, NULL
, skip_internal
));
853 /* make old style backtrace directly */
856 backtrace_each(const rb_execution_context_t
*ec
,
857 void (*init
)(void *arg
, size_t size
),
858 void (*iter_iseq
)(void *arg
, const rb_control_frame_t
*cfp
),
859 void (*iter_cfunc
)(void *arg
, const rb_control_frame_t
*cfp
, ID mid
),
862 const rb_control_frame_t
*last_cfp
= ec
->cfp
;
863 const rb_control_frame_t
*start_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
864 const rb_control_frame_t
*cfp
;
867 // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
868 if (start_cfp
== NULL
) {
873 /* <- start_cfp (end control frame)
876 * top frame <- start_cfp
880 * current frame <- ec->cfp
884 RUBY_VM_NEXT_CONTROL_FRAME(
885 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp
)); /* skip top frames */
887 if (start_cfp
< last_cfp
) {
891 size
= start_cfp
- last_cfp
+ 1;
897 for (i
=0, cfp
= start_cfp
; i
<size
; i
++, cfp
= RUBY_VM_NEXT_CONTROL_FRAME(cfp
)) {
898 /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
904 else if (RUBYVM_CFUNC_FRAME_P(cfp
)) {
905 const rb_callable_method_entry_t
*me
= rb_vm_frame_method_entry(cfp
);
906 ID mid
= me
->def
->original_id
;
908 iter_cfunc(arg
, cfp
, mid
);
916 void (*func
)(void *data
, VALUE file
, int lineno
, VALUE name
);
917 void *data
; /* result */
921 oldbt_init(void *ptr
, size_t dmy
)
923 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
924 arg
->filename
= GET_VM()->progname
;
929 oldbt_iter_iseq(void *ptr
, const rb_control_frame_t
*cfp
)
931 const rb_iseq_t
*iseq
= cfp
->iseq
;
932 const VALUE
*pc
= cfp
->pc
;
933 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
934 VALUE file
= arg
->filename
= rb_iseq_path(iseq
);
935 VALUE name
= iseq
->body
->location
.label
;
936 int lineno
= arg
->lineno
= calc_lineno(iseq
, pc
);
938 (arg
->func
)(arg
->data
, file
, lineno
, name
);
942 oldbt_iter_cfunc(void *ptr
, const rb_control_frame_t
*cfp
, ID mid
)
944 struct oldbt_arg
*arg
= (struct oldbt_arg
*)ptr
;
945 VALUE file
= arg
->filename
;
946 VALUE name
= rb_id2str(mid
);
947 int lineno
= arg
->lineno
;
949 (arg
->func
)(arg
->data
, file
, lineno
, name
);
953 oldbt_print(void *data
, VALUE file
, int lineno
, VALUE name
)
955 FILE *fp
= (FILE *)data
;
958 fprintf(fp
, "\tfrom %s:%d:in unknown method\n",
959 RSTRING_PTR(file
), lineno
);
962 fprintf(fp
, "\tfrom %s:%d:in `%s'\n",
963 RSTRING_PTR(file
), lineno
, RSTRING_PTR(name
));
968 vm_backtrace_print(FILE *fp
)
970 struct oldbt_arg arg
;
972 arg
.func
= oldbt_print
;
973 arg
.data
= (void *)fp
;
974 backtrace_each(GET_EC(),
982 oldbt_bugreport(void *arg
, VALUE file
, int line
, VALUE method
)
984 const char *filename
= NIL_P(file
) ? "ruby" : RSTRING_PTR(file
);
986 fprintf(stderr
, "-- Ruby level backtrace information "
987 "----------------------------------------\n");
991 fprintf(stderr
, "%s:%d:in unknown method\n", filename
, line
);
994 fprintf(stderr
, "%s:%d:in `%s'\n", filename
, line
, RSTRING_PTR(method
));
999 rb_backtrace_print_as_bugreport(void)
1001 struct oldbt_arg arg
;
1004 arg
.func
= oldbt_bugreport
;
1005 arg
.data
= (int *)&i
;
1007 backtrace_each(GET_EC(),
1017 vm_backtrace_print(stderr
);
1020 struct print_to_arg
{
1021 VALUE (*iter
)(VALUE recv
, VALUE str
);
1026 oldbt_print_to(void *data
, VALUE file
, int lineno
, VALUE name
)
1028 const struct print_to_arg
*arg
= data
;
1029 VALUE str
= rb_sprintf("\tfrom %"PRIsVALUE
":%d:in ", file
, lineno
);
1032 rb_str_cat2(str
, "unknown method\n");
1035 rb_str_catf(str
, " `%"PRIsVALUE
"'\n", name
);
1037 (*arg
->iter
)(arg
->output
, str
);
1041 rb_backtrace_each(VALUE (*iter
)(VALUE recv
, VALUE str
), VALUE output
)
1043 struct oldbt_arg arg
;
1044 struct print_to_arg parg
;
1047 parg
.output
= output
;
1048 arg
.func
= oldbt_print_to
;
1050 backtrace_each(GET_EC(),
1058 rb_make_backtrace(void)
1060 return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START
, ALL_BACKTRACE_LINES
);
1064 ec_backtrace_to_ary(const rb_execution_context_t
*ec
, int argc
, const VALUE
*argv
, int lev_default
, int lev_plus
, int to_str
)
1072 rb_scan_args(argc
, argv
, "02", &level
, &vn
);
1074 if (argc
== 2 && NIL_P(vn
)) argc
--;
1078 lev
= lev_default
+ lev_plus
;
1079 n
= ALL_BACKTRACE_LINES
;
1083 long beg
, len
, bt_size
= backtrace_size(ec
);
1084 switch (rb_range_beg_len(level
, &beg
, &len
, bt_size
- lev_plus
, 0)) {
1086 lev
= NUM2LONG(level
);
1088 rb_raise(rb_eArgError
, "negative level (%ld)", lev
);
1091 n
= ALL_BACKTRACE_LINES
;
1096 lev
= beg
+ lev_plus
;
1103 lev
= NUM2LONG(level
);
1106 rb_raise(rb_eArgError
, "negative level (%ld)", lev
);
1109 rb_raise(rb_eArgError
, "negative size (%ld)", n
);
1114 lev
= n
= 0; /* to avoid warning */
1119 return rb_ary_new();
1122 btval
= rb_ec_partial_backtrace_object(ec
, lev
, n
, &too_large
, FALSE
);
1129 r
= backtrace_to_str_ary(btval
);
1132 r
= backtrace_to_location_ary(btval
);
1139 thread_backtrace_to_ary(int argc
, const VALUE
*argv
, VALUE thval
, int to_str
)
1141 rb_thread_t
*target_th
= rb_thread_ptr(thval
);
1143 if (target_th
->to_kill
|| target_th
->status
== THREAD_KILLED
)
1146 return ec_backtrace_to_ary(target_th
->ec
, argc
, argv
, 0, 0, to_str
);
1150 rb_vm_thread_backtrace(int argc
, const VALUE
*argv
, VALUE thval
)
1152 return thread_backtrace_to_ary(argc
, argv
, thval
, 1);
1156 rb_vm_thread_backtrace_locations(int argc
, const VALUE
*argv
, VALUE thval
)
1158 return thread_backtrace_to_ary(argc
, argv
, thval
, 0);
1161 VALUE
rb_vm_backtrace(int argc
, const VALUE
* argv
, struct rb_execution_context_struct
* ec
)
1163 return ec_backtrace_to_ary(ec
, argc
, argv
, 0, 0, 1);
1166 VALUE
rb_vm_backtrace_locations(int argc
, const VALUE
* argv
, struct rb_execution_context_struct
* ec
)
1168 return ec_backtrace_to_ary(ec
, argc
, argv
, 0, 0, 0);
1173 * caller(start=1, length=nil) -> array or nil
1174 * caller(range) -> array or nil
1176 * Returns the current execution stack---an array containing strings in
1177 * the form <code>file:line</code> or <code>file:line: in
1180 * The optional _start_ parameter determines the number of initial stack
1181 * entries to omit from the top of the stack.
1183 * A second optional +length+ parameter can be used to limit how many entries
1184 * are returned from the stack.
1186 * Returns +nil+ if _start_ is greater than the size of
1187 * current execution stack.
1189 * Optionally you can pass a range, which will return an array containing the
1190 * entries within the specified range.
1201 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1202 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1203 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1204 * c(3) #=> ["prog:13:in `<main>'"]
1210 rb_f_caller(int argc
, VALUE
*argv
, VALUE _
)
1212 return ec_backtrace_to_ary(GET_EC(), argc
, argv
, 1, 1, 1);
1217 * caller_locations(start=1, length=nil) -> array or nil
1218 * caller_locations(range) -> array or nil
1220 * Returns the current execution stack---an array containing
1221 * backtrace location objects.
1223 * See Thread::Backtrace::Location for more information.
1225 * The optional _start_ parameter determines the number of initial stack
1226 * entries to omit from the top of the stack.
1228 * A second optional +length+ parameter can be used to limit how many entries
1229 * are returned from the stack.
1231 * Returns +nil+ if _start_ is greater than the size of
1232 * current execution stack.
1234 * Optionally you can pass a range, which will return an array containing the
1235 * entries within the specified range.
1238 rb_f_caller_locations(int argc
, VALUE
*argv
, VALUE _
)
1240 return ec_backtrace_to_ary(GET_EC(), argc
, argv
, 1, 1, 0);
1243 /* called from Init_vm() in vm.c */
1245 Init_vm_backtrace(void)
1248 * An internal representation of the backtrace. The user will never interact with
1249 * objects of this class directly, but class methods can be used to get backtrace
1250 * settings of the current session.
1252 rb_cBacktrace
= rb_define_class_under(rb_cThread
, "Backtrace", rb_cObject
);
1253 rb_define_alloc_func(rb_cBacktrace
, backtrace_alloc
);
1254 rb_undef_method(CLASS_OF(rb_cBacktrace
), "new");
1255 rb_marshal_define_compat(rb_cBacktrace
, rb_cArray
, backtrace_dump_data
, backtrace_load_data
);
1256 rb_define_singleton_method(rb_cBacktrace
, "limit", backtrace_limit
, 0);
1259 * An object representation of a stack frame, initialized by
1260 * Kernel#caller_locations.
1264 * # caller_locations.rb
1266 * caller_locations(skip)
1275 * c(0..2).map do |call|
1279 * Running <code>ruby caller_locations.rb</code> will produce:
1281 * caller_locations.rb:2:in `a'
1282 * caller_locations.rb:5:in `b'
1283 * caller_locations.rb:8:in `c'
1285 * Here's another example with a slightly different result:
1289 * attr_accessor :locations
1290 * def initialize(skip)
1291 * @locations = caller_locations(skip)
1295 * Foo.new(0..2).locations.map do |call|
1299 * Now run <code>ruby foo.rb</code> and you should see:
1301 * init.rb:4:in `initialize'
1302 * init.rb:8:in `new'
1303 * init.rb:8:in `<main>'
1305 rb_cBacktraceLocation
= rb_define_class_under(rb_cBacktrace
, "Location", rb_cObject
);
1306 rb_undef_alloc_func(rb_cBacktraceLocation
);
1307 rb_undef_method(CLASS_OF(rb_cBacktraceLocation
), "new");
1308 rb_define_method(rb_cBacktraceLocation
, "lineno", location_lineno_m
, 0);
1309 rb_define_method(rb_cBacktraceLocation
, "label", location_label_m
, 0);
1310 rb_define_method(rb_cBacktraceLocation
, "base_label", location_base_label_m
, 0);
1311 rb_define_method(rb_cBacktraceLocation
, "path", location_path_m
, 0);
1312 rb_define_method(rb_cBacktraceLocation
, "absolute_path", location_absolute_path_m
, 0);
1313 rb_define_method(rb_cBacktraceLocation
, "to_s", location_to_str_m
, 0);
1314 rb_define_method(rb_cBacktraceLocation
, "inspect", location_inspect_m
, 0);
1316 rb_define_global_function("caller", rb_f_caller
, -1);
1317 rb_define_global_function("caller_locations", rb_f_caller_locations
, -1);
1322 RUBY_SYMBOL_EXPORT_BEGIN
1324 RUBY_SYMBOL_EXPORT_END
1326 struct rb_debug_inspector_struct
{
1327 rb_execution_context_t
*ec
;
1328 rb_control_frame_t
*cfp
;
1330 VALUE contexts
; /* [[klass, binding, iseq, cfp], ...] */
1331 long backtrace_size
;
1335 CALLER_BINDING_SELF
,
1336 CALLER_BINDING_CLASS
,
1337 CALLER_BINDING_BINDING
,
1338 CALLER_BINDING_ISEQ
,
1342 struct collect_caller_bindings_data
{
1347 collect_caller_bindings_init(void *arg
, size_t size
)
1353 get_klass(const rb_control_frame_t
*cfp
)
1356 if (rb_vm_control_frame_id_and_class(cfp
, 0, 0, &klass
)) {
1357 if (RB_TYPE_P(klass
, T_ICLASS
)) {
1358 return RBASIC(klass
)->klass
;
1370 collect_caller_bindings_iseq(void *arg
, const rb_control_frame_t
*cfp
)
1372 struct collect_caller_bindings_data
*data
= (struct collect_caller_bindings_data
*)arg
;
1373 VALUE frame
= rb_ary_new2(5);
1375 rb_ary_store(frame
, CALLER_BINDING_SELF
, cfp
->self
);
1376 rb_ary_store(frame
, CALLER_BINDING_CLASS
, get_klass(cfp
));
1377 rb_ary_store(frame
, CALLER_BINDING_BINDING
, GC_GUARDED_PTR(cfp
)); /* create later */
1378 rb_ary_store(frame
, CALLER_BINDING_ISEQ
, cfp
->iseq
? (VALUE
)cfp
->iseq
: Qnil
);
1379 rb_ary_store(frame
, CALLER_BINDING_CFP
, GC_GUARDED_PTR(cfp
));
1381 rb_ary_push(data
->ary
, frame
);
1385 collect_caller_bindings_cfunc(void *arg
, const rb_control_frame_t
*cfp
, ID mid
)
1387 struct collect_caller_bindings_data
*data
= (struct collect_caller_bindings_data
*)arg
;
1388 VALUE frame
= rb_ary_new2(5);
1390 rb_ary_store(frame
, CALLER_BINDING_SELF
, cfp
->self
);
1391 rb_ary_store(frame
, CALLER_BINDING_CLASS
, get_klass(cfp
));
1392 rb_ary_store(frame
, CALLER_BINDING_BINDING
, Qnil
); /* not available */
1393 rb_ary_store(frame
, CALLER_BINDING_ISEQ
, Qnil
); /* not available */
1394 rb_ary_store(frame
, CALLER_BINDING_CFP
, GC_GUARDED_PTR(cfp
));
1396 rb_ary_push(data
->ary
, frame
);
1400 collect_caller_bindings(const rb_execution_context_t
*ec
)
1402 struct collect_caller_bindings_data data
;
1406 data
.ary
= rb_ary_new();
1409 collect_caller_bindings_init
,
1410 collect_caller_bindings_iseq
,
1411 collect_caller_bindings_cfunc
,
1414 result
= rb_ary_reverse(data
.ary
);
1416 /* bindings should be created from top of frame */
1417 for (i
=0; i
<RARRAY_LEN(result
); i
++) {
1418 VALUE entry
= rb_ary_entry(result
, i
);
1419 VALUE cfp_val
= rb_ary_entry(entry
, CALLER_BINDING_BINDING
);
1421 if (!NIL_P(cfp_val
)) {
1422 rb_control_frame_t
*cfp
= GC_GUARDED_PTR_REF(cfp_val
);
1423 rb_ary_store(entry
, CALLER_BINDING_BINDING
, rb_vm_make_binding(ec
, cfp
));
1431 * Note that the passed `rb_debug_inspector_t' will be disabled
1432 * after `rb_debug_inspector_open'.
1436 rb_debug_inspector_open(rb_debug_inspector_func_t func
, void *data
)
1438 rb_debug_inspector_t dbg_context
;
1439 rb_execution_context_t
*ec
= GET_EC();
1440 enum ruby_tag_type state
;
1441 volatile VALUE
MAYBE_UNUSED(result
);
1443 /* escape all env to heap */
1444 rb_vm_stack_to_heap(ec
);
1446 dbg_context
.ec
= ec
;
1447 dbg_context
.cfp
= dbg_context
.ec
->cfp
;
1448 dbg_context
.backtrace
= rb_ec_backtrace_location_ary(ec
, BACKTRACE_START
, ALL_BACKTRACE_LINES
, FALSE
);
1449 dbg_context
.backtrace_size
= RARRAY_LEN(dbg_context
.backtrace
);
1450 dbg_context
.contexts
= collect_caller_bindings(ec
);
1453 if ((state
= EC_EXEC_TAG()) == TAG_NONE
) {
1454 result
= (*func
)(&dbg_context
, data
);
1458 /* invalidate bindings? */
1461 EC_JUMP_TAG(ec
, state
);
1468 frame_get(const rb_debug_inspector_t
*dc
, long index
)
1470 if (index
< 0 || index
>= dc
->backtrace_size
) {
1471 rb_raise(rb_eArgError
, "no such frame");
1473 return rb_ary_entry(dc
->contexts
, index
);
1477 rb_debug_inspector_frame_self_get(const rb_debug_inspector_t
*dc
, long index
)
1479 VALUE frame
= frame_get(dc
, index
);
1480 return rb_ary_entry(frame
, CALLER_BINDING_SELF
);
1484 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t
*dc
, long index
)
1486 VALUE frame
= frame_get(dc
, index
);
1487 return rb_ary_entry(frame
, CALLER_BINDING_CLASS
);
1491 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t
*dc
, long index
)
1493 VALUE frame
= frame_get(dc
, index
);
1494 return rb_ary_entry(frame
, CALLER_BINDING_BINDING
);
1498 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t
*dc
, long index
)
1500 VALUE frame
= frame_get(dc
, index
);
1501 VALUE iseq
= rb_ary_entry(frame
, CALLER_BINDING_ISEQ
);
1503 return RTEST(iseq
) ? rb_iseqw_new((rb_iseq_t
*)iseq
) : Qnil
;
1507 rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t
*dc
)
1509 return dc
->backtrace
;
1513 rb_profile_frames(int start
, int limit
, VALUE
*buff
, int *lines
)
1516 const rb_execution_context_t
*ec
= GET_EC();
1517 const rb_control_frame_t
*cfp
= ec
->cfp
, *end_cfp
= RUBY_VM_END_CONTROL_FRAME(ec
);
1518 const rb_callable_method_entry_t
*cme
;
1520 for (i
=0; i
<limit
&& cfp
!= end_cfp
;) {
1521 if (VM_FRAME_RUBYFRAME_P(cfp
)) {
1527 /* record frame info */
1528 cme
= rb_vm_frame_method_entry(cfp
);
1529 if (cme
&& cme
->def
->type
== VM_METHOD_TYPE_ISEQ
) {
1530 buff
[i
] = (VALUE
)cme
;
1533 buff
[i
] = (VALUE
)cfp
->iseq
;
1536 if (lines
) lines
[i
] = calc_lineno(cfp
->iseq
, cfp
->pc
);
1541 cme
= rb_vm_frame_method_entry(cfp
);
1542 if (cme
&& cme
->def
->type
== VM_METHOD_TYPE_CFUNC
) {
1543 buff
[i
] = (VALUE
)cme
;
1544 if (lines
) lines
[i
] = 0;
1548 cfp
= RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp
);
1554 static const rb_iseq_t
*
1555 frame2iseq(VALUE frame
)
1557 if (NIL_P(frame
)) return NULL
;
1559 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1560 switch (imemo_type(frame
)) {
1562 return (const rb_iseq_t
*)frame
;
1565 const rb_callable_method_entry_t
*cme
= (rb_callable_method_entry_t
*)frame
;
1566 switch (cme
->def
->type
) {
1567 case VM_METHOD_TYPE_ISEQ
:
1568 return cme
->def
->body
.iseq
.iseqptr
;
1577 rb_bug("frame2iseq: unreachable");
1581 rb_profile_frame_path(VALUE frame
)
1583 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1584 return iseq
? rb_iseq_path(iseq
) : Qnil
;
1587 static const rb_callable_method_entry_t
*
1590 if (NIL_P(frame
)) return NULL
;
1592 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1593 switch (imemo_type(frame
)) {
1596 const rb_callable_method_entry_t
*cme
= (rb_callable_method_entry_t
*)frame
;
1597 switch (cme
->def
->type
) {
1598 case VM_METHOD_TYPE_CFUNC
:
1613 rb_profile_frame_absolute_path(VALUE frame
)
1615 if (cframe(frame
)) {
1616 static VALUE cfunc_str
= Qfalse
;
1618 cfunc_str
= rb_str_new_literal("<cfunc>");
1619 rb_gc_register_mark_object(cfunc_str
);
1623 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1624 return iseq
? rb_iseq_realpath(iseq
) : Qnil
;
1628 rb_profile_frame_label(VALUE frame
)
1630 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1631 return iseq
? rb_iseq_label(iseq
) : Qnil
;
1635 rb_profile_frame_base_label(VALUE frame
)
1637 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1638 return iseq
? rb_iseq_base_label(iseq
) : Qnil
;
1642 rb_profile_frame_first_lineno(VALUE frame
)
1644 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1645 return iseq
? rb_iseq_first_lineno(iseq
) : Qnil
;
1649 frame2klass(VALUE frame
)
1651 if (NIL_P(frame
)) return Qnil
;
1653 if (RB_TYPE_P(frame
, T_IMEMO
)) {
1654 const rb_callable_method_entry_t
*cme
= (rb_callable_method_entry_t
*)frame
;
1656 if (imemo_type(frame
) == imemo_ment
) {
1657 return cme
->defined_class
;
1664 rb_profile_frame_classpath(VALUE frame
)
1666 VALUE klass
= frame2klass(frame
);
1668 if (klass
&& !NIL_P(klass
)) {
1669 if (RB_TYPE_P(klass
, T_ICLASS
)) {
1670 klass
= RBASIC(klass
)->klass
;
1672 else if (FL_TEST(klass
, FL_SINGLETON
)) {
1673 klass
= rb_ivar_get(klass
, id__attached__
);
1674 if (!RB_TYPE_P(klass
, T_CLASS
) && !RB_TYPE_P(klass
, T_MODULE
))
1675 return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass
)), (void*)klass
);
1677 return rb_class_path(klass
);
1685 rb_profile_frame_singleton_method_p(VALUE frame
)
1687 VALUE klass
= frame2klass(frame
);
1689 return RBOOL(klass
&& !NIL_P(klass
) && FL_TEST(klass
, FL_SINGLETON
));
1693 rb_profile_frame_method_name(VALUE frame
)
1695 const rb_callable_method_entry_t
*cme
= cframe(frame
);
1697 ID mid
= cme
->def
->original_id
;
1700 const rb_iseq_t
*iseq
= frame2iseq(frame
);
1701 return iseq
? rb_iseq_method_name(iseq
) : Qnil
;
1705 qualified_method_name(VALUE frame
, VALUE method_name
)
1707 if (method_name
!= Qnil
) {
1708 VALUE classpath
= rb_profile_frame_classpath(frame
);
1709 VALUE singleton_p
= rb_profile_frame_singleton_method_p(frame
);
1711 if (classpath
!= Qnil
) {
1712 return rb_sprintf("%"PRIsVALUE
"%s%"PRIsVALUE
,
1713 classpath
, singleton_p
== Qtrue
? "." : "#", method_name
);
1725 rb_profile_frame_qualified_method_name(VALUE frame
)
1727 VALUE method_name
= rb_profile_frame_method_name(frame
);
1729 return qualified_method_name(frame
, method_name
);
1733 rb_profile_frame_full_label(VALUE frame
)
1735 const rb_callable_method_entry_t
*cme
= cframe(frame
);
1737 ID mid
= cme
->def
->original_id
;
1738 VALUE method_name
= id2str(mid
);
1739 return qualified_method_name(frame
, method_name
);
1742 VALUE label
= rb_profile_frame_label(frame
);
1743 VALUE base_label
= rb_profile_frame_base_label(frame
);
1744 VALUE qualified_method_name
= rb_profile_frame_qualified_method_name(frame
);
1746 if (NIL_P(qualified_method_name
) || base_label
== qualified_method_name
) {
1750 long label_length
= RSTRING_LEN(label
);
1751 long base_label_length
= RSTRING_LEN(base_label
);
1752 int prefix_len
= rb_long2int(label_length
- base_label_length
);
1754 return rb_sprintf("%.*s%"PRIsVALUE
, prefix_len
, RSTRING_PTR(label
), qualified_method_name
);