00001
00002
00003
00004
00005
00006
00007
00008
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
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
00148
00149
00150
00151
00152
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
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
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
00227
00228
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
00257
00258
00259
00260
00261
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
00290
00291
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
00353
00354 static VALUE
00355 location_to_str_m(VALUE self)
00356 {
00357 return location_to_str(location_ptr(self));
00358 }
00359
00360
00361
00362
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
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 start_cfp =
00453 RUBY_VM_NEXT_CONTROL_FRAME(
00454 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp));
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
00466 for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
00467
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
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;
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;
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
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
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
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
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
00990 void
00991 Init_vm_backtrace(void)
00992 {
00993
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
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
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
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;
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));
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);
01134 rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil);
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
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
01173
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
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) {
01257 if (start > 0) {
01258 start--;
01259 continue;
01260 }
01261
01262
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