Ruby  2.0.0p645(2015-04-13revision50299)
vm_backtrace.c
Go to the documentation of this file.
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 "ruby/ruby.h"
13 #include "ruby/encoding.h"
14 #include "ruby/debug.h"
15 
16 #include "internal.h"
17 #include "vm_core.h"
18 #include "eval_intern.h"
19 #include "iseq.h"
20 
23 
24 extern VALUE ruby_engine_name;
25 
26 inline static int
27 calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
28 {
29  return rb_iseq_line_no(iseq, pc - iseq->iseq_encoded);
30 }
31 
32 int
34 {
35  int lineno = 0;
36  const rb_iseq_t *iseq = cfp->iseq;
37 
38  if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
39  lineno = calc_lineno(cfp->iseq, cfp->pc);
40  }
41  return lineno;
42 }
43 
50  } type;
51 
52  union {
53  struct {
54  const rb_iseq_t *iseq;
55  union {
56  const VALUE *pc;
57  int lineno;
58  } lineno;
59  } iseq;
60  struct {
63  } cfunc;
64  } body;
66 
70 };
71 
72 static void
74 {
75  if (ptr) {
76  struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
77  rb_gc_mark(vfi->btobj);
78  }
79 }
80 
81 static void
83 {
84  switch (fi->type) {
85  case LOCATION_TYPE_ISEQ:
86  case LOCATION_TYPE_ISEQ_CALCED:
87  rb_gc_mark(fi->body.iseq.iseq->self);
88  break;
89  case LOCATION_TYPE_CFUNC:
90  case LOCATION_TYPE_IFUNC:
91  default:
92  break;
93  }
94 }
95 
96 static void
98 {
99  if (ptr) {
101  ruby_xfree(fi);
102  }
103 }
104 
105 static size_t
106 location_memsize(const void *ptr)
107 {
108  /* rb_backtrace_location_t *fi = (rb_backtrace_location_t *)ptr; */
109  return sizeof(rb_backtrace_location_t);
110 }
111 
113  "frame_info",
115 };
116 
117 static inline rb_backtrace_location_t *
119 {
120  struct valued_frame_info *vloc;
121  GetCoreDataFromValue(locobj, struct valued_frame_info, vloc);
122  return vloc->loc;
123 }
124 
125 static int
127 {
128  switch (loc->type) {
129  case LOCATION_TYPE_ISEQ:
130  loc->type = LOCATION_TYPE_ISEQ_CALCED;
131  return (loc->body.iseq.lineno.lineno = calc_lineno(loc->body.iseq.iseq, loc->body.iseq.lineno.pc));
132  case LOCATION_TYPE_ISEQ_CALCED:
133  return loc->body.iseq.lineno.lineno;
134  case LOCATION_TYPE_CFUNC:
135  if (loc->body.cfunc.prev_loc) {
136  return location_lineno(loc->body.cfunc.prev_loc);
137  }
138  return 0;
139  default:
140  rb_bug("location_lineno: unreachable");
141  UNREACHABLE;
142  }
143 }
144 
145 /*
146  * Returns the line number of this frame.
147  *
148  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
149  *
150  * loc = c(0..1).first
151  * loc.lineno #=> 2
152  */
153 static VALUE
155 {
156  return INT2FIX(location_lineno(location_ptr(self)));
157 }
158 
159 static VALUE
161 {
162  switch (loc->type) {
163  case LOCATION_TYPE_ISEQ:
164  case LOCATION_TYPE_ISEQ_CALCED:
165  return loc->body.iseq.iseq->location.label;
166  case LOCATION_TYPE_CFUNC:
167  return rb_id2str(loc->body.cfunc.mid);
168  case LOCATION_TYPE_IFUNC:
169  default:
170  rb_bug("location_label: unreachable");
171  UNREACHABLE;
172  }
173 }
174 
175 /*
176  * Returns the label of this frame.
177  *
178  * Usually consists of method, class, module, etc names with decoration.
179  *
180  * Consider the following example:
181  *
182  * def foo
183  * puts caller_locations(0).first.label
184  *
185  * 1.times do
186  * puts caller_locations(0).first.label
187  *
188  * 1.times do
189  * puts caller_locations(0).first.label
190  * end
191  *
192  * end
193  * end
194  *
195  * The result of calling +foo+ is this:
196  *
197  * label: foo
198  * label: block in foo
199  * label: block (2 levels) in foo
200  *
201  */
202 static VALUE
204 {
205  return location_label(location_ptr(self));
206 }
207 
208 static VALUE
210 {
211  switch (loc->type) {
212  case LOCATION_TYPE_ISEQ:
213  case LOCATION_TYPE_ISEQ_CALCED:
214  return loc->body.iseq.iseq->location.base_label;
215  case LOCATION_TYPE_CFUNC:
216  return rb_sym_to_s(ID2SYM(loc->body.cfunc.mid));
217  case LOCATION_TYPE_IFUNC:
218  default:
219  rb_bug("location_base_label: unreachable");
220  UNREACHABLE;
221  }
222 }
223 
224 /*
225  * Returns the base label of this frame.
226  *
227  * Usually same as #label, without decoration.
228  */
229 static VALUE
231 {
232  return location_base_label(location_ptr(self));
233 }
234 
235 static VALUE
237 {
238  switch (loc->type) {
239  case LOCATION_TYPE_ISEQ:
240  case LOCATION_TYPE_ISEQ_CALCED:
241  return loc->body.iseq.iseq->location.path;
242  case LOCATION_TYPE_CFUNC:
243  if (loc->body.cfunc.prev_loc) {
244  return location_path(loc->body.cfunc.prev_loc);
245  }
246  return Qnil;
247  case LOCATION_TYPE_IFUNC:
248  default:
249  rb_bug("location_path: unreachable");
250  UNREACHABLE;
251  }
252 }
253 
254 /*
255  * Returns the file name of this frame.
256  *
257  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
258  *
259  * loc = c(0..1).first
260  * loc.path #=> caller_locations.rb
261  */
262 static VALUE
264 {
265  return location_path(location_ptr(self));
266 }
267 
268 static VALUE
270 {
271  switch (loc->type) {
272  case LOCATION_TYPE_ISEQ:
273  case LOCATION_TYPE_ISEQ_CALCED:
274  return loc->body.iseq.iseq->location.absolute_path;
275  case LOCATION_TYPE_CFUNC:
276  if (loc->body.cfunc.prev_loc) {
277  return location_absolute_path(loc->body.cfunc.prev_loc);
278  }
279  return Qnil;
280  case LOCATION_TYPE_IFUNC:
281  default:
282  rb_bug("location_absolute_path: unreachable");
283  UNREACHABLE;
284  }
285 }
286 
287 /*
288  * Returns the full file path of this frame.
289  *
290  * Same as #path, but includes the absolute path.
291  */
292 static VALUE
294 {
295  return location_absolute_path(location_ptr(self));
296 }
297 
298 static VALUE
300 {
301  if (lineno != 0) {
302  return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:%d:in `%s'",
303  RSTRING_PTR(file), lineno, RSTRING_PTR(name));
304  }
305  else {
306  return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:in `%s'",
307  RSTRING_PTR(file), RSTRING_PTR(name));
308  }
309 }
310 
311 static VALUE
313 {
314  VALUE file, name;
315  int lineno;
316 
317  switch (loc->type) {
318  case LOCATION_TYPE_ISEQ:
319  file = loc->body.iseq.iseq->location.path;
320  name = loc->body.iseq.iseq->location.label;
321 
322  lineno = loc->body.iseq.lineno.lineno = calc_lineno(loc->body.iseq.iseq, loc->body.iseq.lineno.pc);
323  loc->type = LOCATION_TYPE_ISEQ_CALCED;
324  break;
325  case LOCATION_TYPE_ISEQ_CALCED:
326  file = loc->body.iseq.iseq->location.path;
327  lineno = loc->body.iseq.lineno.lineno;
328  name = loc->body.iseq.iseq->location.label;
329  break;
330  case LOCATION_TYPE_CFUNC:
331  if (loc->body.cfunc.prev_loc) {
332  file = loc->body.cfunc.prev_loc->body.iseq.iseq->location.path;
333  lineno = location_lineno(loc->body.cfunc.prev_loc);
334  }
335  else {
337  file = th->vm->progname ? th->vm->progname : ruby_engine_name;
338  lineno = INT2FIX(0);
339  }
340  name = rb_id2str(loc->body.cfunc.mid);
341  break;
342  case LOCATION_TYPE_IFUNC:
343  default:
344  rb_bug("location_to_str: unreachable");
345  }
346 
347  return location_format(file, lineno, name);
348 }
349 
350 /*
351  * Returns a Kernel#caller style string representing this frame.
352  */
353 static VALUE
355 {
356  return location_to_str(location_ptr(self));
357 }
358 
359 /*
360  * Returns the same as calling +inspect+ on the string representation of
361  * #to_str
362  */
363 static VALUE
365 {
367 }
368 
369 typedef struct rb_backtrace_struct {
375 
376 static void
378 {
379  if (ptr) {
380  rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
381  size_t i, s = bt->backtrace_size;
382 
383  for (i=0; i<s; i++) {
385  rb_gc_mark(bt->strary);
386  }
387  }
388 }
389 
390 static void
392 {
393  if (ptr) {
394  rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
395  if (bt->backtrace) ruby_xfree(bt->backtrace_base);
396  ruby_xfree(bt);
397  }
398 }
399 
400 static size_t
401 backtrace_memsize(const void *ptr)
402 {
403  rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
404  return sizeof(rb_backtrace_t) + sizeof(rb_backtrace_location_t) * bt->backtrace_size;
405 }
406 
408  "backtrace",
410 };
411 
412 int
414 {
415  return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
416 }
417 
418 static VALUE
420 {
421  rb_backtrace_t *bt;
422  VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
423  return obj;
424 }
425 
426 static void
428  void (*init)(void *arg, size_t size),
429  void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
430  void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
431  void *arg)
432 {
433  rb_control_frame_t *last_cfp = th->cfp;
435  rb_control_frame_t *cfp;
436  ptrdiff_t size, i;
437 
438  /* <- start_cfp (end control frame)
439  * top frame (dummy)
440  * top frame (dummy)
441  * top frame <- start_cfp
442  * top frame
443  * ...
444  * 2nd frame <- lev:0
445  * current frame <- th->cfp
446  */
447 
448  start_cfp =
450  RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
451 
452  if (start_cfp < last_cfp) {
453  size = 0;
454  }
455  else {
456  size = start_cfp - last_cfp + 1;
457  }
458 
459  init(arg, size);
460 
461  /* SDR(); */
462  for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
463  /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(th->stack + th->stack_size) - cfp); */
464  if (cfp->iseq) {
465  if (cfp->pc) {
466  iter_iseq(arg, cfp);
467  }
468  }
469  else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
470  ID mid = cfp->me->def ? cfp->me->def->original_id : cfp->me->called_id;
471 
472  iter_cfunc(arg, cfp, mid);
473  }
474  }
475 }
476 
477 struct bt_iter_arg {
481 };
482 
483 static void
484 bt_init(void *ptr, size_t size)
485 {
486  struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
489  arg->bt->backtrace_base = arg->bt->backtrace = ruby_xmalloc(sizeof(rb_backtrace_location_t) * size);
490  arg->bt->backtrace_size = 0;
491 }
492 
493 static void
495 {
496  const rb_iseq_t *iseq = cfp->iseq;
497  const VALUE *pc = cfp->pc;
498  struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
499  rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
500  loc->type = LOCATION_TYPE_ISEQ;
501  loc->body.iseq.iseq = iseq;
502  loc->body.iseq.lineno.pc = pc;
503  arg->prev_loc = loc;
504 }
505 
506 static void
507 bt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
508 {
509  struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
510  rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
511  loc->type = LOCATION_TYPE_CFUNC;
512  loc->body.cfunc.mid = mid;
513  loc->body.cfunc.prev_loc = arg->prev_loc;
514 }
515 
516 static VALUE
518 {
519  struct bt_iter_arg arg;
520  arg.prev_loc = 0;
521 
522  backtrace_each(th,
523  bt_init,
524  bt_iter_iseq,
526  &arg);
527 
528  return arg.btobj;
529 }
530 
531 VALUE
533 {
534  return backtrace_object(GET_THREAD());
535 }
536 
537 static VALUE
538 backtrace_collect(rb_backtrace_t *bt, long lev, long n, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
539 {
540  VALUE btary;
541  int i;
542 
543  if (UNLIKELY(lev < 0 || n < 0)) {
544  rb_bug("backtrace_collect: unreachable");
545  }
546 
547  btary = rb_ary_new();
548 
549  for (i=0; i+lev<bt->backtrace_size && i<n; i++) {
550  rb_backtrace_location_t *loc = &bt->backtrace[bt->backtrace_size - 1 - (lev+i)];
551  rb_ary_push(btary, func(loc, arg));
552  }
553 
554  return btary;
555 }
556 
557 static VALUE
559 {
560  return location_to_str(loc);
561 }
562 
563 static VALUE
564 backtrace_to_str_ary(VALUE self, long lev, long n)
565 {
567  int size;
568  VALUE r;
569 
571  size = bt->backtrace_size;
572 
573  if (n == 0) {
574  n = size;
575  }
576  if (lev > size) {
577  return Qnil;
578  }
579 
580  r = backtrace_collect(bt, lev, n, location_to_str_dmyarg, 0);
581  RB_GC_GUARD(self);
582  return r;
583 }
584 
585 VALUE
587 {
590 
591  if (!bt->strary) {
592  bt->strary = backtrace_to_str_ary(self, 0, bt->backtrace_size);
593  }
594  return bt->strary;
595 }
596 
597 static VALUE
599 {
600  VALUE obj;
601  struct valued_frame_info *vloc;
602  obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
603 
604  vloc->loc = srcloc;
605  vloc->btobj = (VALUE)btobj;
606 
607  return obj;
608 }
609 
610 static VALUE
611 backtrace_to_location_ary(VALUE self, long lev, long n)
612 {
613  rb_backtrace_t *bt;
614  int size;
615  VALUE r;
616 
618  size = bt->backtrace_size;
619 
620  if (n == 0) {
621  n = size;
622  }
623  if (lev > size) {
624  return Qnil;
625  }
626 
627  r = backtrace_collect(bt, lev, n, location_create, (void *)self);
628  RB_GC_GUARD(self);
629  return r;
630 }
631 
632 static VALUE
634 {
636  return str;
637 }
638 
639 static VALUE
641 {
642  rb_backtrace_t *bt;
644  bt->strary = str;
645  return self;
646 }
647 
648 VALUE
649 vm_backtrace_str_ary(rb_thread_t *th, long lev, long n)
650 {
651  return backtrace_to_str_ary(backtrace_object(th), lev, n);
652 }
653 
654 VALUE
656 {
657  return backtrace_to_location_ary(backtrace_object(th), lev, n);
658 }
659 
660 /* make old style backtrace directly */
661 
662 struct oldbt_arg {
664  int lineno;
665  void (*func)(void *data, VALUE file, int lineno, VALUE name);
666  void *data; /* result */
667 };
668 
669 static void
670 oldbt_init(void *ptr, size_t dmy)
671 {
672  struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
673  rb_thread_t *th = GET_THREAD();
674 
675  arg->filename = th->vm->progname ? th->vm->progname : ruby_engine_name;;
676  arg->lineno = 0;
677 }
678 
679 static void
681 {
682  const rb_iseq_t *iseq = cfp->iseq;
683  const VALUE *pc = cfp->pc;
684  struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
685  VALUE file = arg->filename = iseq->location.path;
686  VALUE name = iseq->location.label;
687  int lineno = arg->lineno = calc_lineno(iseq, pc);
688 
689  (arg->func)(arg->data, file, lineno, name);
690 }
691 
692 static void
693 oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
694 {
695  struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
696  VALUE file = arg->filename;
697  VALUE name = rb_id2str(mid);
698  int lineno = arg->lineno;
699 
700  (arg->func)(arg->data, file, lineno, name);
701 }
702 
703 static void
704 oldbt_print(void *data, VALUE file, int lineno, VALUE name)
705 {
706  FILE *fp = (FILE *)data;
707 
708  if (NIL_P(name)) {
709  fprintf(fp, "\tfrom %s:%d:in unknown method\n",
710  RSTRING_PTR(file), lineno);
711  }
712  else {
713  fprintf(fp, "\tfrom %s:%d:in `%s'\n",
714  RSTRING_PTR(file), lineno, RSTRING_PTR(name));
715  }
716 }
717 
718 static void
720 {
721  struct oldbt_arg arg;
722 
723  arg.func = oldbt_print;
724  arg.data = (void *)fp;
726  oldbt_init,
729  &arg);
730 }
731 
732 static void
733 oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
734 {
735  const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
736  if (!*(int *)arg) {
737  fprintf(stderr, "-- Ruby level backtrace information "
738  "----------------------------------------\n");
739  *(int *)arg = 1;
740  }
741  if (NIL_P(method)) {
742  fprintf(stderr, "%s:%d:in unknown method\n", filename, line);
743  }
744  else {
745  fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
746  }
747 }
748 
749 void
751 {
752  struct oldbt_arg arg;
753  int i;
754 
755  arg.func = oldbt_bugreport;
756  arg.data = (int *)&i;
757 
759  oldbt_init,
762  &arg);
763 }
764 
765 void
767 {
768  vm_backtrace_print(stderr);
769 }
770 
771 VALUE
773 {
774  return vm_backtrace_str_ary(GET_THREAD(), 0, 0);
775 }
776 
777 static VALUE
778 vm_backtrace_to_ary(rb_thread_t *th, int argc, VALUE *argv, int lev_default, int lev_plus, int to_str)
779 {
780  VALUE level, vn;
781  long lev, n;
782  VALUE btval = backtrace_object(th);
783  VALUE r;
784  rb_backtrace_t *bt;
785 
787 
788  rb_scan_args(argc, argv, "02", &level, &vn);
789 
790  if (argc == 2 && NIL_P(vn)) argc--;
791 
792  switch (argc) {
793  case 0:
794  lev = lev_default + lev_plus;
795  n = bt->backtrace_size - lev;
796  break;
797  case 1:
798  {
799  long beg, len;
800  switch (rb_range_beg_len(level, &beg, &len, bt->backtrace_size - lev_plus, 0)) {
801  case Qfalse:
802  lev = NUM2LONG(level);
803  if (lev < 0) {
804  rb_raise(rb_eArgError, "negative level (%ld)", lev);
805  }
806  lev += lev_plus;
807  n = bt->backtrace_size - lev;
808  break;
809  case Qnil:
810  return Qnil;
811  default:
812  lev = beg + lev_plus;
813  n = len;
814  break;
815  }
816  break;
817  }
818  case 2:
819  lev = NUM2LONG(level);
820  n = NUM2LONG(vn);
821  if (lev < 0) {
822  rb_raise(rb_eArgError, "negative level (%ld)", lev);
823  }
824  if (n < 0) {
825  rb_raise(rb_eArgError, "negative size (%ld)", n);
826  }
827  lev += lev_plus;
828  break;
829  default:
830  lev = n = 0; /* to avoid warning */
831  break;
832  }
833 
834  if (n == 0) {
835  return rb_ary_new();
836  }
837 
838  if (to_str) {
839  r = backtrace_to_str_ary(btval, lev, n);
840  }
841  else {
842  r = backtrace_to_location_ary(btval, lev, n);
843  }
844  RB_GC_GUARD(btval);
845  return r;
846 }
847 
848 static VALUE
849 thread_backtrace_to_ary(int argc, VALUE *argv, VALUE thval, int to_str)
850 {
851  rb_thread_t *th;
852  GetThreadPtr(thval, th);
853 
854  if (th->to_kill || th->status == THREAD_KILLED)
855  return Qnil;
856 
857  return vm_backtrace_to_ary(th, argc, argv, 0, 0, to_str);
858 }
859 
860 VALUE
862 {
863  return thread_backtrace_to_ary(argc, argv, thval, 1);
864 }
865 
866 VALUE
868 {
869  return thread_backtrace_to_ary(argc, argv, thval, 0);
870 }
871 
872 /*
873  * call-seq:
874  * caller(start=1, length=nil) -> array or nil
875  * caller(range) -> array or nil
876  *
877  * Returns the current execution stack---an array containing strings in
878  * the form <code>file:line</code> or <code>file:line: in
879  * `method'</code>.
880  *
881  * The optional _start_ parameter determines the number of initial stack
882  * entries to omit from the top of the stack.
883  *
884  * A second optional +length+ parameter can be used to limit how many entries
885  * are returned from the stack.
886  *
887  * Returns +nil+ if _start_ is greater than the size of
888  * current execution stack.
889  *
890  * Optionally you can pass a range, which will return an array containing the
891  * entries within the specified range.
892  *
893  * def a(skip)
894  * caller(skip)
895  * end
896  * def b(skip)
897  * a(skip)
898  * end
899  * def c(skip)
900  * b(skip)
901  * end
902  * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
903  * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
904  * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
905  * c(3) #=> ["prog:13:in `<main>'"]
906  * c(4) #=> []
907  * c(5) #=> nil
908  */
909 
910 static VALUE
912 {
913  return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 1);
914 }
915 
916 /*
917  * call-seq:
918  * caller_locations(start=1, length=nil) -> array or nil
919  * caller_locations(range) -> array or nil
920  *
921  * Returns the current execution stack---an array containing
922  * backtrace location objects.
923  *
924  * See Thread::Backtrace::Location for more information.
925  *
926  * The optional _start_ parameter determines the number of initial stack
927  * entries to omit from the top of the stack.
928  *
929  * A second optional +length+ parameter can be used to limit how many entries
930  * are returned from the stack.
931  *
932  * Returns +nil+ if _start_ is greater than the size of
933  * current execution stack.
934  *
935  * Optionally you can pass a range, which will return an array containing the
936  * entries within the specified range.
937  */
938 static VALUE
940 {
941  return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 0);
942 }
943 
944 /* called from Init_vm() in vm.c */
945 void
947 {
948  /* :nodoc: */
953 
954  /*
955  * An object representation of a stack frame, initialized by
956  * Kernel#caller_locations.
957  *
958  * For example:
959  *
960  * # caller_locations.rb
961  * def a(skip)
962  * caller_locations(skip)
963  * end
964  * def b(skip)
965  * a(skip)
966  * end
967  * def c(skip)
968  * b(skip)
969  * end
970  *
971  * c(0..2).map do |call|
972  * puts call.to_s
973  * end
974  *
975  * Running <code>ruby caller_locations.rb</code> will produce:
976  *
977  * caller_locations.rb:2:in `a'
978  * caller_locations.rb:5:in `b'
979  * caller_locations.rb:8:in `c'
980  *
981  * Here's another example with a slightly different result:
982  *
983  * # foo.rb
984  * class Foo
985  * attr_accessor :locations
986  * def initialize(skip)
987  * @locations = caller_locations(skip)
988  * end
989  * end
990  *
991  * Foo.new(0..2).locations.map do |call|
992  * puts call.to_s
993  * end
994  *
995  * Now run <code>ruby foo.rb</code> and you should see:
996  *
997  * init.rb:4:in `initialize'
998  * init.rb:8:in `new'
999  * init.rb:8:in `<main>'
1000  */
1011 
1012  rb_define_global_function("caller", rb_f_caller, -1);
1013  rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1014 }
1015 
1016 /* debugger API */
1017 
1018 #if defined __GNUC__ && __GNUC__ >= 4
1019 #pragma GCC visibility push(default)
1020 #endif
1021 
1022 #if defined __GNUC__ && __GNUC__ >= 4
1023 #pragma GCC visibility pop
1024 #endif
1025 
1030  VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1032 };
1033 
1034 enum {
1040 };
1041 
1044 };
1045 
1046 static void
1047 collect_caller_bindings_init(void *arg, size_t size)
1048 {
1049  /* */
1050 }
1051 
1052 static VALUE
1054 {
1055  VALUE klass;
1056  if (rb_vm_control_frame_id_and_class(cfp, 0, &klass)) {
1057  if (RB_TYPE_P(klass, T_ICLASS)) {
1058  return RBASIC(klass)->klass;
1059  }
1060  else {
1061  return klass;
1062  }
1063  }
1064  else {
1065  return Qnil;
1066  }
1067 }
1068 
1069 static void
1071 {
1073  VALUE frame = rb_ary_new2(5);
1074 
1075  rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1077  rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
1078  rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? cfp->iseq->self : Qnil);
1080 
1081  rb_ary_push(data->ary, frame);
1082 }
1083 
1084 static void
1086 {
1088  VALUE frame = rb_ary_new2(5);
1089 
1090  rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1092  rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
1093  rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
1095 
1096  rb_ary_push(data->ary, frame);
1097 }
1098 
1099 static VALUE
1101 {
1102  struct collect_caller_bindings_data data;
1103  VALUE result;
1104  int i;
1105 
1106  data.ary = rb_ary_new();
1107 
1108  backtrace_each(th,
1112  &data);
1113 
1114  result = rb_ary_reverse(data.ary);
1115 
1116  /* bindings should be created from top of frame */
1117  for (i=0; i<RARRAY_LEN(result); i++) {
1118  VALUE entry = rb_ary_entry(result, i);
1119  VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
1120 
1121  if (!NIL_P(cfp_val)) {
1122  rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
1124  }
1125  }
1126 
1127  return result;
1128 }
1129 
1130 /*
1131  * Note that the passed `rb_debug_inspector_t' will be disabled
1132  * after `rb_debug_inspector_open'.
1133  */
1134 
1135 VALUE
1137 {
1138  rb_debug_inspector_t dbg_context;
1139  rb_thread_t *th = GET_THREAD();
1140  int state;
1141  volatile VALUE UNINITIALIZED_VAR(result);
1142 
1143  dbg_context.th = th;
1144  dbg_context.cfp = dbg_context.th->cfp;
1145  dbg_context.backtrace = vm_backtrace_location_ary(th, 0, 0);
1146  dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
1147  dbg_context.contexts = collect_caller_bindings(th);
1148 
1149  TH_PUSH_TAG(th);
1150  if ((state = EXEC_TAG()) == 0) {
1151  result = (*func)(&dbg_context, data);
1152  }
1153  TH_POP_TAG();
1154 
1155  /* invalidate bindings? */
1156 
1157  if (state) {
1158  JUMP_TAG(state);
1159  }
1160 
1161  return result;
1162 }
1163 
1164 static VALUE
1166 {
1167  if (index < 0 || index >= dc->backtrace_size) {
1168  rb_raise(rb_eArgError, "no such frame");
1169  }
1170  return rb_ary_entry(dc->contexts, index);
1171 }
1172 
1173 VALUE
1175 {
1176  VALUE frame = frame_get(dc, index);
1177  return rb_ary_entry(frame, CALLER_BINDING_SELF);
1178 }
1179 
1180 VALUE
1182 {
1183  VALUE frame = frame_get(dc, index);
1184  return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1185 }
1186 
1187 VALUE
1189 {
1190  VALUE frame = frame_get(dc, index);
1191  return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1192 }
1193 
1194 VALUE
1196 {
1197  VALUE frame = frame_get(dc, index);
1198  return rb_ary_entry(frame, CALLER_BINDING_ISEQ);
1199 }
1200 
1201 VALUE
1203 {
1204  return dc->backtrace;
1205 }
1206 
VALUE data
Definition: tcltklib.c:3367
static VALUE location_inspect_m(VALUE self)
Definition: vm_backtrace.c:364
static VALUE location_create(rb_backtrace_location_t *srcloc, void *btobj)
Definition: vm_backtrace.c:598
#define RB_TYPE_P(obj, type)
rb_control_frame_t * cfp
Definition: vm_core.h:500
rb_vm_t * vm
Definition: vm_core.h:495
ssize_t n
Definition: bigdecimal.c:5676
unsigned int rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
Definition: iseq.c:1114
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1088
static VALUE vm_backtrace_to_ary(rb_thread_t *th, int argc, VALUE *argv, int lev_default, int lev_plus, int to_str)
Definition: vm_backtrace.c:778
void rb_bug(const char *fmt,...)
Definition: error.c:295
VALUE vm_backtrace_location_ary(rb_thread_t *th, long lev, long n)
Definition: vm_backtrace.c:655
void rb_backtrace_print_as_bugreport(void)
Definition: vm_backtrace.c:750
static VALUE VALUE th
Definition: tcltklib.c:2947
static void oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
Definition: vm_backtrace.c:680
int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
Definition: vm_backtrace.c:33
VALUE rb_id2str(ID id)
Definition: ripper.c:16946
static VALUE location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
Definition: vm_backtrace.c:558
void Init_vm_backtrace(void)
Definition: vm_backtrace.c:946
VALUE rb_sym_to_s(VALUE)
Definition: string.c:7924
#define RUBY_VM_NORMAL_ISEQ_P(ptr)
Definition: vm_core.h:799
static rb_backtrace_location_t * location_ptr(VALUE locobj)
Definition: vm_backtrace.c:118
VALUE progname
Definition: vm_core.h:381
#define T_ICLASS
static int calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
Definition: vm_backtrace.c:27
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:108
ssize_t i
Definition: bigdecimal.c:5676
VALUE(* rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *)
Definition: debug.h:31
static VALUE location_base_label_m(VALUE self)
Definition: vm_backtrace.c:230
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define UNREACHABLE
Definition: ruby.h:40
VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:822
rb_encoding * rb_enc_compatible(VALUE str1, VALUE str2)
Definition: encoding.c:789
#define RSTRING_PTR(str)
#define CLASS_OF(v)
NIL_P(eventloop_thread)
Definition: tcltklib.c:4067
static VALUE location_label_m(VALUE self)
Definition: vm_backtrace.c:203
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:534
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1788
static VALUE location_to_str(rb_backtrace_location_t *loc)
Definition: vm_backtrace.c:312
static void bt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
Definition: vm_backtrace.c:494
void rb_backtrace(void)
Definition: vm_backtrace.c:766
VALUE rb_backtrace_to_str_ary(VALUE obj)
Definition: vm_backtrace.c:586
int index
Definition: tcltklib.c:4477
static void oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
Definition: vm_backtrace.c:693
static VALUE collect_caller_bindings(rb_thread_t *th)
r
Definition: bigdecimal.c:1210
static int location_lineno(rb_backtrace_location_t *loc)
Definition: vm_backtrace.c:126
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:1526
int state
Definition: tcltklib.c:1461
VALUE filename
Definition: vm_backtrace.c:663
#define ID2SYM(x)
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1362
VALUE rb_enc_sprintf(rb_encoding *enc, const char *format,...)
Definition: sprintf.c:1256
gz lineno
Definition: zlib.c:2268
static VALUE rb_f_caller_locations(int argc, VALUE *argv)
Definition: vm_backtrace.c:939
VALUE vm_thread_backtrace(int argc, VALUE *argv, VALUE thval)
Definition: vm_backtrace.c:861
VALUE * iseq
Definition: vm_core.h:215
int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp)
Definition: vm.c:1524
#define TH_POP_TAG()
Definition: eval_intern.h:129
static VALUE location_absolute_path(rb_backtrace_location_t *loc)
Definition: vm_backtrace.c:269
void * data
Definition: vm_backtrace.c:666
return Qfalse
Definition: tcltklib.c:6778
#define EXEC_TAG()
Definition: eval_intern.h:141
#define RARRAY_LEN(a)
static VALUE rb_cBacktraceLocation
Definition: vm_backtrace.c:22
#define Qnil
Definition: tcltklib.c:1895
static VALUE location_path_m(VALUE self)
Definition: vm_backtrace.c:263
static VALUE char * str
Definition: tcltklib.c:3546
static VALUE thread_backtrace_to_ary(int argc, VALUE *argv, VALUE thval, int to_str)
Definition: vm_backtrace.c:849
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:478
VALUE rb_ary_new(void)
Definition: array.c:424
rb_backtrace_location_t * loc
Definition: vm_backtrace.c:68
VALUE rb_binding_new_with_cfp(rb_thread_t *th, const rb_control_frame_t *src_cfp)
Definition: proc.c:316
unsigned long ID
Definition: ripper.y:105
rb_backtrace_t * bt
Definition: vm_backtrace.c:478
static VALUE backtrace_object(rb_thread_t *th)
Definition: vm_backtrace.c:517
void rb_gc_mark(VALUE)
Definition: gc.c:2600
static void bt_init(void *ptr, size_t size)
Definition: vm_backtrace.c:484
#define JUMP_TAG(st)
Definition: eval_intern.h:148
rb_iseq_t * iseq
Definition: vm_core.h:428
static const rb_data_type_t location_data_type
Definition: vm_backtrace.c:112
#define UNLIKELY(x)
Definition: vm_core.h:115
static void collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
static void oldbt_init(void *ptr, size_t dmy)
Definition: vm_backtrace.c:670
static VALUE VALUE obj
Definition: tcltklib.c:3157
#define INT2FIX(i)
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:719
#define GetCoreDataFromValue(obj, type, ptr)
Definition: vm_core.h:176
static void collect_caller_bindings_init(void *arg, size_t size)
VALUE ruby_engine_name
Definition: version.c:73
volatile ID method
Definition: tcltklib.c:3598
static VALUE backtrace_to_location_ary(VALUE self, long lev, long n)
Definition: vm_backtrace.c:611
union rb_backtrace_location_struct::@145 body
static void collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
VALUE vm_backtrace_str_ary(rb_thread_t *th, long lev, long n)
Definition: vm_backtrace.c:649
#define GC_GUARDED_PTR(p)
Definition: vm_core.h:763
gz level
Definition: zlib.c:2262
VALUE * argv
Definition: tcltklib.c:1970
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
static VALUE backtrace_collect(rb_backtrace_t *bt, long lev, long n, VALUE(*func)(rb_backtrace_location_t *, void *arg), void *arg)
Definition: vm_backtrace.c:538
q result
Definition: tcltklib.c:7069
rb_backtrace_location_t * backtrace
Definition: vm_backtrace.c:370
static VALUE location_format(VALUE file, int lineno, VALUE name)
Definition: vm_backtrace.c:299
register char * s
Definition: os2.c:56
void ruby_xfree(void *x)
Definition: gc.c:3653
VP_EXPORT void
Definition: bigdecimal.c:5104
static VALUE backtrace_to_str_ary(VALUE self, long lev, long n)
Definition: vm_backtrace.c:564
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
#define RUBY_VM_NEXT_CONTROL_FRAME(cfp)
Definition: vm_core.h:790
struct rb_backtrace_location_struct rb_backtrace_location_t
#define RUBYVM_CFUNC_FRAME_P(cfp)
Definition: vm_core.h:745
VALUE rb_str_inspect(VALUE)
Definition: string.c:4512
static void backtrace_each(rb_thread_t *th, void(*init)(void *arg, size_t size), void(*iter_iseq)(void *arg, const rb_control_frame_t *cfp), void(*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid), void *arg)
Definition: vm_backtrace.c:427
#define RB_GC_GUARD(v)
VALUE vm_thread_backtrace_locations(int argc, VALUE *argv, VALUE thval)
Definition: vm_backtrace.c:867
VALUE * iseq_encoded
Definition: vm_core.h:216
int argc
Definition: tcltklib.c:1969
#define UNINITIALIZED_VAR(x)
Definition: vm_core.h:121
void rb_undef_alloc_func(VALUE)
Definition: vm_method.c:493
static void vm_backtrace_print(FILE *fp)
Definition: vm_backtrace.c:719
rb_iseq_location_t location
Definition: vm_core.h:213
#define TH_PUSH_TAG(th)
Definition: eval_intern.h:122
static VALUE rb_f_caller(int argc, VALUE *argv)
Definition: vm_backtrace.c:911
const rb_iseq_t * iseq
Definition: vm_backtrace.c:54
static VALUE location_lineno_m(VALUE self)
Definition: vm_backtrace.c:154
return ptr
Definition: tcltklib.c:784
#define RUBY_VM_END_CONTROL_FRAME(th)
Definition: vm_core.h:791
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Definition: marshal.c:113
enum rb_thread_status status
Definition: vm_core.h:531
void * ruby_xmalloc(size_t size)
Definition: gc.c:3596
arg
Definition: ripper.y:1317
static void location_mark(void *ptr)
Definition: vm_backtrace.c:73
static VALUE backtrace_load_data(VALUE self, VALUE str)
Definition: vm_backtrace.c:640
int size
Definition: encoding.c:52
#define NUM2LONG(x)
VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
static void oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
Definition: vm_backtrace.c:733
static VALUE location_path(rb_backtrace_location_t *loc)
Definition: vm_backtrace.c:236
static VALUE location_to_str_m(VALUE self)
Definition: vm_backtrace.c:354
struct rb_backtrace_location_struct * prev_loc
Definition: vm_backtrace.c:62
#define TypedData_Make_Struct(klass, type, data_type, sval)
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1426
#define RBASIC(obj)
static void location_mark_entry(rb_backtrace_location_t *fi)
Definition: vm_backtrace.c:82
void(* func)(void *data, VALUE file, int lineno, VALUE name)
Definition: vm_backtrace.c:665
klass
Definition: tcltklib.c:3503
VALUE rb_make_backtrace(void)
Definition: vm_backtrace.c:772
static void backtrace_free(void *ptr)
Definition: vm_backtrace.c:391
static void bt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
Definition: vm_backtrace.c:507
VALUE rb_cArray
Definition: array.c:29
#define GetThreadPtr(obj, ptr)
Definition: vm_core.h:452
static VALUE location_base_label(rb_backtrace_location_t *loc)
Definition: vm_backtrace.c:209
VALUE rb_ary_new2(long capa)
Definition: array.c:417
int rb_backtrace_p(VALUE obj)
Definition: vm_backtrace.c:413
enum rb_backtrace_location_struct::LOCATION_TYPE type
VALUE rb_range_beg_len(VALUE, long *, long *, long, int)
Definition: range.c:990
VALUE self
Definition: vm_core.h:292
static VALUE backtrace_alloc(VALUE klass)
Definition: vm_backtrace.c:419
struct rb_backtrace_struct rb_backtrace_t
VALUE rb_ary_reverse(VALUE ary)
Definition: array.c:2031
static VALUE location_absolute_path_m(VALUE self)
Definition: vm_backtrace.c:293
VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
rb_control_frame_t * cfp
static void oldbt_print(void *data, VALUE file, int lineno, VALUE name)
Definition: vm_backtrace.c:704
unsigned long VALUE
Definition: ripper.y:104
#define GC_GUARDED_PTR_REF(p)
Definition: vm_core.h:764
static VALUE frame_get(const rb_debug_inspector_t *dc, long index)
static VALUE get_klass(const rb_control_frame_t *cfp)
rb_backtrace_location_t * backtrace_base
Definition: vm_backtrace.c:371
VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
static size_t location_memsize(const void *ptr)
Definition: vm_backtrace.c:106
rb_backtrace_location_t * prev_loc
Definition: vm_backtrace.c:480
static void location_free(void *ptr)
Definition: vm_backtrace.c:97
VALUE rb_vm_backtrace_object()
Definition: vm_backtrace.c:532
static const rb_data_type_t backtrace_data_type
Definition: vm_backtrace.c:407
static VALUE backtrace_dump_data(VALUE self)
Definition: vm_backtrace.c:633
struct rb_backtrace_location_struct::@145::@147 cfunc
const char * name
Definition: nkf.c:208
static VALUE location_label(rb_backtrace_location_t *loc)
Definition: vm_backtrace.c:160
static rb_thread_t * GET_THREAD(void)
Definition: vm_core.h:890
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
static VALUE rb_cBacktrace
Definition: vm_backtrace.c:21
VALUE rb_eArgError
Definition: error.c:517
RUBY_EXTERN VALUE rb_cThread
Definition: ripper.y:1459
VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
static size_t backtrace_memsize(const void *ptr)
Definition: vm_backtrace.c:401
size_t len
Definition: tcltklib.c:3567
static void backtrace_mark(void *ptr)
Definition: vm_backtrace.c:377