|
Ruby
2.0.0p481(2014-05-08revision45883)
|
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 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; /* to avoid warning */ 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 * call-seq: 00874 * caller(start=1, length=nil) -> array or nil 00875 * caller(range) -> array or nil 00876 * 00877 * Returns the current execution stack---an array containing strings in 00878 * the form <code>file:line</code> or <code>file:line: in 00879 * `method'</code>. 00880 * 00881 * The optional _start_ parameter determines the number of initial stack 00882 * entries to omit from the top of the stack. 00883 * 00884 * A second optional +length+ parameter can be used to limit how many entries 00885 * are returned from the stack. 00886 * 00887 * Returns +nil+ if _start_ is greater than the size of 00888 * current execution stack. 00889 * 00890 * Optionally you can pass a range, which will return an array containing the 00891 * entries within the specified range. 00892 * 00893 * def a(skip) 00894 * caller(skip) 00895 * end 00896 * def b(skip) 00897 * a(skip) 00898 * end 00899 * def c(skip) 00900 * b(skip) 00901 * end 00902 * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `<main>'"] 00903 * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11:in `<main>'"] 00904 * c(2) #=> ["prog:8:in `c'", "prog:12:in `<main>'"] 00905 * c(3) #=> ["prog:13:in `<main>'"] 00906 * c(4) #=> [] 00907 * c(5) #=> nil 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 * call-seq: 00918 * caller_locations(start=1, length=nil) -> array or nil 00919 * caller_locations(range) -> array or nil 00920 * 00921 * Returns the current execution stack---an array containing 00922 * backtrace location objects. 00923 * 00924 * See Thread::Backtrace::Location for more information. 00925 * 00926 * The optional _start_ parameter determines the number of initial stack 00927 * entries to omit from the top of the stack. 00928 * 00929 * A second optional +length+ parameter can be used to limit how many entries 00930 * are returned from the stack. 00931 * 00932 * Returns +nil+ if _start_ is greater than the size of 00933 * current execution stack. 00934 * 00935 * Optionally you can pass a range, which will return an array containing the 00936 * entries within the specified range. 00937 */ 00938 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 /* called from Init_vm() in vm.c */ 00945 void 00946 Init_vm_backtrace(void) 00947 { 00948 /* :nodoc: */ 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 * An object representation of a stack frame, initialized by 00956 * Kernel#caller_locations. 00957 * 00958 * For example: 00959 * 00960 * # caller_locations.rb 00961 * def a(skip) 00962 * caller_locations(skip) 00963 * end 00964 * def b(skip) 00965 * a(skip) 00966 * end 00967 * def c(skip) 00968 * b(skip) 00969 * end 00970 * 00971 * c(0..2).map do |call| 00972 * puts call.to_s 00973 * end 00974 * 00975 * Running <code>ruby caller_locations.rb</code> will produce: 00976 * 00977 * caller_locations.rb:2:in `a' 00978 * caller_locations.rb:5:in `b' 00979 * caller_locations.rb:8:in `c' 00980 * 00981 * Here's another example with a slightly different result: 00982 * 00983 * # foo.rb 00984 * class Foo 00985 * attr_accessor :locations 00986 * def initialize(skip) 00987 * @locations = caller_locations(skip) 00988 * end 00989 * end 00990 * 00991 * Foo.new(0..2).locations.map do |call| 00992 * puts call.to_s 00993 * end 00994 * 00995 * Now run <code>ruby foo.rb</code> and you should see: 00996 * 00997 * init.rb:4:in `initialize' 00998 * init.rb:8:in `new' 00999 * init.rb:8:in `<main>' 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 /* debugger API */ 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; /* [[klass, binding, iseq, cfp], ...] */ 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)); /* create later */ 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); /* not available */ 01093 rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */ 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 /* bindings should be created from top of frame */ 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 * Note that the passed `rb_debug_inspector_t' will be disabled 01132 * after `rb_debug_inspector_open'. 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 /* invalidate bindings? */ 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
1.7.6.1