Ruby  3.4.0dev (2024-11-05 revision 348a53415339076afc4a02fcd09f3ae36e9c4c61)
vm_backtrace.c (348a53415339076afc4a02fcd09f3ae36e9c4c61)
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/class.h"
15 #include "internal/error.h"
16 #include "internal/vm.h"
17 #include "iseq.h"
18 #include "ruby/debug.h"
19 #include "ruby/encoding.h"
20 #include "vm_core.h"
21 
22 static VALUE rb_cBacktrace;
23 static VALUE rb_cBacktraceLocation;
24 
25 static VALUE
26 id2str(ID id)
27 {
28  VALUE str = rb_id2str(id);
29  if (!str) return Qnil;
30  return str;
31 }
32 #define rb_id2str(id) id2str(id)
33 
34 #define BACKTRACE_START 0
35 #define ALL_BACKTRACE_LINES -1
36 
37 inline static int
38 calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id)
39 {
40  VM_ASSERT(iseq);
41 
42  if (pc == NULL) {
43  if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_TOP) {
44  VM_ASSERT(! ISEQ_BODY(iseq)->local_table);
45  VM_ASSERT(! ISEQ_BODY(iseq)->local_table_size);
46  return 0;
47  }
48  if (lineno) *lineno = ISEQ_BODY(iseq)->location.first_lineno;
49 #ifdef USE_ISEQ_NODE_ID
50  if (node_id) *node_id = -1;
51 #endif
52  return 1;
53  }
54  else {
55  VM_ASSERT(ISEQ_BODY(iseq));
56  VM_ASSERT(ISEQ_BODY(iseq)->iseq_encoded);
57  VM_ASSERT(ISEQ_BODY(iseq)->iseq_size);
58 
59  ptrdiff_t n = pc - ISEQ_BODY(iseq)->iseq_encoded;
60  VM_ASSERT(n >= 0);
61 #if SIZEOF_PTRDIFF_T > SIZEOF_INT
62  VM_ASSERT(n <= (ptrdiff_t)UINT_MAX);
63 #endif
64  VM_ASSERT((unsigned int)n <= ISEQ_BODY(iseq)->iseq_size);
65  ASSUME(n >= 0);
66  size_t pos = n; /* no overflow */
67  if (LIKELY(pos)) {
68  /* use pos-1 because PC points next instruction at the beginning of instruction */
69  pos--;
70  }
71 #if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
72  else {
73  /* SDR() is not possible; that causes infinite loop. */
74  rb_print_backtrace(stderr);
75  __builtin_trap();
76  }
77 #endif
78  if (lineno) *lineno = rb_iseq_line_no(iseq, pos);
79 #ifdef USE_ISEQ_NODE_ID
80  if (node_id) *node_id = rb_iseq_node_id(iseq, pos);
81 #endif
82  return 1;
83  }
84 }
85 
86 inline static int
87 calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
88 {
89  int lineno;
90  if (calc_pos(iseq, pc, &lineno, NULL)) return lineno;
91  return 0;
92 }
93 
94 #ifdef USE_ISEQ_NODE_ID
95 inline static int
96 calc_node_id(const rb_iseq_t *iseq, const VALUE *pc)
97 {
98  int node_id;
99  if (calc_pos(iseq, pc, NULL, &node_id)) return node_id;
100  return -1;
101 }
102 #endif
103 
104 int
105 rb_vm_get_sourceline(const rb_control_frame_t *cfp)
106 {
107  if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
108  const rb_iseq_t *iseq = cfp->iseq;
109  int line = calc_lineno(iseq, cfp->pc);
110  if (line != 0) {
111  return line;
112  }
113  else {
114  return ISEQ_BODY(iseq)->location.first_lineno;
115  }
116  }
117  else {
118  return 0;
119  }
120 }
121 
123  const rb_callable_method_entry_t *cme;
124  const rb_iseq_t *iseq;
125  const VALUE *pc;
127 
130  VALUE btobj;
131 };
132 
133 static void
134 location_mark(void *ptr)
135 {
136  struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
137  rb_gc_mark_movable(vfi->btobj);
138 }
139 
140 static void
141 location_ref_update(void *ptr)
142 {
143  struct valued_frame_info *vfi = ptr;
144  vfi->btobj = rb_gc_location(vfi->btobj);
145 }
146 
147 static void
148 location_mark_entry(rb_backtrace_location_t *fi)
149 {
150  rb_gc_mark((VALUE)fi->cme);
151  if (fi->iseq) rb_gc_mark_movable((VALUE)fi->iseq);
152 }
153 
154 static const rb_data_type_t location_data_type = {
155  "frame_info",
156  {
157  location_mark,
159  NULL, // No external memory to report,
160  location_ref_update,
161  },
162  0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
163 };
164 
165 int
166 rb_frame_info_p(VALUE obj)
167 {
168  return rb_typeddata_is_kind_of(obj, &location_data_type);
169 }
170 
171 static inline rb_backtrace_location_t *
172 location_ptr(VALUE locobj)
173 {
174  struct valued_frame_info *vloc;
175  TypedData_Get_Struct(locobj, struct valued_frame_info, &location_data_type, vloc);
176  return vloc->loc;
177 }
178 
179 static int
180 location_lineno(rb_backtrace_location_t *loc)
181 {
182  if (loc->iseq) {
183  return calc_lineno(loc->iseq, loc->pc);
184  }
185  return 0;
186 }
187 
188 /*
189  * Returns the line number of this frame.
190  *
191  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
192  *
193  * loc = c(0..1).first
194  * loc.lineno #=> 2
195  */
196 static VALUE
197 location_lineno_m(VALUE self)
198 {
199  return INT2FIX(location_lineno(location_ptr(self)));
200 }
201 
202 VALUE rb_mod_name0(VALUE klass, bool *permanent);
203 
204 VALUE
205 rb_gen_method_name(VALUE owner, VALUE name)
206 {
207  bool permanent;
208  if (RB_TYPE_P(owner, T_CLASS) || RB_TYPE_P(owner, T_MODULE)) {
209  if (RCLASS_SINGLETON_P(owner)) {
210  VALUE v = RCLASS_ATTACHED_OBJECT(owner);
211  if (RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE)) {
212  v = rb_mod_name0(v, &permanent);
213  if (permanent && !NIL_P(v)) {
214  return rb_sprintf("%"PRIsVALUE".%"PRIsVALUE, v, name);
215  }
216  }
217  }
218  else {
219  owner = rb_mod_name0(owner, &permanent);
220  if (permanent && !NIL_P(owner)) {
221  return rb_sprintf("%"PRIsVALUE"#%"PRIsVALUE, owner, name);
222  }
223  }
224  }
225  return name;
226 }
227 
228 static VALUE
229 calculate_iseq_label(VALUE owner, const rb_iseq_t *iseq)
230 {
231 retry:
232  switch (ISEQ_BODY(iseq)->type) {
233  case ISEQ_TYPE_TOP:
234  case ISEQ_TYPE_CLASS:
235  case ISEQ_TYPE_MAIN:
236  return ISEQ_BODY(iseq)->location.label;
237  case ISEQ_TYPE_METHOD:
238  return rb_gen_method_name(owner, ISEQ_BODY(iseq)->location.label);
239  case ISEQ_TYPE_BLOCK:
240  case ISEQ_TYPE_PLAIN: {
241  int level = 0;
242  const rb_iseq_t *orig_iseq = iseq;
243  if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
244  while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
245  if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
246  level++;
247  }
248  iseq = ISEQ_BODY(iseq)->parent_iseq;
249  }
250  }
251  if (level <= 1) {
252  return rb_sprintf("block in %"PRIsVALUE, calculate_iseq_label(owner, iseq));
253  }
254  else {
255  return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, calculate_iseq_label(owner, iseq));
256  }
257  }
258  case ISEQ_TYPE_RESCUE:
259  case ISEQ_TYPE_ENSURE:
260  case ISEQ_TYPE_EVAL:
261  iseq = ISEQ_BODY(iseq)->parent_iseq;
262  goto retry;
263  default:
264  rb_bug("calculate_iseq_label: unreachable");
265  }
266 }
267 
268 // Return true if a given location is a C method or supposed to behave like one.
269 static inline bool
270 location_cfunc_p(rb_backtrace_location_t *loc)
271 {
272  if (!loc->cme) return false;
273 
274  switch (loc->cme->def->type) {
275  case VM_METHOD_TYPE_CFUNC:
276  return true;
277  case VM_METHOD_TYPE_ISEQ:
278  return rb_iseq_attr_p(loc->cme->def->body.iseq.iseqptr, BUILTIN_ATTR_C_TRACE);
279  default:
280  return false;
281  }
282 }
283 
284 static VALUE
285 location_label(rb_backtrace_location_t *loc)
286 {
287  if (location_cfunc_p(loc)) {
288  return rb_gen_method_name(loc->cme->owner, rb_id2str(loc->cme->def->original_id));
289  }
290  else {
291  VALUE owner = Qnil;
292  if (loc->cme) {
293  owner = loc->cme->owner;
294  }
295  return calculate_iseq_label(owner, loc->iseq);
296  }
297 }
298 /*
299  * Returns the label of this frame.
300  *
301  * Usually consists of method, class, module, etc names with decoration.
302  *
303  * Consider the following example:
304  *
305  * def foo
306  * puts caller_locations(0).first.label
307  *
308  * 1.times do
309  * puts caller_locations(0).first.label
310  *
311  * 1.times do
312  * puts caller_locations(0).first.label
313  * end
314  * end
315  * end
316  *
317  * The result of calling +foo+ is this:
318  *
319  * foo
320  * block in foo
321  * block (2 levels) in foo
322  *
323  */
324 static VALUE
325 location_label_m(VALUE self)
326 {
327  return location_label(location_ptr(self));
328 }
329 
330 static VALUE
331 location_base_label(rb_backtrace_location_t *loc)
332 {
333  if (location_cfunc_p(loc)) {
334  return rb_id2str(loc->cme->def->original_id);
335  }
336 
337  return ISEQ_BODY(loc->iseq)->location.base_label;
338 }
339 
340 /*
341  * Returns the base label of this frame, which is usually equal to the label,
342  * without decoration.
343  *
344  * Consider the following example:
345  *
346  * def foo
347  * puts caller_locations(0).first.base_label
348  *
349  * 1.times do
350  * puts caller_locations(0).first.base_label
351  *
352  * 1.times do
353  * puts caller_locations(0).first.base_label
354  * end
355  * end
356  * end
357  *
358  * The result of calling +foo+ is this:
359  *
360  * foo
361  * foo
362  * foo
363  */
364 static VALUE
365 location_base_label_m(VALUE self)
366 {
367  return location_base_label(location_ptr(self));
368 }
369 
370 static const rb_iseq_t *
371 location_iseq(rb_backtrace_location_t *loc)
372 {
373  return loc->iseq;
374 }
375 
376 /*
377  * Returns the file name of this frame. This will generally be an absolute
378  * path, unless the frame is in the main script, in which case it will be the
379  * script location passed on the command line.
380  *
381  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
382  *
383  * loc = c(0..1).first
384  * loc.path #=> caller_locations.rb
385  */
386 static VALUE
387 location_path_m(VALUE self)
388 {
389  const rb_iseq_t *iseq = location_iseq(location_ptr(self));
390  return iseq ? rb_iseq_path(iseq) : Qnil;
391 }
392 
393 #ifdef USE_ISEQ_NODE_ID
394 static int
395 location_node_id(rb_backtrace_location_t *loc)
396 {
397  if (loc->iseq && loc->pc) {
398  return calc_node_id(loc->iseq, loc->pc);
399  }
400  return -1;
401 }
402 #endif
403 
404 int
405 rb_get_node_id_from_frame_info(VALUE obj)
406 {
407 #ifdef USE_ISEQ_NODE_ID
408  rb_backtrace_location_t *loc = location_ptr(obj);
409  return location_node_id(loc);
410 #else
411  return -1;
412 #endif
413 }
414 
415 const rb_iseq_t *
416 rb_get_iseq_from_frame_info(VALUE obj)
417 {
418  rb_backtrace_location_t *loc = location_ptr(obj);
419  const rb_iseq_t *iseq = location_iseq(loc);
420  return iseq;
421 }
422 
423 static VALUE
424 location_realpath(rb_backtrace_location_t *loc)
425 {
426  if (loc->iseq) {
427  return rb_iseq_realpath(loc->iseq);
428  }
429  return Qnil;
430 }
431 
432 /*
433  * Returns the full file path of this frame.
434  *
435  * Same as #path, except that it will return absolute path
436  * even if the frame is in the main script.
437  */
438 static VALUE
439 location_absolute_path_m(VALUE self)
440 {
441  return location_realpath(location_ptr(self));
442 }
443 
444 static VALUE
445 location_format(VALUE file, int lineno, VALUE name)
446 {
447  VALUE s = rb_enc_sprintf(rb_enc_compatible(file, name), "%s", RSTRING_PTR(file));
448  if (lineno != 0) {
449  rb_str_catf(s, ":%d", lineno);
450  }
451  rb_str_cat_cstr(s, ":in ");
452  if (NIL_P(name)) {
453  rb_str_cat_cstr(s, "unknown method");
454  }
455  else {
456  rb_str_catf(s, "'%s'", RSTRING_PTR(name));
457  }
458  return s;
459 }
460 
461 static VALUE
462 location_to_str(rb_backtrace_location_t *loc)
463 {
464  VALUE file, owner = Qnil, name;
465  int lineno;
466 
467  if (location_cfunc_p(loc)) {
468  if (loc->iseq && loc->pc) {
469  file = rb_iseq_path(loc->iseq);
470  lineno = calc_lineno(loc->iseq, loc->pc);
471  }
472  else {
473  file = GET_VM()->progname;
474  lineno = 0;
475  }
476  name = rb_gen_method_name(loc->cme->owner, rb_id2str(loc->cme->def->original_id));
477  }
478  else {
479  file = rb_iseq_path(loc->iseq);
480  lineno = calc_lineno(loc->iseq, loc->pc);
481  if (loc->cme) {
482  owner = loc->cme->owner;
483  }
484  name = calculate_iseq_label(owner, loc->iseq);
485  }
486 
487  return location_format(file, lineno, name);
488 }
489 
490 /*
491  * Returns a Kernel#caller style string representing this frame.
492  */
493 static VALUE
494 location_to_str_m(VALUE self)
495 {
496  return location_to_str(location_ptr(self));
497 }
498 
499 /*
500  * Returns the same as calling +inspect+ on the string representation of
501  * #to_str
502  */
503 static VALUE
504 location_inspect_m(VALUE self)
505 {
506  return rb_str_inspect(location_to_str(location_ptr(self)));
507 }
508 
509 typedef struct rb_backtrace_struct {
510  int backtrace_size;
511  VALUE strary;
512  VALUE locary;
513  rb_backtrace_location_t backtrace[1];
515 
516 static void
517 backtrace_mark(void *ptr)
518 {
520  size_t i, s = bt->backtrace_size;
521 
522  for (i=0; i<s; i++) {
523  location_mark_entry(&bt->backtrace[i]);
524  }
525  rb_gc_mark_movable(bt->strary);
526  rb_gc_mark_movable(bt->locary);
527 }
528 
529 static void
530 location_update_entry(rb_backtrace_location_t *fi)
531 {
532  fi->cme = (rb_callable_method_entry_t *)rb_gc_location((VALUE)fi->cme);
533  if (fi->iseq) {
534  fi->iseq = (rb_iseq_t *)rb_gc_location((VALUE)fi->iseq);
535  }
536 }
537 
538 static void
539 backtrace_update(void *ptr)
540 {
542  size_t i, s = bt->backtrace_size;
543 
544  for (i=0; i<s; i++) {
545  location_update_entry(&bt->backtrace[i]);
546  }
547  bt->strary = rb_gc_location(bt->strary);
548  bt->locary = rb_gc_location(bt->locary);
549 }
550 
551 static const rb_data_type_t backtrace_data_type = {
552  "backtrace",
553  {
554  backtrace_mark,
556  NULL, // No external memory to report,
557  backtrace_update,
558  },
559  /* Cannot set the RUBY_TYPED_EMBEDDABLE flag because the loc of frame_info
560  * points elements in the backtrace array. This can cause the loc to become
561  * incorrect if this backtrace object is moved by compaction. */
562  0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
563 };
564 
565 int
566 rb_backtrace_p(VALUE obj)
567 {
568  return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
569 }
570 
571 static VALUE
572 backtrace_alloc(VALUE klass)
573 {
574  rb_backtrace_t *bt;
575  VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
576  return obj;
577 }
578 
579 static VALUE
580 backtrace_alloc_capa(long num_frames, rb_backtrace_t **backtrace)
581 {
582  size_t memsize = offsetof(rb_backtrace_t, backtrace) + num_frames * sizeof(rb_backtrace_location_t);
583  VALUE btobj = rb_data_typed_object_zalloc(rb_cBacktrace, memsize, &backtrace_data_type);
584  TypedData_Get_Struct(btobj, rb_backtrace_t, &backtrace_data_type, *backtrace);
585  return btobj;
586 }
587 
588 
589 static long
590 backtrace_size(const rb_execution_context_t *ec)
591 {
592  const rb_control_frame_t *last_cfp = ec->cfp;
593  const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
594 
595  if (start_cfp == NULL) {
596  return -1;
597  }
598 
599  start_cfp =
600  RUBY_VM_NEXT_CONTROL_FRAME(
601  RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
602 
603  if (start_cfp < last_cfp) {
604  return 0;
605  }
606 
607  return start_cfp - last_cfp + 1;
608 }
609 
610 static bool
611 is_internal_location(const rb_control_frame_t *cfp)
612 {
613  static const char prefix[] = "<internal:";
614  const size_t prefix_len = sizeof(prefix) - 1;
615  VALUE file = rb_iseq_path(cfp->iseq);
616  return strncmp(prefix, RSTRING_PTR(file), prefix_len) == 0;
617 }
618 
619 static bool
620 is_rescue_or_ensure_frame(const rb_control_frame_t *cfp)
621 {
622  enum rb_iseq_type type = ISEQ_BODY(cfp->iseq)->type;
623  return type == ISEQ_TYPE_RESCUE || type == ISEQ_TYPE_ENSURE;
624 }
625 
626 static void
627 bt_update_cfunc_loc(unsigned long cfunc_counter, rb_backtrace_location_t *cfunc_loc, const rb_iseq_t *iseq, const VALUE *pc)
628 {
629  for (; cfunc_counter > 0; cfunc_counter--, cfunc_loc--) {
630  cfunc_loc->iseq = iseq;
631  cfunc_loc->pc = pc;
632  }
633 }
634 
635 static VALUE location_create(rb_backtrace_location_t *srcloc, void *btobj);
636 
637 static void
638 bt_yield_loc(rb_backtrace_location_t *loc, long num_frames, VALUE btobj)
639 {
640  for (; num_frames > 0; num_frames--, loc++) {
641  rb_yield(location_create(loc, (void *)btobj));
642  }
643 }
644 
645 static VALUE
646 rb_ec_partial_backtrace_object(const rb_execution_context_t *ec, long start_frame, long num_frames, int* start_too_large, bool skip_internal, bool do_yield)
647 {
648  const rb_control_frame_t *cfp = ec->cfp;
649  const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
650  ptrdiff_t size;
651  rb_backtrace_t *bt = NULL;
652  VALUE btobj = Qnil;
653  rb_backtrace_location_t *loc = NULL;
654  unsigned long cfunc_counter = 0;
655  bool skip_next_frame = FALSE;
656 
657  // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
658  if (end_cfp == NULL) {
659  num_frames = 0;
660  }
661  else {
662  end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
663 
664  /*
665  * top frame (dummy) <- RUBY_VM_END_CONTROL_FRAME
666  * top frame (dummy) <- end_cfp
667  * top frame <- main script
668  * top frame
669  * ...
670  * 2nd frame <- lev:0
671  * current frame <- ec->cfp
672  */
673 
674  size = end_cfp - cfp + 1;
675  if (size < 0) {
676  num_frames = 0;
677  }
678  else if (num_frames < 0 || num_frames > size) {
679  num_frames = size;
680  }
681  }
682 
683  btobj = backtrace_alloc_capa(num_frames, &bt);
684 
685  bt->backtrace_size = 0;
686  if (num_frames == 0) {
687  if (start_too_large) *start_too_large = 0;
688  return btobj;
689  }
690 
691  for (; cfp != end_cfp && (bt->backtrace_size < num_frames); cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
692  if (cfp->iseq) {
693  if (cfp->pc) {
694  if (start_frame > 0) {
695  start_frame--;
696  }
697  else if (!(skip_internal && is_internal_location(cfp))) {
698  if (!skip_next_frame) {
699  const rb_iseq_t *iseq = cfp->iseq;
700  const VALUE *pc = cfp->pc;
701  loc = &bt->backtrace[bt->backtrace_size++];
702  RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
703  // Ruby methods with `Primitive.attr! :c_trace` should behave like C methods
704  if (rb_iseq_attr_p(cfp->iseq, BUILTIN_ATTR_C_TRACE)) {
705  loc->iseq = NULL;
706  loc->pc = NULL;
707  cfunc_counter++;
708  }
709  else {
710  RB_OBJ_WRITE(btobj, &loc->iseq, iseq);
711  loc->pc = pc;
712  bt_update_cfunc_loc(cfunc_counter, loc-1, iseq, pc);
713  if (do_yield) {
714  bt_yield_loc(loc - cfunc_counter, cfunc_counter+1, btobj);
715  }
716  cfunc_counter = 0;
717  }
718  }
719  skip_next_frame = is_rescue_or_ensure_frame(cfp);
720  }
721  }
722  }
723  else {
724  VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
725  if (start_frame > 0) {
726  start_frame--;
727  }
728  else {
729  loc = &bt->backtrace[bt->backtrace_size++];
730  RB_OBJ_WRITE(btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
731  loc->iseq = NULL;
732  loc->pc = NULL;
733  cfunc_counter++;
734  }
735  }
736  }
737 
738  // When a backtrace entry corresponds to a method defined in C (e.g. rb_define_method), the reported file:line
739  // is the one of the caller Ruby frame, so if the last entry is a C frame we find the caller Ruby frame here.
740  if (cfunc_counter > 0) {
741  for (; cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
742  if (cfp->iseq && cfp->pc && !(skip_internal && is_internal_location(cfp))) {
743  VM_ASSERT(!skip_next_frame); // ISEQ_TYPE_RESCUE/ISEQ_TYPE_ENSURE should have a caller Ruby ISEQ, not a cfunc
744  bt_update_cfunc_loc(cfunc_counter, loc, cfp->iseq, cfp->pc);
745  RB_OBJ_WRITTEN(btobj, Qundef, cfp->iseq);
746  if (do_yield) {
747  bt_yield_loc(loc - cfunc_counter, cfunc_counter, btobj);
748  }
749  break;
750  }
751  }
752  }
753 
754  if (start_too_large) *start_too_large = (start_frame > 0 ? -1 : 0);
755  return btobj;
756 }
757 
758 VALUE
759 rb_ec_backtrace_object(const rb_execution_context_t *ec)
760 {
761  return rb_ec_partial_backtrace_object(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, NULL, FALSE, FALSE);
762 }
763 
764 static VALUE
765 backtrace_collect(rb_backtrace_t *bt, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
766 {
767  VALUE btary;
768  int i;
769 
770  btary = rb_ary_new2(bt->backtrace_size);
771 
772  for (i=0; i<bt->backtrace_size; i++) {
773  rb_backtrace_location_t *loc = &bt->backtrace[i];
774  rb_ary_push(btary, func(loc, arg));
775  }
776 
777  return btary;
778 }
779 
780 static VALUE
781 location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
782 {
783  return location_to_str(loc);
784 }
785 
786 static VALUE
787 backtrace_to_str_ary(VALUE self)
788 {
789  VALUE r;
790  rb_backtrace_t *bt;
791  TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
792  r = backtrace_collect(bt, location_to_str_dmyarg, 0);
793  RB_GC_GUARD(self);
794  return r;
795 }
796 
797 VALUE
798 rb_backtrace_to_str_ary(VALUE self)
799 {
800  rb_backtrace_t *bt;
801  TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
802 
803  if (!bt->strary) {
804  RB_OBJ_WRITE(self, &bt->strary, backtrace_to_str_ary(self));
805  }
806  return bt->strary;
807 }
808 
809 void
810 rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self)
811 {
812  rb_backtrace_t *bt;
814 
815  TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
816  VM_ASSERT(bt->backtrace_size > 0);
817 
818  loc = &bt->backtrace[0];
819 
820  VM_ASSERT(!loc->cme || loc->cme->def->type == VM_METHOD_TYPE_ISEQ);
821 
822  loc->pc = NULL; // means location.first_lineno
823 }
824 
825 static VALUE
826 location_create(rb_backtrace_location_t *srcloc, void *btobj)
827 {
828  VALUE obj;
829  struct valued_frame_info *vloc;
830  obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
831 
832  vloc->loc = srcloc;
833  RB_OBJ_WRITE(obj, &vloc->btobj, (VALUE)btobj);
834 
835  return obj;
836 }
837 
838 static VALUE
839 backtrace_to_location_ary(VALUE self)
840 {
841  VALUE r;
842  rb_backtrace_t *bt;
843  TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
844  r = backtrace_collect(bt, location_create, (void *)self);
845  RB_GC_GUARD(self);
846  return r;
847 }
848 
849 VALUE
850 rb_backtrace_to_location_ary(VALUE self)
851 {
852  rb_backtrace_t *bt;
853  TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
854 
855  if (!bt->locary) {
856  RB_OBJ_WRITE(self, &bt->locary, backtrace_to_location_ary(self));
857  }
858  return bt->locary;
859 }
860 
861 VALUE
862 rb_location_ary_to_backtrace(VALUE ary)
863 {
864  if (!RB_TYPE_P(ary, T_ARRAY) || !rb_frame_info_p(RARRAY_AREF(ary, 0))) {
865  return Qfalse;
866  }
867 
868  rb_backtrace_t *new_backtrace;
869  long num_frames = RARRAY_LEN(ary);
870  VALUE btobj = backtrace_alloc_capa(num_frames, &new_backtrace);
871 
872  for (long index = 0; index < RARRAY_LEN(ary); index++) {
873  VALUE locobj = RARRAY_AREF(ary, index);
874 
875  if (!rb_frame_info_p(locobj)) {
876  return Qfalse;
877  }
878 
879  struct valued_frame_info *src_vloc;
880  TypedData_Get_Struct(locobj, struct valued_frame_info, &location_data_type, src_vloc);
881 
882  rb_backtrace_location_t *dst_location = &new_backtrace->backtrace[index];
883  RB_OBJ_WRITE(btobj, &dst_location->cme, src_vloc->loc->cme);
884  RB_OBJ_WRITE(btobj, &dst_location->iseq, src_vloc->loc->iseq);
885  dst_location->pc = src_vloc->loc->pc;
886 
887  new_backtrace->backtrace_size++;
888 
889  RB_GC_GUARD(locobj);
890  }
891 
892  return btobj;
893 }
894 
895 static VALUE
896 backtrace_dump_data(VALUE self)
897 {
898  VALUE str = rb_backtrace_to_str_ary(self);
899  return str;
900 }
901 
902 static VALUE
903 backtrace_load_data(VALUE self, VALUE str)
904 {
905  rb_backtrace_t *bt;
906  TypedData_Get_Struct(self, rb_backtrace_t, &backtrace_data_type, bt);
907  RB_OBJ_WRITE(self, &bt->strary, str);
908  return self;
909 }
910 
911 /*
912  * call-seq: Thread::Backtrace::limit -> integer
913  *
914  * Returns maximum backtrace length set by <tt>--backtrace-limit</tt>
915  * command-line option. The default is <tt>-1</tt> which means unlimited
916  * backtraces. If the value is zero or positive, the error backtraces,
917  * produced by Exception#full_message, are abbreviated and the extra lines
918  * are replaced by <tt>... 3 levels... </tt>
919  *
920  * $ ruby -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
921  * - 1
922  * .../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)
923  * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
924  * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
925  * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
926  * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
927  * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
928  * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
929  * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
930  * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
931  * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
932  * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
933  * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
934  * from .../lib/ruby/3.1.0/net/http.rb:998:in `connect'
935  * from .../lib/ruby/3.1.0/net/http.rb:976:in `do_start'
936  * from .../lib/ruby/3.1.0/net/http.rb:965:in `start'
937  * from .../lib/ruby/3.1.0/net/http.rb:627:in `start'
938  * from .../lib/ruby/3.1.0/net/http.rb:503:in `get_response'
939  * from .../lib/ruby/3.1.0/net/http.rb:474:in `get'
940  * from -e:1:in `<main>'
941  *
942  * $ ruby --backtrace-limit 2 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
943  * 2
944  * .../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)
945  * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
946  * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
947  * ... 7 levels...
948  * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
949  * from .../lib/ruby/3.1.0/socket.rb:227:in `foreach'
950  * from .../lib/ruby/3.1.0/socket.rb:632:in `tcp'
951  * ... 7 levels...
952  *
953  * $ ruby --backtrace-limit 0 -r net/http -e "p Thread::Backtrace.limit; Net::HTTP.get(URI('http://wrong.address'))"
954  * 0
955  * .../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)
956  * ... 9 levels...
957  * .../lib/ruby/3.1.0/socket.rb:227:in `getaddrinfo': getaddrinfo: Name or service not known (SocketError)
958  * ... 9 levels...
959  *
960  */
961 static VALUE
962 backtrace_limit(VALUE self)
963 {
964  return LONG2NUM(rb_backtrace_length_limit);
965 }
966 
967 VALUE
968 rb_ec_backtrace_str_ary(const rb_execution_context_t *ec, long lev, long n)
969 {
970  return rb_backtrace_to_str_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, FALSE));
971 }
972 
973 VALUE
974 rb_ec_backtrace_location_ary(const rb_execution_context_t *ec, long lev, long n, bool skip_internal)
975 {
976  return rb_backtrace_to_location_ary(rb_ec_partial_backtrace_object(ec, lev, n, NULL, skip_internal, FALSE));
977 }
978 
979 /* make old style backtrace directly */
980 
981 static void
982 backtrace_each(const rb_execution_context_t *ec,
983  void (*init)(void *arg, size_t size),
984  void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
985  void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
986  void *arg)
987 {
988  const rb_control_frame_t *last_cfp = ec->cfp;
989  const rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
990  const rb_control_frame_t *cfp;
991  ptrdiff_t size, i;
992 
993  // In the case the thread vm_stack or cfp is not initialized, there is no backtrace.
994  if (start_cfp == NULL) {
995  init(arg, 0);
996  return;
997  }
998 
999  /* <- start_cfp (end control frame)
1000  * top frame (dummy)
1001  * top frame (dummy)
1002  * top frame <- start_cfp
1003  * top frame
1004  * ...
1005  * 2nd frame <- lev:0
1006  * current frame <- ec->cfp
1007  */
1008 
1009  start_cfp =
1010  RUBY_VM_NEXT_CONTROL_FRAME(
1011  RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
1012 
1013  if (start_cfp < last_cfp) {
1014  size = 0;
1015  }
1016  else {
1017  size = start_cfp - last_cfp + 1;
1018  }
1019 
1020  init(arg, size);
1021 
1022  /* SDR(); */
1023  for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
1024  /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp); */
1025  if (cfp->iseq) {
1026  if (cfp->pc) {
1027  iter_iseq(arg, cfp);
1028  }
1029  }
1030  else {
1031  VM_ASSERT(RUBYVM_CFUNC_FRAME_P(cfp));
1032  const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
1033  ID mid = me->def->original_id;
1034 
1035  iter_cfunc(arg, cfp, mid);
1036  }
1037  }
1038 }
1039 
1040 struct oldbt_arg {
1041  VALUE filename;
1042  int lineno;
1043  void (*func)(void *data, VALUE file, int lineno, VALUE name);
1044  void *data; /* result */
1045 };
1046 
1047 static void
1048 oldbt_init(void *ptr, size_t dmy)
1049 {
1050  struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
1051  arg->filename = GET_VM()->progname;
1052  arg->lineno = 0;
1053 }
1054 
1055 static void
1056 oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
1057 {
1058  const rb_iseq_t *iseq = cfp->iseq;
1059  const VALUE *pc = cfp->pc;
1060  struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
1061  VALUE file = arg->filename = rb_iseq_path(iseq);
1062  VALUE name = ISEQ_BODY(iseq)->location.label;
1063  int lineno = arg->lineno = calc_lineno(iseq, pc);
1064 
1065  (arg->func)(arg->data, file, lineno, name);
1066 }
1067 
1068 static void
1069 oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
1070 {
1071  struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
1072  VALUE file = arg->filename;
1073  VALUE name = rb_id2str(mid);
1074  int lineno = arg->lineno;
1075 
1076  (arg->func)(arg->data, file, lineno, name);
1077 }
1078 
1079 static void
1080 oldbt_print(void *data, VALUE file, int lineno, VALUE name)
1081 {
1082  FILE *fp = (FILE *)data;
1083 
1084  if (NIL_P(name)) {
1085  fprintf(fp, "\tfrom %s:%d:in unknown method\n",
1086  RSTRING_PTR(file), lineno);
1087  }
1088  else {
1089  fprintf(fp, "\tfrom %s:%d:in '%s'\n",
1090  RSTRING_PTR(file), lineno, RSTRING_PTR(name));
1091  }
1092 }
1093 
1094 static void
1095 vm_backtrace_print(FILE *fp)
1096 {
1097  struct oldbt_arg arg;
1098 
1099  arg.func = oldbt_print;
1100  arg.data = (void *)fp;
1101  backtrace_each(GET_EC(),
1102  oldbt_init,
1103  oldbt_iter_iseq,
1104  oldbt_iter_cfunc,
1105  &arg);
1106 }
1107 
1109  FILE *fp;
1110  int count;
1111 };
1112 
1113 static void
1114 oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
1115 {
1116  struct oldbt_bugreport_arg *p = arg;
1117  FILE *fp = p->fp;
1118  const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
1119  if (!p->count) {
1120  fprintf(fp, "-- Ruby level backtrace information "
1121  "----------------------------------------\n");
1122  p->count = 1;
1123  }
1124  if (NIL_P(method)) {
1125  fprintf(fp, "%s:%d:in unknown method\n", filename, line);
1126  }
1127  else {
1128  fprintf(fp, "%s:%d:in '%s'\n", filename, line, RSTRING_PTR(method));
1129  }
1130 }
1131 
1132 void
1133 rb_backtrace_print_as_bugreport(FILE *fp)
1134 {
1135  struct oldbt_arg arg;
1136  struct oldbt_bugreport_arg barg = {fp, 0};
1137 
1138  arg.func = oldbt_bugreport;
1139  arg.data = &barg;
1140 
1141  backtrace_each(GET_EC(),
1142  oldbt_init,
1143  oldbt_iter_iseq,
1144  oldbt_iter_cfunc,
1145  &arg);
1146 }
1147 
1148 void
1150 {
1151  vm_backtrace_print(stderr);
1152 }
1153 
1155  VALUE (*iter)(VALUE recv, VALUE str);
1156  VALUE output;
1157 };
1158 
1159 static void
1160 oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
1161 {
1162  const struct print_to_arg *arg = data;
1163  VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
1164 
1165  if (NIL_P(name)) {
1166  rb_str_cat2(str, "unknown method\n");
1167  }
1168  else {
1169  rb_str_catf(str, " '%"PRIsVALUE"'\n", name);
1170  }
1171  (*arg->iter)(arg->output, str);
1172 }
1173 
1174 void
1175 rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output)
1176 {
1177  struct oldbt_arg arg;
1178  struct print_to_arg parg;
1179 
1180  parg.iter = iter;
1181  parg.output = output;
1182  arg.func = oldbt_print_to;
1183  arg.data = &parg;
1184  backtrace_each(GET_EC(),
1185  oldbt_init,
1186  oldbt_iter_iseq,
1187  oldbt_iter_cfunc,
1188  &arg);
1189 }
1190 
1191 VALUE
1193 {
1194  return rb_ec_backtrace_str_ary(GET_EC(), BACKTRACE_START, ALL_BACKTRACE_LINES);
1195 }
1196 
1197 static long
1198 ec_backtrace_range(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, long *len_ptr)
1199 {
1200  VALUE level, vn, opts;
1201  long lev, n;
1202 
1203  rb_scan_args(argc, argv, "02:", &level, &vn, &opts);
1204 
1205  if (!NIL_P(opts)) {
1206  rb_get_kwargs(opts, (ID []){0}, 0, 0, NULL);
1207  }
1208  if (argc == 2 && NIL_P(vn)) argc--;
1209 
1210  switch (argc) {
1211  case 0:
1212  lev = lev_default + lev_plus;
1213  n = ALL_BACKTRACE_LINES;
1214  break;
1215  case 1:
1216  {
1217  long beg, len, bt_size = backtrace_size(ec);
1218  switch (rb_range_beg_len(level, &beg, &len, bt_size - lev_plus, 0)) {
1219  case Qfalse:
1220  lev = NUM2LONG(level);
1221  if (lev < 0) {
1222  rb_raise(rb_eArgError, "negative level (%ld)", lev);
1223  }
1224  lev += lev_plus;
1225  n = ALL_BACKTRACE_LINES;
1226  break;
1227  case Qnil:
1228  return -1;
1229  default:
1230  lev = beg + lev_plus;
1231  n = len;
1232  break;
1233  }
1234  break;
1235  }
1236  case 2:
1237  lev = NUM2LONG(level);
1238  n = NUM2LONG(vn);
1239  if (lev < 0) {
1240  rb_raise(rb_eArgError, "negative level (%ld)", lev);
1241  }
1242  if (n < 0) {
1243  rb_raise(rb_eArgError, "negative size (%ld)", n);
1244  }
1245  lev += lev_plus;
1246  break;
1247  default:
1248  lev = n = 0; /* to avoid warning */
1249  break;
1250  }
1251 
1252  *len_ptr = n;
1253  return lev;
1254 }
1255 
1256 static VALUE
1257 ec_backtrace_to_ary(const rb_execution_context_t *ec, int argc, const VALUE *argv, int lev_default, int lev_plus, int to_str)
1258 {
1259  long lev, n;
1260  VALUE btval, r;
1261  int too_large;
1262 
1263  lev = ec_backtrace_range(ec, argc, argv, lev_default, lev_plus, &n);
1264  if (lev < 0) return Qnil;
1265 
1266  if (n == 0) {
1267  return rb_ary_new();
1268  }
1269 
1270  btval = rb_ec_partial_backtrace_object(ec, lev, n, &too_large, FALSE, FALSE);
1271 
1272  if (too_large) {
1273  return Qnil;
1274  }
1275 
1276  if (to_str) {
1277  r = backtrace_to_str_ary(btval);
1278  }
1279  else {
1280  r = backtrace_to_location_ary(btval);
1281  }
1282  RB_GC_GUARD(btval);
1283  return r;
1284 }
1285 
1286 static VALUE
1287 thread_backtrace_to_ary(int argc, const VALUE *argv, VALUE thval, int to_str)
1288 {
1289  rb_thread_t *target_th = rb_thread_ptr(thval);
1290 
1291  if (target_th->to_kill || target_th->status == THREAD_KILLED)
1292  return Qnil;
1293 
1294  return ec_backtrace_to_ary(target_th->ec, argc, argv, 0, 0, to_str);
1295 }
1296 
1297 VALUE
1298 rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval)
1299 {
1300  return thread_backtrace_to_ary(argc, argv, thval, 1);
1301 }
1302 
1303 VALUE
1304 rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval)
1305 {
1306  return thread_backtrace_to_ary(argc, argv, thval, 0);
1307 }
1308 
1309 VALUE
1310 rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1311 {
1312  return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 1);
1313 }
1314 
1315 VALUE
1316 rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec)
1317 {
1318  return ec_backtrace_to_ary(ec, argc, argv, 0, 0, 0);
1319 }
1320 
1321 /*
1322  * call-seq:
1323  * caller(start=1, length=nil) -> array or nil
1324  * caller(range) -> array or nil
1325  *
1326  * Returns the current execution stack---an array containing strings in
1327  * the form <code>file:line</code> or <code>file:line: in
1328  * `method'</code>.
1329  *
1330  * The optional _start_ parameter determines the number of initial stack
1331  * entries to omit from the top of the stack.
1332  *
1333  * A second optional +length+ parameter can be used to limit how many entries
1334  * are returned from the stack.
1335  *
1336  * Returns +nil+ if _start_ is greater than the size of
1337  * current execution stack.
1338  *
1339  * Optionally you can pass a range, which will return an array containing the
1340  * entries within the specified range.
1341  *
1342  * def a(skip)
1343  * caller(skip)
1344  * end
1345  * def b(skip)
1346  * a(skip)
1347  * end
1348  * def c(skip)
1349  * b(skip)
1350  * end
1351  * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
1352  * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
1353  * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
1354  * c(3) #=> ["prog:13:in `<main>'"]
1355  * c(4) #=> []
1356  * c(5) #=> nil
1357  */
1358 
1359 static VALUE
1360 rb_f_caller(int argc, VALUE *argv, VALUE _)
1361 {
1362  return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 1);
1363 }
1364 
1365 /*
1366  * call-seq:
1367  * caller_locations(start=1, length=nil) -> array or nil
1368  * caller_locations(range) -> array or nil
1369  *
1370  * Returns the current execution stack---an array containing
1371  * backtrace location objects.
1372  *
1373  * See Thread::Backtrace::Location for more information.
1374  *
1375  * The optional _start_ parameter determines the number of initial stack
1376  * entries to omit from the top of the stack.
1377  *
1378  * A second optional +length+ parameter can be used to limit how many entries
1379  * are returned from the stack.
1380  *
1381  * Returns +nil+ if _start_ is greater than the size of
1382  * current execution stack.
1383  *
1384  * Optionally you can pass a range, which will return an array containing the
1385  * entries within the specified range.
1386  */
1387 static VALUE
1388 rb_f_caller_locations(int argc, VALUE *argv, VALUE _)
1389 {
1390  return ec_backtrace_to_ary(GET_EC(), argc, argv, 1, 1, 0);
1391 }
1392 
1393 /*
1394  * call-seq:
1395  * Thread.each_caller_location(...) { |loc| ... } -> nil
1396  *
1397  * Yields each frame of the current execution stack as a
1398  * backtrace location object.
1399  */
1400 static VALUE
1401 each_caller_location(int argc, VALUE *argv, VALUE _)
1402 {
1403  rb_execution_context_t *ec = GET_EC();
1404  long n, lev = ec_backtrace_range(ec, argc, argv, 1, 1, &n);
1405  if (lev >= 0 && n != 0) {
1406  rb_ec_partial_backtrace_object(ec, lev, n, NULL, FALSE, TRUE);
1407  }
1408  return Qnil;
1409 }
1410 
1411 /* called from Init_vm() in vm.c */
1412 void
1413 Init_vm_backtrace(void)
1414 {
1415  /*
1416  * An internal representation of the backtrace. The user will never interact with
1417  * objects of this class directly, but class methods can be used to get backtrace
1418  * settings of the current session.
1419  */
1420  rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
1421  rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
1422  rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
1423  rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
1424  rb_define_singleton_method(rb_cBacktrace, "limit", backtrace_limit, 0);
1425 
1426  /*
1427  * An object representation of a stack frame, initialized by
1428  * Kernel#caller_locations.
1429  *
1430  * For example:
1431  *
1432  * # caller_locations.rb
1433  * def a(skip)
1434  * caller_locations(skip)
1435  * end
1436  * def b(skip)
1437  * a(skip)
1438  * end
1439  * def c(skip)
1440  * b(skip)
1441  * end
1442  *
1443  * c(0..2).map do |call|
1444  * puts call.to_s
1445  * end
1446  *
1447  * Running <code>ruby caller_locations.rb</code> will produce:
1448  *
1449  * caller_locations.rb:2:in `a'
1450  * caller_locations.rb:5:in `b'
1451  * caller_locations.rb:8:in `c'
1452  *
1453  * Here's another example with a slightly different result:
1454  *
1455  * # foo.rb
1456  * class Foo
1457  * attr_accessor :locations
1458  * def initialize(skip)
1459  * @locations = caller_locations(skip)
1460  * end
1461  * end
1462  *
1463  * Foo.new(0..2).locations.map do |call|
1464  * puts call.to_s
1465  * end
1466  *
1467  * Now run <code>ruby foo.rb</code> and you should see:
1468  *
1469  * init.rb:4:in `initialize'
1470  * init.rb:8:in `new'
1471  * init.rb:8:in `<main>'
1472  */
1473  rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
1474  rb_undef_alloc_func(rb_cBacktraceLocation);
1475  rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
1476  rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
1477  rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
1478  rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
1479  rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
1480  rb_define_method(rb_cBacktraceLocation, "absolute_path", location_absolute_path_m, 0);
1481  rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
1482  rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
1483 
1484  rb_define_global_function("caller", rb_f_caller, -1);
1485  rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1486 
1487  rb_define_singleton_method(rb_cThread, "each_caller_location", each_caller_location, -1);
1488 }
1489 
1490 /* debugger API */
1491 
1492 RUBY_SYMBOL_EXPORT_BEGIN
1493 
1494 RUBY_SYMBOL_EXPORT_END
1495 
1498  rb_control_frame_t *cfp;
1499  VALUE backtrace;
1500  VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1501  long backtrace_size;
1502 };
1503 
1504 enum {
1505  CALLER_BINDING_SELF,
1506  CALLER_BINDING_CLASS,
1507  CALLER_BINDING_BINDING,
1508  CALLER_BINDING_ISEQ,
1509  CALLER_BINDING_CFP,
1510  CALLER_BINDING_DEPTH,
1511 };
1512 
1514  VALUE ary;
1515  const rb_execution_context_t *ec;
1516 };
1517 
1518 static void
1519 collect_caller_bindings_init(void *arg, size_t size)
1520 {
1521  /* */
1522 }
1523 
1524 static VALUE
1525 get_klass(const rb_control_frame_t *cfp)
1526 {
1527  VALUE klass;
1528  if (rb_vm_control_frame_id_and_class(cfp, 0, 0, &klass)) {
1529  if (RB_TYPE_P(klass, T_ICLASS)) {
1530  return RBASIC(klass)->klass;
1531  }
1532  else {
1533  return klass;
1534  }
1535  }
1536  else {
1537  return Qnil;
1538  }
1539 }
1540 
1541 static int
1542 frame_depth(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
1543 {
1544  VM_ASSERT(RUBY_VM_END_CONTROL_FRAME(ec) >= cfp);
1545  return (int)(RUBY_VM_END_CONTROL_FRAME(ec) - cfp);
1546 }
1547 
1548 static void
1549 collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
1550 {
1551  struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1552  VALUE frame = rb_ary_new2(6);
1553 
1554  rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1555  rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1556  rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
1557  rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? (VALUE)cfp->iseq : Qnil);
1558  rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1559  rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
1560 
1561  rb_ary_push(data->ary, frame);
1562 }
1563 
1564 static void
1565 collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
1566 {
1567  struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1568  VALUE frame = rb_ary_new2(6);
1569 
1570  rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1571  rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1572  rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
1573  rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
1574  rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1575  rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
1576 
1577  rb_ary_push(data->ary, frame);
1578 }
1579 
1580 static VALUE
1581 collect_caller_bindings(const rb_execution_context_t *ec)
1582 {
1583  int i;
1584  VALUE result;
1585  struct collect_caller_bindings_data data = {
1586  rb_ary_new(), ec
1587  };
1588 
1589  backtrace_each(ec,
1590  collect_caller_bindings_init,
1591  collect_caller_bindings_iseq,
1592  collect_caller_bindings_cfunc,
1593  &data);
1594 
1595  result = rb_ary_reverse(data.ary);
1596 
1597  /* bindings should be created from top of frame */
1598  for (i=0; i<RARRAY_LEN(result); i++) {
1599  VALUE entry = rb_ary_entry(result, i);
1600  VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
1601 
1602  if (!NIL_P(cfp_val)) {
1603  rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
1604  rb_ary_store(entry, CALLER_BINDING_BINDING, rb_vm_make_binding(ec, cfp));
1605  }
1606  }
1607 
1608  return result;
1609 }
1610 
1611 /*
1612  * Note that the passed `rb_debug_inspector_t' will be disabled
1613  * after `rb_debug_inspector_open'.
1614  */
1615 
1616 VALUE
1618 {
1619  rb_debug_inspector_t dbg_context;
1620  rb_execution_context_t *ec = GET_EC();
1621  enum ruby_tag_type state;
1622  volatile VALUE MAYBE_UNUSED(result);
1623 
1624  /* escape all env to heap */
1625  rb_vm_stack_to_heap(ec);
1626 
1627  dbg_context.ec = ec;
1628  dbg_context.cfp = dbg_context.ec->cfp;
1629  dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, BACKTRACE_START, ALL_BACKTRACE_LINES, FALSE);
1630  dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
1631  dbg_context.contexts = collect_caller_bindings(ec);
1632 
1633  EC_PUSH_TAG(ec);
1634  if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1635  result = (*func)(&dbg_context, data);
1636  }
1637  EC_POP_TAG();
1638 
1639  /* invalidate bindings? */
1640 
1641  if (state) {
1642  EC_JUMP_TAG(ec, state);
1643  }
1644 
1645  return result;
1646 }
1647 
1648 static VALUE
1649 frame_get(const rb_debug_inspector_t *dc, long index)
1650 {
1651  if (index < 0 || index >= dc->backtrace_size) {
1652  rb_raise(rb_eArgError, "no such frame");
1653  }
1654  return rb_ary_entry(dc->contexts, index);
1655 }
1656 
1657 VALUE
1659 {
1660  VALUE frame = frame_get(dc, index);
1661  return rb_ary_entry(frame, CALLER_BINDING_SELF);
1662 }
1663 
1664 VALUE
1666 {
1667  VALUE frame = frame_get(dc, index);
1668  return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1669 }
1670 
1671 VALUE
1673 {
1674  VALUE frame = frame_get(dc, index);
1675  return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1676 }
1677 
1678 VALUE
1680 {
1681  VALUE frame = frame_get(dc, index);
1682  VALUE iseq = rb_ary_entry(frame, CALLER_BINDING_ISEQ);
1683 
1684  return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) : Qnil;
1685 }
1686 
1687 VALUE
1689 {
1690  VALUE frame = frame_get(dc, index);
1691  return rb_ary_entry(frame, CALLER_BINDING_DEPTH);
1692 }
1693 
1694 VALUE
1696 {
1697  rb_execution_context_t *ec = GET_EC();
1698  return INT2FIX(frame_depth(ec, ec->cfp));
1699 }
1700 
1701 VALUE
1703 {
1704  return dc->backtrace;
1705 }
1706 
1707 static int
1708 thread_profile_frames(rb_execution_context_t *ec, int start, int limit, VALUE *buff, int *lines)
1709 {
1710  int i;
1711  const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
1712  const rb_control_frame_t *top = cfp;
1713  const rb_callable_method_entry_t *cme;
1714 
1715  // If this function is called inside a thread after thread creation, but
1716  // before the CFP has been created, just return 0. This can happen when
1717  // sampling via signals. Threads can be interrupted randomly by the
1718  // signal, including during the time after the thread has been created, but
1719  // before the CFP has been allocated
1720  if (!cfp) {
1721  return 0;
1722  }
1723 
1724  // Skip dummy frame; see `rb_ec_partial_backtrace_object` for details
1725  end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
1726 
1727  for (i=0; i<limit && cfp != end_cfp; cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)) {
1728  if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->pc != 0) {
1729  if (start > 0) {
1730  start--;
1731  continue;
1732  }
1733 
1734  /* record frame info */
1735  cme = rb_vm_frame_method_entry(cfp);
1736  if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
1737  buff[i] = (VALUE)cme;
1738  }
1739  else {
1740  buff[i] = (VALUE)cfp->iseq;
1741  }
1742 
1743  if (lines) {
1744  // The topmost frame may not have an updated PC because the JIT
1745  // may not have set one. The JIT compiler will update the PC
1746  // before entering a new function (so that `caller` will work),
1747  // so only the topmost frame could possibly have an out of date PC
1748  if (cfp == top && cfp->jit_return) {
1749  lines[i] = 0;
1750  }
1751  else {
1752  lines[i] = calc_lineno(cfp->iseq, cfp->pc);
1753  }
1754  }
1755 
1756  i++;
1757  }
1758  else {
1759  cme = rb_vm_frame_method_entry(cfp);
1760  if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
1761  if (start > 0) {
1762  start--;
1763  continue;
1764  }
1765  buff[i] = (VALUE)cme;
1766  if (lines) lines[i] = 0;
1767  i++;
1768  }
1769  }
1770  }
1771 
1772  return i;
1773 }
1774 
1775 int
1776 rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
1777 {
1778  rb_execution_context_t *ec = rb_current_execution_context(false);
1779 
1780  // If there is no EC, we may be attempting to profile a non-Ruby thread or a
1781  // M:N shared native thread which has no active Ruby thread.
1782  if (!ec) {
1783  return 0;
1784  }
1785 
1786  return thread_profile_frames(ec, start, limit, buff, lines);
1787 }
1788 
1789 int
1790 rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines)
1791 {
1792  rb_thread_t *th = rb_thread_ptr(thread);
1793  return thread_profile_frames(th->ec, start, limit, buff, lines);
1794 }
1795 
1796 static const rb_iseq_t *
1797 frame2iseq(VALUE frame)
1798 {
1799  if (NIL_P(frame)) return NULL;
1800 
1801  if (RB_TYPE_P(frame, T_IMEMO)) {
1802  switch (imemo_type(frame)) {
1803  case imemo_iseq:
1804  return (const rb_iseq_t *)frame;
1805  case imemo_ment:
1806  {
1808  switch (cme->def->type) {
1809  case VM_METHOD_TYPE_ISEQ:
1810  return cme->def->body.iseq.iseqptr;
1811  default:
1812  return NULL;
1813  }
1814  }
1815  default:
1816  break;
1817  }
1818  }
1819  rb_bug("frame2iseq: unreachable");
1820 }
1821 
1822 VALUE
1824 {
1825  const rb_iseq_t *iseq = frame2iseq(frame);
1826  return iseq ? rb_iseq_path(iseq) : Qnil;
1827 }
1828 
1829 static const rb_callable_method_entry_t *
1830 cframe(VALUE frame)
1831 {
1832  if (NIL_P(frame)) return NULL;
1833 
1834  if (RB_TYPE_P(frame, T_IMEMO)) {
1835  switch (imemo_type(frame)) {
1836  case imemo_ment:
1837  {
1839  switch (cme->def->type) {
1840  case VM_METHOD_TYPE_CFUNC:
1841  return cme;
1842  default:
1843  return NULL;
1844  }
1845  }
1846  default:
1847  return NULL;
1848  }
1849  }
1850 
1851  return NULL;
1852 }
1853 
1854 VALUE
1856 {
1857  if (cframe(frame)) {
1858  static VALUE cfunc_str = Qfalse;
1859  if (!cfunc_str) {
1860  cfunc_str = rb_str_new_literal("<cfunc>");
1861  rb_vm_register_global_object(cfunc_str);
1862  }
1863  return cfunc_str;
1864  }
1865  const rb_iseq_t *iseq = frame2iseq(frame);
1866  return iseq ? rb_iseq_realpath(iseq) : Qnil;
1867 }
1868 
1869 VALUE
1871 {
1872  const rb_iseq_t *iseq = frame2iseq(frame);
1873  return iseq ? rb_iseq_label(iseq) : Qnil;
1874 }
1875 
1876 VALUE
1878 {
1879  const rb_iseq_t *iseq = frame2iseq(frame);
1880  return iseq ? rb_iseq_base_label(iseq) : Qnil;
1881 }
1882 
1883 VALUE
1885 {
1886  const rb_iseq_t *iseq = frame2iseq(frame);
1887  return iseq ? rb_iseq_first_lineno(iseq) : Qnil;
1888 }
1889 
1890 static VALUE
1891 frame2klass(VALUE frame)
1892 {
1893  if (NIL_P(frame)) return Qnil;
1894 
1895  if (RB_TYPE_P(frame, T_IMEMO)) {
1897 
1898  if (imemo_type(frame) == imemo_ment) {
1899  return cme->defined_class;
1900  }
1901  }
1902  return Qnil;
1903 }
1904 
1905 VALUE
1907 {
1908  VALUE klass = frame2klass(frame);
1909 
1910  if (klass && !NIL_P(klass)) {
1911  if (RB_TYPE_P(klass, T_ICLASS)) {
1912  klass = RBASIC(klass)->klass;
1913  }
1914  else if (RCLASS_SINGLETON_P(klass)) {
1915  klass = RCLASS_ATTACHED_OBJECT(klass);
1916  if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE))
1917  return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass);
1918  }
1919  return rb_class_path(klass);
1920  }
1921  else {
1922  return Qnil;
1923  }
1924 }
1925 
1926 VALUE
1928 {
1929  VALUE klass = frame2klass(frame);
1930 
1931  return RBOOL(klass && !NIL_P(klass) && RCLASS_SINGLETON_P(klass));
1932 }
1933 
1934 VALUE
1936 {
1937  const rb_callable_method_entry_t *cme = cframe(frame);
1938  if (cme) {
1939  ID mid = cme->def->original_id;
1940  return id2str(mid);
1941  }
1942  const rb_iseq_t *iseq = frame2iseq(frame);
1943  return iseq ? rb_iseq_method_name(iseq) : Qnil;
1944 }
1945 
1946 static VALUE
1947 qualified_method_name(VALUE frame, VALUE method_name)
1948 {
1949  if (method_name != Qnil) {
1950  VALUE classpath = rb_profile_frame_classpath(frame);
1951  VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
1952 
1953  if (classpath != Qnil) {
1954  return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
1955  classpath, singleton_p == Qtrue ? "." : "#", method_name);
1956  }
1957  else {
1958  return method_name;
1959  }
1960  }
1961  else {
1962  return Qnil;
1963  }
1964 }
1965 
1966 VALUE
1968 {
1969  VALUE method_name = rb_profile_frame_method_name(frame);
1970 
1971  return qualified_method_name(frame, method_name);
1972 }
1973 
1974 VALUE
1976 {
1977  const rb_callable_method_entry_t *cme = cframe(frame);
1978  if (cme) {
1979  ID mid = cme->def->original_id;
1980  VALUE method_name = id2str(mid);
1981  return qualified_method_name(frame, method_name);
1982  }
1983 
1984  VALUE label = rb_profile_frame_label(frame);
1985  VALUE base_label = rb_profile_frame_base_label(frame);
1986  VALUE qualified_method_name = rb_profile_frame_qualified_method_name(frame);
1987 
1988  if (NIL_P(qualified_method_name) || base_label == qualified_method_name) {
1989  return label;
1990  }
1991  else {
1992  long label_length = RSTRING_LEN(label);
1993  long base_label_length = RSTRING_LEN(base_label);
1994  int prefix_len = rb_long2int(label_length - base_label_length);
1995 
1996  return rb_sprintf("%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);
1997  }
1998 }
#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_debug_inspector_current_depth(void)
Return current frmae depth.
VALUE rb_profile_frame_method_name(VALUE frame)
Queries the name of the method of the passed frame.
VALUE rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index)
Queries the depth of the passed context's upper 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.
int rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines)
Queries mysterious "frame"s of the given range.
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:218
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:1198
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:1012
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition: class.c:2166
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:2635
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
Definition: class.c:2142
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition: class.c:2424
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:2339
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition: long.h:48
#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 T_MODULE
Old name of RUBY_T_MODULE.
Definition: value_type.h:70
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition: assume.h:27
#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 T_ARRAY
Old name of RUBY_T_ARRAY.
Definition: value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition: value_type.h:58
#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:657
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition: error.c:3627
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:1353
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition: error.c:1088
VALUE rb_eArgError
ArgumentError exception.
Definition: error.c:1404
VALUE rb_cArray
Array class.
Definition: array.c:40
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition: object.c:247
VALUE rb_cThread
Thread class.
Definition: vm.c:543
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition: gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition: gc.h:603
Encoding relates APIs.
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Look for the "common" encoding between the two.
Definition: encoding.c:1125
void rb_gc_mark(VALUE obj)
Marks an object.
Definition: gc.c:2094
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:2076
VALUE rb_gc_location(VALUE obj)
Finds a new "location" of an object.
Definition: gc.c:3004
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
Definition: array.c:3119
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition: array.c:747
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
Definition: array.c:1384
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
Definition: array.c:1737
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:1207
VALUE rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
Deconstructs a numerical range.
Definition: range.c:1842
#define rb_str_new_literal(str)
Just another name of rb_str_new_lit.
Definition: string.h:1750
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:7185
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:3440
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition: variable.c:293
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition: vm_method.c:1286
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:986
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition: io.h:2
int len
Length of the buffer.
Definition: io.h:8
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition: sprintf.c:1217
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:1240
VALUE rb_yield(VALUE val)
Yields the block.
Definition: vm_eval.c:1354
#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:134
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition: memory.h:162
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:56
#define RARRAY_LEN
Just another name of rb_array_len.
Definition: rarray.h:51
#define RARRAY_AREF(a, i)
Definition: rarray.h:403
#define RBASIC(obj)
Convenient casting macro.
Definition: rbasic.h:40
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition: rdata.h:78
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:416
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:367
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition: rtypeddata.h:79
VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type)
Identical to rb_data_typed_object_wrap(), except it allocates a new data region internally instead of...
Definition: gc.c:981
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition: rtypeddata.h:515
#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:497
const char * rb_class2name(VALUE klass)
Queries the name of the passed class.
Definition: variable.c:418
#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:200
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:376