Returns a context-specific temporary Breakpoint object.
VALUE context_breakpoint(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); return debug_context->breakpoint; }
Returns true
if context doesn't represent a live context
and is created during post-mortem exception handling.
static VALUE context_dead(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); return CTX_FL_TEST(debug_context, CTX_FL_DEAD) ? Qtrue : Qfalse; }
Returns frame's argument parameters
static VALUE context_frame_args(int argc, VALUE *argv, VALUE self) { VALUE frame; debug_context_t *debug_context; debug_frame_t *debug_frame; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); debug_frame = GET_FRAME; if (debug_frame->dead) return debug_frame->info.copy.args; else return context_copy_args(debug_frame); }
Returns info saved about call arguments (if any saved).
static VALUE context_frame_args_info(int argc, VALUE *argv, VALUE self) { VALUE frame; debug_context_t *debug_context; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); return RTEST(track_frame_args) ? GET_FRAME->arg_ary : Qnil; }
Returns frame's binding.
static VALUE context_frame_binding(int argc, VALUE *argv, VALUE self) { VALUE frame; debug_context_t *debug_context; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); return GET_FRAME->binding; }
Returns the real class of the frame. It could be different than context.frame_self(frame).class
static VALUE context_frame_class(int argc, VALUE *argv, VALUE self) { VALUE klass; VALUE frame; debug_context_t *debug_context; debug_frame_t *debug_frame; rb_control_frame_t *cfp; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); debug_frame = GET_FRAME; cfp = debug_frame->info.runtime.cfp; klass = real_class(cfp->iseq->klass); if(TYPE(klass) == T_CLASS || TYPE(klass) == T_MODULE) return klass; return Qnil; }
Returns the name of the file.
static VALUE context_frame_file(int argc, VALUE *argv, VALUE self) { VALUE frame; debug_context_t *debug_context; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); return rb_str_new_cstr(GET_FRAME->file); //return(GET_FRAME->info.runtime.cfp->iseq->filename); }
Returns the sym of the called method.
static VALUE context_frame_id(int argc, VALUE *argv, VALUE self) { ID id; VALUE frame; VALUE frame_id; debug_context_t *debug_context; rb_control_frame_t *cfp; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); cfp = GET_FRAME->info.runtime.cfp; #if defined HAVE_RB_CONTROL_FRAME_T_METHOD_ID frame_id = (RUBYVM_CFUNC_FRAME_P(cfp) ? ID2SYM(cfp->method_id) : (cfp->iseq->defined_method_id)); #elif defined HAVE_RB_METHOD_ENTRY_T_CALLED_ID frame_id = (RUBYVM_CFUNC_FRAME_P(cfp) ? ID2SYM(cfp->me->called_id) : (cfp->iseq->defined_method_id)); #endif return (frame_id ? ID2SYM(frame_id) : Qnil); }
Returns the line number in the file.
static VALUE context_frame_line(int argc, VALUE *argv, VALUE self) { VALUE frame; debug_context_t *debug_context; rb_thread_t *th; rb_control_frame_t *cfp; VALUE *pc; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); GetThreadPtr(context_thread_0(debug_context), th); pc = GET_FRAME->info.runtime.last_pc; cfp = GET_FRAME->info.runtime.cfp; while (cfp >= th->cfp) { if ((cfp->iseq != NULL) && (pc >= cfp->iseq->iseq_encoded) && (pc < cfp->iseq->iseq_encoded + cfp->iseq->iseq_size)) return(INT2FIX(rb_vm_get_sourceline(cfp))); cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp); } return(INT2FIX(0)); }
Returns frame's local variables.
static VALUE context_frame_locals(int argc, VALUE *argv, VALUE self) { VALUE frame; debug_context_t *debug_context; debug_frame_t *debug_frame; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); debug_frame = GET_FRAME; if (debug_frame->dead) return debug_frame->info.copy.locals; else return context_copy_locals(debug_context, debug_frame, self); }
Returns the sym of the called method.
static VALUE context_frame_id(int argc, VALUE *argv, VALUE self) { ID id; VALUE frame; VALUE frame_id; debug_context_t *debug_context; rb_control_frame_t *cfp; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); cfp = GET_FRAME->info.runtime.cfp; #if defined HAVE_RB_CONTROL_FRAME_T_METHOD_ID frame_id = (RUBYVM_CFUNC_FRAME_P(cfp) ? ID2SYM(cfp->method_id) : (cfp->iseq->defined_method_id)); #elif defined HAVE_RB_METHOD_ENTRY_T_CALLED_ID frame_id = (RUBYVM_CFUNC_FRAME_P(cfp) ? ID2SYM(cfp->me->called_id) : (cfp->iseq->defined_method_id)); #endif return (frame_id ? ID2SYM(frame_id) : Qnil); }
Returns self object of the frame.
static VALUE context_frame_self(int argc, VALUE *argv, VALUE self) { VALUE frame; debug_context_t *debug_context; debug_frame_t *debug_frame; debug_check_started(); frame = optional_frame_position(argc, argv); Data_Get_Struct(self, debug_context_t, debug_context); debug_frame = GET_FRAME; return(debug_frame->self); }
Returns the ignore flag for the current context.
static VALUE context_ignored(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); return CTX_FL_TEST(debug_context, CTX_FL_IGNORE) ? Qtrue : Qfalse; }
# File lib/ruby-debug-base.rb, line 16 def interrupt self.stop_next = 1 end
Returns true
if jump to line
in filename
file
was successful.
static VALUE context_jump(VALUE self, VALUE line, VALUE file) { debug_context_t *debug_context; debug_frame_t *debug_frame; int i; rb_thread_t *th; rb_control_frame_t *cfp; rb_control_frame_t *cfp_end; rb_control_frame_t *cfp_start = NULL; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); GetThreadPtr(context_thread_0(debug_context), th); debug_frame = get_top_frame(debug_context); if (debug_frame == NULL) rb_raise(rb_eRuntimeError, "No frames collected."); line = FIX2INT(line); /* find topmost frame of the debugged code */ cfp = th->cfp; cfp_end = RUBY_VM_END_CONTROL_FRAME(th); while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, cfp_end)) { if (cfp->pc == debug_frame->info.runtime.last_pc) { cfp_start = cfp; if ((cfp->pc - cfp->iseq->iseq_encoded) >= (cfp->iseq->iseq_size - 1)) return(INT2FIX(1)); /* no space for opt_call_c_function hijack */ break; } cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); } if (cfp_start == NULL) return(INT2FIX(2)); /* couldn't find frame; should never happen */ /* find target frame to jump to */ while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, cfp_end)) { #ifdef HAVE_RB_ISEQ_T_LOCATION if ((cfp->iseq != NULL) && (rb_str_cmp(file, cfp->iseq->location.path) == 0)) #else if ((cfp->iseq != NULL) && (rb_str_cmp(file, cfp->iseq->filename) == 0)) #endif { #ifdef HAVE_RB_ISEQ_T_LINE_INFO_SIZE for (i = 0; i < cfp->iseq->line_info_size; i++) #else for (i = 0; i < cfp->iseq->insn_info_size; i++) #endif { #ifdef HAVE_RB_ISEQ_T_LINE_INFO_SIZE if (cfp->iseq->line_info_table[i].line_no != line) #else if (cfp->iseq->insn_info_table[i].line_no != line) #endif continue; /* hijack the currently running code so that we can change the frame PC */ debug_context->saved_jump_ins[0] = cfp_start->pc[0]; debug_context->saved_jump_ins[1] = cfp_start->pc[1]; cfp_start->pc[0] = opt_call_c_function; cfp_start->pc[1] = (VALUE)do_jump; debug_context->jump_cfp = cfp; #ifdef HAVE_RB_ISEQ_T_LINE_INFO_SIZE debug_context->jump_pc = cfp->iseq->iseq_encoded + cfp->iseq->line_info_table[i].position; #else debug_context->jump_pc = cfp->iseq->iseq_encoded + cfp->iseq->insn_info_table[i].position; #endif return(INT2FIX(0)); /* success */ } } cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); } return(INT2FIX(3)); /* couldn't find a line and file frame match */ }
Returns true
if context is currently running and set flag to
break it at next line
static VALUE context_pause(VALUE self) { debug_context_t *debug_context; rb_thread_t *th; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); if (CTX_FL_TEST(debug_context, CTX_FL_DEAD)) return(Qfalse); GetThreadPtr(context_thread_0(debug_context), th); if (th == GET_THREAD2()) return(Qfalse); debug_context->thread_pause = 1; return(Qtrue); }
Resumes the thread from the suspended mode.
static VALUE context_resume(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); if(!CTX_FL_TEST(debug_context, CTX_FL_SUSPEND)) rb_raise(rb_eRuntimeError, "Thread is not suspended."); context_resume_0(debug_context); return Qnil; }
Sets a context-specific temporary breakpoint, which can be used to implement 'Run to Cursor' debugger function. When this breakpoint is reached, it will be cleared out.
source is a name of a file or a class. pos is a line
number or a method name if source is a class name.
condition is a string which is evaluated to true
when
this breakpoint is activated.
VALUE context_set_breakpoint(int argc, VALUE *argv, VALUE self) { VALUE result; debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); result = create_breakpoint_from_args(argc, argv, 0); debug_context->breakpoint = result; return result; }
Returns the size of the context stack.
static VALUE context_stack_size(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); return INT2FIX(debug_context->stack_size); }
Stops the current context after a number of steps
are made.
force
parameter (if true) ensures that the cursor moves from
the current line.
static VALUE context_stop_next(int argc, VALUE *argv, VALUE self) { VALUE steps, force; debug_context_t *debug_context; debug_check_started(); 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, debug_context); debug_context->stop_next = FIX2INT(steps); if(RTEST(force)) CTX_FL_SET(debug_context, CTX_FL_FORCE_MOVE); else CTX_FL_UNSET(debug_context, CTX_FL_FORCE_MOVE); return steps; }
Steps over a steps
number of times. Make step over operation
on frame
, by default the current frame. force
parameter (if true) ensures that the cursor moves from the current line.
static VALUE context_step_over(int argc, VALUE *argv, VALUE self) { VALUE lines, frame, force; debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); if(debug_context->stack_size == 0) rb_raise(rb_eRuntimeError, "No frames collected."); rb_scan_args(argc, argv, "12", &lines, &frame, &force); debug_context->stop_line = FIX2INT(lines); CTX_FL_UNSET(debug_context, CTX_FL_STEPPED); if(frame == Qnil) { debug_context->dest_frame = debug_context->stack_size; } else { if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size) rb_raise(rb_eRuntimeError, "Destination frame is out of range."); debug_context->dest_frame = debug_context->stack_size - FIX2INT(frame); } if(RTEST(force)) CTX_FL_SET(debug_context, CTX_FL_FORCE_MOVE); else CTX_FL_UNSET(debug_context, CTX_FL_FORCE_MOVE); return Qnil; }
Stops when a frame with number frame
is activated. Implements
finish
and next
commands.
static VALUE context_stop_frame(VALUE self, VALUE frame) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size) rb_raise(rb_eRuntimeError, "Stop frame is out of range."); debug_context->stop_frame = debug_context->stack_size - FIX2INT(frame); return frame; }
Stops the current context after a number of steps
are made.
force
parameter (if true) ensures that the cursor moves from
the current line.
static VALUE context_stop_next(int argc, VALUE *argv, VALUE self) { VALUE steps, force; debug_context_t *debug_context; debug_check_started(); 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, debug_context); debug_context->stop_next = FIX2INT(steps); if(RTEST(force)) CTX_FL_SET(debug_context, CTX_FL_FORCE_MOVE); else CTX_FL_UNSET(debug_context, CTX_FL_FORCE_MOVE); return steps; }
Returns the reason for the stop. It maybe of the following values: :initial, :step, :breakpoint, :catchpoint, :post-mortem
static VALUE context_stop_reason(VALUE self) { debug_context_t *debug_context; const char * sym_name; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); switch(debug_context->stop_reason) { case CTX_STOP_STEP: sym_name = "step"; break; case CTX_STOP_BREAKPOINT: sym_name = "breakpoint"; break; case CTX_STOP_CATCHPOINT: sym_name = "catchpoint"; break; case CTX_STOP_NONE: default: sym_name = "none"; } if(CTX_FL_TEST(debug_context, CTX_FL_DEAD)) sym_name = "post-mortem"; return ID2SYM(rb_intern(sym_name)); }
Suspends the thread when it is running.
static VALUE context_suspend(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND)) rb_raise(rb_eRuntimeError, "Already suspended."); context_suspend_0(debug_context); return Qnil; }
Returns true
if the thread is suspended by debugger.
static VALUE context_is_suspended(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); return CTX_FL_TEST(debug_context, CTX_FL_SUSPEND) ? Qtrue : Qfalse; }
Returns the context's number.
static VALUE context_thnum(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); return INT2FIX(debug_context->thnum); }
Returns a thread this context is associated with.
static VALUE context_thread(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); return(id2ref(debug_context->thread_id)); }
Returns the tracing flag for the current context.
static VALUE context_tracing(VALUE self) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); return CTX_FL_TEST(debug_context, CTX_FL_TRACING) ? Qtrue : Qfalse; }
Controls the tracing for this context.
static VALUE context_set_tracing(VALUE self, VALUE value) { debug_context_t *debug_context; debug_check_started(); Data_Get_Struct(self, debug_context_t, debug_context); if(RTEST(value)) CTX_FL_SET(debug_context, CTX_FL_TRACING); else CTX_FL_UNSET(debug_context, CTX_FL_TRACING); return value; }
# File lib/ruby-debug-base.rb, line 41 def at_breakpoint(breakpoint) handler.at_breakpoint(self, breakpoint) end
# File lib/ruby-debug-base.rb, line 45 def at_catchpoint(excpt) handler.at_catchpoint(self, excpt) end
# File lib/ruby-debug-base.rb, line 54 def at_line(file, line) handler.at_line(self, file, line) end
# File lib/ruby-debug-base.rb, line 58 def at_return(file, line) handler.at_return(self, file, line) end
# File lib/ruby-debug-base.rb, line 49 def at_tracing(file, line) @tracing_started = true if File.identical?(file, File.join(Debugger::INITIAL_DIR, Debugger::PROG_SCRIPT)) handler.at_tracing(self, file, line) if @tracing_started end
# File lib/ruby-debug-base.rb, line 37 def handler Debugger.handler or raise 'No interface loaded' end
# File lib/ruby-debug-base.rb, line 27 def hbinding(frame) hash = frame_locals(frame) code = hash.keys.map{|k| "#{k} = hash['#{k}']" unless k=='self' }.compact.join(';') + ';binding' if obj = frame_self(frame) obj.instance_eval code else eval code, TOPLEVEL_BINDING end end