Ruby  2.4.2p198(2017-09-14revision59899)
vm_trace.c
Go to the documentation of this file.
1 /**********************************************************************
2 
3  vm_trace.c -
4 
5  $Author: ko1 $
6  created at: Tue Aug 14 19:37:09 2012
7 
8  Copyright (C) 1993-2012 Yukihiro Matsumoto
9 
10 **********************************************************************/
11 
12 /*
13  * This file include two parts:
14  *
15  * (1) set_trace_func internal mechanisms
16  * and C level API
17  *
18  * (2) Ruby level API
19  * (2-1) set_trace_func API
20  * (2-2) TracePoint API (not yet)
21  *
22  */
23 
24 #include "internal.h"
25 #include "ruby/debug.h"
26 
27 #include "vm_core.h"
28 #include "eval_intern.h"
29 
30 /* (1) trace mechanisms */
31 
32 typedef struct rb_event_hook_struct {
39 
41 
42 #define MAX_EVENT_NUM 32
43 
45 
46 /* called from vm.c */
47 
48 void
50 {
51  rb_event_hook_t *hook = hooks->hooks;
52 
53  while (hook) {
54  rb_gc_mark(hook->data);
55  hook = hook->next;
56  }
57 }
58 
59 /* ruby_vm_event_flags management */
60 
61 static void
63 {
64  int i;
66 
67  for (i=0; i<MAX_EVENT_NUM; i++) {
68  if (events & ((rb_event_flag_t)1 << i)) {
70  }
71  ruby_vm_event_flags |= ruby_event_flag_count[i] ? (1<<i) : 0;
72  }
73 
75 }
76 
77 static void
79 {
80  int i;
82 
83  for (i=0; i<MAX_EVENT_NUM; i++) {
84  if (events & ((rb_event_flag_t)1 << i)) {
86  }
87  ruby_vm_event_flags |= ruby_event_flag_count[i] ? (1<<i) : 0;
88  }
89 
91 }
92 
93 /* add/remove hooks */
94 
95 static rb_thread_t *
97 {
98  rb_thread_t *th;
99  GetThreadPtr(thval, th);
100  return th;
101 }
102 
103 static rb_event_hook_t *
105 {
106  rb_event_hook_t *hook;
107 
108  if ((events & RUBY_INTERNAL_EVENT_MASK) && (events & ~RUBY_INTERNAL_EVENT_MASK)) {
109  rb_raise(rb_eTypeError, "Can not specify normal event and internal event simultaneously.");
110  }
111 
112  hook = ALLOC(rb_event_hook_t);
113  hook->hook_flags = hook_flags;
114  hook->events = events;
115  hook->func = func;
116  hook->data = data;
117  return hook;
118 }
119 
120 static void
122 {
123  hook->next = list->hooks;
124  list->hooks = hook;
126  list->events |= hook->events;
127 }
128 
129 static void
131 {
132  rb_event_hook_t *hook = alloc_event_hook(func, events, data, hook_flags);
133  connect_event_hook(&th->event_hooks, hook);
134 }
135 
136 void
138 {
140 }
141 
142 void
144 {
145  rb_event_hook_t *hook = alloc_event_hook(func, events, data, RUBY_EVENT_HOOK_FLAG_SAFE);
146  connect_event_hook(&GET_VM()->event_hooks, hook);
147 }
148 
149 void
151 {
152  rb_threadptr_add_event_hook(thval2thread_t(thval), func, events, data, hook_flags);
153 }
154 
155 void
157 {
158  rb_event_hook_t *hook = alloc_event_hook(func, events, data, hook_flags);
159  connect_event_hook(&GET_VM()->event_hooks, hook);
160 }
161 
162 /* if func is 0, then clear all funcs */
163 static int
165 {
166  int ret = 0;
167  rb_event_hook_t *hook = list->hooks;
168 
169  while (hook) {
170  if (func == 0 || hook->func == func) {
171  if (data == Qundef || hook->data == data) {
173  ret+=1;
174  list->need_clean = TRUE;
175  }
176  }
177  hook = hook->next;
178  }
179 
180  return ret;
181 }
182 
183 static int
185 {
186  return remove_event_hook(&th->event_hooks, func, data);
187 }
188 
189 int
191 {
193 }
194 
195 int
197 {
198  return rb_threadptr_remove_event_hook(thval2thread_t(thval), func, data);
199 }
200 
201 int
203 {
204  return remove_event_hook(&GET_VM()->event_hooks, func, Qundef);
205 }
206 
207 int
209 {
210  return remove_event_hook(&GET_VM()->event_hooks, func, data);
211 }
212 
213 void
215 {
216  rb_vm_t *vm = GET_VM();
217  rb_thread_t *th = 0;
218 
219  list_for_each(&vm->living_threads, th, vmlt_node) {
221  }
223 }
224 
225 /* invoke hooks */
226 
227 static void
229 {
230  rb_event_hook_t *hook, **nextp = &list->hooks;
231 
232  list->events = 0;
233  list->need_clean = FALSE;
234 
235  while ((hook = *nextp) != 0) {
237  *nextp = hook->next;
239  xfree(hook);
240  }
241  else {
242  list->events |= hook->events; /* update active events */
243  nextp = &hook->next;
244  }
245  }
246 }
247 
248 static void
250 {
251  rb_event_hook_t *hook;
252 
253  for (hook = list->hooks; hook; hook = hook->next) {
254  if (!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_DELETED) && (trace_arg->event & hook->events)) {
255  if (!(hook->hook_flags & RUBY_EVENT_HOOK_FLAG_RAW_ARG)) {
256  (*hook->func)(trace_arg->event, hook->data, trace_arg->self, trace_arg->id, trace_arg->klass);
257  }
258  else {
259  (*((rb_event_hook_raw_arg_func_t)hook->func))(hook->data, trace_arg);
260  }
261  }
262  }
263 }
264 
265 static int
267 {
268  if (UNLIKELY(list->need_clean != FALSE)) {
269  if (th->vm->trace_running <= 1) { /* only running this hooks */
270  clean_hooks(list);
271  }
272  }
273 
274  return (list->events & trace_arg->event) != 0;
275 }
276 
277 static void
279 {
280  if (exec_hooks_precheck(th, list, trace_arg) == 0) return;
281  exec_hooks_body(th, list, trace_arg);
282 }
283 
284 static int
286 {
287  int state;
288  volatile int raised;
289 
290  if (exec_hooks_precheck(th, list, trace_arg) == 0) return 0;
291 
292  raised = rb_threadptr_reset_raised(th);
293 
294  /* TODO: Support !RUBY_EVENT_HOOK_FLAG_SAFE hooks */
295 
296  TH_PUSH_TAG(th);
297  if ((state = TH_EXEC_TAG()) == 0) {
298  exec_hooks_body(th, list, trace_arg);
299  }
300  TH_POP_TAG();
301 
302  if (raised) {
304  }
305 
306  return state;
307 }
308 
309 static void
311 {
312  rb_thread_t *th = trace_arg->th;
313 
314  if (trace_arg->event & RUBY_INTERNAL_EVENT_MASK) {
315  if (th->trace_arg && (th->trace_arg->event & RUBY_INTERNAL_EVENT_MASK)) {
316  /* skip hooks because this thread doing INTERNAL_EVENT */
317  }
318  else {
319  rb_trace_arg_t *prev_trace_arg = th->trace_arg;
320  th->vm->trace_running++;
321  th->trace_arg = trace_arg;
322  exec_hooks_unprotected(th, &th->event_hooks, trace_arg);
323  exec_hooks_unprotected(th, &th->vm->event_hooks, trace_arg);
324  th->trace_arg = prev_trace_arg;
325  th->vm->trace_running--;
326  }
327  }
328  else {
329  if (th->trace_arg == 0 && /* check reentrant */
330  trace_arg->self != rb_mRubyVMFrozenCore /* skip special methods. TODO: remove it. */) {
331  const VALUE errinfo = th->errinfo;
332  const int outer_state = th->state;
333  const VALUE old_recursive = th->local_storage_recursive_hash;
334  int state = 0;
335 
337  th->state = 0;
338  th->errinfo = Qnil;
339 
340  th->vm->trace_running++;
341  th->trace_arg = trace_arg;
342  {
343  /* thread local traces */
344  state = exec_hooks_protected(th, &th->event_hooks, trace_arg);
345  if (state) goto terminate;
346 
347  /* vm global traces */
348  state = exec_hooks_protected(th, &th->vm->event_hooks, trace_arg);
349  if (state) goto terminate;
350 
351  th->errinfo = errinfo;
352  }
353  terminate:
354  th->trace_arg = 0;
355  th->vm->trace_running--;
356 
358  th->local_storage_recursive_hash = old_recursive;
359 
360  if (state) {
361  if (pop_p) {
362  if (VM_FRAME_FINISHED_P(th->cfp)) {
363  th->tag = th->tag->prev;
364  }
365  rb_vm_pop_frame(th);
366  }
367  TH_JUMP_TAG(th, state);
368  }
369  th->state = outer_state;
370  }
371  }
372 }
373 
374 void
376 {
378 }
379 
380 void
382 {
384 }
385 
386 VALUE
388 {
389  volatile int raised;
390  volatile int outer_state;
391  VALUE result = Qnil;
392  rb_thread_t *volatile th = GET_THREAD();
393  int state;
394  const int tracing = th->trace_arg ? 1 : 0;
395  rb_trace_arg_t dummy_trace_arg;
396  dummy_trace_arg.event = 0;
397 
398  if (!tracing) th->vm->trace_running++;
399  if (!th->trace_arg) th->trace_arg = &dummy_trace_arg;
400 
401  raised = rb_threadptr_reset_raised(th);
402  outer_state = th->state;
403  th->state = 0;
404 
405  TH_PUSH_TAG(th);
406  if ((state = TH_EXEC_TAG()) == 0) {
407  result = (*func)(arg);
408  }
409  TH_POP_TAG();
410 
411  if (raised) {
413  }
414 
415  if (th->trace_arg == &dummy_trace_arg) th->trace_arg = 0;
416  if (!tracing) th->vm->trace_running--;
417 
418  if (state) {
419  TH_JUMP_TAG(th, state);
420  }
421 
422  th->state = outer_state;
423  return result;
424 }
425 
426 static void call_trace_func(rb_event_flag_t, VALUE data, VALUE self, ID id, VALUE klass);
427 
428 /* (2-1) set_trace_func (old API) */
429 
430 /*
431  * call-seq:
432  * set_trace_func(proc) -> proc
433  * set_trace_func(nil) -> nil
434  *
435  * Establishes _proc_ as the handler for tracing, or disables
436  * tracing if the parameter is +nil+.
437  *
438  * *Note:* this method is obsolete, please use TracePoint instead.
439  *
440  * _proc_ takes up to six parameters:
441  *
442  * * an event name
443  * * a filename
444  * * a line number
445  * * an object id
446  * * a binding
447  * * the name of a class
448  *
449  * _proc_ is invoked whenever an event occurs.
450  *
451  * Events are:
452  *
453  * +c-call+:: call a C-language routine
454  * +c-return+:: return from a C-language routine
455  * +call+:: call a Ruby method
456  * +class+:: start a class or module definition
457  * +end+:: finish a class or module definition
458  * +line+:: execute code on a new line
459  * +raise+:: raise an exception
460  * +return+:: return from a Ruby method
461  *
462  * Tracing is disabled within the context of _proc_.
463  *
464  * class Test
465  * def test
466  * a = 1
467  * b = 2
468  * end
469  * end
470  *
471  * set_trace_func proc { |event, file, line, id, binding, classname|
472  * printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
473  * }
474  * t = Test.new
475  * t.test
476  *
477  * line prog.rb:11 false
478  * c-call prog.rb:11 new Class
479  * c-call prog.rb:11 initialize Object
480  * c-return prog.rb:11 initialize Object
481  * c-return prog.rb:11 new Class
482  * line prog.rb:12 false
483  * call prog.rb:2 test Test
484  * line prog.rb:3 test Test
485  * line prog.rb:4 test Test
486  * return prog.rb:4 test Test
487  */
488 
489 static VALUE
491 {
492 
493  rb_remove_event_hook(call_trace_func);
494 
495  if (NIL_P(trace)) {
496  return Qnil;
497  }
498 
499  if (!rb_obj_is_proc(trace)) {
500  rb_raise(rb_eTypeError, "trace_func needs to be Proc");
501  }
502 
503  rb_add_event_hook(call_trace_func, RUBY_EVENT_ALL, trace);
504  return trace;
505 }
506 
507 static void
509 {
510  if (!rb_obj_is_proc(trace)) {
511  rb_raise(rb_eTypeError, "trace_func needs to be Proc");
512  }
513 
515 }
516 
517 /*
518  * call-seq:
519  * thr.add_trace_func(proc) -> proc
520  *
521  * Adds _proc_ as a handler for tracing.
522  *
523  * See Thread#set_trace_func and Kernel#set_trace_func.
524  */
525 
526 static VALUE
528 {
529  rb_thread_t *th;
530 
531  GetThreadPtr(obj, th);
532  thread_add_trace_func(th, trace);
533  return trace;
534 }
535 
536 /*
537  * call-seq:
538  * thr.set_trace_func(proc) -> proc
539  * thr.set_trace_func(nil) -> nil
540  *
541  * Establishes _proc_ on _thr_ as the handler for tracing, or
542  * disables tracing if the parameter is +nil+.
543  *
544  * See Kernel#set_trace_func.
545  */
546 
547 static VALUE
549 {
550  rb_thread_t *th;
551 
552  GetThreadPtr(obj, th);
553  rb_threadptr_remove_event_hook(th, call_trace_func, Qundef);
554 
555  if (NIL_P(trace)) {
556  return Qnil;
557  }
558 
559  thread_add_trace_func(th, trace);
560  return trace;
561 }
562 
563 static const char *
565 {
566  switch (event) {
567  case RUBY_EVENT_LINE: return "line";
568  case RUBY_EVENT_CLASS: return "class";
569  case RUBY_EVENT_END: return "end";
570  case RUBY_EVENT_CALL: return "call";
571  case RUBY_EVENT_RETURN: return "return";
572  case RUBY_EVENT_C_CALL: return "c-call";
573  case RUBY_EVENT_C_RETURN: return "c-return";
574  case RUBY_EVENT_RAISE: return "raise";
575  default:
576  return "unknown";
577  }
578 }
579 
580 static ID
582 {
583  ID id;
584 
585  switch (event) {
586 #define C(name, NAME) case RUBY_EVENT_##NAME: CONST_ID(id, #name); return id;
587  C(line, LINE);
588  C(class, CLASS);
589  C(end, END);
590  C(call, CALL);
591  C(return, RETURN);
592  C(c_call, C_CALL);
593  C(c_return, C_RETURN);
594  C(raise, RAISE);
595  C(b_call, B_CALL);
596  C(b_return, B_RETURN);
597  C(thread_begin, THREAD_BEGIN);
598  C(thread_end, THREAD_END);
599  C(fiber_switch, FIBER_SWITCH);
600  C(specified_line, SPECIFIED_LINE);
601  case RUBY_EVENT_LINE | RUBY_EVENT_SPECIFIED_LINE: CONST_ID(id, "line"); return id;
602 #undef C
603  default:
604  return 0;
605  }
606 }
607 
608 static void
609 call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
610 {
611  int line;
612  const char *srcfile = rb_source_loc(&line);
613  VALUE eventname = rb_str_new2(get_event_name(event));
614  VALUE filename = srcfile ? rb_str_new2(srcfile) : Qnil;
615  VALUE argv[6];
616  rb_thread_t *th = GET_THREAD();
617 
618  if (!klass) {
619  rb_thread_method_id_and_class(th, &id, 0, &klass);
620  }
621 
622  if (klass) {
623  if (RB_TYPE_P(klass, T_ICLASS)) {
624  klass = RBASIC(klass)->klass;
625  }
626  else if (FL_TEST(klass, FL_SINGLETON)) {
627  klass = rb_ivar_get(klass, id__attached__);
628  }
629  }
630 
631  argv[0] = eventname;
632  argv[1] = filename;
633  argv[2] = INT2FIX(line);
634  argv[3] = id ? ID2SYM(id) : Qnil;
635  argv[4] = (self && srcfile) ? rb_binding_new() : Qnil;
636  argv[5] = klass ? klass : Qnil;
637 
638  rb_proc_call_with_block(proc, 6, argv, Qnil);
639 }
640 
641 /* (2-2) TracePoint API */
642 
644 
645 typedef struct rb_tp_struct {
647  int tracing; /* bool */
649  void (*func)(VALUE tpval, void *data);
650  void *data;
652  VALUE self;
653 } rb_tp_t;
654 
655 static void
656 tp_mark(void *ptr)
657 {
658  rb_tp_t *tp = ptr;
659  rb_gc_mark(tp->proc);
660  if (tp->target_th) rb_gc_mark(tp->target_th->self);
661 }
662 
663 static size_t
664 tp_memsize(const void *ptr)
665 {
666  return sizeof(rb_tp_t);
667 }
668 
669 static const rb_data_type_t tp_data_type = {
670  "tracepoint",
673 };
674 
675 static VALUE
677 {
678  rb_tp_t *tp;
679  return TypedData_Make_Struct(klass, rb_tp_t, &tp_data_type, tp);
680 }
681 
682 static rb_event_flag_t
684 {
685  ID id;
686  VALUE sym = rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym");
687  const rb_event_flag_t RUBY_EVENT_A_CALL =
689  const rb_event_flag_t RUBY_EVENT_A_RETURN =
691 
692 #define C(name, NAME) CONST_ID(id, #name); if (sym == ID2SYM(id)) return RUBY_EVENT_##NAME
693  C(line, LINE);
694  C(class, CLASS);
695  C(end, END);
696  C(call, CALL);
697  C(return, RETURN);
698  C(c_call, C_CALL);
699  C(c_return, C_RETURN);
700  C(raise, RAISE);
701  C(b_call, B_CALL);
702  C(b_return, B_RETURN);
703  C(thread_begin, THREAD_BEGIN);
704  C(thread_end, THREAD_END);
705  C(fiber_switch, FIBER_SWITCH);
706  C(specified_line, SPECIFIED_LINE);
707  C(a_call, A_CALL);
708  C(a_return, A_RETURN);
709 #undef C
710  rb_raise(rb_eArgError, "unknown event: %"PRIsVALUE, rb_sym2str(sym));
711 }
712 
713 static rb_tp_t *
714 tpptr(VALUE tpval)
715 {
716  rb_tp_t *tp;
717  TypedData_Get_Struct(tpval, rb_tp_t, &tp_data_type, tp);
718  return tp;
719 }
720 
721 static rb_trace_arg_t *
723 {
724  rb_trace_arg_t *trace_arg = GET_THREAD()->trace_arg;
725  if (trace_arg == 0) {
726  rb_raise(rb_eRuntimeError, "access from outside");
727  }
728  return trace_arg;
729 }
730 
731 struct rb_trace_arg_struct *
733 {
734  return get_trace_arg();
735 }
736 
739 {
740  return trace_arg->event;
741 }
742 
743 VALUE
745 {
746  return ID2SYM(get_event_id(trace_arg->event));
747 }
748 
749 static void
751 {
752  if (trace_arg->path == Qundef) {
753  rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(trace_arg->th, trace_arg->cfp);
754 
755  if (cfp) {
756  trace_arg->path = cfp->iseq->body->location.path;
757  trace_arg->lineno = rb_vm_get_sourceline(cfp);
758  }
759  else {
760  trace_arg->path = Qnil;
761  trace_arg->lineno = 0;
762  }
763  }
764 }
765 
766 VALUE
768 {
769  fill_path_and_lineno(trace_arg);
770  return INT2FIX(trace_arg->lineno);
771 }
772 VALUE
774 {
775  fill_path_and_lineno(trace_arg);
776  return trace_arg->path;
777 }
778 
779 static void
781 {
782  if (!trace_arg->klass_solved) {
783  if (!trace_arg->klass) {
784  rb_vm_control_frame_id_and_class(trace_arg->cfp, &trace_arg->id, &trace_arg->called_id, &trace_arg->klass);
785  }
786 
787  if (trace_arg->klass) {
788  if (RB_TYPE_P(trace_arg->klass, T_ICLASS)) {
789  trace_arg->klass = RBASIC(trace_arg->klass)->klass;
790  }
791  }
792  else {
793  trace_arg->klass = Qnil;
794  }
795 
796  trace_arg->klass_solved = 1;
797  }
798 }
799 
800 VALUE
802 {
803  fill_id_and_klass(trace_arg);
804  return trace_arg->id ? ID2SYM(trace_arg->id) : Qnil;
805 }
806 
807 VALUE
809 {
810  fill_id_and_klass(trace_arg);
811  return trace_arg->called_id ? ID2SYM(trace_arg->called_id) : Qnil;
812 }
813 
814 VALUE
816 {
817  fill_id_and_klass(trace_arg);
818  return trace_arg->klass;
819 }
820 
821 VALUE
823 {
825  cfp = rb_vm_get_binding_creatable_next_cfp(trace_arg->th, trace_arg->cfp);
826 
827  if (cfp) {
828  return rb_vm_make_binding(trace_arg->th, cfp);
829  }
830  else {
831  return Qnil;
832  }
833 }
834 
835 VALUE
837 {
838  return trace_arg->self;
839 }
840 
841 VALUE
843 {
845  /* ok */
846  }
847  else {
848  rb_raise(rb_eRuntimeError, "not supported by this event");
849  }
850  if (trace_arg->data == Qundef) {
851  rb_bug("tp_attr_return_value_m: unreachable");
852  }
853  return trace_arg->data;
854 }
855 
856 VALUE
858 {
859  if (trace_arg->event & (RUBY_EVENT_RAISE)) {
860  /* ok */
861  }
862  else {
863  rb_raise(rb_eRuntimeError, "not supported by this event");
864  }
865  if (trace_arg->data == Qundef) {
866  rb_bug("tp_attr_raised_exception_m: unreachable");
867  }
868  return trace_arg->data;
869 }
870 
871 VALUE
873 {
875  /* ok */
876  }
877  else {
878  rb_raise(rb_eRuntimeError, "not supported by this event");
879  }
880  if (trace_arg->data == Qundef) {
881  rb_bug("tp_attr_raised_exception_m: unreachable");
882  }
883  return trace_arg->data;
884 }
885 
886 /*
887  * Type of event
888  *
889  * See TracePoint@Events for more information.
890  */
891 static VALUE
893 {
895 }
896 
897 /*
898  * Line number of the event
899  */
900 static VALUE
902 {
904 }
905 
906 /*
907  * Path of the file being run
908  */
909 static VALUE
911 {
913 }
914 
915 /*
916  * Return the name at the definition of the method being called
917  */
918 static VALUE
920 {
922 }
923 
924 /*
925  * Return the called name of the method being called
926  */
927 static VALUE
929 {
931 }
932 
933 /*
934  * Return class or module of the method being called.
935  *
936  * class C; def foo; end; end
937  * trace = TracePoint.new(:call) do |tp|
938  * p tp.defined_class #=> C
939  * end.enable do
940  * C.new.foo
941  * end
942  *
943  * If method is defined by a module, then that module is returned.
944  *
945  * module M; def foo; end; end
946  * class C; include M; end;
947  * trace = TracePoint.new(:call) do |tp|
948  * p tp.defined_class #=> M
949  * end.enable do
950  * C.new.foo
951  * end
952  *
953  * <b>Note:</b> #defined_class returns singleton class.
954  *
955  * 6th block parameter of Kernel#set_trace_func passes original class
956  * of attached by singleton class.
957  *
958  * <b>This is a difference between Kernel#set_trace_func and TracePoint.</b>
959  *
960  * class C; def self.foo; end; end
961  * trace = TracePoint.new(:call) do |tp|
962  * p tp.defined_class #=> #<Class:C>
963  * end.enable do
964  * C.foo
965  * end
966  */
967 static VALUE
969 {
971 }
972 
973 /*
974  * Return the generated binding object from event
975  */
976 static VALUE
978 {
980 }
981 
982 /*
983  * Return the trace object during event
984  *
985  * Same as TracePoint#binding:
986  * trace.binding.eval('self')
987  */
988 static VALUE
990 {
992 }
993 
994 /*
995  * Return value from +:return+, +c_return+, and +b_return+ event
996  */
997 static VALUE
999 {
1001 }
1002 
1003 /*
1004  * Value from exception raised on the +:raise+ event
1005  */
1006 static VALUE
1008 {
1010 }
1011 
1012 static void
1014 {
1015  rb_tp_t *tp = tpptr(tpval);
1016 
1017  if (tp->func) {
1018  (*tp->func)(tpval, tp->data);
1019  }
1020  else {
1021  rb_proc_call_with_block((VALUE)tp->proc, 1, &tpval, Qnil);
1022  }
1023 }
1024 
1025 VALUE
1027 {
1028  rb_tp_t *tp;
1029 
1030  tp = tpptr(tpval);
1031 
1032  if (tp->target_th) {
1035  }
1036  else {
1039  }
1040  tp->tracing = 1;
1041  return Qundef;
1042 }
1043 
1044 VALUE
1046 {
1047  rb_tp_t *tp;
1048 
1049  tp = tpptr(tpval);
1050 
1051  if (tp->target_th) {
1053  }
1054  else {
1056  }
1057  tp->tracing = 0;
1058  return Qundef;
1059 }
1060 
1061 /*
1062  * call-seq:
1063  * trace.enable -> true or false
1064  * trace.enable { block } -> obj
1065  *
1066  * Activates the trace
1067  *
1068  * Return true if trace was enabled.
1069  * Return false if trace was disabled.
1070  *
1071  * trace.enabled? #=> false
1072  * trace.enable #=> false (previous state)
1073  * # trace is enabled
1074  * trace.enabled? #=> true
1075  * trace.enable #=> true (previous state)
1076  * # trace is still enabled
1077  *
1078  * If a block is given, the trace will only be enabled within the scope of the
1079  * block.
1080  *
1081  * trace.enabled?
1082  * #=> false
1083  *
1084  * trace.enable do
1085  * trace.enabled?
1086  * # only enabled for this block
1087  * end
1088  *
1089  * trace.enabled?
1090  * #=> false
1091  *
1092  * Note: You cannot access event hooks within the block.
1093  *
1094  * trace.enable { p tp.lineno }
1095  * #=> RuntimeError: access from outside
1096  *
1097  */
1098 static VALUE
1100 {
1101  rb_tp_t *tp = tpptr(tpval);
1102  int previous_tracing = tp->tracing;
1103  rb_tracepoint_enable(tpval);
1104 
1105  if (rb_block_given_p()) {
1106  return rb_ensure(rb_yield, Qnil,
1107  previous_tracing ? rb_tracepoint_enable : rb_tracepoint_disable,
1108  tpval);
1109  }
1110  else {
1111  return previous_tracing ? Qtrue : Qfalse;
1112  }
1113 }
1114 
1115 /*
1116  * call-seq:
1117  * trace.disable -> true or false
1118  * trace.disable { block } -> obj
1119  *
1120  * Deactivates the trace
1121  *
1122  * Return true if trace was enabled.
1123  * Return false if trace was disabled.
1124  *
1125  * trace.enabled? #=> true
1126  * trace.disable #=> false (previous status)
1127  * trace.enabled? #=> false
1128  * trace.disable #=> false
1129  *
1130  * If a block is given, the trace will only be disable within the scope of the
1131  * block.
1132  *
1133  * trace.enabled?
1134  * #=> true
1135  *
1136  * trace.disable do
1137  * trace.enabled?
1138  * # only disabled for this block
1139  * end
1140  *
1141  * trace.enabled?
1142  * #=> true
1143  *
1144  * Note: You cannot access event hooks within the block.
1145  *
1146  * trace.disable { p tp.lineno }
1147  * #=> RuntimeError: access from outside
1148  */
1149 static VALUE
1151 {
1152  rb_tp_t *tp = tpptr(tpval);
1153  int previous_tracing = tp->tracing;
1154  rb_tracepoint_disable(tpval);
1155 
1156  if (rb_block_given_p()) {
1157  return rb_ensure(rb_yield, Qnil,
1158  previous_tracing ? rb_tracepoint_enable : rb_tracepoint_disable,
1159  tpval);
1160  }
1161  else {
1162  return previous_tracing ? Qtrue : Qfalse;
1163  }
1164 }
1165 
1166 /*
1167  * call-seq:
1168  * trace.enabled? -> true or false
1169  *
1170  * The current status of the trace
1171  */
1172 VALUE
1174 {
1175  rb_tp_t *tp = tpptr(tpval);
1176  return tp->tracing ? Qtrue : Qfalse;
1177 }
1178 
1179 static VALUE
1180 tracepoint_new(VALUE klass, rb_thread_t *target_th, rb_event_flag_t events, void (func)(VALUE, void*), void *data, VALUE proc)
1181 {
1182  VALUE tpval = tp_alloc(klass);
1183  rb_tp_t *tp;
1184  TypedData_Get_Struct(tpval, rb_tp_t, &tp_data_type, tp);
1185 
1186  tp->proc = proc;
1187  tp->func = func;
1188  tp->data = data;
1189  tp->events = events;
1190  tp->self = tpval;
1191 
1192  return tpval;
1193 }
1194 
1195 /*
1196  * Creates a tracepoint by registering a callback function for one or more
1197  * tracepoint events. Once the tracepoint is created, you can use
1198  * rb_tracepoint_enable to enable the tracepoint.
1199  *
1200  * Parameters:
1201  * 1. VALUE target_thval - Meant for picking the thread in which the tracepoint
1202  * is to be created. However, current implementation ignore this parameter,
1203  * tracepoint is created for all threads. Simply specify Qnil.
1204  * 2. rb_event_flag_t events - Event(s) to listen to.
1205  * 3. void (*func)(VALUE, void *) - A callback function.
1206  * 4. void *data - Void pointer that will be passed to the callback function.
1207  *
1208  * When the callback function is called, it will be passed 2 parameters:
1209  * 1)VALUE tpval - the TracePoint object from which trace args can be extracted.
1210  * 2)void *data - A void pointer which helps to share scope with the callback function.
1211  *
1212  * It is important to note that you cannot register callbacks for normal events and internal events
1213  * simultaneously because they are different purpose.
1214  * You can use any Ruby APIs (calling methods and so on) on normal event hooks.
1215  * However, in internal events, you can not use any Ruby APIs (even object creations).
1216  * This is why we can't specify internal events by TracePoint directly.
1217  * Limitations are MRI version specific.
1218  *
1219  * Example:
1220  * rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ | RUBY_INTERNAL_EVENT_FREEOBJ, obj_event_i, data);
1221  *
1222  * In this example, a callback function obj_event_i will be registered for
1223  * internal events RUBY_INTERNAL_EVENT_NEWOBJ and RUBY_INTERNAL_EVENT_FREEOBJ.
1224  */
1225 VALUE
1226 rb_tracepoint_new(VALUE target_thval, rb_event_flag_t events, void (*func)(VALUE, void *), void *data)
1227 {
1228  rb_thread_t *target_th = 0;
1229  if (RTEST(target_thval)) {
1230  GetThreadPtr(target_thval, target_th);
1231  /* TODO: Test it!
1232  * Warning: This function is not tested.
1233  */
1234  }
1235  return tracepoint_new(rb_cTracePoint, target_th, events, func, data, Qundef);
1236 }
1237 
1238 /*
1239  * call-seq:
1240  * TracePoint.new(*events) { |obj| block } -> obj
1241  *
1242  * Returns a new TracePoint object, not enabled by default.
1243  *
1244  * Next, in order to activate the trace, you must use TracePoint.enable
1245  *
1246  * trace = TracePoint.new(:call) do |tp|
1247  * p [tp.lineno, tp.defined_class, tp.method_id, tp.event]
1248  * end
1249  * #=> #<TracePoint:disabled>
1250  *
1251  * trace.enable
1252  * #=> false
1253  *
1254  * puts "Hello, TracePoint!"
1255  * # ...
1256  * # [48, IRB::Notifier::AbstractNotifier, :printf, :call]
1257  * # ...
1258  *
1259  * When you want to deactivate the trace, you must use TracePoint.disable
1260  *
1261  * trace.disable
1262  *
1263  * See TracePoint@Events for possible events and more information.
1264  *
1265  * A block must be given, otherwise a ThreadError is raised.
1266  *
1267  * If the trace method isn't included in the given events filter, a
1268  * RuntimeError is raised.
1269  *
1270  * TracePoint.trace(:line) do |tp|
1271  * p tp.raised_exception
1272  * end
1273  * #=> RuntimeError: 'raised_exception' not supported by this event
1274  *
1275  * If the trace method is called outside block, a RuntimeError is raised.
1276  *
1277  * TracePoint.trace(:line) do |tp|
1278  * $tp = tp
1279  * end
1280  * $tp.line #=> access from outside (RuntimeError)
1281  *
1282  * Access from other threads is also forbidden.
1283  *
1284  */
1285 static VALUE
1287 {
1288  rb_event_flag_t events = 0;
1289  int i;
1290 
1291  if (argc > 0) {
1292  for (i=0; i<argc; i++) {
1293  events |= symbol2event_flag(argv[i]);
1294  }
1295  }
1296  else {
1297  events = RUBY_EVENT_TRACEPOINT_ALL;
1298  }
1299 
1300  if (!rb_block_given_p()) {
1301  rb_raise(rb_eThreadError, "must be called with a block");
1302  }
1303 
1304  return tracepoint_new(self, 0, events, 0, 0, rb_block_proc());
1305 }
1306 
1307 static VALUE
1309 {
1310  VALUE trace = tracepoint_new_s(argc, argv, self);
1311  rb_tracepoint_enable(trace);
1312  return trace;
1313 }
1314 
1315 /*
1316  * call-seq:
1317  * trace.inspect -> string
1318  *
1319  * Return a string containing a human-readable TracePoint
1320  * status.
1321  */
1322 
1323 static VALUE
1325 {
1326  rb_tp_t *tp = tpptr(self);
1327  rb_trace_arg_t *trace_arg = GET_THREAD()->trace_arg;
1328 
1329  if (trace_arg) {
1330  switch (trace_arg->event) {
1331  case RUBY_EVENT_LINE:
1333  {
1334  VALUE sym = rb_tracearg_method_id(trace_arg);
1335  if (NIL_P(sym))
1336  goto default_inspect;
1337  return rb_sprintf("#<TracePoint:%"PRIsVALUE"@%"PRIsVALUE":%d in `%"PRIsVALUE"'>",
1338  rb_tracearg_event(trace_arg),
1339  rb_tracearg_path(trace_arg),
1340  FIX2INT(rb_tracearg_lineno(trace_arg)),
1341  sym);
1342  }
1343  case RUBY_EVENT_CALL:
1344  case RUBY_EVENT_C_CALL:
1345  case RUBY_EVENT_RETURN:
1346  case RUBY_EVENT_C_RETURN:
1347  return rb_sprintf("#<TracePoint:%"PRIsVALUE" `%"PRIsVALUE"'@%"PRIsVALUE":%d>",
1348  rb_tracearg_event(trace_arg),
1349  rb_tracearg_method_id(trace_arg),
1350  rb_tracearg_path(trace_arg),
1351  FIX2INT(rb_tracearg_lineno(trace_arg)));
1353  case RUBY_EVENT_THREAD_END:
1354  return rb_sprintf("#<TracePoint:%"PRIsVALUE" %"PRIsVALUE">",
1355  rb_tracearg_event(trace_arg),
1356  rb_tracearg_self(trace_arg));
1357  default:
1359  return rb_sprintf("#<TracePoint:%"PRIsVALUE"@%"PRIsVALUE":%d>",
1360  rb_tracearg_event(trace_arg),
1361  rb_tracearg_path(trace_arg),
1362  FIX2INT(rb_tracearg_lineno(trace_arg)));
1363  }
1364  }
1365  else {
1366  return rb_sprintf("#<TracePoint:%s>", tp->tracing ? "enabled" : "disabled");
1367  }
1368 }
1369 
1370 static void
1372 {
1373  int active = 0, deleted = 0;
1374 
1375  while (hook) {
1377  deleted++;
1378  }
1379  else {
1380  active++;
1381  }
1382  hook = hook->next;
1383  }
1384 
1385  rb_hash_aset(hash, key, rb_ary_new3(2, INT2FIX(active), INT2FIX(deleted)));
1386 }
1387 
1388 /*
1389  * call-seq:
1390  * TracePoint.stat -> obj
1391  *
1392  * Returns internal information of TracePoint.
1393  *
1394  * The contents of the returned value are implementation specific.
1395  * It may be changed in future.
1396  *
1397  * This method is only for debugging TracePoint itself.
1398  */
1399 
1400 static VALUE
1402 {
1403  rb_vm_t *vm = GET_VM();
1404  VALUE stat = rb_hash_new();
1405 
1407  /* TODO: thread local hooks */
1408 
1409  return stat;
1410 }
1411 
1412 static void Init_postponed_job(void);
1413 
1414 /* This function is called from inits.c */
1415 void
1417 {
1418  /* trace_func */
1419  rb_define_global_function("set_trace_func", set_trace_func, 1);
1420  rb_define_method(rb_cThread, "set_trace_func", thread_set_trace_func_m, 1);
1421  rb_define_method(rb_cThread, "add_trace_func", thread_add_trace_func_m, 1);
1422 
1423  /*
1424  * Document-class: TracePoint
1425  *
1426  * A class that provides the functionality of Kernel#set_trace_func in a
1427  * nice Object-Oriented API.
1428  *
1429  * == Example
1430  *
1431  * We can use TracePoint to gather information specifically for exceptions:
1432  *
1433  * trace = TracePoint.new(:raise) do |tp|
1434  * p [tp.lineno, tp.event, tp.raised_exception]
1435  * end
1436  * #=> #<TracePoint:disabled>
1437  *
1438  * trace.enable
1439  * #=> false
1440  *
1441  * 0 / 0
1442  * #=> [5, :raise, #<ZeroDivisionError: divided by 0>]
1443  *
1444  * == Events
1445  *
1446  * If you don't specify the type of events you want to listen for,
1447  * TracePoint will include all available events.
1448  *
1449  * *Note* do not depend on current event set, as this list is subject to
1450  * change. Instead, it is recommended you specify the type of events you
1451  * want to use.
1452  *
1453  * To filter what is traced, you can pass any of the following as +events+:
1454  *
1455  * +:line+:: execute code on a new line
1456  * +:class+:: start a class or module definition
1457  * +:end+:: finish a class or module definition
1458  * +:call+:: call a Ruby method
1459  * +:return+:: return from a Ruby method
1460  * +:c_call+:: call a C-language routine
1461  * +:c_return+:: return from a C-language routine
1462  * +:raise+:: raise an exception
1463  * +:b_call+:: event hook at block entry
1464  * +:b_return+:: event hook at block ending
1465  * +:thread_begin+:: event hook at thread beginning
1466  * +:thread_end+:: event hook at thread ending
1467  * +:fiber_switch+:: event hook at fiber switch
1468  *
1469  */
1470  rb_cTracePoint = rb_define_class("TracePoint", rb_cObject);
1471  rb_undef_alloc_func(rb_cTracePoint);
1472  rb_define_singleton_method(rb_cTracePoint, "new", tracepoint_new_s, -1);
1473  /*
1474  * Document-method: trace
1475  *
1476  * call-seq:
1477  * TracePoint.trace(*events) { |obj| block } -> obj
1478  *
1479  * A convenience method for TracePoint.new, that activates the trace
1480  * automatically.
1481  *
1482  * trace = TracePoint.trace(:call) { |tp| [tp.lineno, tp.event] }
1483  * #=> #<TracePoint:enabled>
1484  *
1485  * trace.enabled? #=> true
1486  */
1487  rb_define_singleton_method(rb_cTracePoint, "trace", tracepoint_trace_s, -1);
1488 
1489  rb_define_method(rb_cTracePoint, "enable", tracepoint_enable_m, 0);
1490  rb_define_method(rb_cTracePoint, "disable", tracepoint_disable_m, 0);
1491  rb_define_method(rb_cTracePoint, "enabled?", rb_tracepoint_enabled_p, 0);
1492 
1493  rb_define_method(rb_cTracePoint, "inspect", tracepoint_inspect, 0);
1494 
1495  rb_define_method(rb_cTracePoint, "event", tracepoint_attr_event, 0);
1496  rb_define_method(rb_cTracePoint, "lineno", tracepoint_attr_lineno, 0);
1497  rb_define_method(rb_cTracePoint, "path", tracepoint_attr_path, 0);
1498  rb_define_method(rb_cTracePoint, "method_id", tracepoint_attr_method_id, 0);
1499  rb_define_method(rb_cTracePoint, "callee_id", tracepoint_attr_callee_id, 0);
1500  rb_define_method(rb_cTracePoint, "defined_class", tracepoint_attr_defined_class, 0);
1501  rb_define_method(rb_cTracePoint, "binding", tracepoint_attr_binding, 0);
1502  rb_define_method(rb_cTracePoint, "self", tracepoint_attr_self, 0);
1503  rb_define_method(rb_cTracePoint, "return_value", tracepoint_attr_return_value, 0);
1504  rb_define_method(rb_cTracePoint, "raised_exception", tracepoint_attr_raised_exception, 0);
1505 
1506  rb_define_singleton_method(rb_cTracePoint, "stat", tracepoint_stat_s, 0);
1507 
1508  /* initialized for postponed job */
1509 
1511 }
1512 
1513 typedef struct rb_postponed_job_struct {
1514  unsigned long flags; /* reserved */
1515  struct rb_thread_struct *th; /* created thread, reserved */
1517  void *data;
1519 
1520 #define MAX_POSTPONED_JOB 1000
1521 #define MAX_POSTPONED_JOB_SPECIAL_ADDITION 24
1522 
1523 static void
1525 {
1526  rb_vm_t *vm = GET_VM();
1528  vm->postponed_job_index = 0;
1529 }
1530 
1535 };
1536 
1539  unsigned int flags, rb_postponed_job_func_t func, void *data, int max, int expected_index)
1540 {
1541  rb_postponed_job_t *pjob;
1542 
1543  if (expected_index >= max) return PJRR_FULL; /* failed */
1544 
1545  if (ATOMIC_CAS(vm->postponed_job_index, expected_index, expected_index+1) == expected_index) {
1546  pjob = &vm->postponed_job_buffer[expected_index];
1547  }
1548  else {
1549  return PJRR_INTERRUPTED;
1550  }
1551 
1552  pjob->flags = flags;
1553  pjob->th = th;
1554  pjob->func = func;
1555  pjob->data = data;
1556 
1558 
1559  return PJRR_SUCESS;
1560 }
1561 
1562 
1563 /* return 0 if job buffer is full */
1564 int
1566 {
1567  rb_thread_t *th = GET_THREAD();
1568  rb_vm_t *vm = th->vm;
1569 
1570  begin:
1571  switch (postponed_job_register(th, vm, flags, func, data, MAX_POSTPONED_JOB, vm->postponed_job_index)) {
1572  case PJRR_SUCESS : return 1;
1573  case PJRR_FULL : return 0;
1574  case PJRR_INTERRUPTED: goto begin;
1575  default: rb_bug("unreachable\n");
1576  }
1577 }
1578 
1579 /* return 0 if job buffer is full */
1580 int
1582 {
1583  rb_thread_t *th = GET_THREAD();
1584  rb_vm_t *vm = th->vm;
1585  rb_postponed_job_t *pjob;
1586  int i, index;
1587 
1588  begin:
1589  index = vm->postponed_job_index;
1590  for (i=0; i<index; i++) {
1591  pjob = &vm->postponed_job_buffer[i];
1592  if (pjob->func == func) {
1594  return 2;
1595  }
1596  }
1597  switch (postponed_job_register(th, vm, flags, func, data, MAX_POSTPONED_JOB + MAX_POSTPONED_JOB_SPECIAL_ADDITION, index)) {
1598  case PJRR_SUCESS : return 1;
1599  case PJRR_FULL : return 0;
1600  case PJRR_INTERRUPTED: goto begin;
1601  default: rb_bug("unreachable\n");
1602  }
1603 }
1604 
1605 void
1607 {
1608  rb_thread_t *th = GET_THREAD();
1609  const unsigned long block_mask = POSTPONED_JOB_INTERRUPT_MASK|TRAP_INTERRUPT_MASK;
1610  unsigned long saved_mask = th->interrupt_mask & block_mask;
1611  VALUE saved_errno = th->errinfo;
1612 
1613  th->errinfo = Qnil;
1614  /* mask POSTPONED_JOB dispatch */
1615  th->interrupt_mask |= block_mask;
1616  {
1617  TH_PUSH_TAG(th);
1618  EXEC_TAG();
1619  {
1620  int index;
1621  while ((index = vm->postponed_job_index) > 0) {
1622  if (ATOMIC_CAS(vm->postponed_job_index, index, index-1) == index) {
1623  rb_postponed_job_t *pjob = &vm->postponed_job_buffer[index-1];
1624  (*pjob->func)(pjob->data);
1625  }
1626  }
1627  }
1628  TH_POP_TAG();
1629  }
1630  /* restore POSTPONED_JOB mask */
1631  th->interrupt_mask &= ~(saved_mask ^ block_mask);
1632  th->errinfo = saved_errno;
1633 }
rb_control_frame_t * cfp
Definition: vm_core.h:708
#define RUBY_EVENT_B_RETURN
Definition: ruby.h:2071
VALUE self
Definition: vm_trace.c:652
#define T_SYMBOL
Definition: ruby.h:508
rb_control_frame_t * rb_vm_get_ruby_level_next_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp)
Definition: vm.c:489
#define RUBY_EVENT_THREAD_END
Definition: ruby.h:2073
rb_vm_t * vm
Definition: vm_core.h:703
VALUE rb_tracearg_lineno(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:767
#define RUBY_EVENT_C_RETURN
Definition: ruby.h:2065
VALUE rb_proc_call_with_block(VALUE, int argc, const VALUE *argv, VALUE)
Definition: proc.c:899
void rb_bug(const char *fmt,...)
Definition: error.c:482
#define FALSE
Definition: nkf.h:174
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1145
int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
Definition: vm_backtrace.c:38
#define RUBY_EVENT_RETURN
Definition: ruby.h:2063
static int max(int a, int b)
Definition: strftime.c:142
static unsigned int hash(str, len) register const char *str
void rb_undef_alloc_func(VALUE)
Definition: vm_method.c:681
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1716
static VALUE set_trace_func(VALUE obj, VALUE trace)
Definition: vm_trace.c:490
static int VM_FRAME_FINISHED_P(const rb_control_frame_t *cfp)
Definition: vm_core.h:1031
#define RUBY_EVENT_RAISE
Definition: ruby.h:2066
#define Qtrue
Definition: ruby.h:437
VALUE rb_tracearg_object(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:872
#define RUBY_EVENT_ALL
Definition: ruby.h:2067
static VALUE tp_alloc(VALUE klass)
Definition: vm_trace.c:676
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1190
const int id
Definition: nkf.c:209
VALUE rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:842
static VALUE tracepoint_new(VALUE klass, rb_thread_t *target_th, rb_event_flag_t events, void(func)(VALUE, void *), void *data, VALUE proc)
Definition: vm_trace.c:1180
static VALUE tracepoint_attr_path(VALUE tpval)
Definition: vm_trace.c:910
static void connect_event_hook(rb_hook_list_t *list, rb_event_hook_t *hook)
Definition: vm_trace.c:121
rb_thread_t * th
Definition: vm_core.h:1581
static VALUE thread_add_trace_func_m(VALUE obj, VALUE trace)
Definition: vm_trace.c:527
#define RUBY_EVENT_CALL
Definition: ruby.h:2062
VALUE rb_eTypeError
Definition: error.c:762
#define TH_JUMP_TAG(th, st)
Definition: eval_intern.h:186
static void rb_threadptr_exec_event_hooks_orig(rb_trace_arg_t *trace_arg, int pop_p)
Definition: vm_trace.c:310
static ID get_event_id(rb_event_flag_t event)
Definition: vm_trace.c:581
struct rb_iseq_constant_body * body
Definition: vm_core.h:395
void rb_threadptr_exec_event_hooks(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:381
static VALUE fiber_switch(rb_fiber_t *fib, int argc, const VALUE *argv, int is_resume)
Definition: cont.c:1424
static size_t tp_memsize(const void *ptr)
Definition: vm_trace.c:664
static rb_tp_t * tpptr(VALUE tpval)
Definition: vm_trace.c:714
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2207
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1260
unsigned long flags
Definition: vm_trace.c:1514
static void tracepoint_stat_event_hooks(VALUE hash, VALUE key, rb_event_hook_t *hook)
Definition: vm_trace.c:1371
static VALUE tracepoint_attr_event(VALUE tpval)
Definition: vm_trace.c:892
rb_thread_t * target_th
Definition: vm_trace.c:648
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Definition: object.c:2630
#define TH_EXEC_TAG()
Definition: eval_intern.h:180
static VALUE tracepoint_attr_callee_id(VALUE tpval)
Definition: vm_trace.c:928
VALUE rb_tracearg_path(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:773
static void clean_hooks(rb_hook_list_t *list)
Definition: vm_trace.c:228
VALUE rb_tracearg_method_id(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:801
void rb_gc_mark(VALUE ptr)
Definition: gc.c:4394
void 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)
Definition: vm_trace.c:150
void rb_clear_trace_func(void)
Definition: vm_trace.c:214
static void recalc_remove_ruby_vm_event_flags(rb_event_flag_t events)
Definition: vm_trace.c:78
VALUE local_storage_recursive_hash_for_trace
Definition: vm_core.h:775
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:1745
rb_event_flag_t events
Definition: vm_core.h:480
VALUE rb_tracearg_event(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:744
const char * rb_source_loc(int *pline)
Definition: vm.c:1291
int rb_remove_event_hook(rb_event_hook_func_t func)
Definition: vm_trace.c:202
static const char * get_event_name(rb_event_flag_t event)
Definition: vm_trace.c:564
VALUE rb_tracearg_callee_id(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:808
static void recalc_add_ruby_vm_event_flags(rb_event_flag_t events)
Definition: vm_trace.c:62
struct rb_tp_struct rb_tp_t
void rb_threadptr_exec_event_hooks_and_pop_frame(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:375
#define GET_THREAD()
Definition: vm_core.h:1513
#define sym(x)
Definition: date_core.c:3721
void Init_vm_trace(void)
Definition: vm_trace.c:1416
#define RUBY_EVENT_CLASS
Definition: ruby.h:2060
static void call_trace_func(rb_event_flag_t, VALUE data, VALUE self, ID id, VALUE klass)
Definition: vm_trace.c:609
void rb_objspace_set_event_hook(const rb_event_flag_t event)
Definition: gc.c:1760
#define FL_SINGLETON
Definition: ruby.h:1215
struct rb_trace_arg_struct * rb_tracearg_from_tracepoint(VALUE tpval)
Definition: vm_trace.c:732
#define RB_TYPE_P(obj, type)
Definition: ruby.h:527
#define END(name)
Definition: asm.h:115
VALUE rb_binding_new(void)
Definition: proc.c:340
static rb_thread_t * thval2thread_t(VALUE thval)
Definition: vm_trace.c:96
#define TH_POP_TAG()
Definition: eval_intern.h:137
struct rb_thread_struct * th
Definition: vm_trace.c:1515
VALUE rb_tracearg_self(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:836
#define FL_TEST(x, f)
Definition: ruby.h:1284
int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp)
Definition: vm.c:2025
const rb_iseq_t * iseq
Definition: vm_core.h:634
VALUE rb_tracepoint_disable(VALUE tpval)
Definition: vm_trace.c:1045
VALUE default_inspect(VALUE self, const char *class_name)
Definition: win32ole.c:1336
#define ALLOC_N(type, n)
Definition: ruby.h:1587
int trace_running
Definition: vm_core.h:501
int rb_block_given_p(void)
Definition: eval.c:797
static VALUE tracepoint_stat_s(VALUE self)
Definition: vm_trace.c:1401
#define EXEC_TAG()
Definition: eval_intern.h:183
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:1576
int rb_threadptr_set_raised(rb_thread_t *th)
Definition: thread.c:2180
struct rb_event_hook_struct * next
Definition: vm_trace.c:37
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1872
VALUE rb_eRuntimeError
Definition: error.c:761
static VALUE tracepoint_enable_m(VALUE tpval)
Definition: vm_trace.c:1099
static void 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)
Definition: vm_trace.c:130
static VALUE rb_cTracePoint
Definition: vm_trace.c:643
VALUE rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:857
VALUE rb_tracepoint_enabled_p(VALUE tpval)
Definition: vm_trace.c:1173
static VALUE tracepoint_attr_defined_class(VALUE tpval)
Definition: vm_trace.c:968
#define NIL_P(v)
Definition: ruby.h:451
static VALUE thread_set_trace_func_m(VALUE obj, VALUE trace)
Definition: vm_trace.c:548
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:646
rb_control_frame_t * cfp
Definition: vm_core.h:1582
VALUE rb_tracearg_defined_class(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:815
int postponed_job_index
Definition: vm_core.h:533
int argc
Definition: ruby.c:183
VALUE proc
Definition: vm_trace.c:651
void(* rb_event_hook_func_t)(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass)
Definition: ruby.h:2096
#define Qfalse
Definition: ruby.h:436
rb_event_flag_t rb_tracearg_event_flag(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:738
VALUE rb_tracearg_binding(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:822
#define rb_str_new2
Definition: intern.h:857
#define RUBY_EVENT_C_CALL
Definition: ruby.h:2064
struct rb_event_hook_struct * hooks
Definition: vm_core.h:479
static void fill_path_and_lineno(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:750
#define ATOMIC_CAS(var, oldval, newval)
Definition: ruby_atomic.h:132
static int ruby_event_flag_count[MAX_EVENT_NUM]
Definition: vm_trace.c:44
#define ALLOC(type)
Definition: ruby.h:1588
static rb_event_hook_t * alloc_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
Definition: vm_trace.c:104
static VALUE tracepoint_inspect(VALUE self)
Definition: vm_trace.c:1324
static rb_event_flag_t symbol2event_flag(VALUE v)
Definition: vm_trace.c:683
static void exec_hooks_body(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:249
static void fill_id_and_klass(rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:780
#define RETURN(val)
Definition: dir.c:276
rb_hook_list_t event_hooks
Definition: vm_core.h:800
void rb_vm_pop_frame(rb_thread_t *th)
rb_event_hook_func_t func
Definition: vm_trace.c:35
#define RUBY_EVENT_SPECIFIED_LINE
Definition: ruby.h:2078
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1020
#define TRUE
Definition: nkf.h:175
VALUE rb_obj_is_proc(VALUE)
Definition: proc.c:117
static VALUE tracepoint_attr_raised_exception(VALUE tpval)
Definition: vm_trace.c:1007
int rb_thread_remove_event_hook_with_data(VALUE thval, rb_event_hook_func_t func, VALUE data)
Definition: vm_trace.c:196
#define C(name, NAME)
void * data
Definition: vm_trace.c:650
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1440
VALUE rb_hash_new(void)
Definition: hash.c:441
static int remove_event_hook(rb_hook_list_t *list, rb_event_hook_func_t func, VALUE data)
Definition: vm_trace.c:164
#define RUBY_EVENT_LINE
Definition: ruby.h:2059
#define PRIsVALUE
Definition: ruby.h:135
unsigned long ID
Definition: ruby.h:86
int rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func)
Definition: vm_trace.c:190
VALUE rb_vm_make_binding(rb_thread_t *th, const rb_control_frame_t *src_cfp)
Definition: vm.c:889
static VALUE tracepoint_attr_return_value(VALUE tpval)
Definition: vm_trace.c:998
#define Qnil
Definition: ruby.h:438
unsigned long VALUE
Definition: ruby.h:85
static VALUE result
Definition: nkf.c:40
RUBY_EXTERN VALUE rb_cThread
Definition: ruby.h:1909
#define RBASIC(obj)
Definition: ruby.h:1204
rb_event_hook_flag_t
Definition: debug.h:92
int rb_threadptr_reset_raised(rb_thread_t *th)
Definition: thread.c:2190
#define FIX2INT(x)
Definition: ruby.h:686
#define RUBY_EVENT_THREAD_BEGIN
Definition: ruby.h:2072
#define rb_ary_new3
Definition: intern.h:91
#define TH_PUSH_TAG(th)
Definition: eval_intern.h:131
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:923
static const rb_data_type_t tp_data_type
Definition: vm_trace.c:669
#define RUBY_EVENT_TRACEPOINT_ALL
Definition: ruby.h:2075
rb_event_hook_flag_t hook_flags
Definition: vm_trace.c:33
#define RUBY_INTERNAL_EVENT_MASK
Definition: ruby.h:2093
static int rb_threadptr_remove_event_hook(rb_thread_t *th, rb_event_hook_func_t func, VALUE data)
Definition: vm_trace.c:184
static VALUE tracepoint_attr_lineno(VALUE tpval)
Definition: vm_trace.c:901
#define MAX_POSTPONED_JOB
Definition: vm_trace.c:1520
static VALUE tracepoint_disable_m(VALUE tpval)
Definition: vm_trace.c:1150
int rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data)
Definition: vm_trace.c:1581
static rb_trace_arg_t * get_trace_arg(void)
Definition: vm_trace.c:722
VALUE rb_mRubyVMFrozenCore
Definition: vm.c:312
static void thread_add_trace_func(rb_thread_t *th, VALUE trace)
Definition: vm_trace.c:508
int rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data)
Definition: vm_trace.c:1565
static VALUE tracepoint_trace_s(int argc, VALUE *argv, VALUE self)
Definition: vm_trace.c:1308
struct rb_event_hook_struct rb_event_hook_t
static void tp_call_trace(VALUE tpval, rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:1013
#define MAX_EVENT_NUM
Definition: vm_trace.c:42
#define INT2FIX(i)
Definition: ruby.h:232
#define RUBY_TYPED_NEVER_FREE
Definition: ruby.h:1142
static int exec_hooks_precheck(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:266
unsigned long interrupt_mask
Definition: vm_core.h:762
VALUE rb_block_proc(void)
Definition: proc.c:787
static void tp_mark(void *ptr)
Definition: vm_trace.c:656
#define RUBY_INTERNAL_EVENT_NEWOBJ
Definition: ruby.h:2085
#define RUBY_INTERNAL_EVENT_FREEOBJ
Definition: ruby.h:2086
VALUE rb_tracepoint_enable(VALUE tpval)
Definition: vm_trace.c:1026
rb_hook_list_t event_hooks
Definition: vm_core.h:526
void rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
Definition: vm_trace.c:137
static VALUE tracepoint_attr_binding(VALUE tpval)
Definition: vm_trace.c:977
static int exec_hooks_protected(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:285
#define RTEST(v)
Definition: ruby.h:450
static enum postponed_job_register_result postponed_job_register(rb_thread_t *th, rb_vm_t *vm, unsigned int flags, rb_postponed_job_func_t func, void *data, int max, int expected_index)
Definition: vm_trace.c:1538
VALUE rb_suppress_tracing(VALUE(*func)(VALUE), VALUE arg)
Definition: vm_trace.c:387
rb_event_flag_t ruby_vm_event_flags
Definition: vm.c:318
struct rb_encoding_entry * list
Definition: encoding.c:55
rb_postponed_job_func_t func
Definition: vm_trace.c:1516
#define RUBY_EVENT_END
Definition: ruby.h:2061
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1182
#define UNLIKELY(x)
Definition: ffi_common.h:126
#define GetThreadPtr(obj, ptr)
Definition: vm_core.h:646
void rb_vm_trace_mark_event_hooks(rb_hook_list_t *hooks)
Definition: vm_trace.c:49
VALUE rb_tracepoint_new(VALUE target_thval, rb_event_flag_t events, void(*func)(VALUE, void *), void *data)
Definition: vm_trace.c:1226
struct rb_postponed_job_struct rb_postponed_job_t
VALUE self
Definition: vm_core.h:485
void rb_postponed_job_flush(rb_vm_t *vm)
Definition: vm_trace.c:1606
#define ID2SYM(x)
Definition: ruby.h:383
static void Init_postponed_job(void)
Definition: vm_trace.c:1524
rb_event_flag_t event
Definition: vm_core.h:1580
postponed_job_register_result
Definition: vm_trace.c:1531
#define MAX_POSTPONED_JOB_SPECIAL_ADDITION
Definition: vm_trace.c:1521
VALUE local_storage_recursive_hash
Definition: vm_core.h:774
struct rb_vm_tag * tag
Definition: vm_core.h:769
uint32_t rb_event_flag_t
Definition: ruby.h:2095
struct rb_vm_tag * prev
Definition: vm_core.h:666
struct list_head living_threads
Definition: vm_core.h:494
void rb_add_event_hook2(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data, rb_event_hook_flag_t hook_flags)
Definition: vm_trace.c:156
#define CONST_ID(var, str)
Definition: ruby.h:1743
struct rb_postponed_job_struct * postponed_job_buffer
Definition: vm_core.h:532
int rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, ID *called_idp, VALUE *klassp)
Definition: vm.c:2041
void void xfree(void *)
void(* rb_postponed_job_func_t)(void *arg)
Definition: debug.h:86
#define RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(th)
Definition: vm_core.h:1550
int rb_remove_event_hook_with_data(rb_event_hook_func_t func, VALUE data)
Definition: vm_trace.c:208
#define stat(path, st)
Definition: win32.h:183
#define Qundef
Definition: ruby.h:439
#define T_ICLASS
Definition: ruby.h:493
static VALUE tracepoint_attr_self(VALUE tpval)
Definition: vm_trace.c:989
#define CALL(n)
Definition: inits.c:14
void(* rb_event_hook_raw_arg_func_t)(VALUE data, const rb_trace_arg_t *arg)
Definition: vm_trace.c:40
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1515
static VALUE tracepoint_attr_method_id(VALUE tpval)
Definition: vm_trace.c:919
rb_event_flag_t events
Definition: vm_trace.c:34
VALUE rb_eThreadError
Definition: eval.c:814
rb_event_flag_t events
Definition: vm_trace.c:646
VALUE rb_eArgError
Definition: error.c:763
rb_control_frame_t * rb_vm_get_binding_creatable_next_cfp(const rb_thread_t *th, const rb_control_frame_t *cfp)
Definition: vm.c:477
static void exec_hooks_unprotected(rb_thread_t *th, rb_hook_list_t *list, const rb_trace_arg_t *trace_arg)
Definition: vm_trace.c:278
struct rb_trace_arg_struct * trace_arg
Definition: vm_core.h:801
#define RUBY_EVENT_B_CALL
Definition: ruby.h:2070
void(* func)(VALUE tpval, void *data)
Definition: vm_trace.c:649
char ** argv
Definition: ruby.c:184
rb_iseq_location_t location
Definition: vm_core.h:358
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
Definition: vm_trace.c:143
#define rb_sym2str(sym)
Definition: console.c:107
static VALUE tracepoint_new_s(int argc, VALUE *argv, VALUE self)
Definition: vm_trace.c:1286
#define GET_VM()
Definition: vm_core.h:1507