Feature #2565 » dtrace.patch
| .gitignore | ||
|---|---|---|
| 
     /exts.mk 
   | 
||
| 
     /goruby 
   | 
||
| 
     /id.h 
   | 
||
| 
     /probes.h 
   | 
||
| 
     /largefile.h 
   | 
||
| 
     /lex.c 
   | 
||
| 
     /libruby*.* 
   | 
||
| Makefile.in | ||
|---|---|---|
| 
     OBJCOPY       = @OBJCOPY@ 
   | 
||
| 
     VCS           = @VCS@ 
   | 
||
| 
     VCSUP         = @VCSUP@ 
   | 
||
| 
     DTRACE        = @DTRACE@ 
   | 
||
| 
     OBJEXT        = @OBJEXT@ 
   | 
||
| 
     ASMEXT        = S 
   | 
||
| ... | ... | |
| 
     $(srcdir)/configure: $(srcdir)/configure.in 
   | 
||
| 
     	$(CHDIR) $(srcdir) && exec $(AUTOCONF) 
   | 
||
| 
     incs: id.h 
   | 
||
| 
     incs: id.h probes.h 
   | 
||
| 
     # Things which should be considered: 
   | 
||
| 
     # * with gperf v.s. without gperf 
   | 
||
| ... | ... | |
| 
     	@$(ECHO) preprocessing $< 
   | 
||
| 
     	$(Q) $(CPP) $(warnflags) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -E $< > $@ 
   | 
||
| 
     .d.h: 
   | 
||
| 
     	@$(ECHO) translating probes $< 
   | 
||
| 
     	$(Q)if test -n '$(DTRACE)'; then\ 
   | 
||
| 
     	  $(DTRACE) -o $@.tmp -h -s $<; \ 
   | 
||
| 
     	  sed -e 's/RUBY_/RUBY_DTRACE_/g' $@.tmp | sed -e 's/PROBES_H_TMP/PROBES_H/g' >$@; \ 
   | 
||
| 
     	  rm $@.tmp; \ 
   | 
||
| 
     	else \ 
   | 
||
| 
     	  sed -f $(srcdir)/tool/gen_dummy_probes.sed $< > $@; \ 
   | 
||
| 
     	fi 
   | 
||
| 
     clean-local:: 
   | 
||
| 
     	$(Q)$(RM) ext/extinit.c ext/extinit.$(OBJEXT) ext/ripper/y.output \ 
   | 
||
| 
     		enc/encinit.c enc/encinit.$(OBJEXT) 
   | 
||
| common.mk | ||
|---|---|---|
| 
     lib: $(LIBRUBY) 
   | 
||
| 
     dll: $(LIBRUBY_SO) 
   | 
||
| 
     .SUFFIXES: .inc .h .c .y .i 
   | 
||
| 
     .SUFFIXES: .inc .h .c .y .i .d 
   | 
||
| 
     # V=0 quiet, V=1 verbose.  other values don't work. 
   | 
||
| 
     V = 0 
   | 
||
| ... | ... | |
| 
     		     {$(VPATH)}subst.h 
   | 
||
| 
     ENCODING_H_INCLUDES= {$(VPATH)}encoding.h {$(VPATH)}oniguruma.h 
   | 
||
| 
     ID_H_INCLUDES      = {$(VPATH)}id.h {$(VPATH)}vm_opts.h 
   | 
||
| 
     PROBES_H_INCLUDES  = {$(VPATH)}probes.h 
   | 
||
| 
     VM_CORE_H_INCLUDES = {$(VPATH)}vm_core.h {$(VPATH)}thread_$(THREAD_MODEL).h \ 
   | 
||
| 
     		     {$(VPATH)}node.h {$(VPATH)}method.h {$(VPATH)}atomic.h \ 
   | 
||
| 
     		     $(ID_H_INCLUDES) 
   | 
||
| ... | ... | |
| 
     eval.$(OBJEXT): {$(VPATH)}eval.c {$(VPATH)}eval_intern.h {$(VPATH)}vm.h \ 
   | 
||
| 
       $(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) {$(VPATH)}eval_error.c \ 
   | 
||
| 
       {$(VPATH)}eval_jump.c {$(VPATH)}debug.h {$(VPATH)}gc.h {$(VPATH)}iseq.h \ 
   | 
||
| 
       $(ENCODING_H_INCLUDES) {$(VPATH)}internal.h 
   | 
||
| 
       $(ENCODING_H_INCLUDES) {$(VPATH)}internal.h $(PROBES_H_INCLUDES) 
   | 
||
| 
     load.$(OBJEXT): {$(VPATH)}load.c {$(VPATH)}eval_intern.h \ 
   | 
||
| 
       {$(VPATH)}util.h $(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) \ 
   | 
||
| 
       {$(VPATH)}dln.h {$(VPATH)}debug.h \ 
   | 
||
| 
       {$(VPATH)}internal.h 
   | 
||
| 
       {$(VPATH)}internal.h $(PROBES_H_INCLUDES) 
   | 
||
| 
     file.$(OBJEXT): {$(VPATH)}file.c $(RUBY_H_INCLUDES) {$(VPATH)}io.h \ 
   | 
||
| 
       $(ENCODING_H_INCLUDES) {$(VPATH)}util.h {$(VPATH)}dln.h \ 
   | 
||
| 
       {$(VPATH)}internal.h 
   | 
||
| ... | ... | |
| 
       {$(VPATH)}regex.h $(ENCODING_H_INCLUDES) $(VM_CORE_H_INCLUDES) \ 
   | 
||
| 
       {$(VPATH)}gc.h {$(VPATH)}io.h {$(VPATH)}eval_intern.h {$(VPATH)}util.h \ 
   | 
||
| 
       {$(VPATH)}debug.h {$(VPATH)}internal.h {$(VPATH)}constant.h \ 
   | 
||
| 
       {$(VPATH)}thread.h 
   | 
||
| 
       {$(VPATH)}thread.h $(PROBES_H_INCLUDES) 
   | 
||
| 
     hash.$(OBJEXT): {$(VPATH)}hash.c $(RUBY_H_INCLUDES) {$(VPATH)}util.h \ 
   | 
||
| 
       $(ENCODING_H_INCLUDES) 
   | 
||
| 
     inits.$(OBJEXT): {$(VPATH)}inits.c $(RUBY_H_INCLUDES) \ 
   | 
||
| ... | ... | |
| 
     numeric.$(OBJEXT): {$(VPATH)}numeric.c $(RUBY_H_INCLUDES) \ 
   | 
||
| 
       {$(VPATH)}util.h $(ENCODING_H_INCLUDES) {$(VPATH)}internal.h 
   | 
||
| 
     object.$(OBJEXT): {$(VPATH)}object.c $(RUBY_H_INCLUDES) {$(VPATH)}util.h \ 
   | 
||
| 
       {$(VPATH)}internal.h {$(VPATH)}constant.h $(ENCODING_H_INCLUDES) 
   | 
||
| 
       {$(VPATH)}internal.h {$(VPATH)}constant.h $(ENCODING_H_INCLUDES) $(PROBES_H_INCLUDES) 
   | 
||
| 
     pack.$(OBJEXT): {$(VPATH)}pack.c $(RUBY_H_INCLUDES) {$(VPATH)}encoding.h \ 
   | 
||
| 
       {$(VPATH)}oniguruma.h 
   | 
||
| 
     parse.$(OBJEXT): {$(VPATH)}parse.c $(RUBY_H_INCLUDES) {$(VPATH)}node.h \ 
   | 
||
| ... | ... | |
| 
     iseq.$(OBJEXT): {$(VPATH)}iseq.c {$(VPATH)}gc.h {$(VPATH)}iseq.h \ 
   | 
||
| 
       $(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) {$(VPATH)}insns.inc \ 
   | 
||
| 
       {$(VPATH)}insns_info.inc {$(VPATH)}node_name.inc {$(VPATH)}debug.h {$(VPATH)}internal.h 
   | 
||
| 
     {$(VPATH)}vm_insnhelper.c:$(PROBES_H_INCLUDES) 
   | 
||
| 
     vm.$(OBJEXT): {$(VPATH)}vm.c {$(VPATH)}gc.h {$(VPATH)}iseq.h \ 
   | 
||
| 
       {$(VPATH)}eval_intern.h $(RUBY_H_INCLUDES) $(ENCODING_H_INCLUDES) \ 
   | 
||
| 
       $(VM_CORE_H_INCLUDES) {$(VPATH)}vm_method.c {$(VPATH)}vm_eval.c \ 
   | 
||
| configure.in | ||
|---|---|---|
| 
     if test x"${build}" != x"${host}"; then 
   | 
||
| 
       AC_CHECK_TOOL(CC, gcc) 
   | 
||
| 
     fi 
   | 
||
| 
     AC_CHECK_TOOL(DTRACE, dtrace) 
   | 
||
| 
     RUBY_MINGW32 
   | 
||
| 
     AC_PROG_CC 
   | 
||
| 
     AC_PROG_CXX 
   | 
||
| eval.c | ||
|---|---|---|
| 
     #include "ruby/encoding.h" 
   | 
||
| 
     #include "internal.h" 
   | 
||
| 
     #include "vm_core.h" 
   | 
||
| 
     #include "probes.h" 
   | 
||
| 
     #define numberof(array) (int)(sizeof(array) / sizeof((array)[0])) 
   | 
||
| ... | ... | |
| 
         } 
   | 
||
| 
         if (tag != TAG_FATAL) { 
   | 
||
| 
     	if(RUBY_DTRACE_RAISE_ENABLED()) { 
   | 
||
| 
     	    RUBY_DTRACE_RAISE(rb_obj_classname(th->errinfo), 
   | 
||
| 
     		    rb_sourcefile(), 
   | 
||
| 
     		    rb_sourceline()); 
   | 
||
| 
     	} 
   | 
||
| 
     	EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self, 0, 0); 
   | 
||
| 
         } 
   | 
||
| 
     } 
   | 
||
| gc.c | ||
|---|---|---|
| 
     #include "gc.h" 
   | 
||
| 
     #include "constant.h" 
   | 
||
| 
     #include "atomic.h" 
   | 
||
| 
     #include "probes.h" 
   | 
||
| 
     #include <stdio.h> 
   | 
||
| 
     #include <setjmp.h> 
   | 
||
| 
     #include <sys/types.h> 
   | 
||
| ... | ... | |
| 
     } 
   | 
||
| 
     #define GC_PROF_TIMER_START do {\ 
   | 
||
| 
     	if (RUBY_DTRACE_GC_BEGIN_ENABLED()) { \ 
   | 
||
| 
     	    RUBY_DTRACE_GC_BEGIN(); \ 
   | 
||
| 
     	} \ 
   | 
||
| 
     	if (objspace->profile.run) {\ 
   | 
||
| 
     	    if (!objspace->profile.record) {\ 
   | 
||
| 
     		objspace->profile.size = 1000;\ 
   | 
||
| ... | ... | |
| 
         } while(0) 
   | 
||
| 
     #define GC_PROF_TIMER_STOP(marked) do {\ 
   | 
||
| 
     	if (RUBY_DTRACE_GC_END_ENABLED()) { \ 
   | 
||
| 
     	    RUBY_DTRACE_GC_END(); \ 
   | 
||
| 
     	} \ 
   | 
||
| 
     	if (objspace->profile.run) {\ 
   | 
||
| 
     	    gc_time = getrusage_time() - gc_time;\ 
   | 
||
| 
     	    if (gc_time < 0) gc_time = 0;\ 
   | 
||
| ... | ... | |
| 
         during_gc++; 
   | 
||
| 
         GC_PROF_TIMER_START; 
   | 
||
| 
         if (RUBY_DTRACE_GC_SWEEP_BEGIN_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_GC_SWEEP_BEGIN(); 
   | 
||
| 
         } 
   | 
||
| 
         GC_PROF_SWEEP_TIMER_START; 
   | 
||
| 
         if (objspace->heap.sweep_slots) { 
   | 
||
| 
             res = lazy_sweep(objspace); 
   | 
||
| 
             if (res) { 
   | 
||
| 
     	    if (RUBY_DTRACE_GC_SWEEP_END_ENABLED()) { 
   | 
||
| 
     		RUBY_DTRACE_GC_SWEEP_END(); 
   | 
||
| 
     	    } 
   | 
||
| 
                 GC_PROF_SWEEP_TIMER_STOP; 
   | 
||
| 
                 GC_PROF_SET_MALLOC_INFO; 
   | 
||
| 
                 GC_PROF_TIMER_STOP(Qfalse); 
   | 
||
| ... | ... | |
| 
     	set_heaps_increment(objspace); 
   | 
||
| 
         } 
   | 
||
| 
         if (RUBY_DTRACE_GC_SWEEP_BEGIN_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_GC_SWEEP_BEGIN(); 
   | 
||
| 
         } 
   | 
||
| 
         GC_PROF_SWEEP_TIMER_START; 
   | 
||
| 
         if (!(res = lazy_sweep(objspace))) { 
   | 
||
| 
             after_gc_sweep(objspace); 
   | 
||
| ... | ... | |
| 
                 during_gc = 0; 
   | 
||
| 
             } 
   | 
||
| 
         } 
   | 
||
| 
         if (RUBY_DTRACE_GC_SWEEP_END_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_GC_SWEEP_END(); 
   | 
||
| 
         } 
   | 
||
| 
         GC_PROF_SWEEP_TIMER_STOP; 
   | 
||
| 
         GC_PROF_TIMER_STOP(Qtrue); 
   | 
||
| ... | ... | |
| 
     { 
   | 
||
| 
         struct gc_list *list; 
   | 
||
| 
         rb_thread_t *th = GET_THREAD(); 
   | 
||
| 
         if (RUBY_DTRACE_GC_MARK_BEGIN_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_GC_MARK_BEGIN(); 
   | 
||
| 
         } 
   | 
||
| 
         GC_PROF_MARK_TIMER_START; 
   | 
||
| 
         objspace->heap.live_num = 0; 
   | 
||
| ... | ... | |
| 
     	    gc_mark_rest(objspace); 
   | 
||
| 
     	} 
   | 
||
| 
         } 
   | 
||
| 
         if (RUBY_DTRACE_GC_MARK_END_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_GC_MARK_END(); 
   | 
||
| 
         } 
   | 
||
| 
         GC_PROF_MARK_TIMER_STOP; 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
         during_gc++; 
   | 
||
| 
         gc_marks(objspace); 
   | 
||
| 
         if (RUBY_DTRACE_GC_SWEEP_BEGIN_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_GC_SWEEP_BEGIN(); 
   | 
||
| 
         } 
   | 
||
| 
         GC_PROF_SWEEP_TIMER_START; 
   | 
||
| 
         gc_sweep(objspace); 
   | 
||
| 
         if (RUBY_DTRACE_GC_SWEEP_END_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_GC_SWEEP_END(); 
   | 
||
| 
         } 
   | 
||
| 
         GC_PROF_SWEEP_TIMER_STOP; 
   | 
||
| 
         GC_PROF_TIMER_STOP(Qtrue); 
   | 
||
| insns.def | ||
|---|---|---|
| 
     () 
   | 
||
| 
     (VALUE val) 
   | 
||
| 
     { 
   | 
||
| 
         if(RUBY_DTRACE_OBJECT_CREATE_START_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_OBJECT_CREATE_START("String", rb_sourcefile(), rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         val = rb_str_resurrect(str); 
   | 
||
| 
         if(RUBY_DTRACE_OBJECT_CREATE_DONE_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_OBJECT_CREATE_DONE("String", rb_sourcefile(), rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
     } 
   | 
||
| 
     /** 
   | 
||
| ... | ... | |
| 
     (...) 
   | 
||
| 
     (VALUE val) // inc += 1 - num; 
   | 
||
| 
     { 
   | 
||
| 
         if(RUBY_DTRACE_OBJECT_CREATE_START_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_OBJECT_CREATE_START("Array", rb_sourcefile(), rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         val = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num)); 
   | 
||
| 
         if(RUBY_DTRACE_OBJECT_CREATE_DONE_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_OBJECT_CREATE_DONE("Array", rb_sourcefile(), rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         POPN(num); 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     (VALUE val) // inc += 1 - num; 
   | 
||
| 
     { 
   | 
||
| 
         rb_num_t i; 
   | 
||
| 
         if(RUBY_DTRACE_OBJECT_CREATE_START_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_OBJECT_CREATE_START("Hash", rb_sourcefile(), rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         val = rb_hash_new(); 
   | 
||
| 
         if(RUBY_DTRACE_OBJECT_CREATE_DONE_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_OBJECT_CREATE_DONE("Hash", rb_sourcefile(), rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         for (i = num; i > 0; i -= 2) { 
   | 
||
| 
     	const VALUE v = TOPN(i - 2); 
   | 
||
| 
     	const VALUE k = TOPN(i - 1); 
   | 
||
| ... | ... | |
| 
     { 
   | 
||
| 
         rb_event_flag_t flag = (rb_event_flag_t)nf; 
   | 
||
| 
         if (RUBY_DTRACE_LINE_ENABLED()) { 
   | 
||
| 
     	if (flag == RUBY_EVENT_LINE) { 
   | 
||
| 
               RUBY_DTRACE_LINE(rb_sourcefile(), rb_sourceline()); 
   | 
||
| 
     	} 
   | 
||
| 
         } 
   | 
||
| 
         if (RUBY_DTRACE_FUNCTION_ENTRY_ENABLED()) { 
   | 
||
| 
             if (flag == RUBY_EVENT_CALL || flag == RUBY_EVENT_C_CALL) { 
   | 
||
| 
               VALUE klass; 
   | 
||
| 
               ID called_id; 
   | 
||
| 
               rb_thread_method_id_and_class(th, &called_id, &klass); 
   | 
||
| 
               RUBY_DTRACE_FUNCTION_ENTRY( 
   | 
||
| 
                       RSTRING_PTR(rb_inspect(klass)), 
   | 
||
| 
                       rb_id2name(called_id), 
   | 
||
| 
                       rb_sourcefile(), 
   | 
||
| 
                       rb_sourceline()); 
   | 
||
| 
             } 
   | 
||
| 
         } 
   | 
||
| 
         if (RUBY_DTRACE_FUNCTION_RETURN_ENABLED()) { 
   | 
||
| 
             if (flag == RUBY_EVENT_RETURN || flag == RUBY_EVENT_C_RETURN) { 
   | 
||
| 
               VALUE klass; 
   | 
||
| 
               ID called_id; 
   | 
||
| 
               rb_thread_method_id_and_class(th, &called_id, &klass); 
   | 
||
| 
               RUBY_DTRACE_FUNCTION_RETURN( 
   | 
||
| 
                       RSTRING_PTR(rb_inspect(klass)), 
   | 
||
| 
                       rb_id2name(called_id), 
   | 
||
| 
                       rb_sourcefile(), 
   | 
||
| 
                       rb_sourceline()); 
   | 
||
| 
             } 
   | 
||
| 
         } 
   | 
||
| 
         EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */); 
   | 
||
| 
     } 
   | 
||
| load.c | ||
|---|---|---|
| 
     #include "internal.h" 
   | 
||
| 
     #include "dln.h" 
   | 
||
| 
     #include "eval_intern.h" 
   | 
||
| 
     #include "probes.h" 
   | 
||
| 
     VALUE ruby_dln_librefs; 
   | 
||
| ... | ... | |
| 
         VALUE fname, wrap, path; 
   | 
||
| 
         rb_scan_args(argc, argv, "11", &fname, &wrap); 
   | 
||
| 
         if(RUBY_DTRACE_LOAD_ENTRY_ENABLED()) { 
   | 
||
| 
           RUBY_DTRACE_LOAD_ENTRY( 
   | 
||
| 
               StringValuePtr(fname), 
   | 
||
| 
               rb_sourcefile(), 
   | 
||
| 
               rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         path = rb_find_file(FilePathValue(fname)); 
   | 
||
| 
         if (!path) { 
   | 
||
| 
     	if (!rb_file_load_ok(RSTRING_PTR(fname))) 
   | 
||
| ... | ... | |
| 
     	path = fname; 
   | 
||
| 
         } 
   | 
||
| 
         rb_load_internal(path, RTEST(wrap)); 
   | 
||
| 
         if(RUBY_DTRACE_LOAD_RETURN_ENABLED()) { 
   | 
||
| 
           RUBY_DTRACE_LOAD_RETURN(StringValuePtr(fname)); 
   | 
||
| 
         } 
   | 
||
| 
         return Qtrue; 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
         } volatile saved; 
   | 
||
| 
         char *volatile ftptr = 0; 
   | 
||
| 
         if(RUBY_DTRACE_REQUIRE_ENTRY_ENABLED()) { 
   | 
||
| 
           RUBY_DTRACE_REQUIRE_ENTRY( 
   | 
||
| 
               StringValuePtr(fname), 
   | 
||
| 
               rb_sourcefile(), 
   | 
||
| 
               rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         PUSH_TAG(); 
   | 
||
| 
         saved.safe = rb_safe_level(); 
   | 
||
| 
         if ((state = EXEC_TAG()) == 0) { 
   | 
||
| ... | ... | |
| 
         th->errinfo = errinfo; 
   | 
||
| 
         if(RUBY_DTRACE_REQUIRE_RETURN_ENABLED()) { 
   | 
||
| 
           RUBY_DTRACE_REQUIRE_RETURN(StringValuePtr(fname)); 
   | 
||
| 
         } 
   | 
||
| 
         return result; 
   | 
||
| 
     } 
   | 
||
| object.c | ||
|---|---|---|
| 
     #include <float.h> 
   | 
||
| 
     #include "constant.h" 
   | 
||
| 
     #include "internal.h" 
   | 
||
| 
     #include "probes.h" 
   | 
||
| 
     VALUE rb_cBasicObject; 
   | 
||
| 
     VALUE rb_mKernel; 
   | 
||
| ... | ... | |
| 
         if (FL_TEST(klass, FL_SINGLETON)) { 
   | 
||
| 
     	rb_raise(rb_eTypeError, "can't create instance of singleton class"); 
   | 
||
| 
         } 
   | 
||
| 
         if (RUBY_DTRACE_OBJECT_CREATE_START_ENABLED()) { 
   | 
||
| 
             const char * file = rb_sourcefile(); 
   | 
||
| 
             RUBY_DTRACE_OBJECT_CREATE_START(rb_class2name(klass), 
   | 
||
| 
                                      file ? file : "", 
   | 
||
| 
                                      rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         obj = rb_funcall(klass, ID_ALLOCATOR, 0, 0); 
   | 
||
| 
         if (RUBY_DTRACE_OBJECT_CREATE_DONE_ENABLED()) { 
   | 
||
| 
             const char * file = rb_sourcefile(); 
   | 
||
| 
             RUBY_DTRACE_OBJECT_CREATE_DONE(rb_class2name(klass), 
   | 
||
| 
                                      file ? file : "", 
   | 
||
| 
                                      rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         if (rb_obj_class(obj) != rb_class_real(klass)) { 
   | 
||
| 
     	rb_raise(rb_eTypeError, "wrong instance allocation"); 
   | 
||
| 
         } 
   | 
||
| probes.d | ||
|---|---|---|
| 
     provider ruby { 
   | 
||
| 
       probe function__entry(const char *, const char *, const char *, int); 
   | 
||
| 
       probe function__return(const char *, const char *, const char *, int); 
   | 
||
| 
       probe require__entry(const char *, const char *, int); 
   | 
||
| 
       probe require__return(const char *); 
   | 
||
| 
       probe load__entry(const char *, const char *, int); 
   | 
||
| 
       probe load__return(const char *); 
   | 
||
| 
       probe raise(const char *, const char *, int); 
   | 
||
| 
       probe object__create__start(const char *, const char *, int); 
   | 
||
| 
       probe object__create__done(const char *, const char *, int); 
   | 
||
| 
       probe gc__begin(); 
   | 
||
| 
       probe gc__end(); 
   | 
||
| 
       probe gc__mark__begin(); 
   | 
||
| 
       probe gc__mark__end(); 
   | 
||
| 
       probe gc__sweep__begin(); 
   | 
||
| 
       probe gc__sweep__end(); 
   | 
||
| 
       probe line(const char *, int); 
   | 
||
| 
     }; 
   | 
||
| 
     #pragma D attributes Stable/Evolving/Common provider ruby provider 
   | 
||
| 
     #pragma D attributes Stable/Evolving/Common provider ruby module 
   | 
||
| 
     #pragma D attributes Stable/Evolving/Common provider ruby function 
   | 
||
| 
     #pragma D attributes Evolving/Evolving/Common provider ruby name 
   | 
||
| 
     #pragma D attributes Evolving/Evolving/Common provider ruby args 
   | 
||
| test/dtrace/dummy.rb | ||
|---|---|---|
| 
     # this is a dummy file used by test/dtrace/test_require.rb 
   | 
||
| test/dtrace/helper.rb | ||
|---|---|---|
| 
     require 'minitest/autorun' 
   | 
||
| 
     require 'tempfile' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestCase < MiniTest::Unit::TestCase 
   | 
||
| 
         INCLUDE = File.expand_path(File.join(File.dirname(__FILE__), '..')) 
   | 
||
| 
         def setup 
   | 
||
| 
           skip "must be setuid 0 to run dtrace tests" unless Process.euid == 0 
   | 
||
| 
         end 
   | 
||
| 
         def trap_probe d_program, ruby_program 
   | 
||
| 
           d = Tempfile.new('probe.d') 
   | 
||
| 
           d.write d_program 
   | 
||
| 
           d.flush 
   | 
||
| 
           rb = Tempfile.new('probed.rb') 
   | 
||
| 
           rb.write ruby_program 
   | 
||
| 
           rb.flush 
   | 
||
| 
           d_path  = d.path 
   | 
||
| 
           rb_path = rb.path 
   | 
||
| 
           cmd = "dtrace -q -s #{d_path} -c '#{Gem.ruby} -I#{INCLUDE} #{rb_path}'" 
   | 
||
| 
           probes = IO.popen(cmd) do |io| 
   | 
||
| 
             io.readlines 
   | 
||
| 
           end 
   | 
||
| 
           d.close(true) 
   | 
||
| 
           rb.close(true) 
   | 
||
| 
           yield(d_path, rb_path, probes) 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| test/dtrace/test_function_entry.rb | ||
|---|---|---|
| 
     require 'dtrace/helper' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestFunctionEntry < TestCase 
   | 
||
| 
         def test_function_entry 
   | 
||
| 
           probe = <<-eoprobe 
   | 
||
| 
     ruby$target:::function-entry 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
           trap_probe(probe, ruby_program) { |d_file, rb_file, probes| 
   | 
||
| 
     	foo_calls = probes.map { |line| line.split }.find_all { |row| 
   | 
||
| 
     	  row.first == 'Foo'  && row[1] == 'foo' 
   | 
||
| 
     	} 
   | 
||
| 
     	assert_equal 10, foo_calls.length 
   | 
||
| 
     	line = '2' 
   | 
||
| 
     	foo_calls.each { |f| assert_equal line, f[3] } 
   | 
||
| 
     	foo_calls.each { |f| assert_equal rb_file, f[2] } 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_function_return 
   | 
||
| 
           probe = <<-eoprobe 
   | 
||
| 
     ruby$target:::function-return 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
           trap_probe(probe, ruby_program) { |d_file, rb_file, probes| 
   | 
||
| 
     	foo_calls = probes.map { |line| line.split }.find_all { |row| 
   | 
||
| 
     	  row.first == 'Foo'  && row[1] == 'foo' 
   | 
||
| 
     	} 
   | 
||
| 
     	assert_equal 10, foo_calls.length 
   | 
||
| 
     	line = '2' 
   | 
||
| 
     	foo_calls.each { |f| assert_equal line, f[3] } 
   | 
||
| 
     	foo_calls.each { |f| assert_equal rb_file, f[2] } 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         private 
   | 
||
| 
         def ruby_program 
   | 
||
| 
           <<-eoruby 
   | 
||
| 
           class Foo 
   | 
||
| 
     	def foo; end 
   | 
||
| 
           end 
   | 
||
| 
           x = Foo.new 
   | 
||
| 
           10.times { x.foo } 
   | 
||
| 
           eoruby 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| test/dtrace/test_gc.rb | ||
|---|---|---|
| 
     require 'dtrace/helper' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestGC < TestCase 
   | 
||
| 
         %w{ 
   | 
||
| 
           gc-begin 
   | 
||
| 
           gc-end 
   | 
||
| 
           gc-mark-begin 
   | 
||
| 
           gc-mark-end 
   | 
||
| 
           gc-sweep-begin 
   | 
||
| 
           gc-sweep-end 
   | 
||
| 
         }.each do |probe_name| 
   | 
||
| 
           define_method(:"test_#{probe_name.gsub(/-/, '_')}") do 
   | 
||
| 
     	probe = "ruby$target:::#{probe_name} { printf(\"#{probe_name}\\n\"); }" 
   | 
||
| 
     	trap_probe(probe, ruby_program) { |_, _, saw| 
   | 
||
| 
     	  assert_operator saw.length, :>, 0 
   | 
||
| 
     	} 
   | 
||
| 
           end 
   | 
||
| 
         end 
   | 
||
| 
         private 
   | 
||
| 
         def ruby_program 
   | 
||
| 
           "100000.times { Object.new }" 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| test/dtrace/test_line.rb | ||
|---|---|---|
| 
     require 'dtrace/helper' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestLine < TestCase 
   | 
||
| 
         def test_line 
   | 
||
| 
           probe = "ruby$target:::line { printf(\"%s %d\\n\", copyinstr(arg0), arg1); }" 
   | 
||
| 
           program = 'x = 2; 10.times { x = x ** 2 }' 
   | 
||
| 
           trap_probe(probe, program) { |_, rbpath, saw| 
   | 
||
| 
     	saw = saw.map(&:split).find_all { |file, _| 
   | 
||
| 
     	  file == rbpath 
   | 
||
| 
     	} 
   | 
||
| 
     	assert_operator saw.length, :>=, 10 
   | 
||
| 
     	saw.each { |f,l| assert_equal '1', l } 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| test/dtrace/test_load.rb | ||
|---|---|---|
| 
     require 'dtrace/helper' 
   | 
||
| 
     require 'tempfile' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestLoad < TestCase 
   | 
||
| 
         def setup 
   | 
||
| 
           super 
   | 
||
| 
           @rbfile = Tempfile.new(['omg', 'rb']) 
   | 
||
| 
           @rbfile.write 'x = 10' 
   | 
||
| 
         end 
   | 
||
| 
         def teardown 
   | 
||
| 
           super 
   | 
||
| 
           @rbfile.close(true) if @rbfile 
   | 
||
| 
         end 
   | 
||
| 
         def test_load_entry 
   | 
||
| 
           probe = <<-eoprobe 
   | 
||
| 
     ruby$target:::load-entry 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
           trap_probe(probe, program) { |dpath, rbpath, saw| 
   | 
||
| 
     	saw = saw.map(&:split).find_all { |loaded, _, _| 
   | 
||
| 
     	  loaded == @rbfile.path 
   | 
||
| 
     	} 
   | 
||
| 
     	assert_equal 10, saw.length 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_load_return 
   | 
||
| 
           probe = <<-eoprobe 
   | 
||
| 
     ruby$target:::load-return 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s\\n", copyinstr(arg0)); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
           trap_probe(probe, program) { |dpath, rbpath, saw| 
   | 
||
| 
     	saw = saw.map(&:split).find_all { |loaded, _, _| 
   | 
||
| 
     	  loaded == @rbfile.path 
   | 
||
| 
     	} 
   | 
||
| 
     	assert_equal 10, saw.length 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         private 
   | 
||
| 
         def program 
   | 
||
| 
           "10.times { load '#{@rbfile.path}' }" 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| test/dtrace/test_object_create_done.rb | ||
|---|---|---|
| 
     require 'dtrace/helper' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestObjectCreateDone < TestCase 
   | 
||
| 
         def test_object 
   | 
||
| 
           trap_probe(probe, '10.times { Object.new }') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |_, file, _| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal 10, saw.length 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_object_name 
   | 
||
| 
           trap_probe(probe, 'Hash.new') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |klass, file, line| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal(%w{ Hash }, saw.map(&:first)) 
   | 
||
| 
             assert_equal([rbfile], saw.map { |line| line[1] }) 
   | 
||
| 
             assert_equal(['1'], saw.map { |line| line[2] }) 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_hash_lit 
   | 
||
| 
           trap_probe(probe, '{}') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |klass, file, line| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal(%w{ Hash }, saw.map(&:first)) 
   | 
||
| 
             assert_equal([rbfile], saw.map { |line| line[1] }) 
   | 
||
| 
             assert_equal(['1'], saw.map { |line| line[2] }) 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_array_lit 
   | 
||
| 
           trap_probe(probe, '[]') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |klass, file, line| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal(%w{ Array }, saw.map(&:first)) 
   | 
||
| 
             assert_equal([rbfile], saw.map { |line| line[1] }) 
   | 
||
| 
             assert_equal(['1'], saw.map { |line| line[2] }) 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_string_lit 
   | 
||
| 
           trap_probe(probe, '"omg"') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |klass, file, line| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal(%w{ String }, saw.map(&:first)) 
   | 
||
| 
             assert_equal([rbfile], saw.map { |line| line[1] }) 
   | 
||
| 
             assert_equal(['1'], saw.map { |line| line[2] }) 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         private 
   | 
||
| 
         def probe 
   | 
||
| 
           <<-eoprobe 
   | 
||
| 
     ruby$target:::object-create-done 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| test/dtrace/test_object_create_start.rb | ||
|---|---|---|
| 
     require 'dtrace/helper' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestObjectCreateStart < TestCase 
   | 
||
| 
         def test_object_create_start 
   | 
||
| 
           trap_probe(probe, '10.times { Object.new }') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |_, file, _| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal 10, saw.length 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_object_create_start_name 
   | 
||
| 
           trap_probe(probe, 'Hash.new') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |klass, file, line| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal(%w{ Hash }, saw.map(&:first)) 
   | 
||
| 
             assert_equal([rbfile], saw.map { |line| line[1] }) 
   | 
||
| 
             assert_equal(['1'], saw.map { |line| line[2] }) 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_object_create_start_hash_lit 
   | 
||
| 
           trap_probe(probe, '{}') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |klass, file, line| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal(%w{ Hash }, saw.map(&:first)) 
   | 
||
| 
             assert_equal([rbfile], saw.map { |line| line[1] }) 
   | 
||
| 
             assert_equal(['1'], saw.map { |line| line[2] }) 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_object_create_start_array_lit 
   | 
||
| 
           trap_probe(probe, '[]') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |klass, file, line| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal(%w{ Array }, saw.map(&:first)) 
   | 
||
| 
             assert_equal([rbfile], saw.map { |line| line[1] }) 
   | 
||
| 
             assert_equal(['1'], saw.map { |line| line[2] }) 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_object_create_start_string_lit 
   | 
||
| 
           trap_probe(probe, '"omg"') { |_,rbfile,saw| 
   | 
||
| 
             saw = saw.map(&:split).find_all { |klass, file, line| 
   | 
||
| 
               file == rbfile 
   | 
||
| 
             } 
   | 
||
| 
             assert_equal(%w{ String }, saw.map(&:first)) 
   | 
||
| 
             assert_equal([rbfile], saw.map { |line| line[1] }) 
   | 
||
| 
             assert_equal(['1'], saw.map { |line| line[2] }) 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         private 
   | 
||
| 
         def probe 
   | 
||
| 
           <<-eoprobe 
   | 
||
| 
     ruby$target:::object-create-start 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| test/dtrace/test_raise.rb | ||
|---|---|---|
| 
     require 'dtrace/helper' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestRaise < TestCase 
   | 
||
| 
         def test_raise 
   | 
||
| 
           probe = <<-eoprobe 
   | 
||
| 
     ruby$target:::raise 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
           trap_probe(probe, program) { |dpath, rbpath, saw| 
   | 
||
| 
     	saw = saw.map(&:split).find_all { |_, source_file, _| 
   | 
||
| 
     	  source_file == rbpath 
   | 
||
| 
     	} 
   | 
||
| 
     	assert_equal 10, saw.length 
   | 
||
| 
     	saw.each do |klass, _, source_line| 
   | 
||
| 
     	  assert_equal 'RuntimeError', klass 
   | 
||
| 
     	  assert_equal '1', source_line 
   | 
||
| 
     	end 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         private 
   | 
||
| 
         def program 
   | 
||
| 
           '10.times { raise rescue nil }' 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| test/dtrace/test_require.rb | ||
|---|---|---|
| 
     require 'dtrace/helper' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestRequire < TestCase 
   | 
||
| 
         def test_require_entry 
   | 
||
| 
           probe = <<-eoprobe 
   | 
||
| 
     ruby$target:::require-entry 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
           trap_probe(probe, ruby_program) { |d_file, rb_file, saw| 
   | 
||
| 
     	required = saw.map { |s| s.split }.find_all do |(required, _)| 
   | 
||
| 
     	  required == 'dtrace/dummy' 
   | 
||
| 
     	end 
   | 
||
| 
     	assert_equal 10, required.length 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_require_return 
   | 
||
| 
           probe = <<-eoprobe 
   | 
||
| 
     ruby$target:::require-return 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s\\n", copyinstr(arg0)); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
         end 
   | 
||
| 
         private 
   | 
||
| 
         def ruby_program 
   | 
||
| 
           "10.times { require 'dtrace/dummy' }" 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| test/dtrace/test_singleton_function.rb | ||
|---|---|---|
| 
     require 'dtrace/helper' 
   | 
||
| 
     module DTrace 
   | 
||
| 
       class TestSingletonFunctionEntry < TestCase 
   | 
||
| 
         def test_entry 
   | 
||
| 
           probe = <<-eoprobe 
   | 
||
| 
     ruby$target:::function-entry 
   | 
||
| 
     /strstr(copyinstr(arg0), "Foo") != NULL/ 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
           trap_probe(probe, ruby_program) { |d_file, rb_file, probes| 
   | 
||
| 
     	foo_calls = probes.map { |line| line.split }.find_all { |row| 
   | 
||
| 
     	  row.first == '#<Class:Foo>'  && row[1] == 'foo' 
   | 
||
| 
     	} 
   | 
||
| 
     	assert_equal 10, foo_calls.length 
   | 
||
| 
     	line = '2' 
   | 
||
| 
     	foo_calls.each { |f| assert_equal line, f[3] } 
   | 
||
| 
     	foo_calls.each { |f| assert_equal rb_file, f[2] } 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def test_exit 
   | 
||
| 
           probe = <<-eoprobe 
   | 
||
| 
     ruby$target:::function-return 
   | 
||
| 
     { 
   | 
||
| 
       printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); 
   | 
||
| 
     } 
   | 
||
| 
           eoprobe 
   | 
||
| 
           trap_probe(probe, ruby_program) { |d_file, rb_file, probes| 
   | 
||
| 
     	foo_calls = probes.map { |line| line.split }.find_all { |row| 
   | 
||
| 
     	  row.first == '#<Class:Foo>'  && row[1] == 'foo' 
   | 
||
| 
     	} 
   | 
||
| 
     	assert_equal 10, foo_calls.length 
   | 
||
| 
     	line = '2' 
   | 
||
| 
     	foo_calls.each { |f| assert_equal line, f[3] } 
   | 
||
| 
     	foo_calls.each { |f| assert_equal rb_file, f[2] } 
   | 
||
| 
           } 
   | 
||
| 
         end 
   | 
||
| 
         def ruby_program 
   | 
||
| 
           <<-eoruby 
   | 
||
| 
           class Foo 
   | 
||
| 
     	def self.foo; end 
   | 
||
| 
           end 
   | 
||
| 
           10.times { Foo.foo } 
   | 
||
| 
           eoruby 
   | 
||
| 
         end 
   | 
||
| 
       end 
   | 
||
| 
     end 
   | 
||
| tool/gen_dummy_probes.sed | ||
|---|---|---|
| 
     # upper case everything 
   | 
||
| 
     y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ 
   | 
||
| 
     # remove the pragma declarations 
   | 
||
| 
     s/^#PRAGMA.*$// 
   | 
||
| 
     # replace the provider section with the start of the header file 
   | 
||
| 
     s/PROVIDER RUBY {/#ifndef	_PROBES_H\ 
   | 
||
| 
     #define	_PROBES_H/ 
   | 
||
| 
     # finish up the #ifndef sandwich 
   | 
||
| 
     s/};/#endif	\/* _PROBES_H *\// 
   | 
||
| 
     s/__/_/g 
   | 
||
| 
     s/([^,)]\{1,\})/(arg0)/ 
   | 
||
| 
     s/([^,)]\{1,\},[^,)]\{1,\})/(arg0, arg1)/ 
   | 
||
| 
     s/([^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\})/(arg0, arg1, arg2)/ 
   | 
||
| 
     s/([^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\})/(arg0, arg1, arg2, arg3)/ 
   | 
||
| 
     s/([^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\})/(arg0, arg1, arg2, arg3, arg4)/ 
   | 
||
| 
     s/[ ]*PROBE[ ]\([^\(]*\)\(([^\)]*)\);/#define RUBY_DTRACE_\1_ENABLED() 0\ 
   | 
||
| 
     #define RUBY_DTRACE_\1\2\ do \{ \} while\(0\)/ 
   | 
||
| vm_eval.c | ||
|---|---|---|
| 
           } 
   | 
||
| 
           case VM_METHOD_TYPE_NOTIMPLEMENTED: 
   | 
||
| 
           case VM_METHOD_TYPE_CFUNC: { 
   | 
||
| 
             if (RUBY_DTRACE_FUNCTION_ENTRY_ENABLED()) { 
   | 
||
| 
                 const char * classname  = rb_class2name(klass); 
   | 
||
| 
                 const char * methodname = rb_id2name(id); 
   | 
||
| 
                 const char * filename   = rb_sourcefile(); 
   | 
||
| 
                 if (classname && methodname && filename) { 
   | 
||
| 
                   RUBY_DTRACE_FUNCTION_ENTRY( 
   | 
||
| 
                           classname, 
   | 
||
| 
                           methodname, 
   | 
||
| 
                           filename, 
   | 
||
| 
                           rb_sourceline()); 
   | 
||
| 
                 } 
   | 
||
| 
             } 
   | 
||
| 
     	EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); 
   | 
||
| 
     	{ 
   | 
||
| 
     	    rb_control_frame_t *reg_cfp = th->cfp; 
   | 
||
| ... | ... | |
| 
     	    } 
   | 
||
| 
     	    vm_pop_frame(th); 
   | 
||
| 
     	} 
   | 
||
| 
             if (RUBY_DTRACE_FUNCTION_RETURN_ENABLED()) { 
   | 
||
| 
                 const char * classname  = rb_class2name(klass); 
   | 
||
| 
                 const char * methodname = rb_id2name(id); 
   | 
||
| 
                 const char * filename   = rb_sourcefile(); 
   | 
||
| 
                 if (classname && methodname && filename) { 
   | 
||
| 
                   RUBY_DTRACE_FUNCTION_RETURN( 
   | 
||
| 
                           classname, 
   | 
||
| 
                           methodname, 
   | 
||
| 
                           filename, 
   | 
||
| 
                           rb_sourceline()); 
   | 
||
| 
                 } 
   | 
||
| 
             } 
   | 
||
| 
     	EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); 
   | 
||
| 
     	break; 
   | 
||
| 
           } 
   | 
||
| ... | ... | |
| 
     	rb_bug("vm_call0: unsupported method type (%d)", def->type); 
   | 
||
| 
     	val = Qundef; 
   | 
||
| 
         } 
   | 
||
| 
         RUBY_VM_CHECK_INTS(); 
   | 
||
| 
         return val; 
   | 
||
| 
     } 
   | 
||
| vm_insnhelper.c | ||
|---|---|---|
| 
     #include <math.h> 
   | 
||
| 
     #include "constant.h" 
   | 
||
| 
     #include "internal.h" 
   | 
||
| 
     #include "probes.h" 
   | 
||
| 
     /* control stack frame */ 
   | 
||
| ... | ... | |
| 
         volatile VALUE val = 0; 
   | 
||
| 
         const rb_method_definition_t *def = me->def; 
   | 
||
| 
         if (RUBY_DTRACE_FUNCTION_ENTRY_ENABLED()) { 
   | 
||
| 
             const char * classname  = rb_class2name(me->klass); 
   | 
||
| 
             const char * methodname = rb_id2name(me->called_id); 
   | 
||
| 
             const char * filename   = rb_sourcefile(); 
   | 
||
| 
             if (classname && methodname && filename) { 
   | 
||
| 
                 RUBY_DTRACE_FUNCTION_ENTRY( 
   | 
||
| 
                         classname, 
   | 
||
| 
                         methodname, 
   | 
||
| 
                         filename, 
   | 
||
| 
                         rb_sourceline()); 
   | 
||
| 
             } 
   | 
||
| 
         } 
   | 
||
| 
         EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass); 
   | 
||
| 
         vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, 
   | 
||
| ... | ... | |
| 
         vm_pop_frame(th); 
   | 
||
| 
         if (RUBY_DTRACE_FUNCTION_RETURN_ENABLED()) { 
   | 
||
| 
             const char * classname  = rb_class2name(me->klass); 
   | 
||
| 
             const char * methodname = rb_id2name(me->called_id); 
   | 
||
| 
             const char * filename   = rb_sourcefile(); 
   | 
||
| 
             if (classname && methodname && filename) { 
   | 
||
| 
                 RUBY_DTRACE_FUNCTION_RETURN( 
   | 
||
| 
                         classname, 
   | 
||
| 
                         methodname, 
   | 
||
| 
                         filename, 
   | 
||
| 
                         rb_sourceline()); 
   | 
||
| 
             } 
   | 
||
| 
         } 
   | 
||
| 
         EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass); 
   | 
||
| 
         return val; 
   | 
||
| ... | ... | |
| 
         rb_proc_t *proc; 
   | 
||
| 
         VALUE val; 
   | 
||
| 
         if (RUBY_DTRACE_FUNCTION_ENTRY_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_FUNCTION_ENTRY( 
   | 
||
| 
     		rb_class2name(me->klass), 
   | 
||
| 
     		rb_id2name(me->called_id), 
   | 
||
| 
     		rb_sourcefile(), 
   | 
||
| 
     		rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, recv, me->called_id, me->klass); 
   | 
||
| 
         /* control block frame */ 
   | 
||
| ... | ... | |
| 
         GetProcPtr(me->def->body.proc, proc); 
   | 
||
| 
         val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr); 
   | 
||
| 
         if (RUBY_DTRACE_FUNCTION_RETURN_ENABLED()) { 
   | 
||
| 
     	RUBY_DTRACE_FUNCTION_RETURN( 
   | 
||
| 
     		rb_class2name(me->klass), 
   | 
||
| 
     		rb_id2name(me->called_id), 
   | 
||
| 
     		rb_sourcefile(), 
   | 
||
| 
     		rb_sourceline()); 
   | 
||
| 
         } 
   | 
||
| 
         EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, recv, me->called_id, me->klass); 
   | 
||
| 
         return val; 
   | 
||