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 };
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
00147
00148
00149
00150
00151
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
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 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
00226
00227
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
00256
00257
00258
00259
00260
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
00289
00290
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
00352
00353 static VALUE
00354 location_to_str_m(VALUE self)
00355 {
00356 return location_to_str(location_ptr(self));
00357 }
00358
00359
00360
00361
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
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 start_cfp =
00449 RUBY_VM_NEXT_CONTROL_FRAME(
00450 RUBY_VM_NEXT_CONTROL_FRAME(start_cfp));
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
00462 for (i=0, cfp = start_cfp; i<size; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
00463
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
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;
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 if (argc == 2 && NIL_P(vn)) argc--;
00791
00792 switch (argc) {
00793 case 0:
00794 lev = lev_default + lev_plus;
00795 n = bt->backtrace_size - lev;
00796 break;
00797 case 1:
00798 {
00799 long beg, len;
00800 switch (rb_range_beg_len(level, &beg, &len, bt->backtrace_size - lev_plus, 0)) {
00801 case Qfalse:
00802 lev = NUM2LONG(level);
00803 if (lev < 0) {
00804 rb_raise(rb_eArgError, "negative level (%ld)", lev);
00805 }
00806 lev += lev_plus;
00807 n = bt->backtrace_size - lev;
00808 break;
00809 case Qnil:
00810 return Qnil;
00811 default:
00812 lev = beg + lev_plus;
00813 n = len;
00814 break;
00815 }
00816 break;
00817 }
00818 case 2:
00819 lev = NUM2LONG(level);
00820 n = NUM2LONG(vn);
00821 if (lev < 0) {
00822 rb_raise(rb_eArgError, "negative level (%ld)", lev);
00823 }
00824 if (n < 0) {
00825 rb_raise(rb_eArgError, "negative size (%ld)", n);
00826 }
00827 lev += lev_plus;
00828 break;
00829 default:
00830 lev = n = 0;
00831 break;
00832 }
00833
00834 if (n == 0) {
00835 return rb_ary_new();
00836 }
00837
00838 if (to_str) {
00839 r = backtrace_to_str_ary(btval, lev, n);
00840 }
00841 else {
00842 r = backtrace_to_location_ary(btval, lev, n);
00843 }
00844 RB_GC_GUARD(btval);
00845 return r;
00846 }
00847
00848 static VALUE
00849 thread_backtrace_to_ary(int argc, VALUE *argv, VALUE thval, int to_str)
00850 {
00851 rb_thread_t *th;
00852 GetThreadPtr(thval, th);
00853
00854 if (th->to_kill || th->status == THREAD_KILLED)
00855 return Qnil;
00856
00857 return vm_backtrace_to_ary(th, argc, argv, 0, 0, to_str);
00858 }
00859
00860 VALUE
00861 vm_thread_backtrace(int argc, VALUE *argv, VALUE thval)
00862 {
00863 return thread_backtrace_to_ary(argc, argv, thval, 1);
00864 }
00865
00866 VALUE
00867 vm_thread_backtrace_locations(int argc, VALUE *argv, VALUE thval)
00868 {
00869 return thread_backtrace_to_ary(argc, argv, thval, 0);
00870 }
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910 static VALUE
00911 rb_f_caller(int argc, VALUE *argv)
00912 {
00913 return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 1);
00914 }
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938 static VALUE
00939 rb_f_caller_locations(int argc, VALUE *argv)
00940 {
00941 return vm_backtrace_to_ary(GET_THREAD(), argc, argv, 1, 1, 0);
00942 }
00943
00944
00945 void
00946 Init_vm_backtrace(void)
00947 {
00948
00949 rb_cBacktrace = rb_define_class_under(rb_cThread, "Backtrace", rb_cObject);
00950 rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
00951 rb_undef_method(CLASS_OF(rb_cBacktrace), "new");
00952 rb_marshal_define_compat(rb_cBacktrace, rb_cArray, backtrace_dump_data, backtrace_load_data);
00953
00954
00955
00956
00957
00958
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
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001 rb_cBacktraceLocation = rb_define_class_under(rb_cBacktrace, "Location", rb_cObject);
01002 rb_undef_alloc_func(rb_cBacktraceLocation);
01003 rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
01004 rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
01005 rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
01006 rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
01007 rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
01008 rb_define_method(rb_cBacktraceLocation, "absolute_path", location_absolute_path_m, 0);
01009 rb_define_method(rb_cBacktraceLocation, "to_s", location_to_str_m, 0);
01010 rb_define_method(rb_cBacktraceLocation, "inspect", location_inspect_m, 0);
01011
01012 rb_define_global_function("caller", rb_f_caller, -1);
01013 rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
01014 }
01015
01016
01017
01018 #if defined __GNUC__ && __GNUC__ >= 4
01019 #pragma GCC visibility push(default)
01020 #endif
01021
01022 #if defined __GNUC__ && __GNUC__ >= 4
01023 #pragma GCC visibility pop
01024 #endif
01025
01026 struct rb_debug_inspector_struct {
01027 rb_thread_t *th;
01028 rb_control_frame_t *cfp;
01029 VALUE backtrace;
01030 VALUE contexts;
01031 long backtrace_size;
01032 };
01033
01034 enum {
01035 CALLER_BINDING_SELF,
01036 CALLER_BINDING_CLASS,
01037 CALLER_BINDING_BINDING,
01038 CALLER_BINDING_ISEQ,
01039 CALLER_BINDING_CFP
01040 };
01041
01042 struct collect_caller_bindings_data {
01043 VALUE ary;
01044 };
01045
01046 static void
01047 collect_caller_bindings_init(void *arg, size_t size)
01048 {
01049
01050 }
01051
01052 static VALUE
01053 get_klass(const rb_control_frame_t *cfp)
01054 {
01055 VALUE klass;
01056 if (rb_vm_control_frame_id_and_class(cfp, 0, &klass)) {
01057 if (RB_TYPE_P(klass, T_ICLASS)) {
01058 return RBASIC(klass)->klass;
01059 }
01060 else {
01061 return klass;
01062 }
01063 }
01064 else {
01065 return Qnil;
01066 }
01067 }
01068
01069 static void
01070 collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
01071 {
01072 struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
01073 VALUE frame = rb_ary_new2(5);
01074
01075 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
01076 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
01077 rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp));
01078 rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? cfp->iseq->self : Qnil);
01079 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
01080
01081 rb_ary_push(data->ary, frame);
01082 }
01083
01084 static void
01085 collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
01086 {
01087 struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
01088 VALUE frame = rb_ary_new2(5);
01089
01090 rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
01091 rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
01092 rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil);
01093 rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil);
01094 rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
01095
01096 rb_ary_push(data->ary, frame);
01097 }
01098
01099 static VALUE
01100 collect_caller_bindings(rb_thread_t *th)
01101 {
01102 struct collect_caller_bindings_data data;
01103 VALUE result;
01104 int i;
01105
01106 data.ary = rb_ary_new();
01107
01108 backtrace_each(th,
01109 collect_caller_bindings_init,
01110 collect_caller_bindings_iseq,
01111 collect_caller_bindings_cfunc,
01112 &data);
01113
01114 result = rb_ary_reverse(data.ary);
01115
01116
01117 for (i=0; i<RARRAY_LEN(result); i++) {
01118 VALUE entry = rb_ary_entry(result, i);
01119 VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
01120
01121 if (!NIL_P(cfp_val)) {
01122 rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
01123 rb_ary_store(entry, CALLER_BINDING_BINDING, rb_binding_new_with_cfp(th, cfp));
01124 }
01125 }
01126
01127 return result;
01128 }
01129
01130
01131
01132
01133
01134
01135 VALUE
01136 rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
01137 {
01138 rb_debug_inspector_t dbg_context;
01139 rb_thread_t *th = GET_THREAD();
01140 int state;
01141 volatile VALUE UNINITIALIZED_VAR(result);
01142
01143 dbg_context.th = th;
01144 dbg_context.cfp = dbg_context.th->cfp;
01145 dbg_context.backtrace = vm_backtrace_location_ary(th, 0, 0);
01146 dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
01147 dbg_context.contexts = collect_caller_bindings(th);
01148
01149 TH_PUSH_TAG(th);
01150 if ((state = EXEC_TAG()) == 0) {
01151 result = (*func)(&dbg_context, data);
01152 }
01153 TH_POP_TAG();
01154
01155
01156
01157 if (state) {
01158 JUMP_TAG(state);
01159 }
01160
01161 return result;
01162 }
01163
01164 static VALUE
01165 frame_get(const rb_debug_inspector_t *dc, long index)
01166 {
01167 if (index < 0 || index >= dc->backtrace_size) {
01168 rb_raise(rb_eArgError, "no such frame");
01169 }
01170 return rb_ary_entry(dc->contexts, index);
01171 }
01172
01173 VALUE
01174 rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
01175 {
01176 VALUE frame = frame_get(dc, index);
01177 return rb_ary_entry(frame, CALLER_BINDING_SELF);
01178 }
01179
01180 VALUE
01181 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
01182 {
01183 VALUE frame = frame_get(dc, index);
01184 return rb_ary_entry(frame, CALLER_BINDING_CLASS);
01185 }
01186
01187 VALUE
01188 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
01189 {
01190 VALUE frame = frame_get(dc, index);
01191 return rb_ary_entry(frame, CALLER_BINDING_BINDING);
01192 }
01193
01194 VALUE
01195 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
01196 {
01197 VALUE frame = frame_get(dc, index);
01198 return rb_ary_entry(frame, CALLER_BINDING_ISEQ);
01199 }
01200
01201 VALUE
01202 rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
01203 {
01204 return dc->backtrace;
01205 }
01206
01207