123456789_123456789_123456789_123456789_123456789_

Class: DEBUGGER__::LineBreakpoint

Relationships & Source Files
Namespace Children
Classes:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Breakpoint
Instance Chain:
Inherits: DEBUGGER__::Breakpoint
Defined in: lib/debug/breakpoint.rb

Class Method Summary

Instance Attribute Summary

Breakpoint - Inherited

Instance Method Summary

Constructor Details

.new(path, line, cond: nil, oneshot: false, hook_call: true, command: nil, skip_activate: false) ⇒ LineBreakpoint

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 144

def initialize path, line, cond: nil, oneshot: false, hook_call: true, command: nil, skip_activate: false
  @line = line
  @oneshot = oneshot
  @hook_call = hook_call
  @pending = false

  @iseq = nil
  @type = nil

  @key = [path, @line].freeze

  super(cond, command, path)

  try_activate unless skip_activate
  @pending = !@iseq
end

Class Method Details

.copy(bp, root_iseq)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 136

def self.copy bp, root_iseq
  nbp = LineBreakpoint.new bp.path, bp.line,
                           cond: bp.cond, oneshot: bp.oneshot, hook_call: bp.hook_call,
                           command: bp.command, skip_activate: true
  nbp.try_activate root_iseq
  nbp
end

Instance Attribute Details

#command (readonly)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 134

attr_reader :path, :line, :iseq, :cond, :oneshot, :hook_call, :command

#cond (readonly)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 134

attr_reader :path, :line, :iseq, :cond, :oneshot, :hook_call, :command

#duplicable?Boolean (readonly)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 221

def duplicable?
  @oneshot
end

#hook_call (readonly)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 134

attr_reader :path, :line, :iseq, :cond, :oneshot, :hook_call, :command

#iseq (readonly)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 134

attr_reader :path, :line, :iseq, :cond, :oneshot, :hook_call, :command

#line (readonly)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 134

attr_reader :path, :line, :iseq, :cond, :oneshot, :hook_call, :command

#oneshot (readonly)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 134

attr_reader :path, :line, :iseq, :cond, :oneshot, :hook_call, :command

#path (readonly)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 134

attr_reader :path, :line, :iseq, :cond, :oneshot, :hook_call, :command

Instance Method Details

#activate(iseq, event, line)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 187

def activate iseq, event, line
  @iseq = iseq
  @type = event
  @line = line
  @path = iseq.absolute_path

  @key = [@path, @line].freeze
  SESSION.rehash_bps
  setup
  enable

  if @pending && !@oneshot
    DEBUGGER__.warn "#{self} is activated."
  end
end

#activate_exact(iseq, events, line)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 203

def activate_exact iseq, events, line
  case
  when events.include?(:RUBY_EVENT_CALL)
    # "def foo" line set bp on the beginning of method foo
    activate(iseq, :call, line)
  when events.include?(:RUBY_EVENT_LINE)
    activate(iseq, :line, line)
  when events.include?(:RUBY_EVENT_RETURN)
    activate(iseq, :return, line)
  when events.include?(:RUBY_EVENT_B_RETURN)
    activate(iseq, :b_return, line)
  when events.include?(:RUBY_EVENT_END)
    activate(iseq, :end, line)
  else
    # not activated
  end
end

#enable

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 173

def enable
  return unless @iseq

  if @type == :line
    @tp.enable(target: @iseq, target_line: @line)
  else
    @tp.enable(target: @iseq)
  end

rescue ArgumentError
  puts @iseq.disasm # for debug
  raise
end

#inspect

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 293

def inspect
  "<#{self.class.name} #{self.to_s}>"
end

#iterate_iseq(root_iseq)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 227

def iterate_iseq root_iseq
  if root_iseq
    is = [root_iseq]
    while iseq = is.pop
      yield iseq
      iseq.each_child do |child_iseq|
        is << child_iseq
      end
    end
  else
    ObjectSpace.each_iseq do |iseq|
      if DEBUGGER__.compare_path((iseq.absolute_path || iseq.path), self.path) &&
         iseq.first_lineno <= self.line &&
         iseq.type != :ensure # ensure iseq is copied (duplicated)
        yield iseq
      end
    end
  end
end

#setup

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 161

def setup
  return unless @type

  @tp = TracePoint.new(@type) do |tp|
    if @cond
      next unless safe_eval tp.binding, @cond
    end
    delete if @oneshot
    suspend
  end
end

#to_s

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 283

def to_s
  oneshot = @oneshot ? " (oneshot)" : ""

  if @iseq
    "#{generate_label("Line")} #{@path}:#{@line} (#{@type})#{oneshot}" + super
  else
    "#{generate_label("Line (pending)")} #{@path}:#{@line}#{oneshot}" + super
  end
end

#try_activate(root_iseq = nil)

[ GitHub ]

  
# File 'lib/debug/breakpoint.rb', line 247

def try_activate root_iseq = nil
  nearest = nil # NearestISeq
  iterate_iseq root_iseq do |iseq|
    iseq.traceable_lines_norec(line_events = {})
    lines = line_events.keys.sort

    if !lines.empty? && lines.last >= line
      nline = lines.bsearch{|l| line <= l}
      events = line_events[nline]

      next if events == [:RUBY_EVENT_B_CALL]

      if @hook_call &&
        events.include?(:RUBY_EVENT_CALL) &&
        self.line == iseq.first_lineno
        nline = iseq.first_lineno
      end

      if !nearest || ((line - nline).abs < (line - nearest.line).abs)
        nearest = NearestISeq.new(iseq, nline, events)
      else
        if @hook_call && nearest.iseq.first_lineno <= iseq.first_lineno
          if (nearest.line > line && !nearest.events.include?(:RUBY_EVENT_CALL)) ||
            (events.include?(:RUBY_EVENT_CALL))
            nearest = NearestISeq.new(iseq, nline, events)
          end
        end
      end
    end
  end

  if nearest
    activate_exact nearest.iseq, nearest.events, nearest.line
  end
end