class Debugger::Context

Public Instance Methods

__c_frame_binding(*args)
Alias for: frame_binding
breakpoint → breakpoint click to toggle source

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;
}
dead? → bool click to toggle source

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;
}
frame_args(frame_position=0) → list click to toggle source

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);
}
frame_args_info(frame_position=0) → list click to toggle source
if track_frame_args or nil otherwise

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;
}
frame_binding(frame_position=0) → binding click to toggle source

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;
}
Also aliased as: __c_frame_binding
frame_class(frame_position) → obj click to toggle source

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;
}
frame_file(frame_position) → string click to toggle source

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);
}
frame_line(frame_position) → int click to toggle source

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));
}
frame_locals(frame) → hash click to toggle source

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);
}
frame_method(frame_position=0) → sym click to toggle source

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);
}
frame_self(frame_postion=0) → obj click to toggle source

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);
}
ignored? → bool click to toggle source

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;
}
interrupt() click to toggle source
# File lib/ruby-debug-base.rb, line 16
def interrupt
  self.stop_next = 1
end
jump(line, file) → bool click to toggle source

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 */
}
break → bool click to toggle source

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);
}
resume → nil click to toggle source

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;
}
set_breakpoint(source, pos, condition = nil) → breakpoint click to toggle source

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;
}
stack_size→ int click to toggle source

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);
}
step(steps, force = false) click to toggle source

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;
}
step_over(steps, frame = nil, force = false) click to toggle source

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;
}
stop_frame(frame) click to toggle source

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;
}
stop_reason → sym click to toggle source

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));
}
suspend → nil click to toggle source

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;
}
suspended? → bool click to toggle source

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;
}
thnum → int click to toggle source

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);
}
thread → thread click to toggle source

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));
}
tracing → bool click to toggle source

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;
}
tracing = bool click to toggle source

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

Private Instance Methods

at_breakpoint(breakpoint) click to toggle source
# File lib/ruby-debug-base.rb, line 41
def at_breakpoint(breakpoint)
  handler.at_breakpoint(self, breakpoint)
end
at_catchpoint(excpt) click to toggle source
# File lib/ruby-debug-base.rb, line 45
def at_catchpoint(excpt)
  handler.at_catchpoint(self, excpt)
end
at_line(file, line) click to toggle source
# File lib/ruby-debug-base.rb, line 54
def at_line(file, line)
  handler.at_line(self, file, line)
end
at_return(file, line) click to toggle source
# File lib/ruby-debug-base.rb, line 58
def at_return(file, line)
  handler.at_return(self, file, line)
end
at_tracing(file, line) click to toggle source
# 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
handler() click to toggle source
# File lib/ruby-debug-base.rb, line 37
def handler
  Debugger.handler or raise 'No interface loaded'
end
hbinding(frame) click to toggle source
# 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