Ruby  3.1.4p223 (2023-03-30 revision HEAD)
vm_backtrace.c
1 /**********************************************************************
2 
3  vm_backtrace.c -
4 
5  $Author: ko1 $
6  created at: Sun Jun 03 00:14:20 2012
7 
8  Copyright (C) 1993-2012 Yukihiro Matsumoto
9 
10 **********************************************************************/
11 
12 #include "eval_intern.h"
13 #include "internal.h"
14 #include "internal/error.h"
15 #include "internal/vm.h"
16 #include "iseq.h"
17 #include "ruby/debug.h"
18 #include "ruby/encoding.h"
19 #include "vm_core.h"
20 
21 static VALUE rb_cBacktrace;
22 static VALUE rb_cBacktraceLocation;
23 
24 static VALUE
25 id2str(ID id)
26 {
27  VALUE str = rb_id2str(id);
28  if (!str) return Qnil;
29  return str;
30 }
31 #define rb_id2str(id) id2str(id)
32 
33 #define BACKTRACE_START 0
34 #define ALL_BACKTRACE_LINES -1
35 
36 inline static int
37 calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
38 {
39  VM_ASSERT(iseq);
40  VM_ASSERT(iseq->body);
41  VM_ASSERT(iseq->body->iseq_encoded);
42  VM_ASSERT(iseq->body->iseq_size);
43  if (! pc) {
44  if (iseq->body->type == ISEQ_TYPE_TOP) {
45  VM_ASSERT(! iseq->body->local_table);
46  VM_ASSERT(! iseq->body->local_table_size);
47  return 0;
48  }
49  if (lineno) *lineno = FIX2INT(iseq->body->location.first_lineno);
50 #ifdef USE_ISEQ_NODE_ID
51  if (node_id) *node_id = -1;
52 #endif
53  return 1;
54  }
55  else {
56  ptrdiff_t n = pc - iseq->body->iseq_encoded;
57  VM_ASSERT(n <= iseq->body->iseq_size);
58  VM_ASSERT(n >= 0);
59  ASSUME(n >= 0);
60  size_t pos = n; /* no overflow */
61  if (LIKELY(pos)) {
62  /* use pos-1 because PC points next instruction at the beginning of instruction */
63  pos--;
64  }
65 #if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
66  else {
67  /* SDR() is not possible; that causes infinite loop. */
68  rb_print_backtrace();
69  __builtin_trap();
70  }
71 #endif
72  if (lineno) *lineno = rb_iseq_line_no(iseq, pos);
73 #ifdef USE_ISEQ_NODE_ID
74  if (node_id) *node_id = rb_iseq_node_id(iseq, pos);
75 #endif
76  return 1;
77  }
78 }
79 
80 inline static int
81 calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
82 {
83  int lineno;
84  if (calc_pos(iseq, pc, &lineno, NULL)) return lineno;
85  return 0;
86 }
87 
88 #ifdef USE_ISEQ_NODE_ID
89 inline static int
90 calc_node_id(const rb_iseq_t *iseq, const VALUE *pc)
91 {
92  int node_id;
93  if (calc_pos(iseq, pc, NULL, &node_id)) return node_id;
94  return -1;
95 }
96 #endif
97 
98 int
99 rb_vm_get_sourceline(const rb_control_frame_t *cfp)
100 {
101  if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
102  const rb_iseq_t *iseq = cfp->iseq;
103  int line = calc_lineno(iseq, cfp->pc);
104  if (line != 0) {
105  return line;
106  }
107  else {
108  return FIX2INT(rb_iseq_first_lineno(iseq));
109  }
110  }
111  else {
112  return 0;
113  }
114 }
115 
117  enum LOCATION_TYPE {
118  LOCATION_TYPE_ISEQ = 1,
119  LOCATION_TYPE_CFUNC,
120  } type;
121 
122  const rb_iseq_t *iseq;
123  const VALUE *pc;
124  ID mid;
126 
129  VALUE btobj;
130 };
131 
132 static void
133 location_mark(void *ptr)
134 {
135  struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
136  rb_gc_mark(vfi->btobj);
137 }
138 
139 static void
140 location_mark_entry(rb_backtrace_location_t *fi)
141 {
142  switch (fi->type) {
143  case LOCATION_TYPE_ISEQ:
144  rb_gc_mark_movable((VALUE)fi->iseq);
145  break;
146  case LOCATION_TYPE_CFUNC:
147  if (fi->iseq) {
148  rb_gc_mark_movable((VALUE)fi->iseq);
149  }
150  break;
151  default:
152  break;
153  }
154 }
155 
156 static size_t
157 location_memsize(const void *ptr)
158 {
159  /* rb_backtrace_location_t *fi = (rb_backtrace_location_t *)ptr; */
160  return sizeof(rb_backtrace_location_t);
161 }
162 
163 static const rb_data_type_t location_data_type = {
164  "frame_info",
165  {location_mark, RUBY_TYPED_DEFAULT_FREE, location_memsize,},
166  0, 0, RUBY_TYPED_FREE_IMMEDIATELY
167 };
168 
169 int
170 rb_frame_info_p(VALUE obj)
171 {
172  return rb_typeddata_is_kind_of(obj, &location_data_type);
173 }
174 
175 static inline rb_backtrace_location_t *
176 location_ptr(VALUE locobj)
177 {
178  struct valued_frame_info *vloc;
179  GetCoreDataFromValue(locobj, struct valued_frame_info, vloc);
180  return vloc->loc;
181 }
182 
183 static int
184 location_lineno(rb_backtrace_location_t *loc)
185 {
186  switch (loc->type) {
187  case LOCATION_TYPE_ISEQ:
188  return calc_lineno(loc->iseq, loc->pc);
189  case LOCATION_TYPE_CFUNC:
190  if (loc->iseq && loc->pc) {
191  return calc_lineno(loc->iseq, loc->pc);
192  }
193  return 0;
194  default:
195  rb_bug("location_lineno: unreachable");
196  UNREACHABLE;
197  }
198 }
199 
200 /*
201  * Returns the line number of this frame.
202  *
203  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
204  *
205  * loc = c(0..1).first
206  * loc.lineno #=> 2
207  */
208 static VALUE
209 location_lineno_m(VALUE self)
210 {
211  return INT2FIX(location_lineno(location_ptr(self)));
212 }
213 
214 static VALUE
215 location_label(rb_backtrace_location_t *loc)
216 {
217  switch (loc->type) {
218  case LOCATION_TYPE_ISEQ:
219  return loc->iseq->body->location.label;
220  case LOCATION_TYPE_CFUNC:
221  return rb_id2str(loc->mid);
222  default:
223  rb_bug("location_label: unreachable");
224  UNREACHABLE;
225  }
226 }
227 
228 /*
229  * Returns the label of this frame.
230  *
231  * Usually consists of method, class, module, etc names with decoration.
232  *
233  * Consider the following example:
234  *
235  * def foo
236  * puts caller_locations(0).first.label
237  *
238  * 1.times do
239  * puts caller_locations(0).first.label
240  *
241  * 1.times do
242  * puts caller_locations(0).first.label
243  * end
244  *
245  * end
246  * end
247  *
248  * The result of calling +foo+ is this:
249  *
250  * label: foo
251  * label: block in foo
252  * label: block (2 levels) in foo
253  *
254  */
255 static VALUE
256 location_label_m(VALUE self)
257 {
258  return location_label(location_ptr(self));
259 }
260 
261 static VALUE
262 location_base_label(rb_backtrace_location_t *loc)
263 {
264  switch (loc->type) {
265  case LOCATION_TYPE_ISEQ:
266  return loc->iseq->body->location.base_label;
267  case LOCATION_TYPE_CFUNC:
268  return rb_id2str(loc->mid);
269  default:
270  rb_bug("location_base_label: unreachable");
271  UNREACHABLE;
272  }
273 }
274 
275 /*
276  * Returns the base label of this frame.
277  *
278  * Usually same as #label, without decoration.
279  */
280 static VALUE
281 location_base_label_m(VALUE self)
282 {
283  return location_base_label(location_ptr(self));
284 }
285 
286 static const rb_iseq_t *
287 location_iseq(rb_backtrace_location_t *loc)
288 {
289  switch (loc->type) {
290  case LOCATION_TYPE_ISEQ:
291  return loc->iseq;
292  case LOCATION_TYPE_CFUNC:
293  return loc->iseq;
294  default:
295  rb_bug("location_iseq: unreachable");
296  UNREACHABLE;
297  }
298 }
299 
300 /*
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.
304  *
305  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
306  *
307  * loc = c(0..1).first
308  * loc.path #=> caller_locations.rb
309  */
310 static VALUE
311 location_path_m(VALUE self)
312 {
313  const rb_iseq_t *iseq = location_iseq(location_ptr(self));
314  return iseq ? rb_iseq_path(iseq) : Qnil;
315 }
316 
317 #ifdef USE_ISEQ_NODE_ID
318 static int
319 location_node_id(rb_backtrace_location_t *loc)
320 {
321  switch (loc->type) {
322  case LOCATION_TYPE_ISEQ:
323  return calc_node_id(loc->iseq, loc->pc);
324  case LOCATION_TYPE_CFUNC:
325  if (loc->iseq && loc->pc) {
326  return calc_node_id(loc->iseq, loc->pc);
327  }
328  return -1;
329  default:
330  rb_bug("location_node_id: unreachable");
331  UNREACHABLE;
332  }
333 }
334 #endif
335 
336 int
337 rb_get_node_id_from_frame_info(VALUE obj)
338 {
339 #ifdef USE_ISEQ_NODE_ID
340  rb_backtrace_location_t *loc = location_ptr(obj);
341  return location_node_id(loc);
342 #else
343  return -1;
344 #endif
345 }
346 
347 const rb_iseq_t *
348 rb_get_iseq_from_frame_info(VALUE obj)
349 {
350  rb_backtrace_location_t *loc = location_ptr(obj);
351  const rb_iseq_t *iseq = location_iseq(loc);
352  return iseq;
353 }
354 
355 static VALUE
356 location_realpath(rb_backtrace_location_t *loc)
357 {
358  switch (loc->type) {
359  case LOCATION_TYPE_ISEQ:
360  return rb_iseq_realpath(loc->iseq);
361  case LOCATION_TYPE_CFUNC:
362  if (loc->iseq) {
363  return rb_iseq_realpath(loc->iseq);
364  }
365  return Qnil;
366  default:
367  rb_bug("location_realpath: unreachable");
368  UNREACHABLE;
369  }
370 }
371 
372 /*
373  * Returns the full file path of this frame.
374  *
375  * Same as #path, except that it will return absolute path
376  * even if the frame is in the main script.
377  */
378 static VALUE
379 location_absolute_path_m(VALUE self)
380 {
381  return location_realpath(location_ptr(self));
382 }
383 
384 static VALUE
385 location_format(VALUE file, int lineno, VALUE name)
386 {
387  VALUE s = rb_enc_sprintf(rb_enc_compatible(file, name), "%s", RSTRING_PTR(file));
388  if (lineno != 0) {
389  rb_str_catf(s, ":%d", lineno);
390  }
391  rb_str_cat_cstr(s, ":in ");
392  if (NIL_P(name)) {
393  rb_str_cat_cstr(s, "unknown method");
394  }
395  else {
396  rb_str_catf(s, "`%s'", RSTRING_PTR(name));
397  }
398  return s;
399 }
400 
401 static VALUE
402 location_to_str(rb_backtrace_location_t *loc)
403 {
404  VALUE file, name;
405  int lineno;
406 
407  switch (loc->type) {
408  case LOCATION_TYPE_ISEQ:
409  file = rb_iseq_path(loc->iseq);
410  name = loc->iseq->body->location.label;
411 
412  lineno = calc_lineno(loc->iseq, loc->pc);
413  break;
414  case LOCATION_TYPE_CFUNC:
415  if (loc->iseq && loc->pc) {
416  file = rb_iseq_path(loc->iseq);
417  lineno = calc_lineno(loc->iseq, loc->pc);
418  }
419  else {
420  file = GET_VM()->progname;
421  lineno = 0;
422  }
423  name = rb_id2str(loc->mid);
424  break;
425  default:
426  rb_bug("location_to_str: unreachable");
427  }
428 
429  return location_format(file, lineno, name);
430 }
431 
432 /*
433  * Returns a Kernel#caller style string representing this frame.
434  */
435 static VALUE
436 location_to_str_m(VALUE self)
437 {
438  return location_to_str(location_ptr(self));
439 }
440 
441 /*
442  * Returns the same as calling +inspect+ on the string representation of
443  * #to_str
444  */
445 static VALUE
446 location_inspect_m(VALUE self)
447 {
448  return rb_str_inspect(location_to_str(location_ptr(self)));
449 }
450 
451 typedef struct rb_backtrace_struct {
452  rb_backtrace_location_t *backtrace;
453  int backtrace_size;
454  VALUE strary;
455  VALUE locary;
457 
458 static void
459 backtrace_mark(void *ptr)
460 {
461  rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
462  size_t i, s = bt->backtrace_size;
463 
464  for (i=0; i<s; i++) {
465  location_mark_entry(&bt->backtrace[i]);
466  }
467  rb_gc_mark_movable(bt->strary);
468  rb_gc_mark_movable(bt->locary);
469 }
470 
471 static void
472 backtrace_free(void *ptr)
473 {
474  rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
475  if (bt->backtrace) ruby_xfree(bt->backtrace);
476  ruby_xfree(bt);
477 }
478 
479 static void
480 location_update_entry(rb_backtrace_location_t *fi)
481 {
482  switch (fi->type) {
483  case LOCATION_TYPE_ISEQ:
484  fi->iseq = (rb_iseq_t*)rb_gc_location((VALUE)fi->iseq);
485  break;
486  case LOCATION_TYPE_CFUNC:
487  if (fi->iseq) {
488  fi->iseq = (rb_iseq_t*)rb_gc_location((VALUE)fi->iseq);
489  }
490  break;
491  default:
492  break;
493  }
494 }
495 
496 static void
497 backtrace_update(void *ptr)
498 {
499  rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
500  size_t i, s = bt->backtrace_size;
501 
502  for (i=0; i<s; i++) {
503  location_update_entry(&bt->backtrace[i]);
504  }
505  bt->strary = rb_gc_location(bt->strary);
506  bt->locary = rb_gc_location(bt->locary);
507 }
508 
509 static size_t
510 backtrace_memsize(const void *ptr)
511 {
512  rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
513  return sizeof(rb_backtrace_t) + sizeof(rb_backtrace_location_t) * bt->backtrace_size;
514 }
515 
516 static const rb_data_type_t backtrace_data_type = {
517  "backtrace",
518  {backtrace_mark, backtrace_free, backtrace_memsize, backtrace_update},
519  0, 0, RUBY_TYPED_FREE_IMMEDIATELY
520 };
521 
522 int
523 rb_backtrace_p(VALUE obj)
524 {
525  return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
526 }
527 
528 static VALUE
529 backtrace_alloc(VALUE klass)
530 {
531  rb_backtrace_t *bt;
532  VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
533  return obj;
534 }
535 
536 static long
537 backtrace_size(const rb_execution_context_t *ec)
538 {
539  const rb_control_frame_t *last_cfp = ec->cfp;
540  const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
541 
542  if (start_cfp == NULL) {
543  return -1;
544  }
545 
546  start_cfp =
547  RUBY_VM_NEXT_CONTROL_FRAME(
548  RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
549 
550  if (start_cfp < last_cfp) {
551  return 0;
552  }
553 
554  return start_cfp - last_cfp + 1;
555 }
556 
557 static bool
558 is_internal_location(const rb_control_frame_t *cfp)
559 {
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;
564 }
565 
566 static void
567 bt_update_cfunc_loc(unsigned long cfunc_counter, rb_backtrace_location_t *cfunc_loc, const rb_iseq_t *iseq, const VALUE *pc)
568 {
569  for (; cfunc_counter > 0; cfunc_counter--, cfunc_loc--) {
570  cfunc_loc->iseq = iseq;
571  cfunc_loc->pc = pc;
572  }
573 }
574 
575 static VALUE
576 rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_frame, long num_frames, int* start_too_large, bool skip_internal)
577 {
578  const rb_control_frame_t *cfp = ec->cfp;
579  const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
580  ptrdiff_t size;
581  rb_backtrace_t *bt;
582  VALUE btobj = backtrace_alloc(rb_cBacktrace);
584  unsigned long cfunc_counter = 0;
585  GetCoreDataFromValue(btobj, rb_backtrace_t, bt);
586 
587  // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
588  if (end_cfp == NULL) {
589  num_frames = 0;
590  }
591  else {
592  end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
593 
594  /*
595  * top frame (dummy) <- RUBY_VM_END_CONTROL_FRAME
596  * top frame (dummy) <- end_cfp
597  * top frame <- main script
598  * top frame
599  * ...
600  * 2nd frame <- lev:0
601  * current frame <- ec->cfp
602  */
603 
604  size = end_cfp - cfp + 1;
605  if (size < 0) {
606  num_frames = 0;
607  }
608  else if (num_frames < 0 || num_frames > size) {
609  num_frames = size;
610  }
611  }
612 
613  bt->backtrace = ZALLOC_N(rb_backtrace_location_t, num_frames);
614  bt->backtrace_size = 0;
615  if (num_frames == 0) {
616  if (start_too_large) *start_too_large = 0;
617  return btobj;
618  }
619 
620  for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
621  if (cfp->iseq) {
622  if (cfp->pc) {
623  if (start_frame > 0) {
624  start_frame--;
625  }
626  else if (!skip_internal || !is_internal_location(cfp)) {
627  const rb_iseq_t *iseq = cfp->iseq;
628  const VALUE *pc = cfp->pc;
629  loc = &bt->backtrace[bt->backtrace_size++];
630  loc->type = LOCATION_TYPE_ISEQ;
631  loc->iseq = iseq;
632  loc->pc = pc;
633  bt_update_cfunc_loc(cfunc_counter, loc-1, iseq, pc);
634  cfunc_counter = 0;
635  }
636  }
637  }
638  else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
639  if (start_frame > 0) {
640  start_frame--;
641  }
642  else {
643  loc = &bt->backtrace[bt->backtrace_size++];
644  loc->type = LOCATION_TYPE_CFUNC;
645  loc->iseq = NULL;
646  loc->pc = NULL;
647  loc->mid = rb_vm_frame_method_entry(cfp)->def->original_id;
648  cfunc_counter++;
649  }
650  }
651  }
652 
653  if (cfunc_counter > 0) {
654  for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
655  if (cfp->iseq && cfp->pc && (!skip_internal || !is_internal_location(cfp))) {
656  bt_update_cfunc_loc(cfunc_counter, loc, cfp->iseq, cfp->pc);
657  break;
658  }
659  }
660  }
661 
662  if (start_too_large) *start_too_large = (start_frame > 0 ? -1 : 0);
663  return btobj;
664 }
665 
666 MJIT_FUNC_EXPORTED VALUE
667 rb_ec_backtrace_object(const rb_execution_context_t *ec)
668 {
669  return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL, FALSE);
670 }
671 
672 static VALUE
673 backtrace_collect(rb_backtrace_t *bt, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
674 {
675  VALUE btary;
676  int i;
677 
678  btary = rb_ary_new2(bt->backtrace_size);
679 
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));
683  }
684 
685  return btary;
686 }
687 
688 static VALUE
689 location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
690 {
691  return location_to_str(loc);
692 }
693 
694 static VALUE
695 backtrace_to_str_ary(VALUE self)
696 {
697  VALUE r;
698  rb_backtrace_t *bt;
699  GetCoreDataFromValue(self, rb_backtrace_t, bt);
700  r = backtrace_collect(bt, location_to_str_dmyarg, 0);
701  RB_GC_GUARD(self);
702  return r;
703 }
704 
705 VALUE
706 rb_backtrace_to_str_ary(VALUE self)
707 {
708  rb_backtrace_t *bt;
709  GetCoreDataFromValue(self, rb_backtrace_t, bt);
710 
711  if (!bt->strary) {
712  bt->strary = backtrace_to_str_ary(self);
713  }
714  return bt->strary;
715 }
716 
717 MJIT_FUNC_EXPORTED void
718 rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self)
719 {
720  const rb_backtrace_t *bt;
722 
723  GetCoreDataFromValue(self, rb_backtrace_t, bt);
724  VM_ASSERT(bt->backtrace_size > 0);
725 
726  loc = &bt->backtrace[0];
727 
728  VM_ASSERT(loc->type == LOCATION_TYPE_ISEQ);
729 
730  loc->pc = NULL; // means location.first_lineno
731 }
732 
733 static VALUE
734 location_create(rb_backtrace_location_t *srcloc, void *btobj)
735 {
736  VALUE obj;
737  struct valued_frame_info *vloc;
738  obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
739 
740  vloc->loc = srcloc;
741  vloc->btobj = (VALUE)btobj;
742 
743  return obj;
744 }
745 
746 static VALUE
747 backtrace_to_location_ary(VALUE self)
748 {
749  VALUE r;
750  rb_backtrace_t *bt;
751  GetCoreDataFromValue(self, rb_backtrace_t, bt);
752  r = backtrace_collect(bt, location_create, (void *)self);
753  RB_GC_GUARD(self);
754  return r;
755 }
756 
757 VALUE
758 rb_backtrace_to_location_ary(VALUE self)
759 {
760  rb_backtrace_t *bt;
761  GetCoreDataFromValue(self, rb_backtrace_t, bt);
762 
763  if (!bt->locary) {
764  bt->locary = backtrace_to_location_ary(self);
765  }
766  return bt->locary;
767 }
768 
769 static VALUE
770 backtrace_dump_data(VALUE self)
771 {
772  VALUE str = rb_backtrace_to_str_ary(self);
773  return str;
774 }
775 
776 static VALUE
777 backtrace_load_data(VALUE self, VALUE str)
778 {
779  rb_backtrace_t *bt;
780  GetCoreDataFromValue(self, rb_backtrace_t, bt);
781  bt->strary = str;
782  return self;
783 }
784 
785 /*
786  * call-seq: Threade::Backtrace::limit -> integer
787  *
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>
793  *
794  * $ ruby -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
795  * - 1
796  * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': Failed to open TCP connection to wrong.address:80 (getaddrinfo: Name or service not known) (SocketError)
797  * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
798  * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
799  * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
800  * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
801  * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
802  * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
803  * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
804  * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
805  * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
806  * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
807  * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
808  * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
809  * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
810  * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
811  * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
812  * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
813  * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
814  * from -e:1:in `<main>'
815  *
816  * $ ruby --backtrace-limit 2 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
817  * 2
818  * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': Failed to open TCP connection to wrong.address:80 (getaddrinfo: Name or service not known) (SocketError)
819  * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
820  * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
821  * ... 7 levels...
822  * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
823  * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
824  * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
825  * ... 7 levels...
826  *
827  * $ ruby --backtrace-limit 0 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
828  * 0
829  * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': Failed to open TCP connection to wrong.address:80 (getaddrinfo: Name or service not known) (SocketError)
830  * ... 9 levels...
831  * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
832  * ... 9 levels...
833  *
834  */
835 static VALUE
836 backtrace_limit(VALUE self)
837 {
838  return LONG2NUM(rb_backtrace_length_limit);
839 }
840 
841 VALUE
842 rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n)
843 {
844  return backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE));
845 }
846 
847 VALUE
848 rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal)
849 {
850  return backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal));
851 }
852 
853 /* make old style backtrace directly */
854 
855 static void
856 backtrace_each(const rb_execution_context_t *ec,
857  void (*init)(void *arg, size_t size),
858  void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
859  void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
860  void *arg)
861 {
862  const rb_control_frame_t *last_cfp = ec->cfp;
863  const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
864  const rb_control_frame_t *cfp;
865  ptrdiff_t size, i;
866 
867  // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
868  if (start_cfp == NULL) {
869  init(arg, 0);
870  return;
871  }
872 
873  /* <- start_cfp (end control frame)
874  * top frame (dummy)
875  * top frame (dummy)
876  * top frame <- start_cfp
877  * top frame
878  * ...
879  * 2nd frame <- lev:0
880  * current frame <- ec->cfp
881  */
882 
883  start_cfp =
884  RUBY_VM_NEXT_CONTROL_FRAME(
885  RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
886 
887  if (start_cfp < last_cfp) {
888  size = 0;
889  }
890  else {
891  size = start_cfp - last_cfp + 1;
892  }
893 
894  init(arg, size);
895 
896  /* SDR(); */
897  for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
898  /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
899  if (cfp->iseq) {
900  if (cfp->pc) {
901  iter_iseq(arg, cfp);
902  }
903  }
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;
907 
908  iter_cfunc(arg, cfp, mid);
909  }
910  }
911 }
912 
913 struct oldbt_arg {
914  VALUE filename;
915  int lineno;
916  void (*func)(void *data, VALUE file, int lineno, VALUE name);
917  void *data; /* result */
918 };
919 
920 static void
921 oldbt_init(void *ptr, size_t dmy)
922 {
923  struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
924  arg->filename = GET_VM()->progname;
925  arg->lineno = 0;
926 }
927 
928 static void
929 oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
930 {
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);
937 
938  (arg->func)(arg->data, file, lineno, name);
939 }
940 
941 static void
942 oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
943 {
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;
948 
949  (arg->func)(arg->data, file, lineno, name);
950 }
951 
952 static void
953 oldbt_print(void *data, VALUE file, int lineno, VALUE name)
954 {
955  FILE *fp = (FILE *)data;
956 
957  if (NIL_P(name)) {
958  fprintf(fp, "\tfrom %s:%d:in unknown method\n",
959  RSTRING_PTR(file), lineno);
960  }
961  else {
962  fprintf(fp, "\tfrom %s:%d:in `%s'\n",
963  RSTRING_PTR(file), lineno, RSTRING_PTR(name));
964  }
965 }
966 
967 static void
968 vm_backtrace_print(FILE *fp)
969 {
970  struct oldbt_arg arg;
971 
972  arg.func = oldbt_print;
973  arg.data = (void *)fp;
974  backtrace_each(GET_EC(),
975  oldbt_init,
976  oldbt_iter_iseq,
977  oldbt_iter_cfunc,
978  &arg);
979 }
980 
981 static void
982 oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
983 {
984  const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
985  if (!*(int *)arg) {
986  fprintf(stderr, "-- Ruby level backtrace information "
987  "----------------------------------------\n");
988  *(int *)arg = 1;
989  }
990  if (NIL_P(method)) {
991  fprintf(stderr, "%s:%d:in unknown method\n", filename, line);
992  }
993  else {
994  fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
995  }
996 }
997 
998 void
999 rb_backtrace_print_as_bugreport(void)
1000 {
1001  struct oldbt_arg arg;
1002  int i = 0;
1003 
1004  arg.func = oldbt_bugreport;
1005  arg.data = (int *)&i;
1006 
1007  backtrace_each(GET_EC(),
1008  oldbt_init,
1009  oldbt_iter_iseq,
1010  oldbt_iter_cfunc,
1011  &arg);
1012 }
1013 
1014 void
1016 {
1017  vm_backtrace_print(stderr);
1018 }
1019 
1021  VALUE (*iter)(VALUE recv, VALUE str);
1022  VALUE output;
1023 };
1024 
1025 static void
1026 oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
1027 {
1028  const struct print_to_arg *arg = data;
1029  VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
1030 
1031  if (NIL_P(name)) {
1032  rb_str_cat2(str, "unknown method\n");
1033  }
1034  else {
1035  rb_str_catf(str, " `%"PRIsVALUE"'\n", name);
1036  }
1037  (*arg->iter)(arg->output, str);
1038 }
1039 
1040 void
1041 rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output)
1042 {
1043  struct oldbt_arg arg;
1044  struct print_to_arg parg;
1045 
1046  parg.iter = iter;
1047  parg.output = output;
1048  arg.func = oldbt_print_to;
1049  arg.data = &parg;
1050  backtrace_each(GET_EC(),
1051  oldbt_init,
1052  oldbt_iter_iseq,
1053  oldbt_iter_cfunc,
1054  &arg);
1055 }
1056 
1057 VALUE
1059 {
1060  return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START, ALL_BACKTRACE_LINES);
1061 }
1062 
1063 static VALUE
1064 ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str)
1065 {
1066  VALUE level, vn;
1067  long lev, n;
1068  VALUE btval;
1069  VALUE r;
1070  int too_large;
1071 
1072  rb_scan_args(argc, argv, "02", &level, &vn);
1073 
1074  if (argc == 2 && NIL_P(vn)) argc--;
1075 
1076  switch (argc) {
1077  case 0:
1078  lev = lev_default + lev_plus;
1079  n = ALL_BACKTRACE_LINES;
1080  break;
1081  case 1:
1082  {
1083  long beg, len, bt_size = backtrace_size(ec);
1084  switch (rb_range_beg_len(level, &beg, &len, bt_size - lev_plus, 0)) {
1085  case Qfalse:
1086  lev = NUM2LONG(level);
1087  if (lev < 0) {
1088  rb_raise(rb_eArgError, "negative level (%ld)", lev);
1089  }
1090  lev += lev_plus;
1091  n = ALL_BACKTRACE_LINES;
1092  break;
1093  case Qnil:
1094  return Qnil;
1095  default:
1096  lev = beg + lev_plus;
1097  n = len;
1098  break;
1099  }
1100  break;
1101  }
1102  case 2:
1103  lev = NUM2LONG(level);
1104  n = NUM2LONG(vn);
1105  if (lev < 0) {
1106  rb_raise(rb_eArgError, "negative level (%ld)", lev);
1107  }
1108  if (n < 0) {
1109  rb_raise(rb_eArgError, "negative size (%ld)", n);
1110  }
1111  lev += lev_plus;
1112  break;
1113  default:
1114  lev = n = 0; /* to avoid warning */
1115  break;
1116  }
1117 
1118  if (n == 0) {
1119  return rb_ary_new();
1120  }
1121 
1122  btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE);
1123 
1124  if (too_large) {
1125  return Qnil;
1126  }
1127 
1128  if (to_str) {
1129  r = backtrace_to_str_ary(btval);
1130  }
1131  else {
1132  r = backtrace_to_location_ary(btval);
1133  }
1134  RB_GC_GUARD(btval);
1135  return r;
1136 }
1137 
1138 static VALUE
1139 thread_backtrace_to_ary(int argc, const VALUE *argv, VALUE thval, int to_str)
1140 {
1141  rb_thread_t *target_th = rb_thread_ptr(thval);
1142 
1143  if (target_th->to_kill || target_th->status == THREAD_KILLED)
1144  return Qnil;
1145 
1146  return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1147 }
1148 
1149 VALUE
1150 rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval)
1151 {
1152  return thread_backtrace_to_ary(argc, argv, thval, 1);
1153 }
1154 
1155 VALUE
1156 rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval)
1157 {
1158  return thread_backtrace_to_ary(argc, argv, thval, 0);
1159 }
1160 
1161 VALUE rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1162 {
1163  return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1164 }
1165 
1166 VALUE rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1167 {
1168  return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1169 }
1170 
1171 /*
1172  * call-seq:
1173  * caller(start=1, length=nil) -> array or nil
1174  * caller(range) -> array or nil
1175  *
1176  * Returns the current execution stack---an array containing strings in
1177  * the form <code>file:line</code> or <code>file:line: in
1178  * `method'</code>.
1179  *
1180  * The optional _start_ parameter determines the number of initial stack
1181  * entries to omit from the top of the stack.
1182  *
1183  * A second optional +length+ parameter can be used to limit how many entries
1184  * are returned from the stack.
1185  *
1186  * Returns +nil+ if _start_ is greater than the size of
1187  * current execution stack.
1188  *
1189  * Optionally you can pass a range, which will return an array containing the
1190  * entries within the specified range.
1191  *
1192  * def a(skip)
1193  * caller(skip)
1194  * end
1195  * def b(skip)
1196  * a(skip)
1197  * end
1198  * def c(skip)
1199  * b(skip)
1200  * end
1201  * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1202  * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1203  * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1204  * c(3) #=> ["prog:13:in `<main>'"]
1205  * c(4) #=> []
1206  * c(5) #=> nil
1207  */
1208 
1209 static VALUE
1210 rb_f_caller(int argc, VALUE *argv, VALUE _)
1211 {
1212  return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1213 }
1214 
1215 /*
1216  * call-seq:
1217  * caller_locations(start=1, length=nil) -> array or nil
1218  * caller_locations(range) -> array or nil
1219  *
1220  * Returns the current execution stack---an array containing
1221  * backtrace location objects.
1222  *
1223  * See Thread::Backtrace::Location for more information.
1224  *
1225  * The optional _start_ parameter determines the number of initial stack
1226  * entries to omit from the top of the stack.
1227  *
1228  * A second optional +length+ parameter can be used to limit how many entries
1229  * are returned from the stack.
1230  *
1231  * Returns +nil+ if _start_ is greater than the size of
1232  * current execution stack.
1233  *
1234  * Optionally you can pass a range, which will return an array containing the
1235  * entries within the specified range.
1236  */
1237 static VALUE
1238 rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
1239 {
1240  return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1241 }
1242 
1243 /* called from Init_vm() in vm.c */
1244 void
1245 Init_vm_backtrace(void)
1246 {
1247  /*
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.
1251  */
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);
1257 
1258  /*
1259  * An object representation of a stack frame, initialized by
1260  * Kernel#caller_locations.
1261  *
1262  * For example:
1263  *
1264  * # caller_locations.rb
1265  * def a(skip)
1266  * caller_locations(skip)
1267  * end
1268  * def b(skip)
1269  * a(skip)
1270  * end
1271  * def c(skip)
1272  * b(skip)
1273  * end
1274  *
1275  * c(0..2).map do |call|
1276  * puts call.to_s
1277  * end
1278  *
1279  * Running <code>ruby caller_locations.rb</code> will produce:
1280  *
1281  * caller_locations.rb:2:in `a'
1282  * caller_locations.rb:5:in `b'
1283  * caller_locations.rb:8:in `c'
1284  *
1285  * Here's another example with a slightly different result:
1286  *
1287  * # foo.rb
1288  * class Foo
1289  * attr_accessor :locations
1290  * def initialize(skip)
1291  * @locations = caller_locations(skip)
1292  * end
1293  * end
1294  *
1295  * Foo.new(0..2).locations.map do |call|
1296  * puts call.to_s
1297  * end
1298  *
1299  * Now run <code>ruby foo.rb</code> and you should see:
1300  *
1301  * init.rb:4:in `initialize'
1302  * init.rb:8:in `new'
1303  * init.rb:8:in `<main>'
1304  */
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);
1315 
1316  rb_define_global_function("caller", rb_f_caller, -1);
1317  rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1318 }
1319 
1320 /* debugger API */
1321 
1322 RUBY_SYMBOL_EXPORT_BEGIN
1323 
1324 RUBY_SYMBOL_EXPORT_END
1325 
1328  rb_control_frame_t *cfp;
1329  VALUE backtrace;
1330  VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1331  long backtrace_size;
1332 };
1333 
1334 enum {
1335  CALLER_BINDING_SELF,
1336  CALLER_BINDING_CLASS,
1337  CALLER_BINDING_BINDING,
1338  CALLER_BINDING_ISEQ,
1339  CALLER_BINDING_CFP
1340 };
1341 
1343  VALUE ary;
1344 };
1345 
1346 static void
1347 collect_caller_bindings_init(void *arg, size_t size)
1348 {
1349  /* */
1350 }
1351 
1352 static VALUE
1353 get_klass(const rb_control_frame_t *cfp)
1354 {
1355  VALUE klass;
1356  if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
1357  if (RB_TYPE_P(klass, T_ICLASS)) {
1358  return RBASIC(klass)->klass;
1359  }
1360  else {
1361  return klass;
1362  }
1363  }
1364  else {
1365  return Qnil;
1366  }
1367 }
1368 
1369 static void
1370 collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
1371 {
1372  struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1373  VALUE frame = rb_ary_new2(5);
1374 
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));
1380 
1381  rb_ary_push(data->ary, frame);
1382 }
1383 
1384 static void
1385 collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
1386 {
1387  struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1388  VALUE frame = rb_ary_new2(5);
1389 
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));
1395 
1396  rb_ary_push(data->ary, frame);
1397 }
1398 
1399 static VALUE
1400 collect_caller_bindings(const rb_execution_context_t *ec)
1401 {
1402  struct collect_caller_bindings_data data;
1403  VALUE result;
1404  int i;
1405 
1406  data.ary = rb_ary_new();
1407 
1408  backtrace_each(ec,
1409  collect_caller_bindings_init,
1410  collect_caller_bindings_iseq,
1411  collect_caller_bindings_cfunc,
1412  &data);
1413 
1414  result = rb_ary_reverse(data.ary);
1415 
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);
1420 
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));
1424  }
1425  }
1426 
1427  return result;
1428 }
1429 
1430 /*
1431  * Note that the passed `rb_debug_inspector_t' will be disabled
1432  * after `rb_debug_inspector_open'.
1433  */
1434 
1435 VALUE
1437 {
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);
1442 
1443  /* escape all env to heap */
1444  rb_vm_stack_to_heap(ec);
1445 
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);
1451 
1452  EC_PUSH_TAG(ec);
1453  if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1454  result = (*func)(&dbg_context, data);
1455  }
1456  EC_POP_TAG();
1457 
1458  /* invalidate bindings? */
1459 
1460  if (state) {
1461  EC_JUMP_TAG(ec, state);
1462  }
1463 
1464  return result;
1465 }
1466 
1467 static VALUE
1468 frame_get(const rb_debug_inspector_t *dc, long index)
1469 {
1470  if (index < 0 || index >= dc->backtrace_size) {
1471  rb_raise(rb_eArgError, "no such frame");
1472  }
1473  return rb_ary_entry(dc->contexts, index);
1474 }
1475 
1476 VALUE
1478 {
1479  VALUE frame = frame_get(dc, index);
1480  return rb_ary_entry(frame, CALLER_BINDING_SELF);
1481 }
1482 
1483 VALUE
1485 {
1486  VALUE frame = frame_get(dc, index);
1487  return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1488 }
1489 
1490 VALUE
1492 {
1493  VALUE frame = frame_get(dc, index);
1494  return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1495 }
1496 
1497 VALUE
1499 {
1500  VALUE frame = frame_get(dc, index);
1501  VALUE iseq = rb_ary_entry(frame, CALLER_BINDING_ISEQ);
1502 
1503  return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) : Qnil;
1504 }
1505 
1506 VALUE
1508 {
1509  return dc->backtrace;
1510 }
1511 
1512 int
1513 rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
1514 {
1515  int i;
1516  const rb_execution_context_t *ec = GET_EC();
1517  const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
1518  const rb_callable_method_entry_t *cme;
1519 
1520  for (i=0; i<limit && cfp != end_cfp;) {
1521  if (VM_FRAME_RUBYFRAME_P(cfp)) {
1522  if (start > 0) {
1523  start--;
1524  continue;
1525  }
1526 
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;
1531  }
1532  else {
1533  buff[i] = (VALUE)cfp->iseq;
1534  }
1535 
1536  if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc);
1537 
1538  i++;
1539  }
1540  else {
1541  cme = rb_vm_frame_method_entry(cfp);
1542  if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
1543  buff[i] = (VALUE)cme;
1544  if (lines) lines[i] = 0;
1545  i++;
1546  }
1547  }
1548  cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
1549  }
1550 
1551  return i;
1552 }
1553 
1554 static const rb_iseq_t *
1555 frame2iseq(VALUE frame)
1556 {
1557  if (NIL_P(frame)) return NULL;
1558 
1559  if (RB_TYPE_P(frame, T_IMEMO)) {
1560  switch (imemo_type(frame)) {
1561  case imemo_iseq:
1562  return (const rb_iseq_t *)frame;
1563  case imemo_ment:
1564  {
1566  switch (cme->def->type) {
1567  case VM_METHOD_TYPE_ISEQ:
1568  return cme->def->body.iseq.iseqptr;
1569  default:
1570  return NULL;
1571  }
1572  }
1573  default:
1574  break;
1575  }
1576  }
1577  rb_bug("frame2iseq: unreachable");
1578 }
1579 
1580 VALUE
1582 {
1583  const rb_iseq_t *iseq = frame2iseq(frame);
1584  return iseq ? rb_iseq_path(iseq) : Qnil;
1585 }
1586 
1587 static const rb_callable_method_entry_t *
1588 cframe(VALUE frame)
1589 {
1590  if (NIL_P(frame)) return NULL;
1591 
1592  if (RB_TYPE_P(frame, T_IMEMO)) {
1593  switch (imemo_type(frame)) {
1594  case imemo_ment:
1595  {
1597  switch (cme->def->type) {
1598  case VM_METHOD_TYPE_CFUNC:
1599  return cme;
1600  default:
1601  return NULL;
1602  }
1603  }
1604  default:
1605  return NULL;
1606  }
1607  }
1608 
1609  return NULL;
1610 }
1611 
1612 VALUE
1614 {
1615  if (cframe(frame)) {
1616  static VALUE cfunc_str = Qfalse;
1617  if (!cfunc_str) {
1618  cfunc_str = rb_str_new_literal("<cfunc>");
1619  rb_gc_register_mark_object(cfunc_str);
1620  }
1621  return cfunc_str;
1622  }
1623  const rb_iseq_t *iseq = frame2iseq(frame);
1624  return iseq ? rb_iseq_realpath(iseq) : Qnil;
1625 }
1626 
1627 VALUE
1629 {
1630  const rb_iseq_t *iseq = frame2iseq(frame);
1631  return iseq ? rb_iseq_label(iseq) : Qnil;
1632 }
1633 
1634 VALUE
1636 {
1637  const rb_iseq_t *iseq = frame2iseq(frame);
1638  return iseq ? rb_iseq_base_label(iseq) : Qnil;
1639 }
1640 
1641 VALUE
1643 {
1644  const rb_iseq_t *iseq = frame2iseq(frame);
1645  return iseq ? rb_iseq_first_lineno(iseq) : Qnil;
1646 }
1647 
1648 static VALUE
1649 frame2klass(VALUE frame)
1650 {
1651  if (NIL_P(frame)) return Qnil;
1652 
1653  if (RB_TYPE_P(frame, T_IMEMO)) {
1655 
1656  if (imemo_type(frame) == imemo_ment) {
1657  return cme->defined_class;
1658  }
1659  }
1660  return Qnil;
1661 }
1662 
1663 VALUE
1665 {
1666  VALUE klass = frame2klass(frame);
1667 
1668  if (klass && !NIL_P(klass)) {
1669  if (RB_TYPE_P(klass, T_ICLASS)) {
1670  klass = RBASIC(klass)->klass;
1671  }
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);
1676  }
1677  return rb_class_path(klass);
1678  }
1679  else {
1680  return Qnil;
1681  }
1682 }
1683 
1684 VALUE
1686 {
1687  VALUE klass = frame2klass(frame);
1688 
1689  return RBOOL(klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON));
1690 }
1691 
1692 VALUE
1694 {
1695  const rb_callable_method_entry_t *cme = cframe(frame);
1696  if (cme) {
1697  ID mid = cme->def->original_id;
1698  return id2str(mid);
1699  }
1700  const rb_iseq_t *iseq = frame2iseq(frame);
1701  return iseq ? rb_iseq_method_name(iseq) : Qnil;
1702 }
1703 
1704 static VALUE
1705 qualified_method_name(VALUE frame, VALUE method_name)
1706 {
1707  if (method_name != Qnil) {
1708  VALUE classpath = rb_profile_frame_classpath(frame);
1709  VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
1710 
1711  if (classpath != Qnil) {
1712  return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
1713  classpath, singleton_p == Qtrue ? "." : "#", method_name);
1714  }
1715  else {
1716  return method_name;
1717  }
1718  }
1719  else {
1720  return Qnil;
1721  }
1722 }
1723 
1724 VALUE
1726 {
1727  VALUE method_name = rb_profile_frame_method_name(frame);
1728 
1729  return qualified_method_name(frame, method_name);
1730 }
1731 
1732 VALUE
1734 {
1735  const rb_callable_method_entry_t *cme = cframe(frame);
1736  if (cme) {
1737  ID mid = cme->def->original_id;
1738  VALUE method_name = id2str(mid);
1739  return qualified_method_name(frame, method_name);
1740  }
1741 
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);
1745 
1746  if (NIL_P(qualified_method_name) || base_label == qualified_method_name) {
1747  return label;
1748  }
1749  else {
1750  long label_length = RSTRING_LEN(label);
1751  long base_label_length = RSTRING_LEN(base_label);
1752  int prefix_len = rb_long2int(label_length - base_label_length);
1753 
1754  return rb_sprintf("%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);
1755  }
1756 }
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:685
int rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
Queries mysterious "frame"s of the given range.
VALUE rb_profile_frame_full_label(VALUE frame)
Identical to rb_profile_frame_label(), except it returns a qualified result.
VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
Queries the instruction sequence of the passed context's upper frame.
VALUE rb_profile_frame_method_name(VALUE frame)
Queries the name of the method of the passed frame.
VALUE rb_profile_frame_qualified_method_name(VALUE frame)
Identical to rb_profile_frame_method_name(), except it "qualifies" the return value with its defining...
VALUE rb_profile_frame_label(VALUE frame)
Queries human-readable "label" string.
VALUE rb_profile_frame_singleton_method_p(VALUE frame)
Queries if the method of the passed frame is a singleton class.
VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
Queries the backtrace object of the context.
VALUE rb_profile_frame_absolute_path(VALUE frame)
Identical to rb_profile_frame_path(), except it tries to expand the returning path.
VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
Prepares, executes, then cleans up a debug session.
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
Queries the current receiver of the passed context's upper frame.
VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
Queries the binding of the passed context's upper frame.
VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
Queries the current class of the passed context's upper frame.
VALUE rb_profile_frame_classpath(VALUE frame)
Queries the class path of the method that the passed frame represents.
VALUE rb_profile_frame_path(VALUE frame)
Queries the path of the passed backtrace.
VALUE rb_profile_frame_first_lineno(VALUE frame)
Queries the first line of the method of the passed frame pointer.
VALUE(* rb_debug_inspector_func_t)(const rb_debug_inspector_t *dc, void *data)
Type of the callback function passed to rb_debug_inspector_open().
Definition: debug.h:198
VALUE rb_profile_frame_base_label(VALUE frame)
Identical to rb_profile_frame_label(), except it does not "qualify" the result.
VALUE rb_enc_sprintf(rb_encoding *enc, const char *fmt,...)
Identical to rb_sprintf(), except it additionally takes an encoding.
Definition: sprintf.c:1182
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:869
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition: class.c:1938
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition: class.c:2406
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
Definition: class.c:1914
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:2110
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
Definition: fl_type.h:58
#define INT2FIX
Old name of RB_INT2FIX.
Definition: long.h:48
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition: assume.h:30
#define T_IMEMO
Old name of RUBY_T_IMEMO.
Definition: value_type.h:67
#define CLASS_OF
Old name of rb_class_of.
Definition: globals.h:203
#define FIX2INT
Old name of RB_FIX2INT.
Definition: int.h:41
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition: value_type.h:70
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition: memory.h:395
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition: assume.h:29
#define T_ICLASS
Old name of RUBY_T_ICLASS.
Definition: value_type.h:66
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition: long.h:50
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition: value_type.h:58
#define FL_TEST
Old name of RB_FL_TEST.
Definition: fl_type.h:139
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition: long.h:51
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition: array.h:651
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition: error.c:3025
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Checks if the given object is of given kind.
Definition: error.c:1049
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition: error.c:802
VALUE rb_eArgError
ArgumentError exception.
Definition: error.c:1100
VALUE rb_cArray
Array class.
Definition: array.c:40
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition: object.c:188
VALUE rb_cThread
Thread class.
Definition: vm.c:397
Encoding relates APIs.
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Look for the "common" encoding between the two.
Definition: encoding.c:1176
void rb_gc_register_mark_object(VALUE object)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Definition: gc.c:8687
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
Definition: array.c:2995
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition: array.c:750
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
Definition: array.c:1308
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
Definition: array.c:1679
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
Definition: array.c:1148
void rb_gc_mark(VALUE obj)
Marks an object.
Definition: gc.c:6775
void rb_gc_mark_movable(VALUE obj)
Maybe this is the only function provided for C extensions to control the pinning of objects,...
Definition: gc.c:6769
VALUE rb_gc_location(VALUE obj)
Finds a new "location" of an object.
Definition: gc.c:9754
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Deconstructs a numerical range.
Definition: range.c:1578
#define rb_str_new_literal(str)
Just another name of rb_str_new_lit.
Definition: string.h:1814
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
VALUE rb_str_inspect(VALUE str)
Generates a "readable" version of the receiver.
Definition: string.c:6456
VALUE rb_str_cat_cstr(VALUE dst, const char *src)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition: string.c:3171
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
Definition: variable.c:1285
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition: variable.c:172
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition: vm_method.c:1117
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
VALUE rb_make_backtrace(void)
Creates the good old fashioned array-of-strings style backtrace info.
void rb_backtrace(void)
Prints the backtrace out to the standard error.
VALUE rb_id2str(ID id)
Identical to rb_id2name(), except it returns a Ruby's String instead of C's.
Definition: symbol.c:935
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition: sprintf.c:1201
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition: sprintf.c:1241
#define rb_long2int
Just another name of rb_long2int_inline.
Definition: long.h:62
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Marshal format compatibility layer.
Definition: marshal.c:148
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition: memory.h:161
#define RARRAY_LEN
Just another name of rb_array_len.
Definition: rarray.h:68
#define RBASIC(obj)
Convenient casting macro.
Definition: rbasic.h:40
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:497
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:483
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition: rtypeddata.h:79
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition: rtypeddata.h:489
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
Definition: variable.c:300
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition: stdarg.h:35
Definition: method.h:62
This is the struct that holds necessary info for a struct.
Definition: rtypeddata.h:190
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
Definition: method.h:135
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition: value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition: value_type.h:375
void ruby_xfree(void *ptr)
Deallocates a storage instance.
Definition: gc.c:11775