static VALUE Context_step_over(int argc, VALUE *argv, VALUE self) { VALUE lines, frame, force; debug_context_t *context; Data_Get_Struct(self, debug_context_t, context); if(context->stack_size == 0) rb_raise(rb_eRuntimeError, "No frames collected."); rb_scan_args(argc, argv, "12", &lines, &frame, &force); context->stop_line = FIX2INT(lines); CTX_FL_UNSET(context, CTX_FL_STEPPED); if (frame == Qnil) { context->dest_frame = context->calced_stack_size; } else { if (FIX2INT(frame) < 0 && FIX2INT(frame) >= context->calced_stack_size) rb_raise(rb_eRuntimeError, "Destination frame is out of range."); context->dest_frame = context->calced_stack_size - FIX2INT(frame); } if(RTEST(force)) CTX_FL_SET(context, CTX_FL_FORCE_MOVE); else CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE); return Qnil; }
static void save_current_position(debug_context_t *dc, VALUE file, VALUE line) { dc->last_file = file; dc->last_line = line; CTX_FL_UNSET(dc, CTX_FL_ENABLE_BKPT); CTX_FL_UNSET(dc, CTX_FL_FORCE_MOVE); }
/* * call-seq: * context.step_out(n_frames = 1, force = false) * * Stops after +n_frames+ frames are finished. +force+ parameter (if true) * ensures that the execution will stop in the specified frame even when there * are no more instructions to run. In that case, it will stop when the return * event for that frame is triggered. */ static VALUE Context_step_out(int argc, VALUE * argv, VALUE self) { int n_args, n_frames; VALUE v_frames, force; debug_context_t *context; n_args = rb_scan_args(argc, argv, "02", &v_frames, &force); n_frames = n_args == 0 ? 1 : FIX2INT(v_frames); Data_Get_Struct(self, debug_context_t, context); if (n_frames < 0 || n_frames > context->calced_stack_size) rb_raise(rb_eRuntimeError, "You want to finish %d frames, but stack size is only %d", n_frames, context->calced_stack_size); context->steps_out = n_frames; if (n_args == 2 && RTEST(force)) CTX_FL_SET(context, CTX_FL_STOP_ON_RET); else CTX_FL_UNSET(context, CTX_FL_STOP_ON_RET); return Qnil; }
/* * call-seq: * context.tracing = bool * * Controls the tracing for this context. */ static VALUE Context_set_tracing(VALUE self, VALUE value) { debug_context_t *context; Data_Get_Struct(self, debug_context_t, context); if (RTEST(value)) CTX_FL_SET(context, CTX_FL_TRACING); else CTX_FL_UNSET(context, CTX_FL_TRACING); return value; }
/* * call-seq: * context.resume -> nil * * Resumes thread from the suspended mode. */ static VALUE Context_resume(VALUE self) { debug_context_t *context; Data_Get_Struct(self, debug_context_t, context); if (!CTX_FL_TEST(context, CTX_FL_SUSPEND)) return Qnil; CTX_FL_UNSET(context, CTX_FL_SUSPEND); if (CTX_FL_TEST(context, CTX_FL_WAS_RUNNING)) rb_thread_wakeup(context->thread); return Qnil; }
static VALUE Context_stop_next(int argc, VALUE *argv, VALUE self) { VALUE steps; VALUE force; debug_context_t *context; rb_scan_args(argc, argv, "11", &steps, &force); if(FIX2INT(steps) < 0) rb_raise(rb_eRuntimeError, "Steps argument can't be negative."); Data_Get_Struct(self, debug_context_t, context); context->stop_next = FIX2INT(steps); if(RTEST(force)) CTX_FL_SET(context, CTX_FL_FORCE_MOVE); else CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE); return steps; }
static void call_event(VALUE trace_point, void *data) { VALUE brkpnt, klass, msym, mid, binding, self, file, line; EVENT_SETUP; if (dc->calced_stack_size <= dc->dest_frame) CTX_FL_UNSET(dc, CTX_FL_IGNORE_STEPS); dc->calced_stack_size++; dc->steps_out = dc->steps_out <= 0 ? -1 : dc->steps_out + 1; /* nil method_id means we are at top level so there can't be a method * breakpoint here. Just leave then. */ msym = rb_tracearg_method_id(trace_arg); if (NIL_P(msym)) { EVENT_TEARDOWN; return; } mid = SYM2ID(msym); klass = rb_tracearg_defined_class(trace_arg); binding = rb_tracearg_binding(trace_arg); self = rb_tracearg_self(trace_arg); file = rb_tracearg_path(trace_arg); line = rb_tracearg_lineno(trace_arg); brkpnt = Qnil; if (!NIL_P(breakpoints)) brkpnt = find_breakpoint_by_method(breakpoints, klass, mid, binding, self); if (!NIL_P(brkpnt)) { call_at_breakpoint(context, dc, brkpnt); call_at_line(context, dc, file, line); } EVENT_TEARDOWN; }
/* * call-seq: * context.suspend -> nil * * Suspends the thread when it is running. */ static VALUE Context_suspend(VALUE self) { VALUE status; debug_context_t *context; Data_Get_Struct(self, debug_context_t, context); status = rb_funcall(context->thread, rb_intern("status"), 0); if (rb_str_cmp(status, rb_str_new2("run")) == 0) CTX_FL_SET(context, CTX_FL_WAS_RUNNING); else if (rb_str_cmp(status, rb_str_new2("sleep")) == 0) CTX_FL_UNSET(context, CTX_FL_WAS_RUNNING); else return Qnil; CTX_FL_SET(context, CTX_FL_SUSPEND); return Qnil; }
static void line_event(VALUE trace_point, void *data) { VALUE brkpnt, file, line, binding; EVENT_SETUP; file = rb_tracearg_path(trace_arg); line = rb_tracearg_lineno(trace_arg); binding = rb_tracearg_binding(trace_arg); if (RTEST(tracing)) call_at_tracing(context, dc); if (!CTX_FL_TEST(dc, CTX_FL_IGNORE_STEPS)) dc->steps = dc->steps <= 0 ? -1 : dc->steps - 1; if (dc->calced_stack_size <= dc->dest_frame) { dc->dest_frame = dc->calced_stack_size; CTX_FL_UNSET(dc, CTX_FL_IGNORE_STEPS); dc->lines = dc->lines <= 0 ? -1 : dc->lines - 1; } if (dc->steps == 0 || dc->lines == 0) call_at_line_check(context, dc, Qnil); else { brkpnt = Qnil; if (!NIL_P(breakpoints)) brkpnt = find_breakpoint_by_pos(breakpoints, file, line, binding); if (!NIL_P(brkpnt)) call_at_line_check(context, dc, brkpnt); } EVENT_TEARDOWN; }
static VALUE call_at_return(VALUE context_obj, debug_context_t *dc, VALUE file, VALUE line) { CTX_FL_UNSET(dc, CTX_FL_STOP_ON_RET); return call_at(context_obj, dc, rb_intern("at_return"), 2, file, line); }