00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "ruby/ruby.h"
00025 #include "ruby/debug.h"
00026 #include "ruby/encoding.h"
00027
00028 #include "internal.h"
00029 #include "vm_core.h"
00030 #include "eval_intern.h"
00031
00032
00033
00034 typedef struct rb_event_hook_struct {
00035 rb_event_hook_flag_t hook_flags;
00036 rb_event_flag_t events;
00037 rb_event_hook_func_t func;
00038 VALUE data;
00039 struct rb_event_hook_struct *next;
00040 } rb_event_hook_t;
00041
00042 typedef void (*rb_event_hook_raw_arg_func_t)(VALUE data, const rb_trace_arg_t *arg);
00043
00044 #define MAX_EVENT_NUM 32
00045
00046 static int ruby_event_flag_count[MAX_EVENT_NUM] = {0};
00047
00048
00049
00050 void
00051 vm_trace_mark_event_hooks(rb_hook_list_t *hooks)
00052 {
00053 rb_event_hook_t *hook = hooks->hooks;
00054
00055 while (hook) {
00056 rb_gc_mark(hook->data);
00057 hook = hook->next;
00058 }
00059 }
00060
00061
00062
00063 static void
00064 recalc_add_ruby_vm_event_flags(rb_event_flag_t events)
00065 {
00066 int i;
00067 ruby_vm_event_flags = 0;
00068
00069 for (i=0; i<MAX_EVENT_NUM; i++) {
00070 if (events & (1 << i)) {
00071 ruby_event_flag_count[i]++;
00072 }
00073 ruby_vm_event_flags |= ruby_event_flag_count[i] ? (1<<i) : 0;
00074 }
00075 }
00076
00077 static void
00078 recalc_remove_ruby_vm_event_flags(rb_event_flag_t events)
00079 {
00080 int i;
00081 ruby_vm_event_flags = 0;
00082
00083 for (i=0; i<MAX_EVENT_NUM; i++) {
00084 if (events & (1 << i)) {
00085 ruby_event_flag_count[i]--;
00086 }
00087 ruby_vm_event_flags |= ruby_event_flag_count[i] ? (1<<i) : 0;
00088 }
00089 }
00090
00091
00092
00093 static rb_thread_t *
00094 thval2thread_t(VALUE thval)
00095 {
00096 rb_thread_t *th;
00097 GetThreadPtr(thval, th);
00098 return th;
00099 }
00100
00101 static rb_event_hook_t *
00102 alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
00103 {
00104 rb_event_hook_t *hook = ALLOC(rb_event_hook_t);
00105 hook->hook_flags = hook_flags;
00106 hook->events = events;
00107 hook->func = func;
00108 hook->data = data;
00109 return hook;
00110 }
00111
00112 static void
00113 connect_event_hook(rb_hook_list_t *list, rb_event_hook_t *hook)
00114 {
00115 hook->next = list->hooks;
00116 list->hooks = hook;
00117 recalc_add_ruby_vm_event_flags(hook->events);
00118 list->events |= hook->events;
00119 }
00120
00121 static void
00122 rb_threadptr_add_event_hook(rb_thread_t *th, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
00123 {
00124 rb_event_hook_t *hook = alloc_event_hook(func, events, data, hook_flags);
00125 connect_event_hook(&th->event_hooks, hook);
00126 }
00127
00128 void
00129 rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
00130 {
00131 rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data, RUBY_EVENT_HOOK_FLAG_SAFE);
00132 }
00133
00134 void
00135 rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
00136 {
00137 rb_event_hook_t *hook = alloc_event_hook(func, events, data, RUBY_EVENT_HOOK_FLAG_SAFE);
00138 connect_event_hook(&GET_VM()->event_hooks, hook);
00139 }
00140
00141 void
00142 rb_thread_add_event_hook2(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
00143 {
00144 rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data, hook_flags);
00145 }
00146
00147 void
00148 rb_add_event_hook2(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
00149 {
00150 rb_event_hook_t *hook = alloc_event_hook(func, events, data, hook_flags);
00151 connect_event_hook(&GET_VM()->event_hooks, hook);
00152 }
00153
00154
00155 static int
00156 remove_event_hook(rb_hook_list_t *list, rb_event_hook_func_t func, VALUE data)
00157 {
00158 int ret = 0;
00159 rb_event_hook_t *hook = list->hooks;
00160
00161 while (hook) {
00162 if (func == 0 || hook->func == func) {
00163 if (data == Qundef || hook->data == data) {
00164 hook->hook_flags |= RUBY_EVENT_HOOK_FLAG_DELETED;
00165 ret+=1;
00166 list->need_clean++;
00167 }
00168 }
00169 hook = hook->next;
00170 }
00171
00172 return ret;
00173 }
00174
00175 static int
00176 rb_threadptr_remove_event_hook(rb_thread_t *th, rb_event_hook_func_t func, VALUE data)
00177 {
00178 return remove_event_hook(&th->event_hooks, func, data);
00179 }
00180
00181 int
00182 rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func)
00183 {
00184 return rb_threadptr_remove_event_hook(thval2thread_t(thval), func, Qundef);
00185 }
00186
00187 int
00188 rb_thread_remove_event_hook_with_data(VALUE thval, rb_event_hook_func_t func, VALUE data)
00189 {
00190 return rb_threadptr_remove_event_hook(thval2thread_t(thval), func, data);
00191 }
00192
00193 int
00194 rb_remove_event_hook(rb_event_hook_func_t func)
00195 {
00196 return remove_event_hook(&GET_VM()->event_hooks, func, Qundef);
00197 }
00198
00199 int
00200 rb_remove_event_hook_with_data(rb_event_hook_func_t func, VALUE data)
00201 {
00202 return remove_event_hook(&GET_VM()->event_hooks, func, data);
00203 }
00204
00205 static int
00206 clear_trace_func_i(st_data_t key, st_data_t val, st_data_t flag)
00207 {
00208 rb_thread_t *th;
00209 GetThreadPtr((VALUE)key, th);
00210 rb_threadptr_remove_event_hook(th, 0, Qundef);
00211 return ST_CONTINUE;
00212 }
00213
00214 void
00215 rb_clear_trace_func(void)
00216 {
00217 st_foreach(GET_VM()->living_threads, clear_trace_func_i, (st_data_t) 0);
00218 rb_remove_event_hook(0);
00219 }
00220
00221
00222
00223 static void
00224 clean_hooks(rb_hook_list_t *list)
00225 {
00226 rb_event_hook_t *hook, **nextp = &list->hooks;
00227
00228 list->events = 0;
00229 list->need_clean = 0;
00230
00231 while ((hook = *nextp) != 0) {
00232 if (hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED) {
00233 *nextp = hook->next;
00234 recalc_remove_ruby_vm_event_flags(hook->events);
00235 xfree(hook);
00236 }
00237 else {
00238 list->events |= hook->events;
00239 nextp = &hook->next;
00240 }
00241 }
00242 }
00243
00244 static int
00245 exec_hooks(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg, int can_clean_hooks)
00246 {
00247 int state;
00248 volatile int raised;
00249
00250 if (UNLIKELY(list->need_clean > 0) && can_clean_hooks) {
00251 clean_hooks(list);
00252 }
00253
00254 raised = rb_threadptr_reset_raised(th);
00255
00256
00257
00258 TH_PUSH_TAG(th);
00259 if ((state = TH_EXEC_TAG()) == 0) {
00260 rb_event_hook_t *hook;
00261
00262 for (hook = list->hooks; hook; hook = hook->next) {
00263 if (LIKELY(!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED)) && (trace_arg->event & hook->events)) {
00264 if (!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_RAW_ARG)) {
00265 (*hook->func)(trace_arg->event, hook->data, trace_arg->self, trace_arg->id, trace_arg->klass);
00266 }
00267 else {
00268 (*((rb_event_hook_raw_arg_func_t)hook->func))(hook->data, trace_arg);
00269 }
00270 }
00271 }
00272 }
00273 TH_POP_TAG();
00274
00275 if (raised) {
00276 rb_threadptr_set_raised(th);
00277 }
00278
00279 return state;
00280 }
00281
00282 static void
00283 rb_threadptr_exec_event_hooks_orig(rb_trace_arg_t *trace_arg, int pop_p)
00284 {
00285 rb_thread_t *th = trace_arg->th;
00286 if (th->trace_arg == 0 &&
00287 trace_arg->self != rb_mRubyVMFrozenCore ) {
00288 const int vm_tracing = th->vm->trace_running;
00289 const VALUE errinfo = th->errinfo;
00290 const int outer_state = th->state;
00291 int state = 0;
00292 th->state = 0;
00293 th->errinfo = Qnil;
00294
00295 th->vm->trace_running++;
00296 th->trace_arg = trace_arg;
00297 {
00298 rb_hook_list_t *list;
00299
00300
00301 list = &th->event_hooks;
00302 if (list->events & trace_arg->event) {
00303 state = exec_hooks(th, list, trace_arg, TRUE);
00304 if (state) goto terminate;
00305 }
00306
00307
00308 list = &th->vm->event_hooks;
00309 if (list->events & trace_arg->event) {
00310 state = exec_hooks(th, list, trace_arg, !vm_tracing);
00311 if (state) goto terminate;
00312 }
00313 th->errinfo = errinfo;
00314 }
00315 terminate:
00316 th->trace_arg = 0;
00317 th->vm->trace_running--;
00318
00319 if (state) {
00320 if (pop_p) {
00321 if (VM_FRAME_TYPE_FINISH_P(th->cfp)) {
00322 th->tag = th->tag->prev;
00323 }
00324 th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
00325 }
00326 TH_JUMP_TAG(th, state);
00327 }
00328 th->state = outer_state;
00329 }
00330 }
00331
00332 void
00333 rb_threadptr_exec_event_hooks_and_pop_frame(rb_trace_arg_t *trace_arg)
00334 {
00335 rb_threadptr_exec_event_hooks_orig(trace_arg, 1);
00336 }
00337
00338 void
00339 rb_threadptr_exec_event_hooks(rb_trace_arg_t *trace_arg)
00340 {
00341 rb_threadptr_exec_event_hooks_orig(trace_arg, 0);
00342 }
00343
00344 VALUE
00345 rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg)
00346 {
00347 volatile int raised;
00348 volatile int outer_state;
00349 VALUE result = Qnil;
00350 rb_thread_t *th = GET_THREAD();
00351 int state;
00352 const int tracing = th->trace_arg ? 1 : 0;
00353 rb_trace_arg_t dummy_trace_arg;
00354
00355 if (!tracing) th->vm->trace_running++;
00356 if (!th->trace_arg) th->trace_arg = &dummy_trace_arg;
00357
00358 raised = rb_threadptr_reset_raised(th);
00359 outer_state = th->state;
00360 th->state = 0;
00361
00362 TH_PUSH_TAG(th);
00363 if ((state = TH_EXEC_TAG()) == 0) {
00364 result = (*func)(arg);
00365 }
00366 TH_POP_TAG();
00367
00368 if (raised) {
00369 rb_threadptr_set_raised(th);
00370 }
00371
00372 if (th->trace_arg == &dummy_trace_arg) th->trace_arg = 0;
00373 if (!tracing) th->vm->trace_running--;
00374
00375 if (state) {
00376 JUMP_TAG(state);
00377 }
00378
00379 th->state = outer_state;
00380 return result;
00381 }
00382
00383 static void call_trace_func(rb_event_flag_t, VALUE data, VALUE self, ID id, VALUE klass);
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 static VALUE
00445 set_trace_func(VALUE obj, VALUE trace)
00446 {
00447 rb_secure(4);
00448
00449 rb_remove_event_hook(call_trace_func);
00450
00451 if (NIL_P(trace)) {
00452 return Qnil;
00453 }
00454
00455 if (!rb_obj_is_proc(trace)) {
00456 rb_raise(rb_eTypeError, "trace_func needs to be Proc");
00457 }
00458
00459 rb_add_event_hook(call_trace_func, RUBY_EVENT_ALL, trace);
00460 return trace;
00461 }
00462
00463 static void
00464 thread_add_trace_func(rb_thread_t *th, VALUE trace)
00465 {
00466 if (!rb_obj_is_proc(trace)) {
00467 rb_raise(rb_eTypeError, "trace_func needs to be Proc");
00468 }
00469
00470 rb_threadptr_add_event_hook(th, call_trace_func, RUBY_EVENT_ALL, trace, RUBY_EVENT_HOOK_FLAG_SAFE);
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 static VALUE
00482 thread_add_trace_func_m(VALUE obj, VALUE trace)
00483 {
00484 rb_thread_t *th;
00485
00486 rb_secure(4);
00487 GetThreadPtr(obj, th);
00488 thread_add_trace_func(th, trace);
00489 return trace;
00490 }
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502 static VALUE
00503 thread_set_trace_func_m(VALUE obj, VALUE trace)
00504 {
00505 rb_thread_t *th;
00506
00507 rb_secure(4);
00508 GetThreadPtr(obj, th);
00509 rb_threadptr_remove_event_hook(th, call_trace_func, Qundef);
00510
00511 if (NIL_P(trace)) {
00512 return Qnil;
00513 }
00514
00515 thread_add_trace_func(th, trace);
00516 return trace;
00517 }
00518
00519 static const char *
00520 get_event_name(rb_event_flag_t event)
00521 {
00522 switch (event) {
00523 case RUBY_EVENT_LINE: return "line";
00524 case RUBY_EVENT_CLASS: return "class";
00525 case RUBY_EVENT_END: return "end";
00526 case RUBY_EVENT_CALL: return "call";
00527 case RUBY_EVENT_RETURN: return "return";
00528 case RUBY_EVENT_C_CALL: return "c-call";
00529 case RUBY_EVENT_C_RETURN: return "c-return";
00530 case RUBY_EVENT_RAISE: return "raise";
00531 default:
00532 return "unknown";
00533 }
00534 }
00535
00536 static ID
00537 get_event_id(rb_event_flag_t event)
00538 {
00539 ID id;
00540
00541 switch (event) {
00542 #define C(name, NAME) case RUBY_EVENT_##NAME: CONST_ID(id, #name); return id;
00543 C(line, LINE);
00544 C(class, CLASS);
00545 C(end, END);
00546 C(call, CALL);
00547 C(return, RETURN);
00548 C(c_call, C_CALL);
00549 C(c_return, C_RETURN);
00550 C(raise, RAISE);
00551 C(b_call, B_CALL);
00552 C(b_return, B_RETURN);
00553 C(thread_begin, THREAD_BEGIN);
00554 C(thread_end, THREAD_END);
00555 C(specified_line, SPECIFIED_LINE);
00556 case RUBY_EVENT_LINE | RUBY_EVENT_SPECIFIED_LINE: CONST_ID(id, "line"); return id;
00557 #undef C
00558 default:
00559 return 0;
00560 }
00561 }
00562
00563 static void
00564 call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
00565 {
00566 const char *srcfile = rb_sourcefile();
00567 VALUE eventname = rb_str_new2(get_event_name(event));
00568 VALUE filename = srcfile ? rb_str_new2(srcfile) : Qnil;
00569 VALUE argv[6];
00570 int line = rb_sourceline();
00571 rb_thread_t *th = GET_THREAD();
00572
00573 if (!klass) {
00574 rb_thread_method_id_and_class(th, &id, &klass);
00575 }
00576
00577 if (klass) {
00578 if (RB_TYPE_P(klass, T_ICLASS)) {
00579 klass = RBASIC(klass)->klass;
00580 }
00581 else if (FL_TEST(klass, FL_SINGLETON)) {
00582 klass = rb_iv_get(klass, "__attached__");
00583 }
00584 }
00585
00586 argv[0] = eventname;
00587 argv[1] = filename;
00588 argv[2] = INT2FIX(line);
00589 argv[3] = id ? ID2SYM(id) : Qnil;
00590 argv[4] = (self && srcfile) ? rb_binding_new() : Qnil;
00591 argv[5] = klass ? klass : Qnil;
00592
00593 rb_proc_call_with_block(proc, 6, argv, Qnil);
00594 }
00595
00596
00597
00598 static VALUE rb_cTracePoint;
00599
00600 typedef struct rb_tp_struct {
00601 rb_event_flag_t events;
00602 rb_thread_t *target_th;
00603 void (*func)(VALUE tpval, void *data);
00604 void *data;
00605 VALUE proc;
00606 int tracing;
00607 VALUE self;
00608 } rb_tp_t;
00609
00610 static void
00611 tp_mark(void *ptr)
00612 {
00613 if (ptr) {
00614 rb_tp_t *tp = (rb_tp_t *)ptr;
00615 rb_gc_mark(tp->proc);
00616 if (tp->target_th) rb_gc_mark(tp->target_th->self);
00617 }
00618 }
00619
00620 static void
00621 tp_free(void *ptr)
00622 {
00623
00624 }
00625
00626 static size_t
00627 tp_memsize(const void *ptr)
00628 {
00629 return sizeof(rb_tp_t);
00630 }
00631
00632 static const rb_data_type_t tp_data_type = {
00633 "tracepoint",
00634 {tp_mark, tp_free, tp_memsize,},
00635 };
00636
00637 static VALUE
00638 tp_alloc(VALUE klass)
00639 {
00640 rb_tp_t *tp;
00641 return TypedData_Make_Struct(klass, rb_tp_t, &tp_data_type, tp);
00642 }
00643
00644 static rb_event_flag_t
00645 symbol2event_flag(VALUE v)
00646 {
00647 static ID id;
00648 VALUE sym = rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym");
00649
00650 #define C(name, NAME) CONST_ID(id, #name); if (sym == ID2SYM(id)) return RUBY_EVENT_##NAME
00651 C(line, LINE);
00652 C(class, CLASS);
00653 C(end, END);
00654 C(call, CALL);
00655 C(return, RETURN);
00656 C(c_call, C_CALL);
00657 C(c_return, C_RETURN);
00658 C(raise, RAISE);
00659 C(b_call, B_CALL);
00660 C(b_return, B_RETURN);
00661 C(thread_begin, THREAD_BEGIN);
00662 C(thread_end, THREAD_END);
00663 C(specified_line, SPECIFIED_LINE);
00664 #undef C
00665 rb_raise(rb_eArgError, "unknown event: %s", rb_id2name(SYM2ID(sym)));
00666 }
00667
00668 static rb_tp_t *
00669 tpptr(VALUE tpval)
00670 {
00671 rb_tp_t *tp;
00672 TypedData_Get_Struct(tpval, rb_tp_t, &tp_data_type, tp);
00673 return tp;
00674 }
00675
00676 static rb_trace_arg_t *
00677 get_trace_arg(void)
00678 {
00679 rb_trace_arg_t *trace_arg = GET_THREAD()->trace_arg;
00680 if (trace_arg == 0) {
00681 rb_raise(rb_eRuntimeError, "access from outside");
00682 }
00683 return trace_arg;
00684 }
00685
00686 struct rb_trace_arg_struct *
00687 rb_tracearg_from_tracepoint(VALUE tpval)
00688 {
00689 return get_trace_arg();
00690 }
00691
00692 VALUE
00693 rb_tracearg_event(rb_trace_arg_t *trace_arg)
00694 {
00695 return ID2SYM(get_event_id(trace_arg->event));
00696 }
00697
00698 static void
00699 fill_path_and_lineno(rb_trace_arg_t *trace_arg)
00700 {
00701 if (trace_arg->path == Qundef) {
00702 rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(trace_arg->th, trace_arg->cfp);
00703
00704 if (cfp) {
00705 trace_arg->path = cfp->iseq->location.path;
00706 trace_arg->lineno = rb_vm_get_sourceline(cfp);
00707 }
00708 else {
00709 trace_arg->path = Qnil;
00710 trace_arg->lineno = 0;
00711 }
00712 }
00713 }
00714
00715 VALUE
00716 rb_tracearg_lineno(rb_trace_arg_t *trace_arg)
00717 {
00718 fill_path_and_lineno(trace_arg);
00719 return INT2FIX(trace_arg->lineno);
00720 }
00721 VALUE
00722 rb_tracearg_path(rb_trace_arg_t *trace_arg)
00723 {
00724 fill_path_and_lineno(trace_arg);
00725 return trace_arg->path;
00726 }
00727
00728 static void
00729 fill_id_and_klass(rb_trace_arg_t *trace_arg)
00730 {
00731 if (!trace_arg->klass_solved) {
00732 if (!trace_arg->klass) {
00733 rb_vm_control_frame_id_and_class(trace_arg->cfp, &trace_arg->id, &trace_arg->klass);
00734 }
00735
00736 if (trace_arg->klass) {
00737 if (RB_TYPE_P(trace_arg->klass, T_ICLASS)) {
00738 trace_arg->klass = RBASIC(trace_arg->klass)->klass;
00739 }
00740 }
00741 else {
00742 trace_arg->klass = Qnil;
00743 }
00744
00745 trace_arg->klass_solved = 1;
00746 }
00747 }
00748
00749 VALUE
00750 rb_tracearg_method_id(rb_trace_arg_t *trace_arg)
00751 {
00752 fill_id_and_klass(trace_arg);
00753 return trace_arg->id ? ID2SYM(trace_arg->id) : Qnil;
00754 }
00755
00756 VALUE
00757 rb_tracearg_defined_class(rb_trace_arg_t *trace_arg)
00758 {
00759 fill_id_and_klass(trace_arg);
00760 return trace_arg->klass;
00761 }
00762
00763 VALUE
00764 rb_tracearg_binding(rb_trace_arg_t *trace_arg)
00765 {
00766 rb_control_frame_t *cfp;
00767 cfp = rb_vm_get_binding_creatable_next_cfp(trace_arg->th, trace_arg->cfp);
00768
00769 if (cfp) {
00770 return rb_binding_new_with_cfp(trace_arg->th, cfp);
00771 }
00772 else {
00773 return Qnil;
00774 }
00775 }
00776
00777 VALUE
00778 rb_tracearg_self(rb_trace_arg_t *trace_arg)
00779 {
00780 return trace_arg->self;
00781 }
00782
00783 VALUE
00784 rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
00785 {
00786 if (trace_arg->event & (RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN | RUBY_EVENT_B_RETURN)) {
00787
00788 }
00789 else {
00790 rb_raise(rb_eRuntimeError, "not supported by this event");
00791 }
00792 if (trace_arg->data == Qundef) {
00793 rb_bug("tp_attr_return_value_m: unreachable");
00794 }
00795 return trace_arg->data;
00796 }
00797
00798 VALUE
00799 rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg)
00800 {
00801 if (trace_arg->event & (RUBY_EVENT_RAISE)) {
00802
00803 }
00804 else {
00805 rb_raise(rb_eRuntimeError, "not supported by this event");
00806 }
00807 if (trace_arg->data == Qundef) {
00808 rb_bug("tp_attr_raised_exception_m: unreachable");
00809 }
00810 return trace_arg->data;
00811 }
00812
00813
00814
00815
00816
00817
00818 static VALUE
00819 tracepoint_attr_event(VALUE tpval)
00820 {
00821 return rb_tracearg_event(get_trace_arg());
00822 }
00823
00824
00825
00826
00827 static VALUE
00828 tracepoint_attr_lineno(VALUE tpval)
00829 {
00830 return rb_tracearg_lineno(get_trace_arg());
00831 }
00832
00833
00834
00835
00836 static VALUE
00837 tracepoint_attr_path(VALUE tpval)
00838 {
00839 return rb_tracearg_path(get_trace_arg());
00840 }
00841
00842
00843
00844
00845 static VALUE
00846 tracepoint_attr_method_id(VALUE tpval)
00847 {
00848 return rb_tracearg_method_id(get_trace_arg());
00849 }
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885 static VALUE
00886 tracepoint_attr_defined_class(VALUE tpval)
00887 {
00888 return rb_tracearg_defined_class(get_trace_arg());
00889 }
00890
00891
00892
00893
00894 static VALUE
00895 tracepoint_attr_binding(VALUE tpval)
00896 {
00897 return rb_tracearg_binding(get_trace_arg());
00898 }
00899
00900
00901
00902
00903
00904
00905
00906 static VALUE
00907 tracepoint_attr_self(VALUE tpval)
00908 {
00909 return rb_tracearg_self(get_trace_arg());
00910 }
00911
00912
00913
00914
00915 static VALUE
00916 tracepoint_attr_return_value(VALUE tpval)
00917 {
00918 return rb_tracearg_return_value(get_trace_arg());
00919 }
00920
00921
00922
00923
00924 static VALUE
00925 tracepoint_attr_raised_exception(VALUE tpval)
00926 {
00927 return rb_tracearg_raised_exception(get_trace_arg());
00928 }
00929
00930 static void
00931 tp_call_trace(VALUE tpval, rb_trace_arg_t *trace_arg)
00932 {
00933 rb_tp_t *tp = tpptr(tpval);
00934
00935 if (tp->func) {
00936 (*tp->func)(tpval, tp->data);
00937 }
00938 else {
00939 rb_proc_call_with_block((VALUE)tp->proc, 1, &tpval, Qnil);
00940 }
00941 }
00942
00943 VALUE
00944 rb_tracepoint_enable(VALUE tpval)
00945 {
00946 rb_tp_t *tp;
00947
00948 rb_secure(4);
00949 tp = tpptr(tpval);
00950
00951 if (tp->target_th) {
00952 rb_thread_add_event_hook2(tp->target_th->self, (rb_event_hook_func_t)tp_call_trace, tp->events, tpval,
00953 RUBY_EVENT_HOOK_FLAG_SAFE | RUBY_EVENT_HOOK_FLAG_RAW_ARG);
00954 }
00955 else {
00956 rb_add_event_hook2((rb_event_hook_func_t)tp_call_trace, tp->events, tpval,
00957 RUBY_EVENT_HOOK_FLAG_SAFE | RUBY_EVENT_HOOK_FLAG_RAW_ARG);
00958 }
00959 tp->tracing = 1;
00960 return Qundef;
00961 }
00962
00963 VALUE
00964 rb_tracepoint_disable(VALUE tpval)
00965 {
00966 rb_tp_t *tp;
00967
00968 rb_secure(4);
00969 tp = tpptr(tpval);
00970
00971 if (tp->target_th) {
00972 rb_thread_remove_event_hook_with_data(tp->target_th->self, (rb_event_hook_func_t)tp_call_trace, tpval);
00973 }
00974 else {
00975 rb_remove_event_hook_with_data((rb_event_hook_func_t)tp_call_trace, tpval);
00976 }
00977 tp->tracing = 0;
00978 return Qundef;
00979 }
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018 static VALUE
01019 tracepoint_enable_m(VALUE tpval)
01020 {
01021 rb_tp_t *tp = tpptr(tpval);
01022 int previous_tracing = tp->tracing;
01023 rb_tracepoint_enable(tpval);
01024
01025 if (rb_block_given_p()) {
01026 return rb_ensure(rb_yield, Qnil,
01027 previous_tracing ? rb_tracepoint_enable : rb_tracepoint_disable,
01028 tpval);
01029 }
01030 else {
01031 return previous_tracing ? Qtrue : Qfalse;
01032 }
01033 }
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069 static VALUE
01070 tracepoint_disable_m(VALUE tpval)
01071 {
01072 rb_tp_t *tp = tpptr(tpval);
01073 int previous_tracing = tp->tracing;
01074 rb_tracepoint_disable(tpval);
01075
01076 if (rb_block_given_p()) {
01077 return rb_ensure(rb_yield, Qnil,
01078 previous_tracing ? rb_tracepoint_enable : rb_tracepoint_disable,
01079 tpval);
01080 }
01081 else {
01082 return previous_tracing ? Qtrue : Qfalse;
01083 }
01084 }
01085
01086
01087
01088
01089
01090
01091
01092 VALUE
01093 rb_tracepoint_enabled_p(VALUE tpval)
01094 {
01095 rb_tp_t *tp = tpptr(tpval);
01096 return tp->tracing ? Qtrue : Qfalse;
01097 }
01098
01099 static VALUE
01100 tracepoint_new(VALUE klass, rb_thread_t *target_th, rb_event_flag_t events, void (func)(VALUE, void*), void *data, VALUE proc)
01101 {
01102 VALUE tpval = tp_alloc(klass);
01103 rb_tp_t *tp;
01104 TypedData_Get_Struct(tpval, rb_tp_t, &tp_data_type, tp);
01105
01106 tp->proc = proc;
01107 tp->func = func;
01108 tp->data = data;
01109 tp->events = events;
01110 tp->self = tpval;
01111
01112 return tpval;
01113 }
01114
01115 VALUE
01116 rb_tracepoint_new(VALUE target_thval, rb_event_flag_t events, void (*func)(VALUE, void *), void *data)
01117 {
01118 rb_thread_t *target_th = 0;
01119 if (RTEST(target_thval)) {
01120 GetThreadPtr(target_thval, target_th);
01121
01122
01123
01124 }
01125 return tracepoint_new(rb_cTracePoint, target_th, events, func, data, Qundef);
01126 }
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175 static VALUE
01176 tracepoint_new_s(int argc, VALUE *argv, VALUE self)
01177 {
01178 rb_event_flag_t events = 0;
01179 int i;
01180
01181 if (argc > 0) {
01182 for (i=0; i<argc; i++) {
01183 events |= symbol2event_flag(argv[i]);
01184 }
01185 }
01186 else {
01187 events = RUBY_EVENT_TRACEPOINT_ALL;
01188 }
01189
01190 if (!rb_block_given_p()) {
01191 rb_raise(rb_eThreadError, "must be called with a block");
01192 }
01193
01194 return tracepoint_new(self, 0, events, 0, 0, rb_block_proc());
01195 }
01196
01197 static VALUE
01198 tracepoint_trace_s(int argc, VALUE *argv, VALUE self)
01199 {
01200 VALUE trace = tracepoint_new_s(argc, argv, self);
01201 rb_tracepoint_enable(trace);
01202 return trace;
01203 }
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213 static VALUE
01214 tracepoint_inspect(VALUE self)
01215 {
01216 rb_tp_t *tp = tpptr(self);
01217 rb_trace_arg_t *trace_arg = GET_THREAD()->trace_arg;
01218
01219 if (trace_arg) {
01220 switch (trace_arg->event) {
01221 case RUBY_EVENT_LINE:
01222 case RUBY_EVENT_SPECIFIED_LINE:
01223 {
01224 VALUE sym = rb_tracearg_method_id(trace_arg);
01225 if (NIL_P(sym))
01226 goto default_inspect;
01227 return rb_sprintf("#<TracePoint:%"PRIsVALUE"@%"PRIsVALUE":%d in `%"PRIsVALUE"'>",
01228 rb_tracearg_event(trace_arg),
01229 rb_tracearg_path(trace_arg),
01230 FIX2INT(rb_tracearg_lineno(trace_arg)),
01231 sym);
01232 }
01233 case RUBY_EVENT_CALL:
01234 case RUBY_EVENT_C_CALL:
01235 case RUBY_EVENT_RETURN:
01236 case RUBY_EVENT_C_RETURN:
01237 return rb_sprintf("#<TracePoint:%"PRIsVALUE" `%"PRIsVALUE"'@%"PRIsVALUE":%d>",
01238 rb_tracearg_event(trace_arg),
01239 rb_tracearg_method_id(trace_arg),
01240 rb_tracearg_path(trace_arg),
01241 FIX2INT(rb_tracearg_lineno(trace_arg)));
01242 case RUBY_EVENT_THREAD_BEGIN:
01243 case RUBY_EVENT_THREAD_END:
01244 return rb_sprintf("#<TracePoint:%"PRIsVALUE" %"PRIsVALUE">",
01245 rb_tracearg_event(trace_arg),
01246 rb_tracearg_self(trace_arg));
01247 default:
01248 default_inspect:
01249 return rb_sprintf("#<TracePoint:%"PRIsVALUE"@%"PRIsVALUE":%d>",
01250 rb_tracearg_event(trace_arg),
01251 rb_tracearg_path(trace_arg),
01252 FIX2INT(rb_tracearg_lineno(trace_arg)));
01253 }
01254 }
01255 else {
01256 return rb_sprintf("#<TracePoint:%s>", tp->tracing ? "enabled" : "disabled");
01257 }
01258 }
01259
01260
01261 void
01262 Init_vm_trace(void)
01263 {
01264
01265 rb_define_global_function("set_trace_func", set_trace_func, 1);
01266 rb_define_method(rb_cThread, "set_trace_func", thread_set_trace_func_m, 1);
01267 rb_define_method(rb_cThread, "add_trace_func", thread_add_trace_func_m, 1);
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315 rb_cTracePoint = rb_define_class("TracePoint", rb_cObject);
01316 rb_undef_alloc_func(rb_cTracePoint);
01317 rb_undef_method(CLASS_OF(rb_cTracePoint), "new");
01318 rb_define_singleton_method(rb_cTracePoint, "new", tracepoint_new_s, -1);
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333 rb_define_singleton_method(rb_cTracePoint, "trace", tracepoint_trace_s, -1);
01334
01335 rb_define_method(rb_cTracePoint, "enable", tracepoint_enable_m, 0);
01336 rb_define_method(rb_cTracePoint, "disable", tracepoint_disable_m, 0);
01337 rb_define_method(rb_cTracePoint, "enabled?", rb_tracepoint_enabled_p, 0);
01338
01339 rb_define_method(rb_cTracePoint, "inspect", tracepoint_inspect, 0);
01340
01341 rb_define_method(rb_cTracePoint, "event", tracepoint_attr_event, 0);
01342 rb_define_method(rb_cTracePoint, "lineno", tracepoint_attr_lineno, 0);
01343 rb_define_method(rb_cTracePoint, "path", tracepoint_attr_path, 0);
01344 rb_define_method(rb_cTracePoint, "method_id", tracepoint_attr_method_id, 0);
01345 rb_define_method(rb_cTracePoint, "defined_class", tracepoint_attr_defined_class, 0);
01346 rb_define_method(rb_cTracePoint, "binding", tracepoint_attr_binding, 0);
01347 rb_define_method(rb_cTracePoint, "self", tracepoint_attr_self, 0);
01348 rb_define_method(rb_cTracePoint, "return_value", tracepoint_attr_return_value, 0);
01349 rb_define_method(rb_cTracePoint, "raised_exception", tracepoint_attr_raised_exception, 0);
01350 }
01351
01352