vm_backtrace.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   vm_backtrace.c -
00004 
00005   $Author: ko1 $
00006   created at: Sun Jun 03 00:14:20 2012
00007 
00008   Copyright (C) 1993-2012 Yukihiro Matsumoto
00009 
00010 **********************************************************************/
00011 
00012 #include "ruby/ruby.h"
00013 #include "ruby/encoding.h"
00014 #include "ruby/debug.h"
00015 
00016 #include "internal.h"
00017 #include "vm_core.h"
00018 #include "eval_intern.h"
00019 #include "iseq.h"
00020 
00021 static VALUE rb_cBacktrace;
00022 static VALUE rb_cBacktraceLocation;
00023 
00024 extern VALUE ruby_engine_name;
00025 
00026 inline static int
00027 calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
00028 {
00029     return rb_iseq_line_no(iseq, pc - iseq->iseq_encoded);
00030 }
00031 
00032 int
00033 rb_vm_get_sourceline(const rb_control_frame_t *cfp)
00034 {
00035     int lineno = 0;
00036     const rb_iseq_t *iseq = cfp->iseq;
00037 
00038     if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
00039         lineno = calc_lineno(cfp->iseq, cfp->pc);
00040     }
00041     return lineno;
00042 }
00043 
00044 typedef struct rb_backtrace_location_struct {
00045     enum LOCATION_TYPE {
00046         LOCATION_TYPE_ISEQ = 1,
00047         LOCATION_TYPE_ISEQ_CALCED,
00048         LOCATION_TYPE_CFUNC,
00049         LOCATION_TYPE_IFUNC
00050     } type;
00051 
00052     union {
00053         struct {
00054             const rb_iseq_t *iseq;
00055             union {
00056                 const VALUE *pc;
00057                 int lineno;
00058             } lineno;
00059         } iseq;
00060         struct {
00061             ID mid;
00062             struct rb_backtrace_location_struct *prev_loc;
00063         } cfunc;
00064     } body;
00065 } rb_backtrace_location_t;
00066 
00067 struct valued_frame_info {
00068     rb_backtrace_location_t *loc;
00069     VALUE btobj;
00070 };
00071 
00072 static void
00073 location_mark(void *ptr)
00074 {
00075     if (ptr) {
00076         struct valued_frame_info *vfi = (struct valued_frame_info *)ptr;
00077         rb_gc_mark(vfi->btobj);
00078     }
00079 }
00080 
00081 static void
00082 location_mark_entry(rb_backtrace_location_t *fi)
00083 {
00084     switch (fi->type) {
00085       case LOCATION_TYPE_ISEQ:
00086       case LOCATION_TYPE_ISEQ_CALCED:
00087         rb_gc_mark(fi->body.iseq.iseq->self);
00088         break;
00089       case LOCATION_TYPE_CFUNC:
00090       case LOCATION_TYPE_IFUNC:
00091       default:
00092         break;
00093     }
00094 }
00095 
00096 static void
00097 location_free(void *ptr)
00098 {
00099     if (ptr) {
00100         rb_backtrace_location_t *fi = (rb_backtrace_location_t *)ptr;
00101         ruby_xfree(fi);
00102     }
00103 }
00104 
00105 static size_t
00106 location_memsize(const void *ptr)
00107 {
00108     /* rb_backtrace_location_t *fi = (rb_backtrace_location_t *)ptr; */
00109     return sizeof(rb_backtrace_location_t);
00110 }
00111 
00112 static const rb_data_type_t location_data_type = {
00113     "frame_info",
00114     {location_mark, location_free, location_memsize,},
00115     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
00116 };
00117 
00118 static inline rb_backtrace_location_t *
00119 location_ptr(VALUE locobj)
00120 {
00121     struct valued_frame_info *vloc;
00122     GetCoreDataFromValue(locobj, struct valued_frame_info, vloc);
00123     return vloc->loc;
00124 }
00125 
00126 static int
00127 location_lineno(rb_backtrace_location_t *loc)
00128 {
00129     switch (loc->type) {
00130       case LOCATION_TYPE_ISEQ:
00131         loc->type = LOCATION_TYPE_ISEQ_CALCED;
00132         return (loc->body.iseq.lineno.lineno = calc_lineno(loc->body.iseq.iseq, loc->body.iseq.lineno.pc));
00133       case LOCATION_TYPE_ISEQ_CALCED:
00134         return loc->body.iseq.lineno.lineno;
00135       case LOCATION_TYPE_CFUNC:
00136         if (loc->body.cfunc.prev_loc) {
00137             return location_lineno(loc->body.cfunc.prev_loc);
00138         }
00139         return 0;
00140       default:
00141         rb_bug("location_lineno: unreachable");
00142         UNREACHABLE;
00143     }
00144 }
00145 
00146 /*
00147  * Returns the line number of this frame.
00148  *
00149  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
00150  *
00151  *      loc = c(0..1).first
00152  *      loc.lineno #=> 2
00153  */
00154 static VALUE
00155 location_lineno_m(VALUE self)
00156 {
00157     return INT2FIX(location_lineno(location_ptr(self)));
00158 }
00159 
00160 static VALUE
00161 location_label(rb_backtrace_location_t *loc)
00162 {
00163     switch (loc->type) {
00164       case LOCATION_TYPE_ISEQ:
00165       case LOCATION_TYPE_ISEQ_CALCED:
00166         return loc->body.iseq.iseq->location.label;
00167       case LOCATION_TYPE_CFUNC:
00168         return rb_id2str(loc->body.cfunc.mid);
00169       case LOCATION_TYPE_IFUNC:
00170       default:
00171         rb_bug("location_label: unreachable");
00172         UNREACHABLE;
00173     }
00174 }
00175 
00176 /*
00177  * Returns the label of this frame.
00178  *
00179  * Usually consists of method, class, module, etc names with decoration.
00180  *
00181  * Consider the following example:
00182  *
00183  *      def foo
00184  *        puts caller_locations(0).first.label
00185  *
00186  *        1.times do
00187  *          puts caller_locations(0).first.label
00188  *
00189  *          1.times do
00190  *            puts caller_locations(0).first.label
00191  *          end
00192  *
00193  *        end
00194  *      end
00195  *
00196  * The result of calling +foo+ is this:
00197  *
00198  *      label: foo
00199  *      label: block in foo
00200  *      label: block (2 levels) in foo
00201  *
00202  */
00203 static VALUE
00204 location_label_m(VALUE self)
00205 {
00206     return location_label(location_ptr(self));
00207 }
00208 
00209 static VALUE
00210 location_base_label(rb_backtrace_location_t *loc)
00211 {
00212     switch (loc->type) {
00213       case LOCATION_TYPE_ISEQ:
00214       case LOCATION_TYPE_ISEQ_CALCED:
00215         return loc->body.iseq.iseq->location.base_label;
00216       case LOCATION_TYPE_CFUNC:
00217         return rb_sym_to_s(ID2SYM(loc->body.cfunc.mid));
00218       case LOCATION_TYPE_IFUNC:
00219       default:
00220         rb_bug("location_base_label: unreachable");
00221         UNREACHABLE;
00222     }
00223 }
00224 
00225 /*
00226  * Returns the base label of this frame.
00227  *
00228  * Usually same as #label, without decoration.
00229  */
00230 static VALUE
00231 location_base_label_m(VALUE self)
00232 {
00233     return location_base_label(location_ptr(self));
00234 }
00235 
00236 static VALUE
00237 location_path(rb_backtrace_location_t *loc)
00238 {
00239     switch (loc->type) {
00240       case LOCATION_TYPE_ISEQ:
00241       case LOCATION_TYPE_ISEQ_CALCED:
00242         return loc->body.iseq.iseq->location.path;
00243       case LOCATION_TYPE_CFUNC:
00244         if (loc->body.cfunc.prev_loc) {
00245             return location_path(loc->body.cfunc.prev_loc);
00246         }
00247         return Qnil;
00248       case LOCATION_TYPE_IFUNC:
00249       default:
00250         rb_bug("location_path: unreachable");
00251         UNREACHABLE;
00252     }
00253 }
00254 
00255 /*
00256  * Returns the file name of this frame.
00257  *
00258  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
00259  *
00260  *      loc = c(0..1).first
00261  *      loc.path #=> caller_locations.rb
00262  */
00263 static VALUE
00264 location_path_m(VALUE self)
00265 {
00266     return location_path(location_ptr(self));
00267 }
00268 
00269 static VALUE
00270 location_absolute_path(rb_backtrace_location_t *loc)
00271 {
00272     switch (loc->type) {
00273       case LOCATION_TYPE_ISEQ:
00274       case LOCATION_TYPE_ISEQ_CALCED:
00275         return loc->body.iseq.iseq->location.absolute_path;
00276       case LOCATION_TYPE_CFUNC:
00277         if (loc->body.cfunc.prev_loc) {
00278             return location_absolute_path(loc->body.cfunc.prev_loc);
00279         }
00280         return Qnil;
00281       case LOCATION_TYPE_IFUNC:
00282       default:
00283         rb_bug("location_absolute_path: unreachable");
00284         UNREACHABLE;
00285     }
00286 }
00287 
00288 /*
00289  * Returns the full file path of this frame.
00290  *
00291  * Same as #path, but includes the absolute path.
00292  */
00293 static VALUE
00294 location_absolute_path_m(VALUE self)
00295 {
00296     return location_absolute_path(location_ptr(self));
00297 }
00298 
00299 static VALUE
00300 location_format(VALUE file, int lineno, VALUE name)
00301 {
00302     if (lineno != 0) {
00303         return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:%d:in `%s'",
00304                               RSTRING_PTR(file), lineno, RSTRING_PTR(name));
00305     }
00306     else {
00307         return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:in `%s'",
00308                               RSTRING_PTR(file), RSTRING_PTR(name));
00309     }
00310 }
00311 
00312 static VALUE
00313 location_to_str(rb_backtrace_location_t *loc)
00314 {
00315     VALUE file, name;
00316     int lineno;
00317 
00318     switch (loc->type) {
00319       case LOCATION_TYPE_ISEQ:
00320         file = loc->body.iseq.iseq->location.path;
00321         name = loc->body.iseq.iseq->location.label;
00322 
00323         lineno = loc->body.iseq.lineno.lineno = calc_lineno(loc->body.iseq.iseq, loc->body.iseq.lineno.pc);
00324         loc->type = LOCATION_TYPE_ISEQ_CALCED;
00325         break;
00326       case LOCATION_TYPE_ISEQ_CALCED:
00327         file = loc->body.iseq.iseq->location.path;
00328         lineno = loc->body.iseq.lineno.lineno;
00329         name = loc->body.iseq.iseq->location.label;
00330         break;
00331       case LOCATION_TYPE_CFUNC:
00332         if (loc->body.cfunc.prev_loc) {
00333             file = loc->body.cfunc.prev_loc->body.iseq.iseq->location.path;
00334             lineno = location_lineno(loc->body.cfunc.prev_loc);
00335         }
00336         else {
00337             rb_thread_t *th = GET_THREAD();
00338             file = th->vm->progname ? th->vm->progname : ruby_engine_name;
00339             lineno = INT2FIX(0);
00340         }
00341         name = rb_id2str(loc->body.cfunc.mid);
00342         break;
00343       case LOCATION_TYPE_IFUNC:
00344       default:
00345         rb_bug("location_to_str: unreachable");
00346     }
00347 
00348     return location_format(file, lineno, name);
00349 }
00350 
00351 /*
00352  * Returns a Kernel#caller style string representing this frame.
00353  */
00354 static VALUE
00355 location_to_str_m(VALUE self)
00356 {
00357     return location_to_str(location_ptr(self));
00358 }
00359 
00360 /*
00361  * Returns the same as calling +inspect+ on the string representation of
00362  * #to_str
00363  */
00364 static VALUE
00365 location_inspect_m(VALUE self)
00366 {
00367     return rb_str_inspect(location_to_str(location_ptr(self)));
00368 }
00369 
00370 typedef struct rb_backtrace_struct {
00371     rb_backtrace_location_t *backtrace;
00372     rb_backtrace_location_t *backtrace_base;
00373     int backtrace_size;
00374     VALUE strary;
00375     VALUE locary;
00376 } rb_backtrace_t;
00377 
00378 static void
00379 backtrace_mark(void *ptr)
00380 {
00381     if (ptr) {
00382         rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
00383         size_t i, s = bt->backtrace_size;
00384 
00385         for (i=0; i<s; i++) {
00386             location_mark_entry(&bt->backtrace[i]);
00387         }
00388         rb_gc_mark(bt->strary);
00389         rb_gc_mark(bt->locary);
00390     }
00391 }
00392 
00393 static void
00394 backtrace_free(void *ptr)
00395 {
00396    if (ptr) {
00397        rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
00398        if (bt->backtrace) ruby_xfree(bt->backtrace_base);
00399        ruby_xfree(bt);
00400    }
00401 }
00402 
00403 static size_t
00404 backtrace_memsize(const void *ptr)
00405 {
00406     rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
00407     return sizeof(rb_backtrace_t) + sizeof(rb_backtrace_location_t) * bt->backtrace_size;
00408 }
00409 
00410 static const rb_data_type_t backtrace_data_type = {
00411     "backtrace",
00412     {backtrace_mark, backtrace_free, backtrace_memsize,},
00413     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
00414 };
00415 
00416 int
00417 rb_backtrace_p(VALUE obj)
00418 {
00419     return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
00420 }
00421 
00422 static VALUE
00423 backtrace_alloc(VALUE klass)
00424 {
00425     rb_backtrace_t *bt;
00426     VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
00427     return obj;
00428 }
00429 
00430 static void
00431 backtrace_each(rb_thread_t *th,
00432                void (*init)(void *arg, size_t size),
00433                void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
00434                void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
00435                void *arg)
00436 {
00437     rb_control_frame_t *last_cfp = th->cfp;
00438     rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(th);
00439     rb_control_frame_t *cfp;
00440     ptrdiff_t size, i;
00441 
00442     /*                <- start_cfp (end control frame)
00443      *  top frame (dummy)
00444      *  top frame (dummy)
00445      *  top frame     <- start_cfp
00446      *  top frame
00447      *  ...
00448      *  2nd frame     <- lev:0
00449      *  current frame <- th->cfp
00450      */
00451 
00452     start_cfp =
00453       RUBY_VM_NEXT_CONTROL_FRAME(
00454           RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
00455 
00456     if (start_cfp < last_cfp) {
00457         size = 0;
00458     }
00459     else {
00460         size = start_cfp - last_cfp + 1;
00461     }
00462 
00463     init(arg, size);
00464 
00465     /* SDR(); */
00466     for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
00467         /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(th->stack + th->stack_size) - cfp); */
00468         if (cfp->iseq) {
00469             if (cfp->pc) {
00470                 iter_iseq(arg, cfp);
00471             }
00472         }
00473         else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
00474             ID mid = cfp->me->def ? cfp->me->def->original_id : cfp->me->called_id;
00475 
00476             iter_cfunc(arg, cfp, mid);
00477         }
00478     }
00479 }
00480 
00481 struct bt_iter_arg {
00482     rb_backtrace_t *bt;
00483     VALUE btobj;
00484     rb_backtrace_location_t *prev_loc;
00485 };
00486 
00487 static void
00488 bt_init(void *ptr, size_t size)
00489 {
00490     struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
00491     arg->btobj = backtrace_alloc(rb_cBacktrace);
00492     GetCoreDataFromValue(arg->btobj, rb_backtrace_t, arg->bt);
00493     arg->bt->backtrace_base = arg->bt->backtrace = ruby_xmalloc(sizeof(rb_backtrace_location_t) * size);
00494     arg->bt->backtrace_size = 0;
00495 }
00496 
00497 static void
00498 bt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
00499 {
00500     const rb_iseq_t *iseq = cfp->iseq;
00501     const VALUE *pc = cfp->pc;
00502     struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
00503     rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
00504     loc->type = LOCATION_TYPE_ISEQ;
00505     loc->body.iseq.iseq = iseq;
00506     loc->body.iseq.lineno.pc = pc;
00507     arg->prev_loc = loc;
00508 }
00509 
00510 static void
00511 bt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
00512 {
00513     struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
00514     rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
00515     loc->type = LOCATION_TYPE_CFUNC;
00516     loc->body.cfunc.mid = mid;
00517     loc->body.cfunc.prev_loc = arg->prev_loc;
00518 }
00519 
00520 static VALUE
00521 backtrace_object(rb_thread_t *th)
00522 {
00523     struct bt_iter_arg arg;
00524     arg.prev_loc = 0;
00525 
00526     backtrace_each(th,
00527                    bt_init,
00528                    bt_iter_iseq,
00529                    bt_iter_cfunc,
00530                    &arg);
00531 
00532     return arg.btobj;
00533 }
00534 
00535 VALUE
00536 rb_vm_backtrace_object(void)
00537 {
00538     return backtrace_object(GET_THREAD());
00539 }
00540 
00541 static VALUE
00542 backtrace_collect(rb_backtrace_t *bt, long lev, long n, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
00543 {
00544     VALUE btary;
00545     int i;
00546 
00547     if (UNLIKELY(lev < 0 || n < 0)) {
00548         rb_bug("backtrace_collect: unreachable");
00549     }
00550 
00551     btary = rb_ary_new();
00552 
00553     for (i=0; i+lev<bt->backtrace_size && i<n; i++) {
00554         rb_backtrace_location_t *loc = &bt->backtrace[bt->backtrace_size - 1 - (lev+i)];
00555         rb_ary_push(btary, func(loc, arg));
00556     }
00557 
00558     return btary;
00559 }
00560 
00561 static VALUE
00562 location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
00563 {
00564     return location_to_str(loc);
00565 }
00566 
00567 static VALUE
00568 backtrace_to_str_ary(VALUE self, long lev, long n)
00569 {
00570     rb_backtrace_t *bt;
00571     int size;
00572     VALUE r;
00573 
00574     GetCoreDataFromValue(self, rb_backtrace_t, bt);
00575     size = bt->backtrace_size;
00576 
00577     if (n == 0) {
00578         n = size;
00579     }
00580     if (lev > size) {
00581         return Qnil;
00582     }
00583 
00584     r = backtrace_collect(bt, lev, n, location_to_str_dmyarg, 0);
00585     RB_GC_GUARD(self);
00586     return r;
00587 }
00588 
00589 VALUE
00590 rb_backtrace_to_str_ary(VALUE self)
00591 {
00592     rb_backtrace_t *bt;
00593     GetCoreDataFromValue(self, rb_backtrace_t, bt);
00594 
00595     if (!bt->strary) {
00596         bt->strary = backtrace_to_str_ary(self, 0, bt->backtrace_size);
00597     }
00598     return bt->strary;
00599 }
00600 
00601 static VALUE
00602 location_create(rb_backtrace_location_t *srcloc, void *btobj)
00603 {
00604     VALUE obj;
00605     struct valued_frame_info *vloc;
00606     obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
00607 
00608     vloc->loc = srcloc;
00609     vloc->btobj = (VALUE)btobj;
00610 
00611     return obj;
00612 }
00613 
00614 static VALUE
00615 backtrace_to_location_ary(VALUE self, long lev, long n)
00616 {
00617     rb_backtrace_t *bt;
00618     int size;
00619     VALUE r;
00620 
00621     GetCoreDataFromValue(self, rb_backtrace_t, bt);
00622     size = bt->backtrace_size;
00623 
00624     if (n == 0) {
00625         n = size;
00626     }
00627     if (lev > size) {
00628         return Qnil;
00629     }
00630 
00631     r = backtrace_collect(bt, lev, n, location_create, (void *)self);
00632     RB_GC_GUARD(self);
00633     return r;
00634 }
00635 
00636 VALUE
00637 rb_backtrace_to_location_ary(VALUE self)
00638 {
00639     rb_backtrace_t *bt;
00640     GetCoreDataFromValue(self, rb_backtrace_t, bt);
00641 
00642     if (!bt->locary) {
00643         bt->locary = backtrace_to_location_ary(self, 0, 0);
00644     }
00645     return bt->locary;
00646 }
00647 
00648 static VALUE
00649 backtrace_dump_data(VALUE self)
00650 {
00651     VALUE str = rb_backtrace_to_str_ary(self);
00652     return str;
00653 }
00654 
00655 static VALUE
00656 backtrace_load_data(VALUE self, VALUE str)
00657 {
00658     rb_backtrace_t *bt;
00659     GetCoreDataFromValue(self, rb_backtrace_t, bt);
00660     bt->strary = str;
00661     return self;
00662 }
00663 
00664 VALUE
00665 rb_vm_backtrace_str_ary(rb_thread_t *th, long lev, long n)
00666 {
00667     return backtrace_to_str_ary(backtrace_object(th), lev, n);
00668 }
00669 
00670 VALUE
00671 rb_vm_backtrace_location_ary(rb_thread_t *th, long lev, long n)
00672 {
00673     return backtrace_to_location_ary(backtrace_object(th), lev, n);
00674 }
00675 
00676 /* make old style backtrace directly */
00677 
00678 struct oldbt_arg {
00679     VALUE filename;
00680     int lineno;
00681     void (*func)(void *data, VALUE file, int lineno, VALUE name);
00682     void *data; /* result */
00683 };
00684 
00685 static void
00686 oldbt_init(void *ptr, size_t dmy)
00687 {
00688     struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
00689     rb_thread_t *th = GET_THREAD();
00690 
00691     arg->filename = th->vm->progname ? th->vm->progname : ruby_engine_name;;
00692     arg->lineno = 0;
00693 }
00694 
00695 static void
00696 oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
00697 {
00698     const rb_iseq_t *iseq = cfp->iseq;
00699     const VALUE *pc = cfp->pc;
00700     struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
00701     VALUE file = arg->filename = iseq->location.path;
00702     VALUE name = iseq->location.label;
00703     int lineno = arg->lineno = calc_lineno(iseq, pc);
00704 
00705     (arg->func)(arg->data, file, lineno, name);
00706 }
00707 
00708 static void
00709 oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
00710 {
00711     struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
00712     VALUE file = arg->filename;
00713     VALUE name = rb_id2str(mid);
00714     int lineno = arg->lineno;
00715 
00716     (arg->func)(arg->data, file, lineno, name);
00717 }
00718 
00719 static void
00720 oldbt_print(void *data, VALUE file, int lineno, VALUE name)
00721 {
00722     FILE *fp = (FILE *)data;
00723 
00724     if (NIL_P(name)) {
00725         fprintf(fp, "\tfrom %s:%d:in unknown method\n",
00726                 RSTRING_PTR(file), lineno);
00727     }
00728     else {
00729         fprintf(fp, "\tfrom %s:%d:in `%s'\n",
00730                 RSTRING_PTR(file), lineno, RSTRING_PTR(name));
00731     }
00732 }
00733 
00734 static void
00735 vm_backtrace_print(FILE *fp)
00736 {
00737     struct oldbt_arg arg;
00738 
00739     arg.func = oldbt_print;
00740     arg.data = (void *)fp;
00741     backtrace_each(GET_THREAD(),
00742                    oldbt_init,
00743                    oldbt_iter_iseq,
00744                    oldbt_iter_cfunc,
00745                    &arg);
00746 }
00747 
00748 static void
00749 oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
00750 {
00751     const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
00752     if (!*(int *)arg) {
00753         fprintf(stderr, "-- Ruby level backtrace information "
00754                 "----------------------------------------\n");
00755         *(int *)arg = 1;
00756     }
00757     if (NIL_P(method)) {
00758         fprintf(stderr, "%s:%d:in unknown method\n", filename, line);
00759     }
00760     else {
00761         fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
00762     }
00763 }
00764 
00765 void
00766 rb_backtrace_print_as_bugreport(void)
00767 {
00768     struct oldbt_arg arg;
00769     int i;
00770 
00771     arg.func = oldbt_bugreport;
00772     arg.data = (int *)&i;
00773 
00774     backtrace_each(GET_THREAD(),
00775                    oldbt_init,
00776                    oldbt_iter_iseq,
00777                    oldbt_iter_cfunc,
00778                    &arg);
00779 }
00780 
00781 void
00782 rb_backtrace(void)
00783 {
00784     vm_backtrace_print(stderr);
00785 }
00786 
00787 static void
00788 oldbt_print_to(void *data, VALUE file, int lineno, VALUE name)
00789 {
00790     VALUE output = (VALUE)data;
00791     VALUE str = rb_sprintf("\tfrom %"PRIsVALUE":%d:in ", file, lineno);
00792 
00793     if (NIL_P(name)) {
00794         rb_str_cat2(str, "unknown method\n");
00795     }
00796     else {
00797         rb_str_catf(str, " `%"PRIsVALUE"'\n", name);
00798     }
00799     rb_io_write(output, str);
00800 }
00801 
00802 void
00803 rb_backtrace_print_to(VALUE output)
00804 {
00805     struct oldbt_arg arg;
00806 
00807     arg.func = oldbt_print_to;
00808     arg.data = (void *)output;
00809     backtrace_each(GET_THREAD(),
00810                    oldbt_init,
00811                    oldbt_iter_iseq,
00812                    oldbt_iter_cfunc,
00813                    &arg);
00814 }
00815 
00816 VALUE
00817 rb_make_backtrace(void)
00818 {
00819     return rb_vm_backtrace_str_ary(GET_THREAD(), 0, 0);
00820 }
00821 
00822 static VALUE
00823 vm_backtrace_to_ary(rb_thread_t *th, int argc, VALUE *argv, int lev_default, int lev_plus, int to_str)
00824 {
00825     VALUE level, vn;
00826     long lev, n;
00827     VALUE btval = backtrace_object(th);
00828     VALUE r;
00829     rb_backtrace_t *bt;
00830 
00831     GetCoreDataFromValue(btval, rb_backtrace_t, bt);
00832 
00833     rb_scan_args(argc, argv, "02", &level, &vn);
00834 
00835     if (argc == 2 && NIL_P(vn)) argc--;
00836 
00837     switch (argc) {
00838       case 0:
00839         lev = lev_default + lev_plus;
00840         n = bt->backtrace_size - lev;
00841         break;
00842       case 1:
00843         {
00844             long beg, len;
00845             switch (rb_range_beg_len(level, &beg, &len, bt->backtrace_size - lev_plus, 0)) {
00846               case Qfalse:
00847                 lev = NUM2LONG(level);
00848                 if (lev < 0) {
00849                     rb_raise(rb_eArgError, "negative level (%ld)", lev);
00850                 }
00851                 lev += lev_plus;
00852                 n = bt->backtrace_size - lev;
00853                 break;
00854               case Qnil:
00855                 return Qnil;
00856               default:
00857                 lev = beg + lev_plus;
00858                 n = len;
00859                 break;
00860             }
00861             break;
00862         }
00863       case 2:
00864         lev = NUM2LONG(level);
00865         n = NUM2LONG(vn);
00866         if (lev < 0) {
00867             rb_raise(rb_eArgError, "negative level (%ld)", lev);
00868         }
00869         if (n < 0) {
00870             rb_raise(rb_eArgError, "negative size (%ld)", n);
00871         }
00872         lev += lev_plus;
00873         break;
00874       default:
00875         lev = n = 0; /* to avoid warning */
00876         break;
00877     }
00878 
00879     if (n == 0) {
00880         return rb_ary_new();
00881     }
00882 
00883     if (to_str) {
00884         r = backtrace_to_str_ary(btval, lev, n);
00885     }
00886     else {
00887         r = backtrace_to_location_ary(btval, lev, n);
00888     }
00889     RB_GC_GUARD(btval);
00890     return r;
00891 }
00892 
00893 static VALUE
00894 thread_backtrace_to_ary(int argc, VALUE *argv, VALUE thval, int to_str)
00895 {
00896     rb_thread_t *th;
00897     GetThreadPtr(thval, th);
00898 
00899     if (th->to_kill || th->status == THREAD_KILLED)
00900         return Qnil;
00901 
00902     return vm_backtrace_to_ary(th, argc, argv, 0, 0, to_str);
00903 }
00904 
00905 VALUE
00906 rb_vm_thread_backtrace(int argc, VALUE *argv, VALUE thval)
00907 {
00908     return thread_backtrace_to_ary(argc, argv, thval, 1);
00909 }
00910 
00911 VALUE
00912 rb_vm_thread_backtrace_locations(int argc, VALUE *argv, VALUE thval)
00913 {
00914     return thread_backtrace_to_ary(argc, argv, thval, 0);
00915 }
00916 
00917 /*
00918  *  call-seq:
00919  *     caller(start=1, length=nil)  -> array or nil
00920  *     caller(range)                -> array or nil
00921  *
00922  *  Returns the current execution stack---an array containing strings in
00923  *  the form <code>file:line</code> or <code>file:line: in
00924  *  `method'</code>.
00925  *
00926  *  The optional _start_ parameter determines the number of initial stack
00927  *  entries to omit from the top of the stack.
00928  *
00929  *  A second optional +length+ parameter can be used to limit how many entries
00930  *  are returned from the stack.
00931  *
00932  *  Returns +nil+ if _start_ is greater than the size of
00933  *  current execution stack.
00934  *
00935  *  Optionally you can pass a range, which will return an array containing the
00936  *  entries within the specified range.
00937  *
00938  *     def a(skip)
00939  *       caller(skip)
00940  *     end
00941  *     def b(skip)
00942  *       a(skip)
00943  *     end
00944  *     def c(skip)
00945  *       b(skip)
00946  *     end
00947  *     c(0)   #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
00948  *     c(1)   #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
00949  *     c(2)   #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
00950  *     c(3)   #=> ["prog:13:in `<main>'"]
00951  *     c(4)   #=> []
00952  *     c(5)   #=> nil
00953  */
00954 
00955 static VALUE
00956 rb_f_caller(int argc, VALUE *argv)
00957 {
00958     return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 1);
00959 }
00960 
00961 /*
00962  *  call-seq:
00963  *     caller_locations(start=1, length=nil)    -> array or nil
00964  *     caller_locations(range)                  -> array or nil
00965  *
00966  *  Returns the current execution stack---an array containing
00967  *  backtrace location objects.
00968  *
00969  *  See Thread::Backtrace::Location for more information.
00970  *
00971  *  The optional _start_ parameter determines the number of initial stack
00972  *  entries to omit from the top of the stack.
00973  *
00974  *  A second optional +length+ parameter can be used to limit how many entries
00975  *  are returned from the stack.
00976  *
00977  *  Returns +nil+ if _start_ is greater than the size of
00978  *  current execution stack.
00979  *
00980  *  Optionally you can pass a range, which will return an array containing the
00981  *  entries within the specified range.
00982  */
00983 static VALUE
00984 rb_f_caller_locations(int argc, VALUE *argv)
00985 {
00986     return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 0);
00987 }
00988 
00989 /* called from Init_vm() in vm.c */
00990 void
00991 Init_vm_backtrace(void)
00992 {
00993     /* :nodoc: */
00994     rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
00995     rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
00996     rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
00997     rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
00998 
00999     /*
01000      *  An object representation of a stack frame, initialized by
01001      *  Kernel#caller_locations.
01002      *
01003      *  For example:
01004      *
01005      *          # caller_locations.rb
01006      *          def a(skip)
01007      *            caller_locations(skip)
01008      *          end
01009      *          def b(skip)
01010      *            a(skip)
01011      *          end
01012      *          def c(skip)
01013      *            b(skip)
01014      *          end
01015      *
01016      *          c(0..2).map do |call|
01017      *            puts call.to_s
01018      *          end
01019      *
01020      *  Running <code>ruby caller_locations.rb</code> will produce:
01021      *
01022      *          caller_locations.rb:2:in `a'
01023      *          caller_locations.rb:5:in `b'
01024      *          caller_locations.rb:8:in `c'
01025      *
01026      *  Here's another example with a slightly different result:
01027      *
01028      *          # foo.rb
01029      *          class Foo
01030      *            attr_accessor :locations
01031      *            def initialize(skip)
01032      *              @locations = caller_locations(skip)
01033      *            end
01034      *          end
01035      *
01036      *          Foo.new(0..2).locations.map do |call|
01037      *            puts call.to_s
01038      *          end
01039      *
01040      *  Now run <code>ruby foo.rb</code> and you should see:
01041      *
01042      *          init.rb:4:in `initialize'
01043      *          init.rb:8:in `new'
01044      *          init.rb:8:in `<main>'
01045      */
01046     rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
01047     rb_undef_alloc_func(rb_cBacktraceLocation);
01048     rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
01049     rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
01050     rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
01051     rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
01052     rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
01053     rb_define_method(rb_cBacktraceLocation, "absolute_path", location_absolute_path_m, 0);
01054     rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
01055     rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
01056 
01057     rb_define_global_function("caller", rb_f_caller, -1);
01058     rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
01059 }
01060 
01061 /* debugger API */
01062 
01063 RUBY_SYMBOL_EXPORT_BEGIN
01064 
01065 RUBY_SYMBOL_EXPORT_END
01066 
01067 struct rb_debug_inspector_struct {
01068     rb_thread_t *th;
01069     rb_control_frame_t *cfp;
01070     VALUE backtrace;
01071     VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
01072     long backtrace_size;
01073 };
01074 
01075 enum {
01076     CALLER_BINDING_SELF,
01077     CALLER_BINDING_CLASS,
01078     CALLER_BINDING_BINDING,
01079     CALLER_BINDING_ISEQ,
01080     CALLER_BINDING_CFP
01081 };
01082 
01083 struct collect_caller_bindings_data {
01084     VALUE ary;
01085 };
01086 
01087 static void
01088 collect_caller_bindings_init(void *arg, size_t size)
01089 {
01090     /* */
01091 }
01092 
01093 static VALUE
01094 get_klass(const rb_control_frame_t *cfp)
01095 {
01096     VALUE klass;
01097     if (rb_vm_control_frame_id_and_class(cfp, 0, &klass)) {
01098         if (RB_TYPE_P(klass, T_ICLASS)) {
01099             return RBASIC(klass)->klass;
01100         }
01101         else {
01102             return klass;
01103         }
01104     }
01105     else {
01106         return Qnil;
01107     }
01108 }
01109 
01110 static void
01111 collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
01112 {
01113     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
01114     VALUE frame = rb_ary_new2(5);
01115 
01116     rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
01117     rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
01118     rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
01119     rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? cfp->iseq->self : Qnil);
01120     rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
01121 
01122     rb_ary_push(data->ary, frame);
01123 }
01124 
01125 static void
01126 collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
01127 {
01128     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
01129     VALUE frame = rb_ary_new2(5);
01130 
01131     rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
01132     rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
01133     rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
01134     rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
01135     rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
01136 
01137     rb_ary_push(data->ary, frame);
01138 }
01139 
01140 static VALUE
01141 collect_caller_bindings(rb_thread_t *th)
01142 {
01143     struct collect_caller_bindings_data data;
01144     VALUE result;
01145     int i;
01146 
01147     data.ary = rb_ary_new();
01148 
01149     backtrace_each(th,
01150                    collect_caller_bindings_init,
01151                    collect_caller_bindings_iseq,
01152                    collect_caller_bindings_cfunc,
01153                    &data);
01154 
01155     result = rb_ary_reverse(data.ary);
01156 
01157     /* bindings should be created from top of frame */
01158     for (i=0; i<RARRAY_LEN(result); i++) {
01159         VALUE entry = rb_ary_entry(result, i);
01160         VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
01161 
01162         if (!NIL_P(cfp_val)) {
01163             rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
01164             rb_ary_store(entry, CALLER_BINDING_BINDING, rb_binding_new_with_cfp(th, cfp));
01165         }
01166     }
01167 
01168     return result;
01169 }
01170 
01171 /*
01172  * Note that the passed `rb_debug_inspector_t' will be disabled
01173  * after `rb_debug_inspector_open'.
01174  */
01175 
01176 VALUE
01177 rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
01178 {
01179     rb_debug_inspector_t dbg_context;
01180     rb_thread_t *th = GET_THREAD();
01181     int state;
01182     volatile VALUE UNINITIALIZED_VAR(result);
01183 
01184     dbg_context.th = th;
01185     dbg_context.cfp = dbg_context.th->cfp;
01186     dbg_context.backtrace = rb_vm_backtrace_location_ary(th, 0, 0);
01187     dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
01188     dbg_context.contexts = collect_caller_bindings(th);
01189 
01190     TH_PUSH_TAG(th);
01191     if ((state = EXEC_TAG()) == 0) {
01192         result = (*func)(&dbg_context, data);
01193     }
01194     TH_POP_TAG();
01195 
01196     /* invalidate bindings? */
01197 
01198     if (state) {
01199         JUMP_TAG(state);
01200     }
01201 
01202     return result;
01203 }
01204 
01205 static VALUE
01206 frame_get(const rb_debug_inspector_t *dc, long index)
01207 {
01208     if (index < 0 || index >= dc->backtrace_size) {
01209         rb_raise(rb_eArgError, "no such frame");
01210     }
01211     return rb_ary_entry(dc->contexts, index);
01212 }
01213 
01214 VALUE
01215 rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
01216 {
01217     VALUE frame = frame_get(dc, index);
01218     return rb_ary_entry(frame, CALLER_BINDING_SELF);
01219 }
01220 
01221 VALUE
01222 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
01223 {
01224     VALUE frame = frame_get(dc, index);
01225     return rb_ary_entry(frame, CALLER_BINDING_CLASS);
01226 }
01227 
01228 VALUE
01229 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
01230 {
01231     VALUE frame = frame_get(dc, index);
01232     return rb_ary_entry(frame, CALLER_BINDING_BINDING);
01233 }
01234 
01235 VALUE
01236 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
01237 {
01238     VALUE frame = frame_get(dc, index);
01239     return rb_ary_entry(frame, CALLER_BINDING_ISEQ);
01240 }
01241 
01242 VALUE
01243 rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
01244 {
01245     return dc->backtrace;
01246 }
01247 
01248 int
01249 rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
01250 {
01251     int i;
01252     rb_thread_t *th = GET_THREAD();
01253     rb_control_frame_t *cfp = th->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(th);
01254 
01255     for (i=0; i<limit && cfp != end_cfp;) {
01256         if (cfp->iseq && cfp->pc) { /* should be NORMAL_ISEQ */
01257             if (start > 0) {
01258                 start--;
01259                 continue;
01260             }
01261 
01262             /* record frame info */
01263             buff[i] = cfp->iseq->self;
01264             if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc);
01265             i++;
01266         }
01267         cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
01268     }
01269 
01270     return i;
01271 }
01272 
01273 #define frame2iseq(frame) frame
01274 
01275 VALUE
01276 rb_profile_frame_path(VALUE frame)
01277 {
01278     return rb_iseq_path(frame2iseq(frame));
01279 }
01280 
01281 VALUE
01282 rb_profile_frame_absolute_path(VALUE frame)
01283 {
01284     return rb_iseq_absolute_path(frame2iseq(frame));
01285 }
01286 
01287 VALUE
01288 rb_profile_frame_label(VALUE frame)
01289 {
01290     return rb_iseq_label(frame2iseq(frame));
01291 }
01292 
01293 VALUE
01294 rb_profile_frame_base_label(VALUE frame)
01295 {
01296     return rb_iseq_base_label(frame2iseq(frame));
01297 }
01298 
01299 VALUE
01300 rb_profile_frame_first_lineno(VALUE frame)
01301 {
01302     return rb_iseq_first_lineno(frame2iseq(frame));
01303 }
01304 
01305 VALUE
01306 rb_profile_frame_classpath(VALUE frame)
01307 {
01308     VALUE klass = rb_iseq_klass(frame2iseq(frame));
01309 
01310     if (klass && !NIL_P(klass)) {
01311         if (RB_TYPE_P(klass, T_ICLASS)) {
01312             klass = RBASIC(klass)->klass;
01313         }
01314         else if (FL_TEST(klass, FL_SINGLETON)) {
01315             klass = rb_ivar_get(klass, id__attached__);
01316             if (!RB_TYPE_P(klass, T_CLASS))
01317                 return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass);
01318         }
01319         return rb_class_path(klass);
01320     }
01321     else {
01322         return Qnil;
01323     }
01324 }
01325 
01326 VALUE
01327 rb_profile_frame_singleton_method_p(VALUE frame)
01328 {
01329     VALUE klass = rb_iseq_klass(frame2iseq(frame));
01330     if (klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON)) {
01331         return Qtrue;
01332     }
01333     else {
01334         return Qfalse;
01335     }
01336 }
01337 
01338 VALUE
01339 rb_profile_frame_method_name(VALUE frame)
01340 {
01341     return rb_iseq_method_name(frame2iseq(frame));
01342 }
01343 
01344 VALUE
01345 rb_profile_frame_qualified_method_name(VALUE frame)
01346 {
01347     VALUE method_name = rb_iseq_method_name(frame2iseq(frame));
01348     if (method_name != Qnil) {
01349         VALUE classpath = rb_profile_frame_classpath(frame);
01350         VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
01351 
01352         if (classpath != Qnil) {
01353             return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
01354                               classpath, singleton_p == Qtrue ? "." : "#", method_name);
01355         }
01356         else {
01357             return method_name;
01358         }
01359     }
01360     else {
01361         return Qnil;
01362     }
01363 }
01364 
01365 VALUE
01366 rb_profile_frame_full_label(VALUE frame)
01367 {
01368     VALUE label = rb_profile_frame_label(frame);
01369     VALUE base_label = rb_profile_frame_base_label(frame);
01370     VALUE qualified_method_name = rb_profile_frame_qualified_method_name(frame);
01371 
01372     if (NIL_P(qualified_method_name) || base_label == qualified_method_name) {
01373         return label;
01374     }
01375     else {
01376         long label_length = RSTRING_LEN(label);
01377         long base_label_length = RSTRING_LEN(base_label);
01378         int prefix_len = rb_long2int(label_length - base_label_length);
01379 
01380         return rb_sprintf("%.*s%"PRIsVALUE, prefix_len, RSTRING_PTR(label), qualified_method_name);
01381     }
01382 }
01383 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7