summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-01-29 08:25:32 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-01-29 08:25:32 +0000
commit18e01f63816ec36d10b8d958b8298b73950dd89f (patch)
tree21cf859454214cadb1f901ff5d119d0d8372418c
parent499ca89e24c47cfada7e493a7dfd81cdb9323a45 (diff)
* 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
-rw-r--r--ChangeLog21
-rw-r--r--ext/-test-/debug/extconf.rb6
-rw-r--r--ext/-test-/debug/init.c11
-rw-r--r--ext/-test-/debug/inspector.c32
-rw-r--r--include/ruby/debug.h3
-rw-r--r--test/-ext-/debug/test_debug.rb58
-rw-r--r--vm.c2
-rw-r--r--vm_backtrace.c85
-rw-r--r--vm_core.h1
-rw-r--r--vm_trace.c2
10 files changed, 204 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index 8bc8fa3..651d630 100644
--- a/ChangeLog
+++ b/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>
* vm_trace.c (rb_tracepoint_enable, rb_tracepoint_disable): check safe
diff --git a/ext/-test-/debug/extconf.rb b/ext/-test-/debug/extconf.rb
new file mode 100644
index 0000000..8f7922e
--- /dev/null
+++ b/ext/-test-/debug/extconf.rb
@@ -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")
diff --git a/ext/-test-/debug/init.c b/ext/-test-/debug/init.c
new file mode 100644
index 0000000..4b10112
--- /dev/null
+++ b/ext/-test-/debug/init.c
@@ -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);
+}
diff --git a/ext/-test-/debug/inspector.c b/ext/-test-/debug/inspector.c
new file mode 100644
index 0000000..6212b2e
--- /dev/null
+++ b/ext/-test-/debug/inspector.c
@@ -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);
+}
diff --git a/include/ruby/debug.h b/include/ruby/debug.h
index 3cdf60a..4ef45a8 100644
--- a/include/ruby/debug.h
+++ b/include/ruby/debug.h
@@ -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 *);
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_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_backtrace_locations(const rb_debug_inspector_t *dc);
diff --git a/test/-ext-/debug/test_debug.rb b/test/-ext-/debug/test_debug.rb
new file mode 100644
index 0000000..4c45057
--- /dev/null
+++ b/test/-ext-/debug/test_debug.rb
@@ -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
diff --git a/vm.c b/vm.c
index e6a2a6d..c8f0a29 100644
--- a/vm.c
+++ b/vm.c
@@ -1414,7 +1414,7 @@ rb_iseq_eval_main(VALUE iseqval)
}
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;
if (!iseq && cfp->me) {
diff --git a/vm_backtrace.c b/vm_backtrace.c
index f22b95c..15bf163 100644
--- a/vm_backtrace.c
+++ b/vm_backtrace.c
@@ -1012,8 +1012,15 @@ struct rb_debug_inspector_struct {
long backtrace_size;
};
+enum {
+ CALLER_BINDING_SELF,
+ CALLER_BINDING_CLASS,
+ CALLER_BINDING_BINDING,
+ CALLER_BINDING_ISEQ,
+ CALLER_BINDING_CFP
+};
+
struct collect_caller_bindings_data {
- rb_thread_t *th;
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
collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
{
struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
- rb_ary_push(data->ary,
- rb_ary_new3(4,
- cfp->klass,
- rb_binding_new_with_cfp(data->th, cfp),
- cfp->iseq ? cfp->iseq->self : Qnil,
- GC_GUARDED_PTR(cfp)));
+ 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, GC_GUARDED_PTR(cfp)); /* create later */
+ 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
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;
- 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
collect_caller_bindings(rb_thread_t *th)
{
struct collect_caller_bindings_data data;
+ VALUE result;
+ int i;
+
data.ary = rb_ary_new();
- data.th = th;
+
backtrace_each(th,
collect_caller_bindings_init,
collect_caller_bindings_iseq,
collect_caller_bindings_cfunc,
&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;
}
/*
@@ -1100,24 +1152,31 @@ frame_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 frame = frame_get(dc, index);
+ return rb_ary_entry(frame, CALLER_BINDING_SELF);
+}
+
+VALUE
rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
{
VALUE frame = frame_get(dc, index);
- return rb_ary_entry(frame, 0);
+ return rb_ary_entry(frame, CALLER_BINDING_CLASS);
}
VALUE
rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
{
VALUE frame = frame_get(dc, index);
- return rb_ary_entry(frame, 1);
+ return rb_ary_entry(frame, CALLER_BINDING_BINDING);
}
VALUE
rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
{
VALUE frame = frame_get(dc, index);
- return rb_ary_entry(frame, 2);
+ return rb_ary_entry(frame, CALLER_BINDING_ISEQ);
}
VALUE
diff --git a/vm_core.h b/vm_core.h
index 7526c20..2e50170 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -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);
void rb_vm_stack_to_heap(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);
diff --git a/vm_trace.c b/vm_trace.c
index dd68715..93e6212 100644
--- a/vm_trace.c
+++ b/vm_trace.c
@@ -694,8 +694,6 @@ rb_tracearg_event(rb_trace_arg_t *trace_arg)
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
fill_path_and_lineno(rb_trace_arg_t *trace_arg)
{