ext/byebug/byebug.c in byebug-0.0.1 vs ext/byebug/byebug.c in byebug-1.0.0

- old
+ new

@@ -2,26 +2,24 @@ static VALUE mByebug; /* Ruby Byebug Module object */ static VALUE cContext; static VALUE cDebugThread; -static VALUE debug = Qfalse; -static VALUE locker = Qnil; +static VALUE tracing = 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 tpReturn; static VALUE tpRaise; static VALUE idAlive; -static VALUE idAtBreakpoint; -static VALUE idAtCatchpoint; -static VALUE idAtLine; -static VALUE idAtTracing; static void print_debug_info(char *event, VALUE path, VALUE lineno, VALUE method_id, VALUE defined_class, int stack_size) { @@ -85,13 +83,11 @@ */ if(CTX_FL_TEST(context, CTX_FL_IGNORE)) return 0; while(1) { - /* halt execution of the current thread if the byebug - is activated in another - */ + /* halt execution of the current thread if byebug is activated in another */ while(locker != Qnil && locker != thread) { add_to_locked(thread); rb_thread_stop(); } @@ -138,74 +134,80 @@ static void call_at_line(debug_context_t *context, char *file, int line, VALUE context_object, VALUE path, VALUE lineno) { - CTX_FL_UNSET(context, CTX_FL_STEPPED); + CTX_FL_UNSET(context, CTX_FL_ENABLE_BKPT); CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE); context->last_file = file; context->last_line = line; - rb_funcall(context_object, idAtLine, 2, path, lineno); + rb_funcall(context_object, rb_intern("at_line"), 2, path, lineno); } static void process_line_event(VALUE trace_point, void *data) { VALUE path, lineno, method_id, defined_class, binding, self; VALUE context_object; VALUE breakpoint; debug_context_t *context; - int moved; + 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; - load_frame_info(trace_point, &path, &lineno, &method_id, &defined_class, - &binding, &self); + load_frame_info( + trace_point, &path, &lineno, &method_id, &defined_class, &binding, &self); if (debug == Qtrue) - print_debug_info("line", path, lineno, method_id, defined_class, - context->stack_size); + print_debug_info( + "line", path, lineno, method_id, defined_class, context->stack_size); update_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id, defined_class, binding, self); - moved = context->last_line != FIX2INT(lineno) || context->last_file == NULL || - strcmp(context->last_file, RSTRING_PTR(path)) != 0; + 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; + } - if (CTX_FL_TEST(context, CTX_FL_TRACING)) - rb_funcall(context_object, idAtTracing, 2, path, lineno); + if (RTEST(tracing)) + rb_funcall(context_object, rb_intern("at_tracing"), 2, path, lineno); if (context->dest_frame == -1 || context->stack_size == context->dest_frame) { - if (moved || !CTX_FL_TEST(context, CTX_FL_FORCE_MOVE)) - context->stop_next--; - if (context->stop_next < 0) - context->stop_next = -1; - if (moved || (CTX_FL_TEST(context, CTX_FL_STEPPED) && !CTX_FL_TEST(context, CTX_FL_FORCE_MOVE))) - { - context->stop_line--; - CTX_FL_UNSET(context, CTX_FL_STEPPED); - } + if (moved || !CTX_FL_TEST(context, CTX_FL_FORCE_MOVE)) { + context->stop_next = context->stop_next <= 0 ? -1 : context->stop_next-1; + context->stop_line = context->stop_line <= 0 ? -1 : context->stop_line-1; + } } else if (context->stack_size < context->dest_frame) { context->stop_next = 0; } - breakpoint = find_breakpoint_by_pos(breakpoints, path, lineno, binding); - if (context->stop_next == 0 || context->stop_line == 0 || - breakpoint != Qnil) + if (context->stop_next == 0 || context->stop_line == 0) { context->stop_reason = CTX_STOP_STEP; + reset_stepping_stop_points(context); + call_at_line( + context, RSTRING_PTR(path), FIX2INT(lineno), context_object, path, lineno); + } + else if (CTX_FL_TEST(context, CTX_FL_ENABLE_BKPT)) + { + breakpoint = find_breakpoint_by_pos(breakpoints, path, lineno, binding); if (breakpoint != Qnil) { - rb_funcall(context_object, idAtBreakpoint, 1, breakpoint); + context->stop_reason = CTX_STOP_BREAKPOINT; + reset_stepping_stop_points(context); + rb_funcall(context_object, rb_intern("at_breakpoint"), 1, breakpoint); + call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object, + path, lineno); } - reset_stepping_stop_points(context); - call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object, - path, lineno); } + cleanup(context); } static void process_return_event(VALUE trace_point, void *data) @@ -216,11 +218,11 @@ 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 == context->stop_frame) + if (context->stack_size == context->stop_frame) { context->stop_next = 1; context->stop_frame = 0; } @@ -228,13 +230,13 @@ &binding, &self); if (debug == Qtrue) print_debug_info("return", path, lineno, method_id, defined_class, context->stack_size); - // rb_funcall(context_object, idAtReturn, 2, path, lineno); - + //rb_funcall(context_object, idAtReturn, 2, path, lineno); pop_frame(context_object); + cleanup(context); } static void process_call_event(VALUE trace_point, void *data) @@ -260,11 +262,11 @@ breakpoint = find_breakpoint_by_method(breakpoints, defined_class, SYM2ID(method_id), binding, self); if (breakpoint != Qnil) { context->stop_reason = CTX_STOP_BREAKPOINT; - rb_funcall(context_object, idAtBreakpoint, 1, breakpoint); + rb_funcall(context_object, rb_intern("at_breakpoint"), 1, breakpoint); call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object, path, lineno); } cleanup(context); @@ -273,46 +275,66 @@ static void process_raise_event(VALUE trace_point, void *data) { VALUE path, lineno, method_id, defined_class, binding, self; VALUE context_object; - VALUE hit_count; - VALUE exception_name; + VALUE expn_class, aclass; + VALUE err = rb_errinfo(); + VALUE ancestors; debug_context_t *context; - int c_hit_count; + 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); update_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id, defined_class, binding, self); - if (catchpoint_hit_count(catchpoints, rb_errinfo(), &exception_name) != Qnil) { - /* On 64-bit systems with gcc and -O2 there seems to be - an optimization bug in running INT2FIX(FIX2INT...)..) - So we do this in two steps. - */ - c_hit_count = FIX2INT(rb_hash_aref(catchpoints, exception_name)) + 1; - hit_count = INT2FIX(c_hit_count); - rb_hash_aset(catchpoints, exception_name, hit_count); - context->stop_reason = CTX_STOP_CATCHPOINT; - rb_funcall(context_object, idAtCatchpoint, 1, rb_errinfo()); - call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object, - path, lineno); + if (debug == Qtrue) + print_debug_info("call", path, lineno, method_id, defined_class, + context->stack_size); + expn_class = rb_obj_class(err); + + if (catchpoints == Qnil || + context->stack_size == 0 || + CTX_FL_TEST(context, CTX_FL_CATCHING) || + RHASH_TBL(catchpoints)->num_entries == 0) { + cleanup(context); + return; } + ancestors = rb_mod_ancestors(expn_class); + for (i = 0; i < RARRAY_LEN(ancestors); i++) { + VALUE mod_name; + VALUE hit_count; + + aclass = rb_ary_entry(ancestors, i); + mod_name = rb_mod_name(aclass); + hit_count = rb_hash_aref(catchpoints, mod_name); + + if (hit_count != Qnil) { + /* increment exception */ + rb_hash_aset(catchpoints, mod_name, INT2FIX(FIX2INT(hit_count) + 1)); + context->stop_reason = CTX_STOP_CATCHPOINT; + rb_funcall(context_object, rb_intern("at_catchpoint"), 1, rb_errinfo()); + call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object, + path, lineno); + break; + } + } + cleanup(context); } - static VALUE Byebug_setup_tracepoints(VALUE self) { if (catchpoints != Qnil) return Qnil; + contexts = rb_hash_new(); breakpoints = rb_ary_new(); catchpoints = rb_hash_new(); tpLine = rb_tracepoint_new(Qnil, @@ -434,11 +456,22 @@ rb_exec_end_proc(); return Qnil; } +static VALUE +Byebug_tracing(VALUE self) +{ + return tracing; +} +static VALUE +Byebug_set_tracing(VALUE self, VALUE value) +{ + tracing = RTEST(value) ? Qtrue : Qfalse; + return value; +} static VALUE Byebug_contexts(VALUE self) { VALUE ary; @@ -465,37 +498,50 @@ if (catchpoints == Qnil) rb_raise(rb_eRuntimeError, "Byebug.start is not called yet."); return catchpoints; } +static VALUE +Byebug_add_catchpoint(VALUE self, VALUE value) +{ + if (TYPE(value) != T_STRING) + rb_raise(rb_eTypeError, "value of a catchpoint must be String"); + + rb_hash_aset(catchpoints, rb_str_dup(value), INT2FIX(0)); + return value; +} + /* * Document-class: Byebug * * == Summary * - * This is a singleton class allows controlling the byebug. Use it to start/stop + * This is a singleton class allows controlling byebug. Use it to start/stop * byebug, set/remove breakpoints, etc. */ void Init_byebug() { mByebug = rb_define_module("Byebug"); - rb_define_module_function(mByebug, "setup_tracepoints", Byebug_setup_tracepoints, 0); - rb_define_module_function(mByebug, "remove_tracepoints", Byebug_remove_tracepoints, 0); - rb_define_module_function(mByebug, "current_context", Byebug_current_context, 0); + rb_define_module_function(mByebug, "setup_tracepoints", + Byebug_setup_tracepoints, 0); + rb_define_module_function(mByebug, "remove_tracepoints", + Byebug_remove_tracepoints, 0); + rb_define_module_function(mByebug, "current_context", + Byebug_current_context, 0); rb_define_module_function(mByebug, "contexts", Byebug_contexts, 0); rb_define_module_function(mByebug, "breakpoints", Byebug_breakpoints, 0); + rb_define_module_function(mByebug, "add_catchpoint", + 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_set_tracing, 1); rb_define_module_function(mByebug, "debug_load", Byebug_load, -1); idAlive = rb_intern("alive?"); - idAtBreakpoint = rb_intern("at_breakpoint"); - idAtCatchpoint = rb_intern("at_catchpoint"); - idAtTracing = rb_intern("at_tracing"); - idAtLine = rb_intern("at_line"); cContext = Init_context(mByebug); Init_breakpoint(mByebug);