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.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/debug/breakpoint.rb', line 144

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.



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

def command
  @command
end

#condObject (readonly)

Returns the value of attribute cond.



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

def cond
  @cond
end

#hook_callObject (readonly)

Returns the value of attribute hook_call.



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

def hook_call
  @hook_call
end

#iseqObject (readonly)

Returns the value of attribute iseq.



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

def iseq
  @iseq
end

#lineObject (readonly)

Returns the value of attribute line.



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

def line
  @line
end

#oneshotObject (readonly)

Returns the value of attribute oneshot.



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

def oneshot
  @oneshot
end

#pathObject (readonly)

Returns the value of attribute path.



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

def path
  @path
end

Class Method Details

.copy(bp, root_iseq) ⇒ Object



136
137
138
139
140
141
142
# 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 Method Details

#activate(iseq, event, line) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/debug/breakpoint.rb', line 188

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

  @pending = false
end

#activate_exact(iseq, events, line) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/debug/breakpoint.rb', line 206

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)


224
225
226
# File 'lib/debug/breakpoint.rb', line 224

def duplicable?
  @oneshot
end

#enableObject



174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/debug/breakpoint.rb', line 174

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



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

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

#iterate_iseq(root_iseq) ⇒ Object



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/debug/breakpoint.rb', line 230

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

#path_is?(path) ⇒ Boolean

Returns:

  • (Boolean)


297
298
299
# File 'lib/debug/breakpoint.rb', line 297

def path_is? path
  DEBUGGER__.compare_path(@path, path)
end

#setupObject



162
163
164
165
166
167
168
169
170
171
172
# File 'lib/debug/breakpoint.rb', line 162

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



283
284
285
286
287
288
289
290
291
# 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) ⇒ Object



250
251
252
253
254
255
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
# File 'lib/debug/breakpoint.rb', line 250

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