Ruby
2.0.0p247(2013-06-27revision41674)
|
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