mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* vm_backtrace.c: fix issue of rb_debug_inspector_open().
The order of making binding should be stack (frame) top to bottom. [Bug #7635] And also fix issue of collecting klass. Collecting klass is same as TracePoint#defined_class. (previous version, it returns T_ICLASS (internal objects). * test/-ext-/debug/test_debug.rb: add a test. * ext/-test-/debug/extconf.rb, init.c, inspector.c: ditto. * vm_backtrace.c: remove magic number and add enum CALLER_BINDING_*. * vm_backtrace.c, include/ruby/debug.h: add new C api (experimental) rb_debug_inspector_frame_self_get(). * vm.c, vm_core.h, vm_trace.c: move decl. of rb_vm_control_frame_id_and_class() and constify first parameter. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38970 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									499ca89e24
								
							
						
					
					
						commit
						18e01f6381
					
				
					 10 changed files with 204 additions and 17 deletions
				
			
		
							
								
								
									
										21
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								ChangeLog
									
										
									
									
									
								
							|  | @ -1,3 +1,24 @@ | ||||||
|  | Tue Jan 29 17:03:28 2013  Koichi Sasada  <ko1@atdot.net> | ||||||
|  | 
 | ||||||
|  | 	* vm_backtrace.c: fix issue of rb_debug_inspector_open(). | ||||||
|  | 	  The order of making binding should be stack (frame) top to bottom. | ||||||
|  | 	  [Bug #7635] | ||||||
|  | 	  And also fix issue of collecting klass. Collecting klass is same | ||||||
|  | 	  as TracePoint#defined_class. | ||||||
|  | 	  (previous version, it returns T_ICLASS (internal objects). | ||||||
|  | 
 | ||||||
|  | 	* test/-ext-/debug/test_debug.rb: add a test. | ||||||
|  | 
 | ||||||
|  | 	* ext/-test-/debug/extconf.rb, init.c, inspector.c: ditto. | ||||||
|  | 
 | ||||||
|  | 	* vm_backtrace.c: remove magic number and add enum CALLER_BINDING_*. | ||||||
|  | 
 | ||||||
|  | 	* vm_backtrace.c, include/ruby/debug.h: add new C api (experimental) | ||||||
|  | 	  rb_debug_inspector_frame_self_get(). | ||||||
|  | 
 | ||||||
|  | 	* vm.c, vm_core.h, vm_trace.c: move decl. of  | ||||||
|  | 	  rb_vm_control_frame_id_and_class() and constify first parameter. | ||||||
|  | 
 | ||||||
| Tue Jan 29 16:50:58 2013  Nobuyoshi Nakada  <nobu@ruby-lang.org> | Tue Jan 29 16:50:58 2013  Nobuyoshi Nakada  <nobu@ruby-lang.org> | ||||||
| 
 | 
 | ||||||
| 	* vm_trace.c (rb_tracepoint_enable, rb_tracepoint_disable): check safe | 	* vm_trace.c (rb_tracepoint_enable, rb_tracepoint_disable): check safe | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								ext/-test-/debug/extconf.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								ext/-test-/debug/extconf.rb
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | $srcs = Dir[File.join($srcdir, "*.{#{SRC_EXT.join(%q{,})}}")] | ||||||
|  | inits = $srcs.map {|s| File.basename(s, ".*")} | ||||||
|  | inits.delete("init") | ||||||
|  | inits.map! {|s|"X(#{s})"} | ||||||
|  | $defs << "-DTEST_INIT_FUNCS(X)=\"#{inits.join(' ')}\"" | ||||||
|  | create_makefile("-test-/debug") | ||||||
							
								
								
									
										11
									
								
								ext/-test-/debug/init.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								ext/-test-/debug/init.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | #include "ruby.h" | ||||||
|  | 
 | ||||||
|  | #define init(n) {void Init_##n(VALUE klass); Init_##n(klass);} | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | Init_debug(void) | ||||||
|  | { | ||||||
|  |     VALUE mBug = rb_define_module("Bug"); | ||||||
|  |     VALUE klass = rb_define_class_under(mBug, "Debug", rb_cModule); | ||||||
|  |     TEST_INIT_FUNCS(init); | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								ext/-test-/debug/inspector.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								ext/-test-/debug/inspector.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | #include "ruby/ruby.h" | ||||||
|  | #include "ruby/debug.h" | ||||||
|  | 
 | ||||||
|  | static VALUE | ||||||
|  | callback(const rb_debug_inspector_t *dbg_context, void *data) | ||||||
|  | { | ||||||
|  |     VALUE locs = rb_debug_inspector_backtrace_locations(dbg_context); | ||||||
|  |     int i, len = RARRAY_LENINT(locs); | ||||||
|  |     VALUE binds = rb_ary_new(); | ||||||
|  |     for (i = 0; i < len; ++i) { | ||||||
|  | 	VALUE entry = rb_ary_new(); | ||||||
|  | 	rb_ary_push(binds, entry); | ||||||
|  | 	rb_ary_push(entry, rb_debug_inspector_frame_self_get(dbg_context, i)); | ||||||
|  | 	rb_ary_push(entry, rb_debug_inspector_frame_binding_get(dbg_context, i)); | ||||||
|  | 	rb_ary_push(entry, rb_debug_inspector_frame_class_get(dbg_context, i)); | ||||||
|  | 	rb_ary_push(entry, rb_debug_inspector_frame_iseq_get(dbg_context, i)); | ||||||
|  | 	rb_ary_push(entry, rb_ary_entry(locs, i)); | ||||||
|  |     } | ||||||
|  |     return binds; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static VALUE | ||||||
|  | debug_inspector(VALUE self) | ||||||
|  | { | ||||||
|  |     return rb_debug_inspector_open(callback, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | Init_inspector(VALUE klass) | ||||||
|  | { | ||||||
|  |     rb_define_module_function(klass, "inspector", debug_inspector, 0); | ||||||
|  | } | ||||||
|  | @ -31,8 +31,9 @@ typedef struct rb_debug_inspector_struct rb_debug_inspector_t; | ||||||
| typedef VALUE (*rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *); | typedef VALUE (*rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *); | ||||||
| 
 | 
 | ||||||
| VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data); | VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data); | ||||||
| VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index); | VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index); | ||||||
| VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index); | VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index); | ||||||
|  | VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index); | ||||||
| VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index); | VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index); | ||||||
| VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc); | VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										58
									
								
								test/-ext-/debug/test_debug.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								test/-ext-/debug/test_debug.rb
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | ||||||
|  | require 'test/unit' | ||||||
|  | require '-test-/debug' | ||||||
|  | 
 | ||||||
|  | class TestDebug < Test::Unit::TestCase | ||||||
|  | 
 | ||||||
|  |   def binds_check binds | ||||||
|  |     count = Hash.new(0) | ||||||
|  |     assert_instance_of(Array, binds) | ||||||
|  |     binds.each{|(_self, bind, klass, iseq, loc)| | ||||||
|  |       if _self == self | ||||||
|  |         count[:self] += 1 | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       if bind | ||||||
|  |         assert_instance_of(Binding, bind) | ||||||
|  |         count[:bind] += 1 | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       if klass | ||||||
|  |         assert(klass.instance_of?(Module) || klass.instance_of?(Class)) | ||||||
|  |         count[:class] += 1 | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       if iseq | ||||||
|  |         count[:iseq] += 1 | ||||||
|  |         assert_instance_of(RubyVM::InstructionSequence, iseq) | ||||||
|  | 
 | ||||||
|  |         # check same location | ||||||
|  |         assert_equal(loc.path, iseq.path) | ||||||
|  |         assert_equal(loc.absolute_path, iseq.absolute_path) | ||||||
|  |         assert_equal(loc.label, iseq.label) | ||||||
|  |         assert_operator(loc.lineno, :>=, iseq.first_lineno) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       assert_instance_of(Thread::Backtrace::Location, loc) | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  |     assert_operator(0, :<, count[:self]) | ||||||
|  |     assert_operator(0, :<, count[:bind]) | ||||||
|  |     assert_operator(0, :<, count[:iseq]) | ||||||
|  |     assert_operator(0, :<, count[:class]) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def test_inspector_open | ||||||
|  |     binds = Bug::Debug.inspector | ||||||
|  |     binds_check binds | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def inspector_in_eval | ||||||
|  |     eval("Bug::Debug.inspector") | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def test_inspector_open_in_eval | ||||||
|  |     bug7635 = '[ruby-core:51640]' | ||||||
|  |     binds = inspector_in_eval | ||||||
|  |     binds_check binds | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										2
									
								
								vm.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								vm.c
									
										
									
									
									
								
							|  | @ -1414,7 +1414,7 @@ rb_iseq_eval_main(VALUE iseqval) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int | int | ||||||
| rb_vm_control_frame_id_and_class(rb_control_frame_t *cfp, ID *idp, VALUE *klassp) | rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp) | ||||||
| { | { | ||||||
|     rb_iseq_t *iseq = cfp->iseq; |     rb_iseq_t *iseq = cfp->iseq; | ||||||
|     if (!iseq && cfp->me) { |     if (!iseq && cfp->me) { | ||||||
|  |  | ||||||
|  | @ -1012,8 +1012,15 @@ struct rb_debug_inspector_struct { | ||||||
|     long backtrace_size; |     long backtrace_size; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum { | ||||||
|  |     CALLER_BINDING_SELF, | ||||||
|  |     CALLER_BINDING_CLASS, | ||||||
|  |     CALLER_BINDING_BINDING, | ||||||
|  |     CALLER_BINDING_ISEQ, | ||||||
|  |     CALLER_BINDING_CFP | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct collect_caller_bindings_data { | struct collect_caller_bindings_data { | ||||||
|     rb_thread_t *th; |  | ||||||
|     VALUE ary; |     VALUE ary; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -1023,37 +1030,82 @@ collect_caller_bindings_init(void *arg, size_t size) | ||||||
|     /* */ |     /* */ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static VALUE | ||||||
|  | get_klass(const rb_control_frame_t *cfp) | ||||||
|  | { | ||||||
|  |     VALUE klass; | ||||||
|  |     if (rb_vm_control_frame_id_and_class(cfp, 0, &klass)) { | ||||||
|  | 	if (RB_TYPE_P(klass, T_ICLASS)) { | ||||||
|  | 	    return RBASIC(klass)->klass; | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 	    return klass; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  | 	return Qnil; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void | static void | ||||||
| collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp) | collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp) | ||||||
| { | { | ||||||
|     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg; |     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg; | ||||||
|     rb_ary_push(data->ary, |     VALUE frame = rb_ary_new2(5); | ||||||
| 		rb_ary_new3(4, | 
 | ||||||
| 			    cfp->klass, |     rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self); | ||||||
| 			    rb_binding_new_with_cfp(data->th, cfp), |     rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp)); | ||||||
| 			    cfp->iseq ? cfp->iseq->self : Qnil, |     rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */ | ||||||
| 			    GC_GUARDED_PTR(cfp))); |     rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? cfp->iseq->self : Qnil); | ||||||
|  |     rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp)); | ||||||
|  | 
 | ||||||
|  |     rb_ary_push(data->ary, frame); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid) | collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid) | ||||||
| { | { | ||||||
|     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg; |     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg; | ||||||
|     rb_ary_push(data->ary, rb_ary_new3(2, cfp->klass, Qnil)); |     VALUE frame = rb_ary_new2(5); | ||||||
|  | 
 | ||||||
|  |     rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self); | ||||||
|  |     rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp)); | ||||||
|  |     rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */ | ||||||
|  |     rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */ | ||||||
|  |     rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp)); | ||||||
|  | 
 | ||||||
|  |     rb_ary_push(data->ary, frame); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static VALUE | static VALUE | ||||||
| collect_caller_bindings(rb_thread_t *th) | collect_caller_bindings(rb_thread_t *th) | ||||||
| { | { | ||||||
|     struct collect_caller_bindings_data data; |     struct collect_caller_bindings_data data; | ||||||
|  |     VALUE result; | ||||||
|  |     int i; | ||||||
|  | 
 | ||||||
|     data.ary = rb_ary_new(); |     data.ary = rb_ary_new(); | ||||||
|     data.th = th; | 
 | ||||||
|     backtrace_each(th, |     backtrace_each(th, | ||||||
| 		   collect_caller_bindings_init, | 		   collect_caller_bindings_init, | ||||||
| 		   collect_caller_bindings_iseq, | 		   collect_caller_bindings_iseq, | ||||||
| 		   collect_caller_bindings_cfunc, | 		   collect_caller_bindings_cfunc, | ||||||
| 		   &data); | 		   &data); | ||||||
|     return rb_ary_reverse(data.ary); | 
 | ||||||
|  |     result = rb_ary_reverse(data.ary); | ||||||
|  | 
 | ||||||
|  |     /* bindings should be created from top of frame */ | ||||||
|  |     for (i=0; i<RARRAY_LEN(result); i++) { | ||||||
|  | 	VALUE entry = rb_ary_entry(result, i); | ||||||
|  | 	VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING); | ||||||
|  | 
 | ||||||
|  | 	if (!NIL_P(cfp_val)) { | ||||||
|  | 	    rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val); | ||||||
|  | 	    rb_ary_store(entry, CALLER_BINDING_BINDING, rb_binding_new_with_cfp(th, cfp)); | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -1099,25 +1151,32 @@ frame_get(const rb_debug_inspector_t *dc, long index) | ||||||
|     return rb_ary_entry(dc->contexts, index); |     return rb_ary_entry(dc->contexts, index); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | VALUE | ||||||
|  | rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index) | ||||||
|  | { | ||||||
|  |     VALUE frame = frame_get(dc, index); | ||||||
|  |     return rb_ary_entry(frame, CALLER_BINDING_SELF); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| VALUE | VALUE | ||||||
| rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index) | rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index) | ||||||
| { | { | ||||||
|     VALUE frame = frame_get(dc, index); |     VALUE frame = frame_get(dc, index); | ||||||
|     return rb_ary_entry(frame, 0); |     return rb_ary_entry(frame, CALLER_BINDING_CLASS); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| VALUE | VALUE | ||||||
| rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index) | rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index) | ||||||
| { | { | ||||||
|     VALUE frame = frame_get(dc, index); |     VALUE frame = frame_get(dc, index); | ||||||
|     return rb_ary_entry(frame, 1); |     return rb_ary_entry(frame, CALLER_BINDING_BINDING); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| VALUE | VALUE | ||||||
| rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index) | rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index) | ||||||
| { | { | ||||||
|     VALUE frame = frame_get(dc, index); |     VALUE frame = frame_get(dc, index); | ||||||
|     return rb_ary_entry(frame, 2); |     return rb_ary_entry(frame, CALLER_BINDING_ISEQ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| VALUE | VALUE | ||||||
|  |  | ||||||
|  | @ -847,6 +847,7 @@ int rb_vm_get_sourceline(const rb_control_frame_t *); | ||||||
| VALUE rb_name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method); | VALUE rb_name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method); | ||||||
| void rb_vm_stack_to_heap(rb_thread_t *th); | void rb_vm_stack_to_heap(rb_thread_t *th); | ||||||
| void ruby_thread_init_stack(rb_thread_t *th); | void ruby_thread_init_stack(rb_thread_t *th); | ||||||
|  | int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp); | ||||||
| 
 | 
 | ||||||
| void rb_gc_mark_machine_stack(rb_thread_t *th); | void rb_gc_mark_machine_stack(rb_thread_t *th); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -694,8 +694,6 @@ rb_tracearg_event(rb_trace_arg_t *trace_arg) | ||||||
|     return ID2SYM(get_event_id(trace_arg->event)); |     return ID2SYM(get_event_id(trace_arg->event)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int rb_vm_control_frame_id_and_class(rb_control_frame_t *cfp, ID *idp, VALUE *klassp); |  | ||||||
| 
 |  | ||||||
| static void | static void | ||||||
| fill_path_and_lineno(rb_trace_arg_t *trace_arg) | fill_path_and_lineno(rb_trace_arg_t *trace_arg) | ||||||
| { | { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 ko1
						ko1