class Byebug::Context
Mantains context information for the debugger and it's the main communication point between the library and the C-extension through the #at_breakpoint, #at_catchpoint, #at_tracing, #at_line and #at_return callbacks
Attributes
Public Class Methods
List of files byebug will ignore while debugging
# File lib/byebug/context.rb, line 23 def ignored_files @ignored_files ||= Byebug.mode == :standalone ? lib_files + [bin_file] : lib_files end
# File lib/byebug/context.rb, line 30 def interface @interface ||= LocalInterface.new end
# File lib/byebug/context.rb, line 36 def processor @processor ||= CommandProcessor end
Public Instance Methods
Breakpoint handler
# File lib/byebug/context.rb, line 111 def at_breakpoint(breakpoint) processor.at_breakpoint(breakpoint) end
Catchpoint handler
# File lib/byebug/context.rb, line 118 def at_catchpoint(exception) processor.at_catchpoint(exception) end
End of class definition handler
# File lib/byebug/context.rb, line 134 def at_end return if ignored_file?(file) processor.at_end end
Line handler
# File lib/byebug/context.rb, line 92 def at_line self.frame = 0 return if ignored_file?(file) processor.at_line end
Return handler
# File lib/byebug/context.rb, line 125 def at_return(return_value) return if ignored_file?(file) processor.at_return(return_value) end
Tracing handler
# File lib/byebug/context.rb, line 102 def at_tracing return if ignored_file?(file) processor.at_tracing end
inline VALUE
Context_backtrace(VALUE self)
{
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
return dc_backtrace(context);
}
inline VALUE
Context_dead(VALUE self)
{
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
return CTX_FL_TEST(context, CTX_FL_DEAD) ? Qtrue : Qfalse;
}
Reader for the current frame
# File lib/byebug/context.rb, line 44 def frame @frame ||= Frame.new(self, 0) end
Writer for the current frame
# File lib/byebug/context.rb, line 51 def frame=(pos) @frame = Frame.new(self, pos) end
Returns frame's binding.
static VALUE
Context_frame_binding(int argc, VALUE * argv, VALUE self)
{
FRAME_SETUP;
return dc_frame_binding(context, frame_n);
}
Returns frame's defined class.
static VALUE
Context_frame_class(int argc, VALUE * argv, VALUE self)
{
FRAME_SETUP;
return dc_frame_class(context, frame_n);
}
Returns the name of the file in the frame.
static VALUE
Context_frame_file(int argc, VALUE * argv, VALUE self)
{
VALUE loc, absolute_path;
FRAME_SETUP;
loc = dc_frame_location(context, frame_n);
absolute_path = rb_funcall(loc, rb_intern("absolute_path"), 0);
if (!NIL_P(absolute_path))
return absolute_path;
return rb_funcall(loc, rb_intern("path"), 0);
}
Returns the line number in the file in the frame.
static VALUE
Context_frame_line(int argc, VALUE * argv, VALUE self)
{
VALUE loc;
FRAME_SETUP;
loc = dc_frame_location(context, frame_n);
return rb_funcall(loc, rb_intern("lineno"), 0);
}
Returns the sym of the method in the frame.
static VALUE
Context_frame_method(int argc, VALUE * argv, VALUE self)
{
VALUE loc;
FRAME_SETUP;
loc = dc_frame_location(context, frame_n);
return rb_str_intern(rb_funcall(loc, rb_intern("label"), 0));
}
Returns self object of the frame.
static VALUE
Context_frame_self(int argc, VALUE * argv, VALUE self)
{
FRAME_SETUP;
return dc_frame_self(context, frame_n);
}
Current file, line and source code information
# File lib/byebug/context.rb, line 68 def full_location return location if virtual_file?(file) "#{location} #{get_line(file, line)}" end
inline VALUE
Context_ignored(VALUE self)
{
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
return CTX_FL_TEST(context, CTX_FL_IGNORE) ? Qtrue : Qfalse;
}
# File lib/byebug/context.rb, line 85 def interrupt step_into 1 end
Current file & line information
# File lib/byebug/context.rb, line 61 def location "#{normalize(file)}:#{line}" end
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;
}
Context's stack size
# File lib/byebug/context.rb, line 77 def stack_size return 0 unless backtrace backtrace.drop_while { |l| ignored_file?(l.first.path) } .take_while { |l| !ignored_file?(l.first.path) } .size end
Stops the current context after a number of steps are made
from frame frame (by default the newest one).
static VALUE
Context_step_into(int argc, VALUE * argv, VALUE self)
{
VALUE steps, v_frame;
int n_args, from_frame;
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
if (context->calced_stack_size == 0)
rb_raise(rb_eRuntimeError, "No frames collected.");
n_args = rb_scan_args(argc, argv, "11", &steps, &v_frame);
if (FIX2INT(steps) <= 0)
rb_raise(rb_eRuntimeError, "Steps argument must be positive.");
from_frame = n_args == 1 ? 0 : FIX2INT(v_frame);
if (from_frame < 0 || from_frame >= context->calced_stack_size)
rb_raise(rb_eRuntimeError, "Destination frame (%d) is out of range (%d)",
from_frame, context->calced_stack_size);
else if (from_frame > 0)
CTX_FL_SET(context, CTX_FL_IGNORE_STEPS);
context->steps = FIX2INT(steps);
context->dest_frame = context->calced_stack_size - from_frame;
return steps;
}
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;
}
Steps over lines lines in frame frame (by default
the newest one) or higher (if frame frame finishes).
static VALUE
Context_step_over(int argc, VALUE * argv, VALUE self)
{
int n_args, frame;
VALUE lines, v_frame;
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
if (context->calced_stack_size == 0)
rb_raise(rb_eRuntimeError, "No frames collected.");
n_args = rb_scan_args(argc, argv, "11", &lines, &v_frame);
frame = n_args == 1 ? 0 : FIX2INT(v_frame);
if (frame < 0 || frame >= context->calced_stack_size)
rb_raise(rb_eRuntimeError, "Destination frame (%d) is out of range (%d)",
frame, context->calced_stack_size);
context->lines = FIX2INT(lines);
context->dest_frame = context->calced_stack_size - frame;
return Qnil;
}
static VALUE
Context_stop_reason(VALUE self)
{
debug_context_t *context;
const char *symbol;
Data_Get_Struct(self, debug_context_t, context);
if (CTX_FL_TEST(context, CTX_FL_DEAD))
symbol = "post-mortem";
else
switch (context->stop_reason)
{
case CTX_STOP_STEP:
symbol = "step";
break;
case CTX_STOP_BREAKPOINT:
symbol = "breakpoint";
break;
case CTX_STOP_CATCHPOINT:
symbol = "catchpoint";
break;
case CTX_STOP_NONE:
default:
symbol = "none";
}
return ID2SYM(rb_intern(symbol));
}
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;
}
Returns true if the thread is suspended by debugger.
static VALUE
Context_is_suspended(VALUE self)
{
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
return CTX_FL_TEST(context, CTX_FL_SUSPEND) ? Qtrue : Qfalse;
}
Switches execution to this context.
static VALUE
Context_switch(VALUE self)
{
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
next_thread = context->thread;
context->steps = 1;
context->steps_out = 0;
CTX_FL_SET(context, CTX_FL_STOP_ON_RET);
return Qnil;
}
inline VALUE
Context_thnum(VALUE self)
{
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
return INT2FIX(context->thnum);
}
inline VALUE
Context_thread(VALUE self)
{
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
return context->thread;
}
Returns the tracing flag for the current context.
static VALUE
Context_tracing(VALUE self)
{
debug_context_t *context;
Data_Get_Struct(self, debug_context_t, context);
return CTX_FL_TEST(context, CTX_FL_TRACING) ? Qtrue : Qfalse;
}
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;
}
Private Instance Methods
Tells whether a file is ignored by the debugger.
@param path [String] filename to be checked.
# File lib/byebug/context.rb, line 151 def ignored_file?(path) self.class.ignored_files.include?(path) end
# File lib/byebug/context.rb, line 142 def processor @processor ||= self.class.processor.new(self) end