Class: Byebug::Context

Inherits:
Object
  • Object
show all
Extended by:
Helpers::PathHelper, Forwardable
Includes:
Helpers::FileHelper
Defined in:
lib/byebug/context.rb,
ext/byebug/context.c

Overview

Maintains 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

Class Attribute Summary collapse

Instance Method Summary collapse

Methods included from Helpers::PathHelper

all_files, bin_file, gem_files, lib_files, root_path, test_files

Methods included from Helpers::FileHelper

#get_line, #get_lines, #n_lines, #normalize, #shortpath, #virtual_file?

Class Attribute Details

.ignored_filesObject

List of files byebug will ignore while debugging



25
26
27
28
# File 'lib/byebug/context.rb', line 25

def ignored_files
  @ignored_files ||=
    Byebug.mode == :standalone ? lib_files + [bin_file] : lib_files
end

.interfaceObject



32
33
34
# File 'lib/byebug/context.rb', line 32

def interface
  @interface ||= LocalInterface.new
end

.processorObject



38
39
40
# File 'lib/byebug/context.rb', line 38

def processor
  @processor ||= CommandProcessor
end

Instance Method Details

#at_breakpoint(breakpoint) ⇒ Object

Breakpoint handler



113
114
115
# File 'lib/byebug/context.rb', line 113

def at_breakpoint(breakpoint)
  processor.at_breakpoint(breakpoint)
end

#at_catchpoint(exception) ⇒ Object

Catchpoint handler



120
121
122
# File 'lib/byebug/context.rb', line 120

def at_catchpoint(exception)
  processor.at_catchpoint(exception)
end

#at_endObject

End of class definition handler



136
137
138
139
140
# File 'lib/byebug/context.rb', line 136

def at_end
  return if ignored_file?(file)

  processor.at_end
end

#at_lineObject

Line handler



94
95
96
97
98
99
# File 'lib/byebug/context.rb', line 94

def at_line
  self.frame = 0
  return if ignored_file?(file)

  processor.at_line
end

#at_return(return_value) ⇒ Object

Return handler



127
128
129
130
131
# File 'lib/byebug/context.rb', line 127

def at_return(return_value)
  return if ignored_file?(file)

  processor.at_return(return_value)
end

#at_tracingObject

Tracing handler



104
105
106
107
108
# File 'lib/byebug/context.rb', line 104

def at_tracing
  return if ignored_file?(file)

  processor.at_tracing
end

#backtraceObject

#dead?Boolean

Returns:

  • (Boolean)

#frameObject

Reader for the current frame



46
47
48
# File 'lib/byebug/context.rb', line 46

def frame
  @frame ||= Frame.new(self, 0)
end

#frame=(pos) ⇒ Object

Writer for the current frame



53
54
55
# File 'lib/byebug/context.rb', line 53

def frame=(pos)
  @frame = Frame.new(self, pos)
end

#frame_binding(frame_position = 0) ⇒ Binding

Returns frame’s binding.

Returns:

  • (Binding)


242
243
244
245
246
247
248
# File 'ext/byebug/context.c', line 242

static VALUE
Context_frame_binding(int argc, VALUE *argv, VALUE self)
{
  FRAME_SETUP;

  return dc_frame_binding(context, frame_n);
}

#frame_class(frame_position = 0) ⇒ Class

Returns frame’s defined class.

Returns:

  • (Class)


256
257
258
259
260
261
262
# File 'ext/byebug/context.c', line 256

static VALUE
Context_frame_class(int argc, VALUE *argv, VALUE self)
{
  FRAME_SETUP;

  return dc_frame_class(context, frame_n);
}

#frame_file(frame_position = 0) ⇒ String

Returns the name of the file in the frame.

Returns:

  • (String)


270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'ext/byebug/context.c', line 270

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

#frame_line(frame_position = 0) ⇒ Integer

Returns the line number in the file in the frame.

Returns:

  • (Integer)


293
294
295
296
297
298
299
300
301
302
303
# File 'ext/byebug/context.c', line 293

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

#frame_method(frame_position = 0) ⇒ Object

Returns the sym of the method in the frame.



311
312
313
314
315
316
317
318
319
320
321
# File 'ext/byebug/context.c', line 311

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

#frame_self(frame_postion = 0) ⇒ Object

Returns self object of the frame.

Returns:

  • (Object)


329
330
331
332
333
334
335
# File 'ext/byebug/context.c', line 329

static VALUE
Context_frame_self(int argc, VALUE *argv, VALUE self)
{
  FRAME_SETUP;

  return dc_frame_self(context, frame_n);
}

#full_locationObject

Current file, line and source code information



70
71
72
73
74
# File 'lib/byebug/context.rb', line 70

def full_location
  return location if virtual_file?(file)

  "#{location} #{get_line(file, line)}"
end

#ignored?Boolean

Returns:

  • (Boolean)

#interruptObject



87
88
89
# File 'lib/byebug/context.rb', line 87

def interrupt
  step_into 1
end

#locationObject

Current file & line information



63
64
65
# File 'lib/byebug/context.rb', line 63

def location
  "#{normalize(file)}:#{line}"
end

#resumenil

Resumes thread from the suspended mode.

Returns:

  • (nil)


358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'ext/byebug/context.c', line 358

static VALUE
Context_resume(VALUE self)
{
  debug_context_t *context = debug_context_ptr(self);

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

#stack_sizeObject

Context’s stack size



79
80
81
82
83
84
85
# File 'lib/byebug/context.rb', line 79

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

#step_into(steps, frame = 0) ⇒ Object

Stops the current context after a number of steps are made from frame frame (by default the newest one).



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'ext/byebug/context.c', line 422

static VALUE
Context_step_into(int argc, VALUE *argv, VALUE self)
{
  VALUE steps, v_frame;
  int n_args, from_frame;
  debug_context_t *context = debug_context_ptr(self);

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

#step_out(n_frames = 1, force = false) ⇒ Object

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.



460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'ext/byebug/context.c', line 460

static VALUE
Context_step_out(int argc, VALUE *argv, VALUE self)
{
  int n_args, n_frames;
  VALUE v_frames, force;
  debug_context_t *context = debug_context_ptr(self);

  n_args = rb_scan_args(argc, argv, "02", &v_frames, &force);
  n_frames = n_args == 0 ? 1 : FIX2INT(v_frames);

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

#step_over(lines, frame = 0) ⇒ Object

Steps over lines lines in frame frame (by default the newest one) or higher (if frame frame finishes).



491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
# File 'ext/byebug/context.c', line 491

static VALUE
Context_step_over(int argc, VALUE *argv, VALUE self)
{
  int n_args, frame;
  VALUE lines, v_frame;
  debug_context_t *context = debug_context_ptr(self);

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

#stop_reasonObject



388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'ext/byebug/context.c', line 388

static VALUE
Context_stop_reason(VALUE self)
{
  debug_context_t *context = debug_context_ptr(self);
  const char *symbol;

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

#suspendnil

Suspends the thread when it is running.

Returns:

  • (nil)


520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# File 'ext/byebug/context.c', line 520

static VALUE
Context_suspend(VALUE self)
{
  VALUE status;
  debug_context_t *context = debug_context_ptr(self);

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

#suspended?Boolean

Returns true if the thread is suspended by debugger.

Returns:

  • (Boolean)


566
567
568
569
570
571
572
# File 'ext/byebug/context.c', line 566

static VALUE
Context_is_suspended(VALUE self)
{
  debug_context_t *context = debug_context_ptr(self);

  return CTX_FL_TEST(context, CTX_FL_SUSPEND) ? Qtrue : Qfalse;
}

#switchnil

Switches execution to this context.

Returns:

  • (nil)


546
547
548
549
550
551
552
553
554
555
556
557
558
# File 'ext/byebug/context.c', line 546

static VALUE
Context_switch(VALUE self)
{
  debug_context_t *context = debug_context_ptr(self);

  next_thread = context->thread;

  context->steps = 1;
  context->steps_out = 0;
  CTX_FL_SET(context, CTX_FL_STOP_ON_RET);

  return Qnil;
}

#thnumObject

#threadObject

#tracingBoolean

Returns the tracing flag for the current context.

Returns:

  • (Boolean)


608
609
610
611
612
613
614
# File 'ext/byebug/context.c', line 608

static VALUE
Context_tracing(VALUE self)
{
  debug_context_t *context = debug_context_ptr(self);

  return CTX_FL_TEST(context, CTX_FL_TRACING) ? Qtrue : Qfalse;
}

#tracing=(bool) ⇒ Object

Controls the tracing for this context.



622
623
624
625
626
627
628
629
630
631
632
# File 'ext/byebug/context.c', line 622

static VALUE
Context_set_tracing(VALUE self, VALUE value)
{
  debug_context_t *context = debug_context_ptr(self);

  if (RTEST(value))
    CTX_FL_SET(context, CTX_FL_TRACING);
  else
    CTX_FL_UNSET(context, CTX_FL_TRACING);
  return value;
}