Ruby  2.0.0p247(2013-06-27revision41674)
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 };
00116 
00117 static inline rb_backtrace_location_t *
00118 location_ptr(VALUE locobj)
00119 {
00120     struct valued_frame_info *vloc;
00121     GetCoreDataFromValue(locobj, struct valued_frame_info, vloc);
00122     return vloc->loc;
00123 }
00124 
00125 static int
00126 location_lineno(rb_backtrace_location_t *loc)
00127 {
00128     switch (loc->type) {
00129       case LOCATION_TYPE_ISEQ:
00130         loc->type = LOCATION_TYPE_ISEQ_CALCED;
00131         return (loc->body.iseq.lineno.lineno = calc_lineno(loc->body.iseq.iseq, loc->body.iseq.lineno.pc));
00132       case LOCATION_TYPE_ISEQ_CALCED:
00133         return loc->body.iseq.lineno.lineno;
00134       case LOCATION_TYPE_CFUNC:
00135         if (loc->body.cfunc.prev_loc) {
00136             return location_lineno(loc->body.cfunc.prev_loc);
00137         }
00138         return 0;
00139       default:
00140         rb_bug("location_lineno: unreachable");
00141         UNREACHABLE;
00142     }
00143 }
00144 
00145 /*
00146  * Returns the line number of this frame.
00147  *
00148  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
00149  *
00150  *      loc = c(0..1).first
00151  *      loc.lineno #=> 2
00152  */
00153 static VALUE
00154 location_lineno_m(VALUE self)
00155 {
00156     return INT2FIX(location_lineno(location_ptr(self)));
00157 }
00158 
00159 static VALUE
00160 location_label(rb_backtrace_location_t *loc)
00161 {
00162     switch (loc->type) {
00163       case LOCATION_TYPE_ISEQ:
00164       case LOCATION_TYPE_ISEQ_CALCED:
00165         return loc->body.iseq.iseq->location.label;
00166       case LOCATION_TYPE_CFUNC:
00167         return rb_id2str(loc->body.cfunc.mid);
00168       case LOCATION_TYPE_IFUNC:
00169       default:
00170         rb_bug("location_label: unreachable");
00171         UNREACHABLE;
00172     }
00173 }
00174 
00175 /*
00176  * Returns the label of this frame.
00177  *
00178  * Usually consists of method, class, module, etc names with decoration.
00179  *
00180  * Consider the following example:
00181  *
00182  *      def foo
00183  *        puts caller_locations(0).first.label
00184  *
00185  *        1.times do
00186  *          puts caller_locations(0).first.label
00187  *
00188  *          1.times do
00189  *            puts caller_locations(0).first.label
00190  *          end
00191  *
00192  *        end
00193  *      end
00194  *
00195  * The result of calling +foo+ is this:
00196  *
00197  *      label: foo
00198  *      label: block in foo
00199  *      label: block (2 levels) in foo
00200  *
00201  */
00202 static VALUE
00203 location_label_m(VALUE self)
00204 {
00205     return location_label(location_ptr(self));
00206 }
00207 
00208 static VALUE
00209 location_base_label(rb_backtrace_location_t *loc)
00210 {
00211     switch (loc->type) {
00212       case LOCATION_TYPE_ISEQ:
00213       case LOCATION_TYPE_ISEQ_CALCED:
00214         return loc->body.iseq.iseq->location.base_label;
00215       case LOCATION_TYPE_CFUNC:
00216         return rb_sym_to_s(ID2SYM(loc->body.cfunc.mid));
00217       case LOCATION_TYPE_IFUNC:
00218       default:
00219         rb_bug("location_base_label: unreachable");
00220         UNREACHABLE;
00221     }
00222 }
00223 
00224 /*
00225  * Returns the base label of this frame.
00226  *
00227  * Usually same as #label, without decoration.
00228  */
00229 static VALUE
00230 location_base_label_m(VALUE self)
00231 {
00232     return location_base_label(location_ptr(self));
00233 }
00234 
00235 static VALUE
00236 location_path(rb_backtrace_location_t *loc)
00237 {
00238     switch (loc->type) {
00239       case LOCATION_TYPE_ISEQ:
00240       case LOCATION_TYPE_ISEQ_CALCED:
00241         return loc->body.iseq.iseq->location.path;
00242       case LOCATION_TYPE_CFUNC:
00243         if (loc->body.cfunc.prev_loc) {
00244             return location_path(loc->body.cfunc.prev_loc);
00245         }
00246         return Qnil;
00247       case LOCATION_TYPE_IFUNC:
00248       default:
00249         rb_bug("location_path: unreachable");
00250         UNREACHABLE;
00251     }
00252 }
00253 
00254 /*
00255  * Returns the file name of this frame.
00256  *
00257  * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
00258  *
00259  *      loc = c(0..1).first
00260  *      loc.path #=> caller_locations.rb
00261  */
00262 static VALUE
00263 location_path_m(VALUE self)
00264 {
00265     return location_path(location_ptr(self));
00266 }
00267 
00268 static VALUE
00269 location_absolute_path(rb_backtrace_location_t *loc)
00270 {
00271     switch (loc->type) {
00272       case LOCATION_TYPE_ISEQ:
00273       case LOCATION_TYPE_ISEQ_CALCED:
00274         return loc->body.iseq.iseq->location.absolute_path;
00275       case LOCATION_TYPE_CFUNC:
00276         if (loc->body.cfunc.prev_loc) {
00277             return location_absolute_path(loc->body.cfunc.prev_loc);
00278         }
00279         return Qnil;
00280       case LOCATION_TYPE_IFUNC:
00281       default:
00282         rb_bug("location_absolute_path: unreachable");
00283         UNREACHABLE;
00284     }
00285 }
00286 
00287 /*
00288  * Returns the full file path of this frame.
00289  *
00290  * Same as #path, but includes the absolute path.
00291  */
00292 static VALUE
00293 location_absolute_path_m(VALUE self)
00294 {
00295     return location_absolute_path(location_ptr(self));
00296 }
00297 
00298 static VALUE
00299 location_format(VALUE file, int lineno, VALUE name)
00300 {
00301     if (lineno != 0) {
00302         return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:%d:in `%s'",
00303                               RSTRING_PTR(file), lineno, RSTRING_PTR(name));
00304     }
00305     else {
00306         return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:in `%s'",
00307                               RSTRING_PTR(file), RSTRING_PTR(name));
00308     }
00309 }
00310 
00311 static VALUE
00312 location_to_str(rb_backtrace_location_t *loc)
00313 {
00314     VALUE file, name;
00315     int lineno;
00316 
00317     switch (loc->type) {
00318       case LOCATION_TYPE_ISEQ:
00319         file = loc->body.iseq.iseq->location.path;
00320         name = loc->body.iseq.iseq->location.label;
00321 
00322         lineno = loc->body.iseq.lineno.lineno = calc_lineno(loc->body.iseq.iseq, loc->body.iseq.lineno.pc);
00323         loc->type = LOCATION_TYPE_ISEQ_CALCED;
00324         break;
00325       case LOCATION_TYPE_ISEQ_CALCED:
00326         file = loc->body.iseq.iseq->location.path;
00327         lineno = loc->body.iseq.lineno.lineno;
00328         name = loc->body.iseq.iseq->location.label;
00329         break;
00330       case LOCATION_TYPE_CFUNC:
00331         if (loc->body.cfunc.prev_loc) {
00332             file = loc->body.cfunc.prev_loc->body.iseq.iseq->location.path;
00333             lineno = location_lineno(loc->body.cfunc.prev_loc);
00334         }
00335         else {
00336             rb_thread_t *th = GET_THREAD();
00337             file = th->vm->progname ? th->vm->progname : ruby_engine_name;
00338             lineno = INT2FIX(0);
00339         }
00340         name = rb_id2str(loc->body.cfunc.mid);
00341         break;
00342       case LOCATION_TYPE_IFUNC:
00343       default:
00344         rb_bug("location_to_str: unreachable");
00345     }
00346 
00347     return location_format(file, lineno, name);
00348 }
00349 
00350 /*
00351  * Returns a Kernel#caller style string representing this frame.
00352  */
00353 static VALUE
00354 location_to_str_m(VALUE self)
00355 {
00356     return location_to_str(location_ptr(self));
00357 }
00358 
00359 /*
00360  * Returns the same as calling +inspect+ on the string representation of
00361  * #to_str
00362  */
00363 static VALUE
00364 location_inspect_m(VALUE self)
00365 {
00366     return rb_str_inspect(location_to_str(location_ptr(self)));
00367 }
00368 
00369 typedef struct rb_backtrace_struct {
00370     rb_backtrace_location_t *backtrace;
00371     rb_backtrace_location_t *backtrace_base;
00372     int backtrace_size;
00373     VALUE strary;
00374 } rb_backtrace_t;
00375 
00376 static void
00377 backtrace_mark(void *ptr)
00378 {
00379     if (ptr) {
00380         rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
00381         size_t i, s = bt->backtrace_size;
00382 
00383         for (i=0; i<s; i++) {
00384             location_mark_entry(&bt->backtrace[i]);
00385             rb_gc_mark(bt->strary);
00386         }
00387     }
00388 }
00389 
00390 static void
00391 backtrace_free(void *ptr)
00392 {
00393    if (ptr) {
00394        rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
00395        if (bt->backtrace) ruby_xfree(bt->backtrace_base);
00396        ruby_xfree(bt);
00397    }
00398 }
00399 
00400 static size_t
00401 backtrace_memsize(const void *ptr)
00402 {
00403     rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
00404     return sizeof(rb_backtrace_t) + sizeof(rb_backtrace_location_t) * bt->backtrace_size;
00405 }
00406 
00407 static const rb_data_type_t backtrace_data_type = {
00408     "backtrace",
00409     {backtrace_mark, backtrace_free, backtrace_memsize,},
00410 };
00411 
00412 int
00413 rb_backtrace_p(VALUE obj)
00414 {
00415     return rb_typeddata_is_kind_of(obj, &backtrace_data_type);
00416 }
00417 
00418 static VALUE
00419 backtrace_alloc(VALUE klass)
00420 {
00421     rb_backtrace_t *bt;
00422     VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
00423     return obj;
00424 }
00425 
00426 static void
00427 backtrace_each(rb_thread_t *th,
00428                void (*init)(void *arg, size_t size),
00429                void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
00430                void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
00431                void *arg)
00432 {
00433     rb_control_frame_t *last_cfp = th->cfp;
00434     rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(th);
00435     rb_control_frame_t *cfp;
00436     ptrdiff_t size, i;
00437 
00438     /*                <- start_cfp (end control frame)
00439      *  top frame (dummy)
00440      *  top frame (dummy)
00441      *  top frame     <- start_cfp
00442      *  top frame
00443      *  ...
00444      *  2nd frame     <- lev:0
00445      *  current frame <- th->cfp
00446      */
00447 
00448     start_cfp =
00449       RUBY_VM_NEXT_CONTROL_FRAME(
00450           RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
00451 
00452     if (start_cfp < last_cfp) {
00453         size = 0;
00454     }
00455     else {
00456         size = start_cfp - last_cfp + 1;
00457     }
00458 
00459     init(arg, size);
00460 
00461     /* SDR(); */
00462     for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
00463         /* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(th->stack + th->stack_size) - cfp); */
00464         if (cfp->iseq) {
00465             if (cfp->pc) {
00466                 iter_iseq(arg, cfp);
00467             }
00468         }
00469         else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
00470             ID mid = cfp->me->def ? cfp->me->def->original_id : cfp->me->called_id;
00471 
00472             iter_cfunc(arg, cfp, mid);
00473         }
00474     }
00475 }
00476 
00477 struct bt_iter_arg {
00478     rb_backtrace_t *bt;
00479     VALUE btobj;
00480     rb_backtrace_location_t *prev_loc;
00481 };
00482 
00483 static void
00484 bt_init(void *ptr, size_t size)
00485 {
00486     struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
00487     arg->btobj = backtrace_alloc(rb_cBacktrace);
00488     GetCoreDataFromValue(arg->btobj, rb_backtrace_t, arg->bt);
00489     arg->bt->backtrace_base = arg->bt->backtrace = ruby_xmalloc(sizeof(rb_backtrace_location_t) * size);
00490     arg->bt->backtrace_size = 0;
00491 }
00492 
00493 static void
00494 bt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
00495 {
00496     const rb_iseq_t *iseq = cfp->iseq;
00497     const VALUE *pc = cfp->pc;
00498     struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
00499     rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
00500     loc->type = LOCATION_TYPE_ISEQ;
00501     loc->body.iseq.iseq = iseq;
00502     loc->body.iseq.lineno.pc = pc;
00503     arg->prev_loc = loc;
00504 }
00505 
00506 static void
00507 bt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
00508 {
00509     struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
00510     rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
00511     loc->type = LOCATION_TYPE_CFUNC;
00512     loc->body.cfunc.mid = mid;
00513     loc->body.cfunc.prev_loc = arg->prev_loc;
00514 }
00515 
00516 static VALUE
00517 backtrace_object(rb_thread_t *th)
00518 {
00519     struct bt_iter_arg arg;
00520     arg.prev_loc = 0;
00521 
00522     backtrace_each(th,
00523                    bt_init,
00524                    bt_iter_iseq,
00525                    bt_iter_cfunc,
00526                    &arg);
00527 
00528     return arg.btobj;
00529 }
00530 
00531 VALUE
00532 rb_vm_backtrace_object(void)
00533 {
00534     return backtrace_object(GET_THREAD());
00535 }
00536 
00537 static VALUE
00538 backtrace_collect(rb_backtrace_t *bt, long lev, long n, VALUE (*func)(rb_backtrace_location_t *, void *arg), void *arg)
00539 {
00540     VALUE btary;
00541     int i;
00542 
00543     if (UNLIKELY(lev < 0 || n < 0)) {
00544         rb_bug("backtrace_collect: unreachable");
00545     }
00546 
00547     btary = rb_ary_new();
00548 
00549     for (i=0; i+lev<bt->backtrace_size && i<n; i++) {
00550         rb_backtrace_location_t *loc = &bt->backtrace[bt->backtrace_size - 1 - (lev+i)];
00551         rb_ary_push(btary, func(loc, arg));
00552     }
00553 
00554     return btary;
00555 }
00556 
00557 static VALUE
00558 location_to_str_dmyarg(rb_backtrace_location_t *loc, void *dmy)
00559 {
00560     return location_to_str(loc);
00561 }
00562 
00563 static VALUE
00564 backtrace_to_str_ary(VALUE self, long lev, long n)
00565 {
00566     rb_backtrace_t *bt;
00567     int size;
00568     VALUE r;
00569 
00570     GetCoreDataFromValue(self, rb_backtrace_t, bt);
00571     size = bt->backtrace_size;
00572 
00573     if (n == 0) {
00574         n = size;
00575     }
00576     if (lev > size) {
00577         return Qnil;
00578     }
00579 
00580     r = backtrace_collect(bt, lev, n, location_to_str_dmyarg, 0);
00581     RB_GC_GUARD(self);
00582     return r;
00583 }
00584 
00585 VALUE
00586 rb_backtrace_to_str_ary(VALUE self)
00587 {
00588     rb_backtrace_t *bt;
00589     GetCoreDataFromValue(self, rb_backtrace_t, bt);
00590 
00591     if (!bt->strary) {
00592         bt->strary = backtrace_to_str_ary(self, 0, bt->backtrace_size);
00593     }
00594     return bt->strary;
00595 }
00596 
00597 static VALUE
00598 location_create(rb_backtrace_location_t *srcloc, void *btobj)
00599 {
00600     VALUE obj;
00601     struct valued_frame_info *vloc;
00602     obj = TypedData_Make_Struct(rb_cBacktraceLocation, struct valued_frame_info, &location_data_type, vloc);
00603 
00604     vloc->loc = srcloc;
00605     vloc->btobj = (VALUE)btobj;
00606 
00607     return obj;
00608 }
00609 
00610 static VALUE
00611 backtrace_to_location_ary(VALUE self, long lev, long n)
00612 {
00613     rb_backtrace_t *bt;
00614     int size;
00615     VALUE r;
00616 
00617     GetCoreDataFromValue(self, rb_backtrace_t, bt);
00618     size = bt->backtrace_size;
00619 
00620     if (n == 0) {
00621         n = size;
00622     }
00623     if (lev > size) {
00624         return Qnil;
00625     }
00626 
00627     r = backtrace_collect(bt, lev, n, location_create, (void *)self);
00628     RB_GC_GUARD(self);
00629     return r;
00630 }
00631 
00632 static VALUE
00633 backtrace_dump_data(VALUE self)
00634 {
00635     VALUE str = rb_backtrace_to_str_ary(self);
00636     return str;
00637 }
00638 
00639 static VALUE
00640 backtrace_load_data(VALUE self, VALUE str)
00641 {
00642     rb_backtrace_t *bt;
00643     GetCoreDataFromValue(self, rb_backtrace_t, bt);
00644     bt->strary = str;
00645     return self;
00646 }
00647 
00648 VALUE
00649 vm_backtrace_str_ary(rb_thread_t *th, long lev, long n)
00650 {
00651     return backtrace_to_str_ary(backtrace_object(th), lev, n);
00652 }
00653 
00654 VALUE
00655 vm_backtrace_location_ary(rb_thread_t *th, long lev, long n)
00656 {
00657     return backtrace_to_location_ary(backtrace_object(th), lev, n);
00658 }
00659 
00660 /* make old style backtrace directly */
00661 
00662 struct oldbt_arg {
00663     VALUE filename;
00664     int lineno;
00665     void (*func)(void *data, VALUE file, int lineno, VALUE name);
00666     void *data; /* result */
00667 };
00668 
00669 static void
00670 oldbt_init(void *ptr, size_t dmy)
00671 {
00672     struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
00673     rb_thread_t *th = GET_THREAD();
00674 
00675     arg->filename = th->vm->progname ? th->vm->progname : ruby_engine_name;;
00676     arg->lineno = 0;
00677 }
00678 
00679 static void
00680 oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
00681 {
00682     const rb_iseq_t *iseq = cfp->iseq;
00683     const VALUE *pc = cfp->pc;
00684     struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
00685     VALUE file = arg->filename = iseq->location.path;
00686     VALUE name = iseq->location.label;
00687     int lineno = arg->lineno = calc_lineno(iseq, pc);
00688 
00689     (arg->func)(arg->data, file, lineno, name);
00690 }
00691 
00692 static void
00693 oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
00694 {
00695     struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
00696     VALUE file = arg->filename;
00697     VALUE name = rb_id2str(mid);
00698     int lineno = arg->lineno;
00699 
00700     (arg->func)(arg->data, file, lineno, name);
00701 }
00702 
00703 static void
00704 oldbt_print(void *data, VALUE file, int lineno, VALUE name)
00705 {
00706     FILE *fp = (FILE *)data;
00707 
00708     if (NIL_P(name)) {
00709         fprintf(fp, "\tfrom %s:%d:in unknown method\n",
00710                 RSTRING_PTR(file), lineno);
00711     }
00712     else {
00713         fprintf(fp, "\tfrom %s:%d:in `%s'\n",
00714                 RSTRING_PTR(file), lineno, RSTRING_PTR(name));
00715     }
00716 }
00717 
00718 static void
00719 vm_backtrace_print(FILE *fp)
00720 {
00721     struct oldbt_arg arg;
00722 
00723     arg.func = oldbt_print;
00724     arg.data = (void *)fp;
00725     backtrace_each(GET_THREAD(),
00726                    oldbt_init,
00727                    oldbt_iter_iseq,
00728                    oldbt_iter_cfunc,
00729                    &arg);
00730 }
00731 
00732 static void
00733 oldbt_bugreport(void *arg, VALUE file, int line, VALUE method)
00734 {
00735     const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
00736     if (!*(int *)arg) {
00737         fprintf(stderr, "-- Ruby level backtrace information "
00738                 "----------------------------------------\n");
00739         *(int *)arg = 1;
00740     }
00741     if (NIL_P(method)) {
00742         fprintf(stderr, "%s:%d:in unknown method\n", filename, line);
00743     }
00744     else {
00745         fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
00746     }
00747 }
00748 
00749 void
00750 rb_backtrace_print_as_bugreport(void)
00751 {
00752     struct oldbt_arg arg;
00753     int i;
00754 
00755     arg.func = oldbt_bugreport;
00756     arg.data = (int *)&i;
00757 
00758     backtrace_each(GET_THREAD(),
00759                    oldbt_init,
00760                    oldbt_iter_iseq,
00761                    oldbt_iter_cfunc,
00762                    &arg);
00763 }
00764 
00765 void
00766 rb_backtrace(void)
00767 {
00768     vm_backtrace_print(stderr);
00769 }
00770 
00771 VALUE
00772 rb_make_backtrace(void)
00773 {
00774     return vm_backtrace_str_ary(GET_THREAD(), 0, 0);
00775 }
00776 
00777 static VALUE
00778 vm_backtrace_to_ary(rb_thread_t *th, int argc, VALUE *argv, int lev_default, int lev_plus, int to_str)
00779 {
00780     VALUE level, vn;
00781     long lev, n;
00782     VALUE btval = backtrace_object(th);
00783     VALUE r;
00784     rb_backtrace_t *bt;
00785 
00786     GetCoreDataFromValue(btval, rb_backtrace_t, bt);
00787 
00788     rb_scan_args(argc, argv, "02", &level, &vn);
00789 
00790     switch (argc) {
00791       case 0:
00792         lev = lev_default + lev_plus;
00793         n = bt->backtrace_size - lev;
00794         break;
00795       case 1:
00796         {
00797             long beg, len;
00798             switch (rb_range_beg_len(level, &beg, &len, bt->backtrace_size - lev_plus, 0)) {
00799               case Qfalse:
00800                 lev = NUM2LONG(level);
00801                 if (lev < 0) {
00802                     rb_raise(rb_eArgError, "negative level (%ld)", lev);
00803                 }
00804                 lev += lev_plus;
00805                 n = bt->backtrace_size - lev;
00806                 break;
00807               case Qnil:
00808                 return Qnil;
00809               default:
00810                 lev = beg + lev_plus;
00811                 n = len;
00812                 break;
00813             }
00814             break;
00815         }
00816       case 2:
00817         lev = NUM2LONG(level);
00818         n = NUM2LONG(vn);
00819         if (lev < 0) {
00820             rb_raise(rb_eArgError, "negative level (%ld)", lev);
00821         }
00822         if (n < 0) {
00823             rb_raise(rb_eArgError, "negative size (%ld)", n);
00824         }
00825         lev += lev_plus;
00826         break;
00827       default:
00828         lev = n = 0; /* to avoid warning */
00829         break;
00830     }
00831 
00832     if (n == 0) {
00833         return rb_ary_new();
00834     }
00835 
00836     if (to_str) {
00837         r = backtrace_to_str_ary(btval, lev, n);
00838     }
00839     else {
00840         r = backtrace_to_location_ary(btval, lev, n);
00841     }
00842     RB_GC_GUARD(btval);
00843     return r;
00844 }
00845 
00846 static VALUE
00847 thread_backtrace_to_ary(int argc, VALUE *argv, VALUE thval, int to_str)
00848 {
00849     rb_thread_t *th;
00850     GetThreadPtr(thval, th);
00851 
00852     if (th->to_kill || th->status == THREAD_KILLED)
00853         return Qnil;
00854 
00855     return vm_backtrace_to_ary(th, argc, argv, 0, 0, to_str);
00856 }
00857 
00858 VALUE
00859 vm_thread_backtrace(int argc, VALUE *argv, VALUE thval)
00860 {
00861     return thread_backtrace_to_ary(argc, argv, thval, 1);
00862 }
00863 
00864 VALUE
00865 vm_thread_backtrace_locations(int argc, VALUE *argv, VALUE thval)
00866 {
00867     return thread_backtrace_to_ary(argc, argv, thval, 0);
00868 }
00869 
00870 /*
00871  *  call-seq:
00872  *     caller(start=1, length=nil)  -> array or nil
00873  *     caller(range)                -> array or nil
00874  *
00875  *  Returns the current execution stack---an array containing strings in
00876  *  the form <code>file:line</code> or <code>file:line: in
00877  *  `method'</code>.
00878  *
00879  *  The optional _start_ parameter determines the number of initial stack
00880  *  entries to omit from the top of the stack.
00881  *
00882  *  A second optional +length+ parameter can be used to limit how many entries
00883  *  are returned from the stack.
00884  *
00885  *  Returns +nil+ if _start_ is greater than the size of
00886  *  current execution stack.
00887  *
00888  *  Optionally you can pass a range, which will return an array containing the
00889  *  entries within the specified range.
00890  *
00891  *     def a(skip)
00892  *       caller(skip)
00893  *     end
00894  *     def b(skip)
00895  *       a(skip)
00896  *     end
00897  *     def c(skip)
00898  *       b(skip)
00899  *     end
00900  *     c(0)   #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"]
00901  *     c(1)   #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"]
00902  *     c(2)   #=> ["prog:8:in `c'", "prog:12:in `<main>'"]
00903  *     c(3)   #=> ["prog:13:in `<main>'"]
00904  *     c(4)   #=> []
00905  *     c(5)   #=> nil
00906  */
00907 
00908 static VALUE
00909 rb_f_caller(int argc, VALUE *argv)
00910 {
00911     return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 1);
00912 }
00913 
00914 /*
00915  *  call-seq:
00916  *     caller_locations(start=1, length=nil)    -> array or nil
00917  *     caller_locations(range)                  -> array or nil
00918  *
00919  *  Returns the current execution stack---an array containing
00920  *  backtrace location objects.
00921  *
00922  *  See Thread::Backtrace::Location for more information.
00923  *
00924  *  The optional _start_ parameter determines the number of initial stack
00925  *  entries to omit from the top of the stack.
00926  *
00927  *  A second optional +length+ parameter can be used to limit how many entries
00928  *  are returned from the stack.
00929  *
00930  *  Returns +nil+ if _start_ is greater than the size of
00931  *  current execution stack.
00932  *
00933  *  Optionally you can pass a range, which will return an array containing the
00934  *  entries within the specified range.
00935  */
00936 static VALUE
00937 rb_f_caller_locations(int argc, VALUE *argv)
00938 {
00939     return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 0);
00940 }
00941 
00942 /* called from Init_vm() in vm.c */
00943 void
00944 Init_vm_backtrace(void)
00945 {
00946     /* :nodoc: */
00947     rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
00948     rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
00949     rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
00950     rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
00951 
00952     /*
00953      *  An object representation of a stack frame, initialized by
00954      *  Kernel#caller_locations.
00955      *
00956      *  For example:
00957      *
00958      *          # caller_locations.rb
00959      *          def a(skip)
00960      *            caller_locations(skip)
00961      *          end
00962      *          def b(skip)
00963      *            a(skip)
00964      *          end
00965      *          def c(skip)
00966      *            b(skip)
00967      *          end
00968      *
00969      *          c(0..2).map do |call|
00970      *            puts call.to_s
00971      *          end
00972      *
00973      *  Running <code>ruby caller_locations.rb</code> will produce:
00974      *
00975      *          caller_locations.rb:2:in `a'
00976      *          caller_locations.rb:5:in `b'
00977      *          caller_locations.rb:8:in `c'
00978      *
00979      *  Here's another example with a slightly different result:
00980      *
00981      *          # foo.rb
00982      *          class Foo
00983      *            attr_accessor :locations
00984      *            def initialize(skip)
00985      *              @locations = caller_locations(skip)
00986      *            end
00987      *          end
00988      *
00989      *          Foo.new(0..2).locations.map do |call|
00990      *            puts call.to_s
00991      *          end
00992      *
00993      *  Now run <code>ruby foo.rb</code> and you should see:
00994      *
00995      *          init.rb:4:in `initialize'
00996      *          init.rb:8:in `new'
00997      *          init.rb:8:in `<main>'
00998      */
00999     rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
01000     rb_undef_alloc_func(rb_cBacktraceLocation);
01001     rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
01002     rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
01003     rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
01004     rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
01005     rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
01006     rb_define_method(rb_cBacktraceLocation, "absolute_path", location_absolute_path_m, 0);
01007     rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
01008     rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
01009 
01010     rb_define_global_function("caller", rb_f_caller, -1);
01011     rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
01012 }
01013 
01014 /* debugger API */
01015 
01016 #if defined __GNUC__ && __GNUC__ >= 4
01017 #pragma GCC visibility push(default)
01018 #endif
01019 
01020 #if defined __GNUC__ && __GNUC__ >= 4
01021 #pragma GCC visibility pop
01022 #endif
01023 
01024 struct rb_debug_inspector_struct {
01025     rb_thread_t *th;
01026     rb_control_frame_t *cfp;
01027     VALUE backtrace;
01028     VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
01029     long backtrace_size;
01030 };
01031 
01032 enum {
01033     CALLER_BINDING_SELF,
01034     CALLER_BINDING_CLASS,
01035     CALLER_BINDING_BINDING,
01036     CALLER_BINDING_ISEQ,
01037     CALLER_BINDING_CFP
01038 };
01039 
01040 struct collect_caller_bindings_data {
01041     VALUE ary;
01042 };
01043 
01044 static void
01045 collect_caller_bindings_init(void *arg, size_t size)
01046 {
01047     /* */
01048 }
01049 
01050 static VALUE
01051 get_klass(const rb_control_frame_t *cfp)
01052 {
01053     VALUE klass;
01054     if (rb_vm_control_frame_id_and_class(cfp, 0, &klass)) {
01055         if (RB_TYPE_P(klass, T_ICLASS)) {
01056             return RBASIC(klass)->klass;
01057         }
01058         else {
01059             return klass;
01060         }
01061     }
01062     else {
01063         return Qnil;
01064     }
01065 }
01066 
01067 static void
01068 collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
01069 {
01070     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
01071     VALUE frame = rb_ary_new2(5);
01072 
01073     rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
01074     rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
01075     rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
01076     rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? cfp->iseq->self : Qnil);
01077     rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
01078 
01079     rb_ary_push(data->ary, frame);
01080 }
01081 
01082 static void
01083 collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
01084 {
01085     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
01086     VALUE frame = rb_ary_new2(5);
01087 
01088     rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
01089     rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
01090     rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
01091     rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
01092     rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
01093 
01094     rb_ary_push(data->ary, frame);
01095 }
01096 
01097 static VALUE
01098 collect_caller_bindings(rb_thread_t *th)
01099 {
01100     struct collect_caller_bindings_data data;
01101     VALUE result;
01102     int i;
01103 
01104     data.ary = rb_ary_new();
01105 
01106     backtrace_each(th,
01107                    collect_caller_bindings_init,
01108                    collect_caller_bindings_iseq,
01109                    collect_caller_bindings_cfunc,
01110                    &data);
01111 
01112     result = rb_ary_reverse(data.ary);
01113 
01114     /* bindings should be created from top of frame */
01115     for (i=0; i<RARRAY_LEN(result); i++) {
01116         VALUE entry = rb_ary_entry(result, i);
01117         VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
01118 
01119         if (!NIL_P(cfp_val)) {
01120             rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
01121             rb_ary_store(entry, CALLER_BINDING_BINDING, rb_binding_new_with_cfp(th, cfp));
01122         }
01123     }
01124 
01125     return result;
01126 }
01127 
01128 /*
01129  * Note that the passed `rb_debug_inspector_t' will be disabled
01130  * after `rb_debug_inspector_open'.
01131  */
01132 
01133 VALUE
01134 rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
01135 {
01136     rb_debug_inspector_t dbg_context;
01137     rb_thread_t *th = GET_THREAD();
01138     int state;
01139     volatile VALUE UNINITIALIZED_VAR(result);
01140 
01141     dbg_context.th = th;
01142     dbg_context.cfp = dbg_context.th->cfp;
01143     dbg_context.backtrace = vm_backtrace_location_ary(th, 0, 0);
01144     dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
01145     dbg_context.contexts = collect_caller_bindings(th);
01146 
01147     TH_PUSH_TAG(th);
01148     if ((state = EXEC_TAG()) == 0) {
01149         result = (*func)(&dbg_context, data);
01150     }
01151     TH_POP_TAG();
01152 
01153     /* invalidate bindings? */
01154 
01155     if (state) {
01156         JUMP_TAG(state);
01157     }
01158 
01159     return result;
01160 }
01161 
01162 static VALUE
01163 frame_get(const rb_debug_inspector_t *dc, long index)
01164 {
01165     if (index < 0 || index >= dc->backtrace_size) {
01166         rb_raise(rb_eArgError, "no such frame");
01167     }
01168     return rb_ary_entry(dc->contexts, index);
01169 }
01170 
01171 VALUE
01172 rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
01173 {
01174     VALUE frame = frame_get(dc, index);
01175     return rb_ary_entry(frame, CALLER_BINDING_SELF);
01176 }
01177 
01178 VALUE
01179 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
01180 {
01181     VALUE frame = frame_get(dc, index);
01182     return rb_ary_entry(frame, CALLER_BINDING_CLASS);
01183 }
01184 
01185 VALUE
01186 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
01187 {
01188     VALUE frame = frame_get(dc, index);
01189     return rb_ary_entry(frame, CALLER_BINDING_BINDING);
01190 }
01191 
01192 VALUE
01193 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
01194 {
01195     VALUE frame = frame_get(dc, index);
01196     return rb_ary_entry(frame, CALLER_BINDING_ISEQ);
01197 }
01198 
01199 VALUE
01200 rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
01201 {
01202     return dc->backtrace;
01203 }
01204 
01205