[前][次][番号順一覧][スレッド一覧]

ruby-changes:25922

From: ko1 <ko1@a...>
Date: Thu, 29 Nov 2012 16:05:36 +0900 (JST)
Subject: [ruby-changes:25922] ko1:r37979 (trunk): * include/ruby/debug.h: add rb_debug_inspector_* APIs.

ko1	2012-11-29 16:05:27 +0900 (Thu, 29 Nov 2012)

  New Revision: 37979

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=37979

  Log:
    * include/ruby/debug.h: add rb_debug_inspector_* APIs.
    * vm_backtrace.c: ditto.
    * common.mk: add dpendency from vm_backtrace.o to
      include/ruby/debug.h.
    * proc.c (rb_binding_new_with_cfp): constify.
    * vm.c (rb_vm_get_ruby_level_next_cfp): consitify.
    * vm_core.h, vm_trace.c: move decls.

  Modified files:
    trunk/ChangeLog
    trunk/common.mk
    trunk/include/ruby/debug.h
    trunk/proc.c
    trunk/vm.c
    trunk/vm_backtrace.c
    trunk/vm_core.h
    trunk/vm_trace.c

Index: include/ruby/debug.h
===================================================================
--- include/ruby/debug.h	(revision 37978)
+++ include/ruby/debug.h	(revision 37979)
@@ -26,6 +26,16 @@
 /* Note: This file contains experimental APIs. */
 /* APIs can be replaced at Ruby 2.0.1 or later */
 
+/* debug inspector APIs */
+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, int index);
+VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, int index);
+VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, int index);
+VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc);
+
 /* Old style set_trace_func APIs */
 
 void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
@@ -55,7 +65,7 @@
 VALUE rb_tracearg_return_value(struct rb_trace_arg_struct *trace_arg);
 VALUE rb_tracearg_raised_exception(struct rb_trace_arg_struct *trace_arg);
 
-/* undocumented advanced APIs */
+/* undocumented advanced tracing APIs */
 
 typedef enum {
     RUBY_EVENT_HOOK_FLAG_SAFE    = 0x01,
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 37978)
+++ ChangeLog	(revision 37979)
@@ -1,3 +1,18 @@
+Thu Nov 29 15:59:55 2012  Koichi Sasada  <ko1@a...>
+
+	* include/ruby/debug.h: add rb_debug_inspector_* APIs.
+
+	* vm_backtrace.c: ditto.
+
+	* common.mk: add dpendency from vm_backtrace.o to
+	  include/ruby/debug.h.
+
+	* proc.c (rb_binding_new_with_cfp): constify.
+
+	* vm.c (rb_vm_get_ruby_level_next_cfp): consitify.
+
+	* vm_core.h, vm_trace.c: move decls.
+
 Thu Nov 29 15:56:14 2012  NARUSE, Yui  <naruse@r...>
 
 	* lib/rdoc/test_case.rb (RDoc::TestCase#verbose_capture_io):
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 37978)
+++ vm_core.h	(revision 37979)
@@ -793,6 +793,7 @@
 			int argc, const VALUE *argv, const rb_block_t *blockptr);
 VALUE rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass);
 VALUE rb_vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp);
+VALUE rb_binding_new_with_cfp(rb_thread_t *th, const rb_control_frame_t *src_cfp);
 void rb_vm_inc_const_missing_count(void);
 void rb_vm_gvl_destroy(rb_vm_t *vm);
 VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc,
@@ -808,7 +809,7 @@
 
 int ruby_thread_has_gvl_p(void);
 typedef int rb_backtrace_iter_func(void *, VALUE, int, VALUE);
-rb_control_frame_t *rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, rb_control_frame_t *cfp);
+rb_control_frame_t *rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, const rb_control_frame_t *cfp);
 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);
Index: proc.c
===================================================================
--- proc.c	(revision 37978)
+++ proc.c	(revision 37979)
@@ -310,7 +310,7 @@
 }
 
 VALUE
-rb_binding_new_with_cfp(rb_thread_t *th, rb_control_frame_t *src_cfp)
+rb_binding_new_with_cfp(rb_thread_t *th, const rb_control_frame_t *src_cfp)
 {
     rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, src_cfp);
     VALUE bindval = binding_alloc(rb_cBinding);
Index: common.mk
===================================================================
--- common.mk	(revision 37978)
+++ common.mk	(revision 37979)
@@ -774,7 +774,7 @@
 id.$(OBJEXT): {$(VPATH)}id.c $(RUBY_H_INCLUDES) $(ID_H_INCLUDES) {$(VPATH)}vm_opts.h
 vm_backtrace.$(OBJEXT): {$(VPATH)}vm_backtrace.c \
   $(VM_CORE_H_INCLUDES) $(RUBY_H_INCLUDES) $(ENCODING_H_INCLUDES) \
-  {$(VPATH)}internal.h {$(VPATH)}iseq.h
+  {$(VPATH)}internal.h {$(VPATH)}iseq.h {$(VPATH)}debug.h
 vm_trace.$(OBJEXT): {$(VPATH)}vm_trace.c $(ENCODING_H_INCLUDES) \
   $(VM_CORE_H_INCLUDES) $(RUBY_H_INCLUDES) {$(VPATH)}debug.h \
   {$(VPATH)}internal.h
Index: vm_backtrace.c
===================================================================
--- vm_backtrace.c	(revision 37978)
+++ vm_backtrace.c	(revision 37979)
@@ -11,9 +11,11 @@
 
 #include "ruby/ruby.h"
 #include "ruby/encoding.h"
+#include "ruby/debug.h"
 
 #include "internal.h"
 #include "vm_core.h"
+#include "eval_intern.h"
 #include "iseq.h"
 
 static VALUE rb_cBacktrace;
@@ -358,8 +360,8 @@
 static void
 backtrace_each(rb_thread_t *th,
 	       void (*init)(void *arg, size_t size),
-	       void (*iter_iseq)(void *arg, const rb_iseq_t *iseq, const VALUE *pc),
-	       void (*iter_cfunc)(void *arg, ID mid),
+	       void (*iter_iseq)(void *arg, const rb_control_frame_t *cfp),
+	       void (*iter_cfunc)(void *arg, const rb_control_frame_t *cfp, ID mid),
 	       void *arg)
 {
     rb_control_frame_t *last_cfp = th->cfp;
@@ -395,13 +397,13 @@
 	/* fprintf(stderr, "cfp: %d\n", (rb_control_frame_t *)(th->stack + th->stack_size) - cfp); */
 	if (cfp->iseq) {
 	    if (cfp->pc) {
-		iter_iseq(arg, cfp->iseq, cfp->pc);
+		iter_iseq(arg, cfp);
 	    }
 	}
 	else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
 	    ID mid = cfp->me->def ? cfp->me->def->original_id : cfp->me->called_id;
 
-	    iter_cfunc(arg, mid);
+	    iter_cfunc(arg, cfp, mid);
 	}
     }
 }
@@ -423,8 +425,10 @@
 }
 
 static void
-bt_iter_iseq(void *ptr, const rb_iseq_t *iseq, const VALUE *pc)
+bt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
 {
+    const rb_iseq_t *iseq = cfp->iseq;
+    const VALUE *pc = cfp->pc;
     struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
     rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
     loc->type = LOCATION_TYPE_ISEQ;
@@ -434,7 +438,7 @@
 }
 
 static void
-bt_iter_cfunc(void *ptr, ID mid)
+bt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
 {
     struct bt_iter_arg *arg = (struct bt_iter_arg *)ptr;
     rb_backtrace_location_t *loc = &arg->bt->backtrace[arg->bt->backtrace_size++];
@@ -599,8 +603,10 @@
 }
 
 static void
-oldbt_iter_iseq(void *ptr, const rb_iseq_t *iseq, const VALUE *pc)
+oldbt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
 {
+    const rb_iseq_t *iseq = cfp->iseq;
+    const VALUE *pc = cfp->pc;
     struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
     VALUE file = arg->filename = iseq->location.path;
     VALUE name = iseq->location.label;
@@ -610,7 +616,7 @@
 }
 
 static void
-oldbt_iter_cfunc(void *ptr, ID mid)
+oldbt_iter_cfunc(void *ptr, const rb_control_frame_t *cfp, ID mid)
 {
     struct oldbt_arg *arg = (struct oldbt_arg *)ptr;
     VALUE file = arg->filename;
@@ -846,3 +852,137 @@
     rb_define_global_function("caller", rb_f_caller, -1);
     rb_define_global_function("caller_locations", rb_f_caller_locations, -1);
 }
+
+/* debugger API */
+
+#if defined __GNUC__ && __GNUC__ >= 4
+#pragma GCC visibility push(default)
+#endif
+
+#if defined __GNUC__ && __GNUC__ >= 4
+#pragma GCC visibility pop
+#endif
+
+struct rb_debug_inspector_struct {
+    rb_thread_t *th;
+    rb_control_frame_t *cfp;
+    VALUE backtrace;
+    VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
+    int backtrace_size;
+};
+
+struct collect_caller_bindings_data {
+    rb_thread_t *th;
+    VALUE ary;
+};
+
+static void
+collect_caller_bindings_init(void *arg, size_t size)
+{
+    /* */
+}
+
+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)));
+}
+
+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));
+}
+
+static VALUE
+collect_caller_bindings(rb_thread_t *th)
+{
+    struct collect_caller_bindings_data data;
+    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);
+}
+
+/*
+ * Note that the passed `rb_debug_inspector_t' will be disabled
+ * after `rb_debug_inspector_open'.
+ */
+
+VALUE
+rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
+{
+    rb_debug_inspector_t dbg_context;
+    rb_thread_t *th = GET_THREAD();
+    int state;
+    VALUE result;
+
+    dbg_context.th = th;
+    dbg_context.cfp = dbg_context.th->cfp;
+    dbg_context.backtrace = vm_backtrace_location_ary(th, 0, 0);
+    dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
+    dbg_context.contexts = collect_caller_bindings(th);
+
+    TH_PUSH_TAG(th);
+    if ((state = EXEC_TAG()) == 0) {
+	result = (*func)(&dbg_context, data);
+    }
+    TH_POP_TAG();
+
+    /* invalidate bindings? */
+    
+
+    if (state) {
+	JUMP_TAG(state);
+    }
+
+    return result;
+}
+
+static VALUE
+frame_get(const rb_debug_inspector_t *dc, int index)
+{
+    if (index < 0 || index >= dc->backtrace_size) {
+	rb_raise(rb_eArgError, "no such frame");
+    }
+    return rb_ary_entry(dc->contexts, index);
+}
+
+VALUE
+rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, int index)
+{
+    VALUE frame = frame_get(dc, index);
+    return rb_ary_entry(frame, 0);
+}
+
+VALUE
+rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, int index)
+{
+    VALUE frame = frame_get(dc, index);
+    return rb_ary_entry(frame, 1);
+}
+
+VALUE
+rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, int index)
+{
+    VALUE frame = frame_get(dc, index);
+    return rb_ary_entry(frame, 2);
+}
+
+VALUE
+rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
+{
+    return dc->backtrace;
+}
+
Index: vm_trace.c
===================================================================
--- vm_trace.c	(revision 37978)
+++ vm_trace.c	(revision 37979)
@@ -644,9 +644,7 @@
     return ID2SYM(get_event_id(trace_arg->event));
 }
 
-rb_control_frame_t *rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, rb_control_frame_t *cfp);
 int rb_vm_control_frame_id_and_class(rb_control_frame_t *cfp, ID *idp, VALUE *klassp);
-VALUE rb_binding_new_with_cfp(rb_thread_t *th, rb_control_frame_t *src_cfp);
 
 static void
 fill_path_and_lineno(rb_trace_arg_t *trace_arg)
Index: vm.c
===================================================================
--- vm.c	(revision 37978)
+++ vm.c	(revision 37979)
@@ -186,11 +186,11 @@
 }
 
 rb_control_frame_t *
-rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, rb_control_frame_t *cfp)
+rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, const rb_control_frame_t *cfp)
 {
     while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
 	if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) {
-	    return cfp;
+	    return (rb_control_frame_t *)cfp;
 	}
 	cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
     }

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]