Class: DEBUGGER__::LineBreakpoint

Inherits:
Breakpoint show all
Defined in:
lib/debug/breakpoint.rb

Defined Under Namespace

Classes: NearestISeq

Instance Attribute Summary collapse

Attributes inherited from Breakpoint

#key, #skip_src

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Breakpoint

#delete, #deleted?, #description, #disable, #enabled?, #generate_label, #oneshot?, #safe_eval, #skip_path?, #suspend

Methods included from Color

#color_pp, #colored_inspect, #colorize, #colorize_blue, #colorize_code, #colorize_cyan, #colorize_dim, #colorize_magenta, #irb_colorize, #with_inspection_error_guard

Methods included from SkipPathHelper

#skip_config_skip_path?, #skip_internal_path?, #skip_location?, #skip_path?

Constructor Details

#initialize(path, line, cond: nil, oneshot: false, hook_call: true, command: nil, skip_activate: false, skip_src: false) ⇒ LineBreakpoint

Returns a new instance of LineBreakpoint.



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/debug/breakpoint.rb', line 148

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

  @iseq = nil
  @type = nil

  @key = [path, @line].freeze

  super(cond, command, path)

  try_activate unless skip_activate
  @pending = !@iseq
end

Instance Attribute Details

#commandObject (readonly)

Returns the value of attribute command.



138
139
140
# File 'lib/debug/breakpoint.rb', line 138

def command
  @command
end

#condObject (readonly)

Returns the value of attribute cond.



138
139
140
# File 'lib/debug/breakpoint.rb', line 138

def cond
  @cond
end

#hook_callObject (readonly)

Returns the value of attribute hook_call.



138
139
140
# File 'lib/debug/breakpoint.rb', line 138

def hook_call
  @hook_call
end

#iseqObject (readonly)

Returns the value of attribute iseq.



138
139
140
# File 'lib/debug/breakpoint.rb', line 138

def iseq
  @iseq
end

#lineObject (readonly)

Returns the value of attribute line.



138
139
140
# File 'lib/debug/breakpoint.rb', line 138

def line
  @line
end

#oneshotObject (readonly)

Returns the value of attribute oneshot.



138
139
140
# File 'lib/debug/breakpoint.rb', line 138

def oneshot
  @oneshot
end

#pathObject (readonly)

Returns the value of attribute path.



138
139
140
# File 'lib/debug/breakpoint.rb', line 138

def path
  @path
end

Class Method Details

.copy(bp, root_iseq) ⇒ Object



140
141
142
143
144
145
146
# File 'lib/debug/breakpoint.rb', line 140

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 Method Details

#activate(iseq, event, line) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/debug/breakpoint.rb', line 196

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__.info "#{self} is activated."
  end
end

#activate_exact(iseq, events, line) ⇒ Object



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/debug/breakpoint.rb', line 212

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

#duplicable?Boolean

Returns:

  • (Boolean)


230
231
232
# File 'lib/debug/breakpoint.rb', line 230

def duplicable?
  @oneshot
end

#enableObject



182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/debug/breakpoint.rb', line 182

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

#inspectObject



299
300
301
# File 'lib/debug/breakpoint.rb', line 299

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

#iterate_iseq(root_iseq) ⇒ Object



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/debug/breakpoint.rb', line 236

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

#pending_until_load?Boolean

Returns:

  • (Boolean)


166
167
168
# File 'lib/debug/breakpoint.rb', line 166

def pending_until_load?
  @pending
end

#setupObject



170
171
172
173
174
175
176
177
178
179
180
# File 'lib/debug/breakpoint.rb', line 170

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_sObject



289
290
291
292
293
294
295
296
297
# File 'lib/debug/breakpoint.rb', line 289

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



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/debug/breakpoint.rb', line 256

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)
      elsif @hook_call &&
            nearest.line == iseq.first_line &&
            events.include?(:RUBY_EVENT_CALL)
        nearest = NearestISeq.new(iseq, nline, events)
      end
    end
  end

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