Class: Byebug::Context

Inherits:
Object
  • Object
show all
Defined in:
lib/byebug/context.rb,
ext/byebug/context.c

Overview

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

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.bin_fileObject


15
16
17
# File 'lib/byebug/context.rb', line 15

def self.bin_file
  @bin_file ||= Gem.bin_path('byebug', 'byebug')
end

.ignored_filesObject

List of files byebug will ignore while debugging


11
12
13
# File 'lib/byebug/context.rb', line 11

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

.lib_filesObject


19
20
21
# File 'lib/byebug/context.rb', line 19

def self.lib_files
  @lib_files ||= Dir.glob(File.expand_path('../../**/*.rb', __FILE__))
end

Instance Method Details

#at_breakpoint(brkpnt) ⇒ Object


74
75
76
# File 'lib/byebug/context.rb', line 74

def at_breakpoint(brkpnt)
  handler.at_breakpoint(self, brkpnt)
end

#at_catchpoint(excpt) ⇒ Object


78
79
80
# File 'lib/byebug/context.rb', line 78

def at_catchpoint(excpt)
  handler.at_catchpoint(self, excpt)
end

#at_line(file, line) ⇒ Object


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

def at_line(file, line)
  handler.at_line(self, file, line) unless ignored_file?(file)
end

#at_return(file, line) ⇒ Object


90
91
92
# File 'lib/byebug/context.rb', line 90

def at_return(file, line)
  handler.at_return(self, file, line) unless ignored_file?(file)
end

#at_tracing(file, line) ⇒ Object


82
83
84
# File 'lib/byebug/context.rb', line 82

def at_tracing(file, line)
  handler.at_tracing(self, file, line) unless ignored_file?(file)
end

#backtraceObject

#dead?Boolean

Returns:

  • (Boolean)

#frame_args(frame_no = 0) ⇒ Object

Gets current method arguments for a frame.

Parameters:

  • frame_no (defaults to: 0)

    Frame index in the backtrace. Defaults to 0.


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

def frame_args(frame_no = 0)
  bind = frame_binding(frame_no)
  return c_frame_args(frame_no) unless bind

  ruby_frame_args(bind)
end

#frame_binding(frame_position = 0) ⇒ Binding

Returns frame's binding.

Returns:

  • (Binding)

211
212
213
214
215
216
217
# File 'ext/byebug/context.c', line 211

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) ⇒ Binding

Returns frame's defined class.

Returns:

  • (Binding)

225
226
227
228
229
230
231
# File 'ext/byebug/context.c', line 225

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)

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'ext/byebug/context.c', line 239

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.

Returns:

  • (Integer)

262
263
264
265
266
267
268
269
270
271
272
# File 'ext/byebug/context.c', line 262

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_locals(frame_no = 0) ⇒ Object

Gets local variables for a frame.

TODO: Use brand new local_variable_get,set,defined? for rubies >= 2.1

Parameters:

  • frame_no (defaults to: 0)

    Frame index in the backtrace. Defaults to 0.


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

def frame_locals(frame_no = 0)
  bind = frame_binding(frame_no)
  return [] unless bind

  bind.eval('local_variables.inject({}){|h, v| h[v] = eval(v.to_s); h}')
end

#frame_method(frame_position = 0) ⇒ Object

Returns the sym of the called method.


280
281
282
283
284
285
286
287
288
289
290
# File 'ext/byebug/context.c', line 280

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)

298
299
300
301
302
303
304
# File 'ext/byebug/context.c', line 298

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

  return dc_frame_self(context, frame_n);
}

#handlerObject


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

def handler
  Byebug.handler || fail('No interface loaded')
end

#ignored?Boolean

Returns:

  • (Boolean)

#ignored_file?(path) ⇒ Boolean

Tells whether a file is ignored by the debugger.

Parameters:

  • path (String)

    filename to be checked.

Returns:

  • (Boolean)

28
29
30
# File 'lib/byebug/context.rb', line 28

def ignored_file?(path)
  self.class.ignored_files.include?(path)
end

#interruptObject


40
41
42
# File 'lib/byebug/context.rb', line 40

def interrupt
  step_into 1
end

#resumenil

Resumes thread from the suspended mode.

Returns:

  • (nil)

328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
# File 'ext/byebug/context.c', line 328

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

#stack_sizeObject


32
33
34
35
36
37
38
# File 'lib/byebug/context.rb', line 32

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).


398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'ext/byebug/context.c', line 398

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 can't be negative.");

  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.


438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'ext/byebug/context.c', line 438

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

#step_over(lines, frame = 0) ⇒ Object

Steps over lines lines in frame frame (by default the newest one).


470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
# File 'ext/byebug/context.c', line 470

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

#stop_reasonObject


362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'ext/byebug/context.c', line 362

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

#suspendnil

Suspends the thread when it is running.

Returns:

  • (nil)

501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
# File 'ext/byebug/context.c', line 501

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

#suspended?Boolean

Returns true if the thread is suspended by debugger.

Returns:

  • (Boolean)

Returns:

  • (Boolean)

551
552
553
554
555
556
557
558
559
# File 'ext/byebug/context.c', line 551

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

#switchnil

Switches execution to this context.

Returns:

  • (nil)

529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
# File 'ext/byebug/context.c', line 529

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

#thnumObject

#threadObject

#tracingBoolean

Returns the tracing flag for the current context.

Returns:

  • (Boolean)

597
598
599
600
601
602
603
604
# File 'ext/byebug/context.c', line 597

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

#tracing=(bool) ⇒ Object

Controls the tracing for this context.


612
613
614
615
616
617
618
619
620
621
622
623
624
# File 'ext/byebug/context.c', line 612

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