ext/byebug/byebug.c in byebug-1.0.3 vs ext/byebug/byebug.c in byebug-1.1.0
- old
+ new
@@ -2,25 +2,26 @@
static VALUE mByebug; /* Ruby Byebug Module object */
static VALUE cContext;
static VALUE cDebugThread;
-static VALUE tracing = Qfalse;
-static VALUE debug = Qfalse;
-static VALUE locker = Qnil;
+static VALUE tracing = Qfalse;
+static VALUE post_mortem = Qfalse;
+static VALUE debug = Qfalse;
+static VALUE locker = Qnil;
static VALUE contexts;
static VALUE catchpoints;
static VALUE breakpoints;
static VALUE tpLine;
static VALUE tpCall;
+static VALUE tpCCall;
static VALUE tpReturn;
+static VALUE tpCReturn;
static VALUE tpRaise;
-static VALUE idAlive;
-
static VALUE
tp_inspect(VALUE trace_point) {
rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(trace_point);
if (trace_arg) {
VALUE event = rb_tracearg_event(trace_arg);
@@ -57,11 +58,11 @@
{
VALUE context;
context = rb_hash_aref(contexts, thread);
if (context == Qnil) {
- context = context_create(thread, cDebugThread);
+ context = Context_create(thread, cDebugThread);
rb_hash_aset(contexts, thread, context);
}
return context;
}
@@ -69,15 +70,17 @@
Byebug_current_context(VALUE self)
{
return Byebug_thread_context(self, rb_thread_current());
}
+/*
static int
remove_dead_threads(VALUE thread, VALUE context, VALUE ignored)
{
return (IS_THREAD_ALIVE(thread)) ? ST_CONTINUE : ST_DELETE;
}
+*/
static void
cleanup(debug_context_t *context)
{
VALUE thread;
@@ -94,13 +97,11 @@
}
static int
check_start_processing(debug_context_t *context, VALUE thread)
{
- /* return if thread is marked as 'ignored'.
- byebug's threads are marked this way
- */
+ /* return if thread is marked as 'ignored' */
if(CTX_FL_TEST(context, CTX_FL_IGNORE)) return 0;
while(1)
{
/* halt execution of the current thread if byebug is activated in another */
@@ -159,31 +160,37 @@
context->last_file = file;
context->last_line = line;
rb_funcall(context_object, rb_intern("at_line"), 2, path, lineno);
}
+#define EVENT_SETUP \
+ VALUE path, lineno, method_id, defined_class, binding, self; \
+ VALUE context_object; \
+ debug_context_t *context; \
+ context_object = Byebug_current_context(mByebug); \
+ Data_Get_Struct(context_object, debug_context_t, context); \
+ if (!check_start_processing(context, rb_thread_current())) return; \
+ load_frame_info(trace_point, &path, &lineno, &method_id, &defined_class, \
+ &binding, &self); \
+ if (debug == Qtrue) \
+ printf("%s (stack_size: %d)\n", \
+ RSTRING_PTR(tp_inspect(trace_point)), context->stack_size); \
+
static void
process_line_event(VALUE trace_point, void *data)
{
- VALUE path, lineno, method_id, defined_class, binding, self;
- VALUE context_object;
+ EVENT_SETUP;
VALUE breakpoint;
- debug_context_t *context;
int moved = 0;
- context_object = Byebug_current_context(mByebug);
- Data_Get_Struct(context_object, debug_context_t, context);
- if (!check_start_processing(context, rb_thread_current())) return;
+ if (context->stack_size == 0)
+ push_frame(context, RSTRING_PTR(path), FIX2INT(lineno), method_id,
+ defined_class, binding, self);
+ else
+ update_frame(context->stack, RSTRING_PTR(path), FIX2INT(lineno), method_id,
+ defined_class, binding, self);
- load_frame_info(
- trace_point, &path, &lineno, &method_id, &defined_class, &binding, &self);
- if (debug == Qtrue)
- printf("%s (stack_size: %d)\n", RSTRING_PTR(tp_inspect(trace_point)),
- context->stack_size);
- update_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id,
- defined_class, binding, self);
-
if (context->last_line != FIX2INT(lineno) || context->last_file == NULL ||
strcmp(context->last_file, RSTRING_PTR(path)))
{
CTX_FL_SET(context, CTX_FL_ENABLE_BKPT);
moved = 1;
@@ -225,57 +232,53 @@
cleanup(context);
}
static void
-process_return_event(VALUE trace_point, void *data)
+process_c_return_event(VALUE trace_point, void *data)
{
- VALUE path, lineno, method_id, defined_class, binding, self;
- VALUE context_object;
- debug_context_t *context;
+ EVENT_SETUP;
- context_object = Byebug_current_context(mByebug);
- Data_Get_Struct(context_object, debug_context_t, context);
- if (!check_start_processing(context, rb_thread_current())) return;
+ pop_frame(context);
- load_frame_info(
- trace_point, &path, &lineno, &method_id, &defined_class, &binding, &self);
- if (debug == Qtrue)
- printf("%s (stack_size: %d)\n", RSTRING_PTR(tp_inspect(trace_point)),
- context->stack_size);
+ cleanup(context);
+}
+static void
+process_return_event(VALUE trace_point, void *data)
+{
+ EVENT_SETUP;
+
if (context->stack_size == context->stop_frame)
{
context->stop_next = 1;
context->stop_frame = 0;
}
+ pop_frame(context);
- pop_frame(context_object);
+ cleanup(context);
+}
+static void
+process_c_call_event(VALUE trace_point, void *data)
+{
+ EVENT_SETUP;
+
+ push_frame(context, RSTRING_PTR(path), FIX2INT(lineno), method_id,
+ defined_class, binding, self);
cleanup(context);
}
static void
process_call_event(VALUE trace_point, void *data)
{
- VALUE path, lineno, method_id, defined_class, binding, self;
- VALUE context_object;
+ EVENT_SETUP;
VALUE breakpoint;
- debug_context_t *context;
- context_object = Byebug_current_context(mByebug);
- Data_Get_Struct(context_object, debug_context_t, context);
- if (!check_start_processing(context, rb_thread_current())) return;
+ push_frame(context, RSTRING_PTR(path), FIX2INT(lineno), method_id,
+ defined_class, binding, self);
- load_frame_info(
- trace_point, &path, &lineno, &method_id, &defined_class, &binding, &self);
- if (debug == Qtrue)
- printf("%s (stack_size: %d)\n", RSTRING_PTR(tp_inspect(trace_point)),
- context->stack_size);
- push_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id,
- defined_class, binding, self);
-
breakpoint = find_breakpoint_by_method(breakpoints, defined_class,
SYM2ID(method_id),
binding, self);
if (breakpoint != Qnil) {
context->stop_reason = CTX_STOP_BREAKPOINT;
@@ -288,34 +291,31 @@
}
static void
process_raise_event(VALUE trace_point, void *data)
{
- VALUE path, lineno, method_id, defined_class, binding, self;
- VALUE context_object;
+ EVENT_SETUP;
VALUE expn_class, aclass;
VALUE err = rb_errinfo();
VALUE ancestors;
- debug_context_t *context;
int i;
- context_object = Byebug_current_context(mByebug);
- Data_Get_Struct(context_object, debug_context_t, context);
- if (!check_start_processing(context, rb_thread_current())) return;
-
- load_frame_info(
- trace_point, &path, &lineno, &method_id, &defined_class, &binding, &self);
- if (debug == Qtrue)
- printf("%s (stack_size: %d)\n", RSTRING_PTR(tp_inspect(trace_point)),
- context->stack_size);
- update_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id,
+ update_frame(context->stack, RSTRING_PTR(path), FIX2INT(lineno), method_id,
defined_class, binding, self);
+ if (post_mortem == Qtrue && self)
+ {
+ VALUE binding = rb_binding_new();
+ rb_ivar_set(rb_errinfo(), rb_intern("@__debug_file"), path);
+ rb_ivar_set(rb_errinfo(), rb_intern("@__debug_line"), lineno);
+ rb_ivar_set(rb_errinfo(), rb_intern("@__debug_binding"), binding);
+ rb_ivar_set(rb_errinfo(), rb_intern("@__debug_context"), Context_dup(context));
+ }
+
expn_class = rb_obj_class(err);
- if (catchpoints == Qnil ||
- context->stack_size == 0 ||
+ if (catchpoints == Qnil || context->stack_size == 0 ||
CTX_FL_TEST(context, CTX_FL_CATCHING) ||
RHASH_TBL(catchpoints)->num_entries == 0) {
cleanup(context);
return;
}
@@ -351,26 +351,38 @@
contexts = rb_hash_new();
breakpoints = rb_ary_new();
catchpoints = rb_hash_new();
tpLine = rb_tracepoint_new(Qnil,
- RUBY_EVENT_LINE,
- process_line_event, NULL);
- rb_tracepoint_enable(tpLine);
+ RUBY_EVENT_LINE,
+ process_line_event, NULL);
+ tpCall = rb_tracepoint_new(Qnil,
+ RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS,
+ process_call_event, NULL);
+
+ tpCCall = rb_tracepoint_new(Qnil,
+ RUBY_EVENT_C_CALL,
+ process_c_call_event, NULL);
+
tpReturn = rb_tracepoint_new(Qnil,
- RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END,
- process_return_event, NULL);
- rb_tracepoint_enable(tpReturn);
+ RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END,
+ process_return_event, NULL);
- tpCall = rb_tracepoint_new(Qnil,
- RUBY_EVENT_CALL | RUBY_EVENT_C_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS,
- process_call_event, NULL);
- rb_tracepoint_enable(tpCall);
+ tpCReturn = rb_tracepoint_new(Qnil,
+ RUBY_EVENT_C_RETURN,
+ process_c_return_event, NULL);
tpRaise = rb_tracepoint_new(Qnil,
- RUBY_EVENT_RAISE, process_raise_event, NULL);
+ RUBY_EVENT_RAISE,
+ process_raise_event, NULL);
+
+ rb_tracepoint_enable(tpLine);
+ rb_tracepoint_enable(tpCall);
+ rb_tracepoint_enable(tpCCall);
+ rb_tracepoint_enable(tpReturn);
+ rb_tracepoint_enable(tpCReturn);
rb_tracepoint_enable(tpRaise);
return Qnil;
}
@@ -379,38 +391,55 @@
{
contexts = Qnil;
breakpoints = Qnil;
catchpoints = Qnil;
- if (tpLine != Qnil) rb_tracepoint_disable(tpLine);
- tpLine = Qnil;
- if (tpReturn != Qnil) rb_tracepoint_disable(tpReturn);
- tpReturn = Qnil;
- if (tpCall != Qnil) rb_tracepoint_disable(tpCall);
- tpCall = Qnil;
- if (tpRaise != Qnil) rb_tracepoint_disable(tpRaise);
- tpRaise = Qnil;
+ if (tpLine != Qnil) {
+ rb_tracepoint_disable(tpLine);
+ tpLine = Qnil;
+ }
+ if (tpCall != Qnil) {
+ rb_tracepoint_disable(tpCall);
+ tpCall = Qnil;
+ }
+ if (tpCCall != Qnil) {
+ rb_tracepoint_disable(tpCCall);
+ tpCCall = Qnil;
+ }
+ if (tpReturn != Qnil) {
+ rb_tracepoint_disable(tpReturn);
+ tpReturn = Qnil;
+ }
+ if (tpCReturn != Qnil) {
+ rb_tracepoint_disable(tpCReturn);
+ tpCReturn = Qnil;
+ }
+ if (tpRaise != Qnil) {
+ rb_tracepoint_disable(tpRaise);
+ tpRaise = Qnil;
+ }
return Qnil;
}
static int
values_i(VALUE key, VALUE value, VALUE ary)
{
rb_ary_push(ary, value);
return ST_CONTINUE;
}
+#define BYEBUG_STARTED (catchpoints != Qnil)
static VALUE
Byebug_started(VALUE self)
{
- return catchpoints != Qnil ? Qtrue : Qfalse;
+ return BYEBUG_STARTED;
}
static VALUE
Byebug_stop(VALUE self)
{
- if (Byebug_started(self))
+ if (BYEBUG_STARTED)
{
Byebug_remove_tracepoints(self);
return Qfalse;
}
return Qtrue;
@@ -419,11 +448,11 @@
static VALUE
Byebug_start(VALUE self)
{
VALUE result;
- if (Byebug_started(self))
+ if (BYEBUG_STARTED)
result = Qfalse;
else
{
Byebug_setup_tracepoints(self);
result = Qtrue;
@@ -434,10 +463,25 @@
return result;
}
static VALUE
+set_current_skipped_status(VALUE status)
+{
+ VALUE context_object;
+ debug_context_t *context;
+
+ context_object = Byebug_current_context(mByebug);
+ Data_Get_Struct(context_object, debug_context_t, context);
+ if (status)
+ CTX_FL_SET(context, CTX_FL_SKIPPED);
+ else
+ CTX_FL_UNSET(context, CTX_FL_SKIPPED);
+ return Qnil;
+}
+
+static VALUE
Byebug_load(int argc, VALUE *argv, VALUE self)
{
VALUE file, stop, context_object;
debug_context_t *context;
int state = 0;
@@ -464,39 +508,80 @@
reset_stepping_stop_points(context);
rb_set_errinfo(Qnil);
return errinfo;
}
- /* We should run all at_exit handler's in order to provide,
- * for instance, a chance to run all defined test cases */
+ /* We should run all at_exit handler's in order to provide, for instance, a
+ * chance to run all defined test cases */
rb_exec_end_proc();
return Qnil;
}
static VALUE
+debug_at_exit_c(VALUE proc)
+{
+ return rb_funcall(proc, rb_intern("call"), 0);
+}
+
+static void
+debug_at_exit_i(VALUE proc)
+{
+ if (BYEBUG_STARTED)
+ {
+ set_current_skipped_status(Qtrue);
+ rb_ensure(debug_at_exit_c, proc, set_current_skipped_status, Qfalse);
+ }
+ else
+ debug_at_exit_c(proc);
+}
+
+static VALUE
+Byebug_at_exit(VALUE self)
+{
+ VALUE proc;
+ if (!rb_block_given_p()) rb_raise(rb_eArgError, "called without a block");
+ proc = rb_block_proc();
+ rb_set_end_proc(debug_at_exit_i, proc);
+ return proc;
+}
+
+static VALUE
Byebug_tracing(VALUE self)
{
- return tracing;
+ return tracing;
}
static VALUE
Byebug_set_tracing(VALUE self, VALUE value)
{
- tracing = RTEST(value) ? Qtrue : Qfalse;
- return value;
+ tracing = RTEST(value) ? Qtrue : Qfalse;
+ return value;
}
static VALUE
+Byebug_post_mortem(VALUE self)
+{
+ return post_mortem;
+}
+
+static VALUE
+Byebug_set_post_mortem(VALUE self, VALUE value)
+{
+ post_mortem = RTEST(value) ? Qtrue : Qfalse;
+ return value;
+}
+
+static VALUE
Byebug_contexts(VALUE self)
{
VALUE ary;
ary = rb_ary_new();
/* check that all contexts point to alive threads */
- rb_hash_foreach(contexts, remove_dead_threads, 0);
+ /*rb_hash_foreach(contexts, remove_dead_threads, self);*/
rb_hash_foreach(contexts, values_i, ary);
return ary;
}
@@ -549,14 +634,15 @@
Byebug_add_catchpoint, 1);
rb_define_module_function(mByebug, "catchpoints", Byebug_catchpoints, 0);
rb_define_module_function(mByebug, "_start", Byebug_start, 0);
rb_define_module_function(mByebug, "stop", Byebug_stop, 0);
rb_define_module_function(mByebug, "started?", Byebug_started, 0);
- rb_define_module_function(mByebug, "tracing", Byebug_tracing, 0);
+ rb_define_module_function(mByebug, "tracing?", Byebug_tracing, 0);
rb_define_module_function(mByebug, "tracing=", Byebug_set_tracing, 1);
rb_define_module_function(mByebug, "debug_load", Byebug_load, -1);
-
- idAlive = rb_intern("alive?");
+ rb_define_module_function(mByebug, "debug_at_exit", Byebug_at_exit, 0);
+ rb_define_module_function(mByebug, "post_mortem?", Byebug_post_mortem, 0);
+ rb_define_module_function(mByebug, "post_mortem=", Byebug_set_post_mortem, 1);
cContext = Init_context(mByebug);
Init_breakpoint(mByebug);