class Debugger::Context

Public Instance Methods

__c_frame_binding(frame) click to toggle source
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) click to toggle source

Returns frame's binding.

# File lib/ruby-debug-base.rb, line 21
def frame_binding(frame)
  __c_frame_binding(frame) || hbinding(frame)
end
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(GET_FRAME->info.runtime.cfp->iseq->filename);
}
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;
    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
    return(RUBYVM_CFUNC_FRAME_P(cfp) ? ID2SYM(cfp->method_id) : ID2SYM(cfp->iseq->defined_method_id));
#elif defined HAVE_RB_METHOD_ENTRY_T_CALLED_ID
    return(RUBYVM_CFUNC_FRAME_P(cfp) ? ID2SYM(cfp->me->called_id) : ID2SYM(cfp->iseq->defined_method_id));
#endif
}
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;
    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
    return(RUBYVM_CFUNC_FRAME_P(cfp) ? ID2SYM(cfp->method_id) : ID2SYM(cfp->iseq->defined_method_id));
#elif defined HAVE_RB_METHOD_ENTRY_T_CALLED_ID
    return(RUBYVM_CFUNC_FRAME_P(cfp) ? ID2SYM(cfp->me->called_id) : ID2SYM(cfp->iseq->defined_method_id));
#endif
}
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))
    {
        if ((cfp->iseq != NULL) && (rb_str_cmp(file, cfp->iseq->filename) == 0))
        {
            for (i = 0; i < cfp->iseq->insn_info_size; i++)
            {
                if (cfp->iseq->insn_info_table[i].line_no != line)
                    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;
                debug_context->jump_pc =
                    cfp->iseq->iseq_encoded + cfp->iseq->insn_info_table[i].position;

                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_THREAD())
        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;
}
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;
}
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;
}