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);