debug 1.0.0.alpha1 → 1.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +20 -19
- data/README.md +353 -51
- data/Rakefile +21 -1
- data/debug.gemspec +6 -11
- data/exe/rdbg +32 -1
- data/ext/debug/debug.c +118 -0
- data/ext/debug/extconf.rb +2 -0
- data/ext/debug/iseq_collector.c +91 -0
- data/lib/debug.rb +1 -1
- data/lib/debug/breakpoint.rb +310 -36
- data/lib/debug/client.rb +4 -11
- data/lib/debug/config.rb +100 -7
- data/lib/debug/console.rb +89 -0
- data/lib/debug/open.rb +10 -0
- data/lib/debug/run.rb +2 -0
- data/lib/debug/server.rb +128 -21
- data/lib/debug/session.rb +605 -170
- data/lib/debug/source_repository.rb +27 -20
- data/lib/debug/thread_client.rb +294 -119
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +325 -0
- metadata +22 -42
- data/lib/debug/repl.rb +0 -69
- data/lib/debug/tcpserver.rb +0 -22
- data/lib/debug/unixserver.rb +0 -18
@@ -1,20 +1,27 @@
|
|
1
|
-
module DEBUGGER__
|
2
|
-
class SourceRepository
|
3
|
-
def initialize
|
4
|
-
@files = {} # filename => [src, iseq]
|
5
|
-
end
|
6
|
-
|
7
|
-
def add iseq, src
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
1
|
+
module DEBUGGER__
|
2
|
+
class SourceRepository
|
3
|
+
def initialize
|
4
|
+
@files = {} # filename => [src, iseq]
|
5
|
+
end
|
6
|
+
|
7
|
+
def add iseq, src
|
8
|
+
path = iseq.absolute_path
|
9
|
+
path = '-e' if iseq.path == '-e'
|
10
|
+
|
11
|
+
case
|
12
|
+
when path = iseq.absolute_path
|
13
|
+
src = File.read(path)
|
14
|
+
when iseq.path == '-e'
|
15
|
+
path = '-e'
|
16
|
+
else
|
17
|
+
src = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
@files[path] = src.lines if src
|
21
|
+
end
|
22
|
+
|
23
|
+
def get path
|
24
|
+
@files[path]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/debug/thread_client.rb
CHANGED
@@ -1,25 +1,31 @@
|
|
1
|
+
require 'objspace'
|
2
|
+
require 'pp'
|
3
|
+
|
1
4
|
module DEBUGGER__
|
2
5
|
class ThreadClient
|
3
6
|
def self.current
|
4
7
|
Thread.current[:DEBUGGER__ThreadClient] || begin
|
5
|
-
tc = SESSION.thread_client
|
8
|
+
tc = ::DEBUGGER__::SESSION.thread_client
|
6
9
|
Thread.current[:DEBUGGER__ThreadClient] = tc
|
7
10
|
end
|
8
11
|
end
|
9
12
|
|
10
|
-
attr_reader :location, :thread
|
13
|
+
attr_reader :location, :thread, :mode, :id
|
11
14
|
|
12
|
-
def initialize q_evt, q_cmd, thr = Thread.current
|
15
|
+
def initialize id, q_evt, q_cmd, thr = Thread.current
|
16
|
+
@id = id
|
13
17
|
@thread = thr
|
14
18
|
@q_evt = q_evt
|
15
19
|
@q_cmd = q_cmd
|
16
20
|
@step_tp = nil
|
17
21
|
@output = []
|
18
|
-
@
|
22
|
+
@src_lines_on_stop = (DEBUGGER__::CONFIG[:show_src_lines] || 10).to_i
|
23
|
+
@show_frames_on_stop = (DEBUGGER__::CONFIG[:show_frames] || 2).to_i
|
24
|
+
set_mode nil
|
19
25
|
end
|
20
26
|
|
21
27
|
def inspect
|
22
|
-
"#<
|
28
|
+
"#<DBG:TC #{self.id}:#{self.mode}@#{@thread.backtrace[-1]}>"
|
23
29
|
end
|
24
30
|
|
25
31
|
def puts str = ''
|
@@ -44,11 +50,11 @@ module DEBUGGER__
|
|
44
50
|
|
45
51
|
## events
|
46
52
|
|
47
|
-
def on_trap
|
48
|
-
if
|
49
|
-
raise Interrupt
|
53
|
+
def on_trap sig
|
54
|
+
if self.mode == :wait_next_action
|
55
|
+
# raise Interrupt
|
50
56
|
else
|
51
|
-
on_suspend :trap
|
57
|
+
on_suspend :trap, sig: sig
|
52
58
|
end
|
53
59
|
end
|
54
60
|
|
@@ -56,18 +62,24 @@ module DEBUGGER__
|
|
56
62
|
on_suspend :pause
|
57
63
|
end
|
58
64
|
|
65
|
+
def on_thread_begin th
|
66
|
+
event! :thread_begin, th
|
67
|
+
wait_next_action
|
68
|
+
end
|
69
|
+
|
59
70
|
def on_load iseq, eval_src
|
60
71
|
event! :load, iseq, eval_src
|
61
72
|
wait_next_action
|
62
73
|
end
|
63
74
|
|
64
|
-
def on_breakpoint tp
|
65
|
-
on_suspend tp.event, tp
|
75
|
+
def on_breakpoint tp, bp
|
76
|
+
on_suspend tp.event, tp, bp: bp
|
66
77
|
end
|
67
78
|
|
68
|
-
def on_suspend event, tp = nil
|
79
|
+
def on_suspend event, tp = nil, bp: nil, sig: nil
|
69
80
|
@current_frame_index = 0
|
70
|
-
@target_frames =
|
81
|
+
@target_frames = DEBUGGER__.capture_frames __dir__
|
82
|
+
|
71
83
|
cf = @target_frames.first
|
72
84
|
if cf
|
73
85
|
@location = cf.location
|
@@ -79,85 +91,140 @@ module DEBUGGER__
|
|
79
91
|
end
|
80
92
|
|
81
93
|
if event != :pause
|
82
|
-
show_src
|
83
|
-
|
84
|
-
|
94
|
+
show_src max_lines: @src_lines_on_stop
|
95
|
+
show_frames @show_frames_on_stop
|
96
|
+
|
97
|
+
if bp
|
98
|
+
event! :suspend, :breakpoint, bp.key
|
99
|
+
elsif sig
|
100
|
+
event! :suspend, :trap, sig
|
101
|
+
else
|
102
|
+
event! :suspend, event
|
103
|
+
end
|
85
104
|
end
|
86
105
|
|
87
106
|
wait_next_action
|
88
107
|
end
|
89
|
-
|
108
|
+
|
90
109
|
## control all
|
91
110
|
|
111
|
+
begin
|
112
|
+
TracePoint.new(:raise){}.enable(target_thread: Thread.current)
|
113
|
+
SUPPORT_TARGET_THREAD = true
|
114
|
+
rescue ArgumentError
|
115
|
+
SUPPORT_TARGET_THREAD = false
|
116
|
+
end
|
117
|
+
|
92
118
|
def step_tp
|
93
119
|
@step_tp.disable if @step_tp
|
94
|
-
@step_tp = TracePoint.new(:line, :b_return, :return){|tp|
|
95
|
-
next if SESSION.break? tp.path, tp.lineno
|
96
|
-
next if !yield
|
97
|
-
tp.disable
|
98
|
-
on_suspend tp.event, tp
|
99
|
-
}
|
100
|
-
|
101
|
-
@step_tp.enable(target_thread: Thread.current)
|
102
|
-
end
|
103
|
-
|
104
|
-
FrameInfo = Struct.new(:location, :self, :binding, :iseq, :class, :has_return_value, :return_value)
|
105
|
-
|
106
|
-
def target_frames
|
107
|
-
RubyVM::DebugInspector.open{|dc|
|
108
|
-
locs = dc.backtrace_locations
|
109
|
-
locs.map.with_index{|e, i|
|
110
|
-
unless File.dirname(e.path) == File.dirname(__FILE__)
|
111
|
-
FrameInfo.new(
|
112
|
-
e,
|
113
|
-
dc.frame_self(i),
|
114
|
-
dc.frame_binding(i),
|
115
|
-
dc.frame_iseq(i),
|
116
|
-
dc.frame_class(i))
|
117
|
-
end
|
118
|
-
}.compact
|
119
|
-
}
|
120
|
-
end
|
121
120
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
121
|
+
thread = Thread.current
|
122
|
+
|
123
|
+
if SUPPORT_TARGET_THREAD
|
124
|
+
@step_tp = TracePoint.new(:line, :b_return, :return){|tp|
|
125
|
+
next if SESSION.break? tp.path, tp.lineno
|
126
|
+
next if !yield
|
127
|
+
next if tp.path.start_with?(__dir__)
|
128
|
+
tp.disable
|
129
|
+
on_suspend tp.event, tp
|
130
|
+
}
|
131
|
+
@step_tp.enable(target_thread: thread)
|
132
|
+
else
|
133
|
+
@step_tp = TracePoint.new(:line, :b_return, :return){|tp|
|
134
|
+
next if thread != Thread.current
|
135
|
+
next if SESSION.break? tp.path, tp.lineno
|
136
|
+
next if !yield
|
137
|
+
tp.disable
|
138
|
+
on_suspend tp.event, tp
|
127
139
|
}
|
128
|
-
|
140
|
+
@step_tp.enable
|
141
|
+
end
|
129
142
|
end
|
130
143
|
|
131
144
|
def current_frame
|
132
|
-
@target_frames
|
145
|
+
if @target_frames
|
146
|
+
@target_frames[@current_frame_index]
|
147
|
+
else
|
148
|
+
nil
|
149
|
+
end
|
133
150
|
end
|
134
151
|
|
135
152
|
def file_lines path
|
136
|
-
if (
|
137
|
-
|
153
|
+
if (src_lines = SESSION.source(path))
|
154
|
+
src_lines
|
138
155
|
elsif File.exist?(path)
|
139
156
|
File.readlines(path)
|
140
157
|
end
|
141
158
|
end
|
142
159
|
|
143
|
-
def show_src
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
160
|
+
def show_src(frame_index: @current_frame_index,
|
161
|
+
update_line: false,
|
162
|
+
max_lines: 10,
|
163
|
+
start_line: nil,
|
164
|
+
end_line: nil,
|
165
|
+
dir: +1)
|
166
|
+
#
|
167
|
+
if @target_frames && frame = @target_frames[frame_index]
|
168
|
+
if file_lines = file_lines(path = frame.location.path)
|
169
|
+
frame_line = frame.location.lineno - 1
|
170
|
+
|
171
|
+
lines = file_lines.map.with_index do |e, i|
|
172
|
+
if i == frame_line
|
150
173
|
"=> #{'%4d' % (i+1)}| #{e}"
|
151
174
|
else
|
152
175
|
" #{'%4d' % (i+1)}| #{e}"
|
153
176
|
end
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
177
|
+
end
|
178
|
+
|
179
|
+
unless start_line
|
180
|
+
if frame.show_line
|
181
|
+
if dir > 0
|
182
|
+
start_line = frame.show_line
|
183
|
+
else
|
184
|
+
end_line = frame.show_line - max_lines
|
185
|
+
start_line = [end_line - max_lines, 0].max
|
186
|
+
end
|
187
|
+
else
|
188
|
+
start_line = [frame_line - max_lines/2, 0].max
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
unless end_line
|
193
|
+
end_line = [start_line + max_lines, lines.size].min
|
194
|
+
end
|
195
|
+
|
196
|
+
if update_line
|
197
|
+
frame.show_line = end_line
|
198
|
+
end
|
199
|
+
|
200
|
+
if start_line != end_line
|
201
|
+
puts "[#{start_line+1}, #{end_line}] in #{path}" unless update_line
|
202
|
+
puts lines[start_line ... end_line]
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def show_by_editor path = nil
|
209
|
+
unless path
|
210
|
+
if @target_frames && frame = @target_frames[@current_frame_index]
|
211
|
+
path = frame.location.path
|
212
|
+
else
|
213
|
+
return # can't get path
|
159
214
|
end
|
160
215
|
end
|
216
|
+
|
217
|
+
if File.exist?(path)
|
218
|
+
if editor = (ENV['RUBY_DEBUG_EDITOR'] || ENV['EDITOR'])
|
219
|
+
puts "command: #{editor}"
|
220
|
+
puts " path: #{path}"
|
221
|
+
system(editor, path)
|
222
|
+
else
|
223
|
+
puts "can not find editor setting: ENV['RUBY_DEBUG_EDITOR'] or ENV['EDITOR']"
|
224
|
+
end
|
225
|
+
else
|
226
|
+
puts "Can not find file: #{path}"
|
227
|
+
end
|
161
228
|
end
|
162
229
|
|
163
230
|
def show_locals
|
@@ -176,39 +243,48 @@ module DEBUGGER__
|
|
176
243
|
|
177
244
|
def show_ivars
|
178
245
|
if s = current_frame&.self
|
179
|
-
|
180
|
-
s.instance_variables.eaach{|iv|
|
246
|
+
s.instance_variables.each{|iv|
|
181
247
|
puts " #{iv} => #{s.instance_variable_get(iv)}"
|
182
248
|
}
|
183
249
|
end
|
184
250
|
end
|
185
251
|
|
186
|
-
def frame_eval src,
|
252
|
+
def frame_eval src, re_raise: false
|
187
253
|
begin
|
254
|
+
@success_last_eval = false
|
255
|
+
|
188
256
|
b = current_frame.binding
|
189
|
-
if b
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
257
|
+
result = if b
|
258
|
+
f, l = b.source_location
|
259
|
+
b.eval(src, "(rdbg)/#{f}")
|
260
|
+
else
|
261
|
+
frame_self = current_frame.self
|
262
|
+
frame_self.instance_eval(src)
|
263
|
+
end
|
264
|
+
@success_last_eval = true
|
265
|
+
result
|
266
|
+
|
196
267
|
rescue Exception => e
|
197
|
-
return
|
268
|
+
return yield(e) if block_given?
|
269
|
+
|
270
|
+
puts "eval error: #{e}"
|
198
271
|
|
199
|
-
puts "Error: #{e}"
|
200
272
|
e.backtrace_locations.each do |loc|
|
201
273
|
break if loc.path == __FILE__
|
202
274
|
puts " #{loc}"
|
203
275
|
end
|
204
|
-
|
276
|
+
raise if re_raise
|
205
277
|
end
|
206
278
|
end
|
207
279
|
|
208
280
|
def parameters_info b, vars
|
209
281
|
vars.map{|var|
|
210
|
-
|
211
|
-
|
282
|
+
begin
|
283
|
+
"#{var}=#{short_inspect(b.local_variable_get(var))}"
|
284
|
+
rescue NameError, TypeError
|
285
|
+
nil
|
286
|
+
end
|
287
|
+
}.compact.join(', ')
|
212
288
|
end
|
213
289
|
|
214
290
|
def klass_sig frame
|
@@ -246,13 +322,12 @@ module DEBUGGER__
|
|
246
322
|
if b && (iseq = frame.iseq)
|
247
323
|
if iseq.type == :block
|
248
324
|
if (argc = iseq.argc) > 0
|
249
|
-
args = parameters_info b, iseq.locals[0...
|
325
|
+
args = parameters_info b, iseq.locals[0...argc]
|
250
326
|
buff << " {|#{args}|}"
|
251
327
|
end
|
252
328
|
else
|
253
|
-
callee = b.eval('__callee__')
|
254
|
-
|
255
|
-
args = parameters_info b, m.parameters.map{|type, v| v}
|
329
|
+
if (callee = b.eval('__callee__', __FILE__, __LINE__)) && (argc = iseq.argc) > 0
|
330
|
+
args = parameters_info b, iseq.locals[0...argc]
|
256
331
|
ksig = klass_sig frame
|
257
332
|
buff << " #{ksig}#{callee}(#{args})"
|
258
333
|
end
|
@@ -268,30 +343,67 @@ module DEBUGGER__
|
|
268
343
|
buff
|
269
344
|
end
|
270
345
|
|
271
|
-
def
|
272
|
-
@target_frames
|
273
|
-
|
274
|
-
|
346
|
+
def show_frames max = (@target_frames || []).size
|
347
|
+
if max > 0 && frames = @target_frames
|
348
|
+
size = @target_frames.size
|
349
|
+
max += 1 if size == max + 1
|
350
|
+
max.times{|i|
|
351
|
+
break if i >= size
|
352
|
+
puts frame_str(i)
|
353
|
+
}
|
354
|
+
puts " # and #{size - max} frames (use `bt' command for all frames)" if max < size
|
355
|
+
end
|
275
356
|
end
|
276
357
|
|
277
|
-
def
|
358
|
+
def show_frame i=0
|
278
359
|
puts frame_str(i)
|
279
360
|
end
|
280
361
|
|
281
|
-
def
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
362
|
+
def show_object_info expr
|
363
|
+
begin
|
364
|
+
result = frame_eval(expr, re_raise: true)
|
365
|
+
rescue Exception
|
366
|
+
# ignore
|
367
|
+
else
|
368
|
+
klass = ObjectSpace.internal_class_of(result)
|
369
|
+
exists = []
|
370
|
+
klass.ancestors.each{|k|
|
371
|
+
puts "= #{k}"
|
372
|
+
if (ms = (k.instance_methods(false) - exists)).size > 0
|
373
|
+
puts ms.sort.join("\t")
|
374
|
+
exists |= ms
|
375
|
+
end
|
376
|
+
}
|
288
377
|
end
|
289
378
|
end
|
290
379
|
|
380
|
+
def add_breakpoint args
|
381
|
+
case args.first
|
382
|
+
when :method
|
383
|
+
klass_name, op, method_name, cond = args[1..]
|
384
|
+
bp = MethodBreakpoint.new(current_frame.binding, klass_name, op, method_name, cond)
|
385
|
+
begin
|
386
|
+
bp.enable
|
387
|
+
rescue Exception => e
|
388
|
+
puts e.message
|
389
|
+
::DEBUGGER__::METHOD_ADDED_TRACKER.enable
|
390
|
+
end
|
391
|
+
event! :result, :method_breakpoint, bp
|
392
|
+
else
|
393
|
+
raise "unknown breakpoint: #{args}"
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
def set_mode mode
|
398
|
+
@mode = mode
|
399
|
+
end
|
400
|
+
|
291
401
|
def wait_next_action
|
292
|
-
|
402
|
+
set_mode :wait_next_action
|
293
403
|
|
294
404
|
while cmds = @q_cmd.pop
|
405
|
+
# pp [self, cmds: cmds]
|
406
|
+
|
295
407
|
cmd, *args = *cmds
|
296
408
|
|
297
409
|
case cmd
|
@@ -303,20 +415,43 @@ module DEBUGGER__
|
|
303
415
|
when :in
|
304
416
|
step_tp{true}
|
305
417
|
when :next
|
306
|
-
|
418
|
+
frame = @target_frames.first
|
419
|
+
path = frame.location.absolute_path || "!eval:#{frame.location.path}"
|
420
|
+
line = frame.location.lineno
|
421
|
+
frame.iseq.traceable_lines_norec(lines = {})
|
422
|
+
next_line = lines.keys.bsearch{|e| e > line}
|
423
|
+
if !next_line && (last_line = frame.iseq.last_line) > line
|
424
|
+
next_line = last_line
|
425
|
+
end
|
426
|
+
depth = @target_frames.first.frame_depth
|
427
|
+
|
307
428
|
step_tp{
|
308
|
-
|
429
|
+
loc = caller_locations(2, 1).first
|
430
|
+
loc_path = loc.absolute_path || "!eval:#{loc.path}"
|
431
|
+
|
432
|
+
(next_line && loc_path == path &&
|
433
|
+
(loc_lineno = loc.lineno) > line && loc_lineno <= next_line) ||
|
434
|
+
(DEBUGGER__.frame_depth - 3 < depth)
|
309
435
|
}
|
310
436
|
when :finish
|
311
|
-
|
312
|
-
step_tp{
|
437
|
+
depth = @target_frames.first.frame_depth
|
438
|
+
step_tp{
|
439
|
+
# 3 is debugger's frame count
|
440
|
+
DEBUGGER__.frame_depth - 3 < depth
|
441
|
+
}
|
313
442
|
else
|
314
443
|
raise
|
315
444
|
end
|
316
445
|
break
|
317
446
|
when :eval
|
318
447
|
eval_type, eval_src = *args
|
319
|
-
|
448
|
+
|
449
|
+
case eval_type
|
450
|
+
when :display, :try_display
|
451
|
+
else
|
452
|
+
result = frame_eval(eval_src)
|
453
|
+
end
|
454
|
+
result_type = nil
|
320
455
|
|
321
456
|
case eval_type
|
322
457
|
when :p
|
@@ -327,15 +462,31 @@ module DEBUGGER__
|
|
327
462
|
puts out
|
328
463
|
when :call
|
329
464
|
result = frame_eval(eval_src)
|
330
|
-
when :display
|
465
|
+
when :display, :try_display
|
466
|
+
failed_results = []
|
331
467
|
eval_src.each_with_index{|src, i|
|
332
|
-
|
468
|
+
result = frame_eval(src){|e|
|
469
|
+
failed_results << [i, e.message]
|
470
|
+
"<error: #{e.message}>"
|
471
|
+
}
|
472
|
+
puts "#{i}: #{src} = #{result}"
|
333
473
|
}
|
334
|
-
|
474
|
+
|
475
|
+
result_type = eval_type
|
476
|
+
result = failed_results
|
477
|
+
when :watch
|
478
|
+
if @success_last_eval
|
479
|
+
puts "#{eval_src} = #{result}"
|
480
|
+
result = WatchExprBreakpoint.new(eval_src, result)
|
481
|
+
result_type = :watch
|
482
|
+
else
|
483
|
+
result = nil
|
484
|
+
end
|
335
485
|
else
|
336
|
-
raise "unknown error option: #{args.
|
486
|
+
raise "unknown error option: #{args.inspect}"
|
337
487
|
end
|
338
|
-
|
488
|
+
|
489
|
+
event! :result, result_type, result
|
339
490
|
when :frame
|
340
491
|
type, arg = *args
|
341
492
|
case type
|
@@ -343,13 +494,13 @@ module DEBUGGER__
|
|
343
494
|
if @current_frame_index + 1 < @target_frames.size
|
344
495
|
@current_frame_index += 1
|
345
496
|
show_src max_lines: 1
|
346
|
-
|
497
|
+
show_frame(@current_frame_index)
|
347
498
|
end
|
348
499
|
when :down
|
349
500
|
if @current_frame_index > 0
|
350
501
|
@current_frame_index -= 1
|
351
502
|
show_src max_lines: 1
|
352
|
-
|
503
|
+
show_frame(@current_frame_index)
|
353
504
|
end
|
354
505
|
when :set
|
355
506
|
if arg
|
@@ -361,28 +512,43 @@ module DEBUGGER__
|
|
361
512
|
end
|
362
513
|
end
|
363
514
|
show_src max_lines: 1
|
364
|
-
|
515
|
+
show_frame(@current_frame_index)
|
365
516
|
else
|
366
517
|
raise "unsupported frame operation: #{arg.inspect}"
|
367
518
|
end
|
368
519
|
event! :result, nil
|
369
520
|
when :show
|
370
|
-
type
|
521
|
+
type = args.shift
|
522
|
+
|
371
523
|
case type
|
372
524
|
when :backtrace
|
373
|
-
|
525
|
+
show_frames
|
526
|
+
|
374
527
|
when :list
|
375
|
-
show_src
|
376
|
-
|
528
|
+
show_src(update_line: true, **(args.first || {}))
|
529
|
+
|
530
|
+
when :edit
|
531
|
+
show_by_editor(args.first)
|
532
|
+
|
533
|
+
when :local
|
534
|
+
show_frame
|
377
535
|
show_locals
|
378
|
-
when :ivars
|
379
536
|
show_ivars
|
537
|
+
|
538
|
+
when :object_info
|
539
|
+
expr = args.shift
|
540
|
+
show_object_info expr
|
541
|
+
|
380
542
|
else
|
381
|
-
raise "unknown show param: " + args.inspect
|
543
|
+
raise "unknown show param: " + [type, *args].inspect
|
382
544
|
end
|
545
|
+
|
383
546
|
event! :result, nil
|
547
|
+
|
548
|
+
when :breakpoint
|
549
|
+
add_breakpoint args
|
384
550
|
else
|
385
|
-
raise [
|
551
|
+
raise [cmd, *args].inspect
|
386
552
|
end
|
387
553
|
end
|
388
554
|
|
@@ -392,11 +558,20 @@ module DEBUGGER__
|
|
392
558
|
pp [__FILE__, __LINE__, e, e.backtrace]
|
393
559
|
raise
|
394
560
|
ensure
|
395
|
-
|
561
|
+
set_mode nil
|
396
562
|
end
|
397
563
|
|
398
564
|
def to_s
|
399
|
-
|
565
|
+
loc = current_frame&.location
|
566
|
+
|
567
|
+
if loc
|
568
|
+
str = "(#{@thread.name || @thread.status})@#{loc}"
|
569
|
+
else
|
570
|
+
str = "(#{@thread.name || @thread.status})@#{@thread.to_s}"
|
571
|
+
end
|
572
|
+
|
573
|
+
str += " (not under control)" unless self.mode
|
574
|
+
str
|
400
575
|
end
|
401
576
|
end
|
402
577
|
end
|