Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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
21 static VALUE rb_cBacktrace;
22 static VALUE rb_cBacktraceLocation;
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
33 rb_vm_get_sourceline(const rb_control_frame_t *cfp)
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
44 typedef struct rb_backtrace_location_struct {
45 enum LOCATION_TYPE {
46 LOCATION_TYPE_ISEQ = 1,
47 LOCATION_TYPE_ISEQ_CALCED,
48 LOCATION_TYPE_CFUNC,
49 LOCATION_TYPE_IFUNC
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 {
61 ID mid;
62 struct rb_backtrace_location_struct *prev_loc;
63 } cfunc;
64 } body;
65 } rb_backtrace_location_t;
66
67 struct valued_frame_info {
68 rb_backtrace_location_t *loc;
69 VALUE btobj;
70 };
71
72 static void
73 location_mark(void *ptr)
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
82 location_mark_entry(rb_backtrace_location_t *fi)
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
97 location_free(void *ptr)
98 {
99 if (ptr) {
100 rb_backtrace_location_t *fi = (rb_backtrace_location_t *)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
112 static const rb_data_type_t location_data_type = {
113 "frame_info",
114 {location_mark, location_free, location_memsize,},
115 };
116
117 static inline rb_backtrace_location_t *
118 location_ptr(VALUE locobj)
119 {
120 struct valued_frame_info *vloc;
121 GetCoreDataFromValue(locobj, struct valued_frame_info, vloc);
122 return vloc->loc;
123 }
124
125 static int
126 location_lineno(rb_backtrace_location_t *loc)
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
154 location_lineno_m(VALUE self)
155 {
156 return INT2FIX(location_lineno(location_ptr(self)));
157 }
158
159 static VALUE
160 location_label(rb_backtrace_location_t *loc)
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
203 location_label_m(VALUE self)
204 {
205 return location_label(location_ptr(self));
206 }
207
208 static VALUE
209 location_base_label(rb_backtrace_location_t *loc)
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
230 location_base_label_m(VALUE self)
231 {
232 return location_base_label(location_ptr(self));
233 }
234
235 static VALUE
236 location_path(rb_backtrace_location_t *loc)
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
263 location_path_m(VALUE self)
264 {
265 return location_path(location_ptr(self));
266 }
267
268 static VALUE
269 location_absolute_path(rb_backtrace_location_t *loc)
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
293 location_absolute_path_m(VALUE self)
294 {
295 return location_absolute_path(location_ptr(self));
296 }
297
298 static VALUE
299 location_format(VALUE file, int lineno, VALUE name)
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
312 location_to_str(rb_backtrace_location_t *loc)
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 {
336 rb_thread_t *th = GET_THREAD();
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
354 location_to_str_m(VALUE self)
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
364 location_inspect_m(VALUE self)
365 {
366 return rb_str_inspect(location_to_str(location_ptr(self)));
367 }
368
369 typedef struct rb_backtrace_struct {
370 rb_backtrace_location_t *backtrace;
371 rb_backtrace_location_t *backtrace_base;
372 int backtrace_size;
373 VALUE strary;
374 } rb_backtrace_t;
375
376 static void
377 backtrace_mark(void *ptr)
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++) {
384 location_mark_entry(&bt->backtrace[i]);
385 rb_gc_mark(bt->strary);
386 }
387 }
388 }
389
390 static void
391 backtrace_free(void *ptr)
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
407 static const rb_data_type_t backtrace_data_type = {
408 "backtrace",
409 {backtrace_mark, backtrace_free, backtrace_memsize,},
410 };
411
412 int
413 rb_backtrace_p(VALUE obj)
414 {
415 return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
416 }
417
418 static VALUE
419 backtrace_alloc(VALUE klass)
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
427 backtrace_each(rb_thread_t *th,
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;
434 rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(th);
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 =
449 RUBY_VM_NEXT_CONTROL_FRAME(
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 {
478 rb_backtrace_t *bt;
479 VALUE btobj;
480 rb_backtrace_location_t *prev_loc;
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;
487 arg->btobj = backtrace_alloc(rb_cBacktrace);
488 GetCoreDataFromValue(arg->btobj, rb_backtrace_t, arg->bt);
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
494 bt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
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
517 backtrace_object(rb_thread_t *th)
518 {
519 struct bt_iter_arg arg;
520 arg.prev_loc = 0;
521
522 backtrace_each(th,
523 bt_init,
524 bt_iter_iseq,
525 bt_iter_cfunc,
526 &arg);
527
528 return arg.btobj;
529 }
530
531 VALUE
532 rb_vm_backtrace_object(void)
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
558 location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
559 {
560 return location_to_str(loc);
561 }
562
563 static VALUE
564 backtrace_to_str_ary(VALUE self, long lev, long n)
565 {
566 rb_backtrace_t *bt;
567 int size;
568 VALUE r;
569
570 GetCoreDataFromValue(self, rb_backtrace_t, bt);
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
586 rb_backtrace_to_str_ary(VALUE self)
587 {
588 rb_backtrace_t *bt;
589 GetCoreDataFromValue(self, rb_backtrace_t, bt);
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
598 location_create(rb_backtrace_location_t *srcloc, void *btobj)
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
617 GetCoreDataFromValue(self, rb_backtrace_t, bt);
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
633 backtrace_dump_data(VALUE self)
634 {
635 VALUE str = rb_backtrace_to_str_ary(self);
636 return str;
637 }
638
639 static VALUE
640 backtrace_load_data(VALUE self, VALUE str)
641 {
642 rb_backtrace_t *bt;
643 GetCoreDataFromValue(self, 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
655 vm_backtrace_location_ary(rb_thread_t *th, long lev, long n)
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 {
663 VALUE filename;
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
680 oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
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
719 vm_backtrace_print(FILE *fp)
720 {
721 struct oldbt_arg arg;
722
723 arg.func = oldbt_print;
724 arg.data = (void *)fp;
725 backtrace_each(GET_THREAD(),
726 oldbt_init,
727 oldbt_iter_iseq,
728 oldbt_iter_cfunc,
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
750 rb_backtrace_print_as_bugreport(void)
751 {
752 struct oldbt_arg arg;
753 int i;
754
755 arg.func = oldbt_bugreport;
756 arg.data = (int *)&i;
757
758 backtrace_each(GET_THREAD(),
759 oldbt_init,
760 oldbt_iter_iseq,
761 oldbt_iter_cfunc,
762 &arg);
763 }
764
765 void
766 rb_backtrace(void)
767 {
768 vm_backtrace_print(stderr);
769 }
770
771 VALUE
772 rb_make_backtrace(void)
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
786 GetCoreDataFromValue(btval, rb_backtrace_t, bt);
787
788 rb_scan_args(argc, argv, "02", &level, &vn);
789
790 switch (argc) {
791 case 0:
792 lev = lev_default + lev_plus;
793 n = bt->backtrace_size - lev;
794 break;
795 case 1:
796 {
797 long beg, len;
798 switch (rb_range_beg_len(level, &beg, &len, bt->backtrace_size - lev_plus, 0)) {
799 case Qfalse:
800 lev = NUM2LONG(level);
801 if (lev < 0) {
802 rb_raise(rb_eArgError, "negative level (%ld)", lev);
803 }
804 lev += lev_plus;
805 n = bt->backtrace_size - lev;
806 break;
807 case Qnil:
808 return Qnil;
809 default:
810 lev = beg + lev_plus;
811 n = len;
812 break;
813 }
814 break;
815 }
816 case 2:
817 lev = NUM2LONG(level);
818 n = NUM2LONG(vn);
819 if (lev < 0) {
820 rb_raise(rb_eArgError, "negative level (%ld)", lev);
821 }
822 if (n < 0) {
823 rb_raise(rb_eArgError, "negative size (%ld)", n);
824 }
825 lev += lev_plus;
826 break;
827 default:
828 lev = n = 0; /* to avoid warning */
829 break;
830 }
831
832 if (n == 0) {
833 return rb_ary_new();
834 }
835
836 if (to_str) {
837 r = backtrace_to_str_ary(btval, lev, n);
838 }
839 else {
840 r = backtrace_to_location_ary(btval, lev, n);
841 }
842 RB_GC_GUARD(btval);
843 return r;
844 }
845
846 static VALUE
847 thread_backtrace_to_ary(int argc, VALUE *argv, VALUE thval, int to_str)
848 {
849 rb_thread_t *th;
850 GetThreadPtr(thval, th);
851
852 if (th->to_kill || th->status == THREAD_KILLED)
853 return Qnil;
854
855 return vm_backtrace_to_ary(th, argc, argv, 0, 0, to_str);
856 }
857
858 VALUE
859 vm_thread_backtrace(int argc, VALUE *argv, VALUE thval)
860 {
861 return thread_backtrace_to_ary(argc, argv, thval, 1);
862 }
863
864 VALUE
865 vm_thread_backtrace_locations(int argc, VALUE *argv, VALUE thval)
866 {
867 return thread_backtrace_to_ary(argc, argv, thval, 0);
868 }
869
870 /*
871 * call-seq:
872 * caller(start=1, length=nil) -> array or nil
873 * caller(range) -> array or nil
874 *
875 * Returns the current execution stack---an array containing strings in
876 * the form <code>file:line</code> or <code>file:line: in
877 * `method'</code>.
878 *
879 * The optional _start_ parameter determines the number of initial stack
880 * entries to omit from the top of the stack.
881 *
882 * A second optional +length+ parameter can be used to limit how many entries
883 * are returned from the stack.
884 *
885 * Returns +nil+ if _start_ is greater than the size of
886 * current execution stack.
887 *
888 * Optionally you can pass a range, which will return an array containing the
889 * entries within the specified range.
890 *
891 * def a(skip)
892 * caller(skip)
893 * end
894 * def b(skip)
895 * a(skip)
896 * end
897 * def c(skip)
898 * b(skip)
899 * end
900 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
901 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
902 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
903 * c(3) #=> ["prog:13:in `<main>'"]
904 * c(4) #=> []
905 * c(5) #=> nil
906 */
907
908 static VALUE
909 rb_f_caller(int argc, VALUE *argv)
910 {
911 return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 1);
912 }
913
914 /*
915 * call-seq:
916 * caller_locations(start=1, length=nil) -> array or nil
917 * caller_locations(range) -> array or nil
918 *
919 * Returns the current execution stack---an array containing
920 * backtrace location objects.
921 *
922 * See Thread::Backtrace::Location for more information.
923 *
924 * The optional _start_ parameter determines the number of initial stack
925 * entries to omit from the top of the stack.
926 *
927 * A second optional +length+ parameter can be used to limit how many entries
928 * are returned from the stack.
929 *
930 * Returns +nil+ if _start_ is greater than the size of
931 * current execution stack.
932 *
933 * Optionally you can pass a range, which will return an array containing the
934 * entries within the specified range.
935 */
936 static VALUE
937 rb_f_caller_locations(int argc, VALUE *argv)
938 {
939 return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 0);
940 }
941
942 /* called from Init_vm() in vm.c */
943 void
944 Init_vm_backtrace(void)
945 {
946 /* :nodoc: */
947 rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
948 rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
949 rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
950 rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
951
952 /*
953 * An object representation of a stack frame, initialized by
954 * Kernel#caller_locations.
955 *
956 * For example:
957 *
958 * # caller_locations.rb
959 * def a(skip)
960 * caller_locations(skip)
961 * end
962 * def b(skip)
963 * a(skip)
964 * end
965 * def c(skip)
966 * b(skip)
967 * end
968 *
969 * c(0..2).map do |call|
970 * puts call.to_s
971 * end
972 *
973 * Running <code>ruby caller_locations.rb</code> will produce:
974 *
975 * caller_locations.rb:2:in `a'
976 * caller_locations.rb:5:in `b'
977 * caller_locations.rb:8:in `c'
978 *
979 * Here's another example with a slightly different result:
980 *
981 * # foo.rb
982 * class Foo
983 * attr_accessor :locations
984 * def initialize(skip)
985 * @locations = caller_locations(skip)
986 * end
987 * end
988 *
989 * Foo.new(0..2).locations.map do |call|
990 * puts call.to_s
991 * end
992 *
993 * Now run <code>ruby foo.rb</code> and you should see:
994 *
995 * init.rb:4:in `initialize'
996 * init.rb:8:in `new'
997 * init.rb:8:in `<main>'
998 */
999 rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
1000 rb_undef_alloc_func(rb_cBacktraceLocation);
1001 rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
1002 rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
1003 rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
1004 rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
1005 rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
1006 rb_define_method(rb_cBacktraceLocation, "absolute_path", location_absolute_path_m, 0);
1007 rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
1008 rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
1009
1010 rb_define_global_function("caller", rb_f_caller, -1);
1011 rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
1012 }
1013
1014 /* debugger API */
1015
1016 #if defined __GNUC__ && __GNUC__ >= 4
1017 #pragma GCC visibility push(default)
1018 #endif
1019
1020 #if defined __GNUC__ && __GNUC__ >= 4
1021 #pragma GCC visibility pop
1022 #endif
1023
1024 struct rb_debug_inspector_struct {
1025 rb_thread_t *th;
1026 rb_control_frame_t *cfp;
1027 VALUE backtrace;
1028 VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1029 long backtrace_size;
1030 };
1031
1032 enum {
1033 CALLER_BINDING_SELF,
1034 CALLER_BINDING_CLASS,
1035 CALLER_BINDING_BINDING,
1036 CALLER_BINDING_ISEQ,
1037 CALLER_BINDING_CFP
1038 };
1039
1040 struct collect_caller_bindings_data {
1041 VALUE ary;
1042 };
1043
1044 static void
1045 collect_caller_bindings_init(void *arg, size_t size)
1046 {
1047 /* */
1048 }
1049
1050 static VALUE
1051 get_klass(const rb_control_frame_t *cfp)
1052 {
1053 VALUE klass;
1054 if (rb_vm_control_frame_id_and_class(cfp, 0, &klass)) {
1055 if (RB_TYPE_P(klass, T_ICLASS)) {
1056 return RBASIC(klass)->klass;
1057 }
1058 else {
1059 return klass;
1060 }
1061 }
1062 else {
1063 return Qnil;
1064 }
1065 }
1066
1067 static void
1068 collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
1069 {
1070 struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1071 VALUE frame = rb_ary_new2(5);
1072
1073 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1074 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1075 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
1076 rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? cfp->iseq->self : Qnil);
1077 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1078
1079 rb_ary_push(data->ary, frame);
1080 }
1081
1082 static void
1083 collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
1084 {
1085 struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1086 VALUE frame = rb_ary_new2(5);
1087
1088 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
1089 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
1090 rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
1091 rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
1092 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1093
1094 rb_ary_push(data->ary, frame);
1095 }
1096
1097 static VALUE
1098 collect_caller_bindings(rb_thread_t *th)
1099 {
1100 struct collect_caller_bindings_data data;
1101 VALUE result;
1102 int i;
1103
1104 data.ary = rb_ary_new();
1105
1106 backtrace_each(th,
1107 collect_caller_bindings_init,
1108 collect_caller_bindings_iseq,
1109 collect_caller_bindings_cfunc,
1110 &data);
1111
1112 result = rb_ary_reverse(data.ary);
1113
1114 /* bindings should be created from top of frame */
1115 for (i=0; i<RARRAY_LEN(result); i++) {
1116 VALUE entry = rb_ary_entry(result, i);
1117 VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
1118
1119 if (!NIL_P(cfp_val)) {
1120 rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
1121 rb_ary_store(entry, CALLER_BINDING_BINDING, rb_binding_new_with_cfp(th, cfp));
1122 }
1123 }
1124
1125 return result;
1126 }
1127
1128 /*
1129 * Note that the passed `rb_debug_inspector_t' will be disabled
1130 * after `rb_debug_inspector_open'.
1131 */
1132
1133 VALUE
1134 rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
1135 {
1136 rb_debug_inspector_t dbg_context;
1137 rb_thread_t *th = GET_THREAD();
1138 int state;
1139 volatile VALUE UNINITIALIZED_VAR(result);
1140
1141 dbg_context.th = th;
1142 dbg_context.cfp = dbg_context.th->cfp;
1143 dbg_context.backtrace = vm_backtrace_location_ary(th, 0, 0);
1144 dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
1145 dbg_context.contexts = collect_caller_bindings(th);
1146
1147 TH_PUSH_TAG(th);
1148 if ((state = EXEC_TAG()) == 0) {
1149 result = (*func)(&dbg_context, data);
1150 }
1151 TH_POP_TAG();
1152
1153 /* invalidate bindings? */
1154
1155 if (state) {
1156 JUMP_TAG(state);
1157 }
1158
1159 return result;
1160 }
1161
1162 static VALUE
1163 frame_get(const rb_debug_inspector_t *dc, long index)
1164 {
1165 if (index < 0 || index >= dc->backtrace_size) {
1166 rb_raise(rb_eArgError, "no such frame");
1167 }
1168 return rb_ary_entry(dc->contexts, index);
1169 }
1170
1171 VALUE
1172 rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
1173 {
1174 VALUE frame = frame_get(dc, index);
1175 return rb_ary_entry(frame, CALLER_BINDING_SELF);
1176 }
1177
1178 VALUE
1179 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
1180 {
1181 VALUE frame = frame_get(dc, index);
1182 return rb_ary_entry(frame, CALLER_BINDING_CLASS);
1183 }
1184
1185 VALUE
1186 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
1187 {
1188 VALUE frame = frame_get(dc, index);
1189 return rb_ary_entry(frame, CALLER_BINDING_BINDING);
1190 }
1191
1192 VALUE
1193 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
1194 {
1195 VALUE frame = frame_get(dc, index);
1196 return rb_ary_entry(frame, CALLER_BINDING_ISEQ);
1197 }
1198
1199 VALUE
1200 rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
1201 {
1202 return dc->backtrace;
1203 }
1204
1205