debug 1.7.1 → 1.8.0
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/CONTRIBUTING.md +2 -2
- data/README.md +6 -3
- data/Rakefile +8 -3
- data/lib/debug/breakpoint.rb +6 -8
- data/lib/debug/config.rb +24 -2
- data/lib/debug/dap_custom/traceInspector.rb +336 -0
- data/lib/debug/frame_info.rb +9 -0
- data/lib/debug/server.rb +5 -6
- data/lib/debug/server_cdp.rb +69 -70
- data/lib/debug/server_dap.rb +224 -178
- data/lib/debug/session.rb +73 -43
- data/lib/debug/source_repository.rb +2 -2
- data/lib/debug/thread_client.rb +33 -11
- data/lib/debug/tracer.rb +4 -5
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +1 -1
- metadata +3 -2
data/lib/debug/session.rb
CHANGED
@@ -128,16 +128,16 @@ module DEBUGGER__
|
|
128
128
|
@obj_map = {} # { object_id => ... } for CDP
|
129
129
|
|
130
130
|
@tp_thread_begin = nil
|
131
|
+
@tp_thread_end = nil
|
132
|
+
|
131
133
|
@commands = {}
|
132
134
|
@unsafe_context = false
|
133
135
|
|
134
|
-
has_keep_script_lines = RubyVM.respond_to? :keep_script_lines
|
136
|
+
@has_keep_script_lines = RubyVM.respond_to? :keep_script_lines
|
135
137
|
|
136
138
|
@tp_load_script = TracePoint.new(:script_compiled){|tp|
|
137
|
-
|
138
|
-
|
139
|
-
ThreadClient.current.on_load tp.instruction_sequence, eval_script
|
140
|
-
end
|
139
|
+
eval_script = tp.eval_script unless @has_keep_script_lines
|
140
|
+
ThreadClient.current.on_load tp.instruction_sequence, eval_script
|
141
141
|
}
|
142
142
|
@tp_load_script.enable
|
143
143
|
|
@@ -169,12 +169,17 @@ module DEBUGGER__
|
|
169
169
|
@ui = ui if ui
|
170
170
|
|
171
171
|
@tp_thread_begin&.disable
|
172
|
+
@tp_thread_end&.disable
|
172
173
|
@tp_thread_begin = nil
|
173
|
-
|
174
|
+
@tp_thread_end = nil
|
174
175
|
@ui.activate self, on_fork: on_fork
|
175
176
|
|
176
177
|
q = Queue.new
|
178
|
+
first_q = Queue.new
|
177
179
|
@session_server = Thread.new do
|
180
|
+
# make sure `@session_server` is assigned
|
181
|
+
first_q.pop; first_q = nil
|
182
|
+
|
178
183
|
Thread.current.name = 'DEBUGGER__::SESSION@server'
|
179
184
|
Thread.current.abort_on_exception = true
|
180
185
|
|
@@ -192,10 +197,16 @@ module DEBUGGER__
|
|
192
197
|
end
|
193
198
|
@tp_thread_begin.enable
|
194
199
|
|
200
|
+
@tp_thread_end = TracePoint.new(:thread_end) do |tp|
|
201
|
+
@th_clients.delete(Thread.current)
|
202
|
+
end
|
203
|
+
@tp_thread_end.enable
|
204
|
+
|
195
205
|
# session start
|
196
206
|
q << true
|
197
207
|
session_server_main
|
198
208
|
end
|
209
|
+
first_q << :ok
|
199
210
|
|
200
211
|
q.pop
|
201
212
|
end
|
@@ -205,6 +216,7 @@ module DEBUGGER__
|
|
205
216
|
@thread_stopper.disable
|
206
217
|
@tp_load_script.disable
|
207
218
|
@tp_thread_begin.disable
|
219
|
+
@tp_thread_end.disable
|
208
220
|
@bps.each_value{|bp| bp.disable}
|
209
221
|
@th_clients.each_value{|thc| thc.close}
|
210
222
|
@tracers.values.each{|t| t.disable}
|
@@ -219,11 +231,13 @@ module DEBUGGER__
|
|
219
231
|
|
220
232
|
# activate new ui
|
221
233
|
@tp_thread_begin.disable
|
234
|
+
@tp_thread_end.disable
|
222
235
|
@ui.activate self
|
223
236
|
if @ui.respond_to?(:reader_thread) && thc = get_thread_client(@ui.reader_thread)
|
224
237
|
thc.mark_as_management
|
225
238
|
end
|
226
239
|
@tp_thread_begin.enable
|
240
|
+
@tp_thread_end.enable
|
227
241
|
end
|
228
242
|
|
229
243
|
def pop_event
|
@@ -329,16 +343,13 @@ module DEBUGGER__
|
|
329
343
|
opt = ev_args[3]
|
330
344
|
add_tracer ObjectTracer.new(@ui, obj_id, obj_inspect, **opt)
|
331
345
|
else
|
332
|
-
|
346
|
+
stop_all_threads
|
333
347
|
end
|
334
348
|
|
335
349
|
wait_command_loop
|
336
350
|
|
337
|
-
when :
|
338
|
-
|
339
|
-
wait_command_loop
|
340
|
-
when :cdp_result
|
341
|
-
cdp_event ev_args
|
351
|
+
when :protocol_result
|
352
|
+
process_protocol_result ev_args
|
342
353
|
wait_command_loop
|
343
354
|
end
|
344
355
|
end
|
@@ -480,9 +491,9 @@ module DEBUGGER__
|
|
480
491
|
# * `u[ntil]`
|
481
492
|
# * Similar to `next` command, but only stop later lines or the end of the current frame.
|
482
493
|
# * Similar to gdb's `advance` command.
|
483
|
-
# * `u[ntil] <[file:]line
|
494
|
+
# * `u[ntil] <[file:]line>`
|
484
495
|
# * Run til the program reaches given location or the end of the current frame.
|
485
|
-
# * `u[ntil] <name
|
496
|
+
# * `u[ntil] <name>`
|
486
497
|
# * Run til the program invokes a method `<name>`. `<name>` can be a regexp with `/name/`.
|
487
498
|
register_command 'u', 'until',
|
488
499
|
repeat: true,
|
@@ -889,13 +900,13 @@ module DEBUGGER__
|
|
889
900
|
# * `p <expr>`
|
890
901
|
# * Evaluate like `p <expr>` on the current frame.
|
891
902
|
register_command 'p' do |arg|
|
892
|
-
|
903
|
+
request_eval :p, arg.to_s
|
893
904
|
end
|
894
905
|
|
895
906
|
# * `pp <expr>`
|
896
907
|
# * Evaluate like `pp <expr>` on the current frame.
|
897
908
|
register_command 'pp' do |arg|
|
898
|
-
|
909
|
+
request_eval :pp, arg.to_s
|
899
910
|
end
|
900
911
|
|
901
912
|
# * `eval <expr>`
|
@@ -906,7 +917,7 @@ module DEBUGGER__
|
|
906
917
|
@ui.puts "\nTo evaluate the variable `#{cmd}`, use `pp #{cmd}` instead."
|
907
918
|
:retry
|
908
919
|
else
|
909
|
-
|
920
|
+
request_eval :call, arg
|
910
921
|
end
|
911
922
|
end
|
912
923
|
|
@@ -917,7 +928,7 @@ module DEBUGGER__
|
|
917
928
|
@ui.puts "not supported on the remote console."
|
918
929
|
:retry
|
919
930
|
end
|
920
|
-
|
931
|
+
request_eval :irb, nil
|
921
932
|
end
|
922
933
|
|
923
934
|
### Trace
|
@@ -1137,7 +1148,7 @@ module DEBUGGER__
|
|
1137
1148
|
@repl_prev_line = nil
|
1138
1149
|
check_unsafe
|
1139
1150
|
|
1140
|
-
|
1151
|
+
request_eval :pp, line
|
1141
1152
|
end
|
1142
1153
|
|
1143
1154
|
rescue Interrupt
|
@@ -1153,6 +1164,11 @@ module DEBUGGER__
|
|
1153
1164
|
return :retry
|
1154
1165
|
end
|
1155
1166
|
|
1167
|
+
def request_eval type, src
|
1168
|
+
restart_all_threads
|
1169
|
+
request_tc [:eval, type, src]
|
1170
|
+
end
|
1171
|
+
|
1156
1172
|
def step_command type, arg
|
1157
1173
|
if type == :until
|
1158
1174
|
leave_subsession [:step, type, arg]
|
@@ -1321,10 +1337,6 @@ module DEBUGGER__
|
|
1321
1337
|
|
1322
1338
|
# breakpoint management
|
1323
1339
|
|
1324
|
-
def bps_pending_until_load?
|
1325
|
-
@bps.any?{|key, bp| bp.pending_until_load?}
|
1326
|
-
end
|
1327
|
-
|
1328
1340
|
def iterate_bps
|
1329
1341
|
deleted_bps = []
|
1330
1342
|
i = 0
|
@@ -1500,7 +1512,7 @@ module DEBUGGER__
|
|
1500
1512
|
def clear_line_breakpoints path
|
1501
1513
|
path = resolve_path(path)
|
1502
1514
|
clear_breakpoints do |k, bp|
|
1503
|
-
bp.is_a?(LineBreakpoint) &&
|
1515
|
+
bp.is_a?(LineBreakpoint) && bp.path_is?(path)
|
1504
1516
|
end
|
1505
1517
|
rescue Errno::ENOENT
|
1506
1518
|
# just ignore
|
@@ -1524,7 +1536,7 @@ module DEBUGGER__
|
|
1524
1536
|
# tracers
|
1525
1537
|
|
1526
1538
|
def add_tracer tracer
|
1527
|
-
if @tracers
|
1539
|
+
if @tracers[tracer.key]&.enabled?
|
1528
1540
|
tracer.disable
|
1529
1541
|
@ui.puts "Duplicated tracer: #{tracer}"
|
1530
1542
|
else
|
@@ -1724,25 +1736,26 @@ module DEBUGGER__
|
|
1724
1736
|
file_path, reloaded = @sr.add(iseq, src)
|
1725
1737
|
@ui.event :load, file_path, reloaded
|
1726
1738
|
|
1727
|
-
|
1728
|
-
|
1729
|
-
|
1730
|
-
|
1731
|
-
pending_line_breakpoints.each do |_key, bp|
|
1732
|
-
if DEBUGGER__.compare_path(bp.path, (iseq.absolute_path || iseq.path))
|
1733
|
-
bp.try_activate iseq
|
1734
|
-
end
|
1735
|
-
end
|
1736
|
-
|
1737
|
-
if reloaded
|
1738
|
-
@bps.find_all do |key, bp|
|
1739
|
-
LineBreakpoint === bp && DEBUGGER__.compare_path(bp.path, file_path)
|
1739
|
+
# check breakpoints
|
1740
|
+
if file_path
|
1741
|
+
@bps.find_all do |_key, bp|
|
1742
|
+
LineBreakpoint === bp && bp.path_is?(file_path)
|
1740
1743
|
end.each do |_key, bp|
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
+
if !bp.iseq
|
1745
|
+
bp.try_activate iseq
|
1746
|
+
elsif reloaded
|
1747
|
+
@bps.delete bp.key # to allow duplicate
|
1748
|
+
if nbp = LineBreakpoint.copy(bp, iseq)
|
1749
|
+
add_bp nbp
|
1750
|
+
end
|
1744
1751
|
end
|
1745
1752
|
end
|
1753
|
+
else # !file_path => file_path is not existing
|
1754
|
+
@bps.find_all do |_key, bp|
|
1755
|
+
LineBreakpoint === bp && !bp.iseq && DEBUGGER__.compare_path(bp.path, (iseq.absolute_path || iseq.path))
|
1756
|
+
end.each do |_key, bp|
|
1757
|
+
bp.try_activate iseq
|
1758
|
+
end
|
1746
1759
|
end
|
1747
1760
|
end
|
1748
1761
|
|
@@ -1980,6 +1993,13 @@ module DEBUGGER__
|
|
1980
1993
|
def after_fork_parent
|
1981
1994
|
@ui.after_fork_parent
|
1982
1995
|
end
|
1996
|
+
|
1997
|
+
# experimental API
|
1998
|
+
def extend_feature session: nil, thread_client: nil, ui: nil
|
1999
|
+
Session.include session if session
|
2000
|
+
ThreadClient.include thread_client if thread_client
|
2001
|
+
@ui.extend ui if ui
|
2002
|
+
end
|
1983
2003
|
end
|
1984
2004
|
|
1985
2005
|
class ProcessGroup
|
@@ -2438,7 +2458,7 @@ module DEBUGGER__
|
|
2438
2458
|
end
|
2439
2459
|
|
2440
2460
|
module DaemonInterceptor
|
2441
|
-
def daemon
|
2461
|
+
def daemon(*args)
|
2442
2462
|
return super unless defined?(SESSION) && SESSION.active?
|
2443
2463
|
|
2444
2464
|
_, child_hook = __fork_setup_for_debugger(:child)
|
@@ -2504,7 +2524,17 @@ module DEBUGGER__
|
|
2504
2524
|
|
2505
2525
|
module TrapInterceptor
|
2506
2526
|
def trap sig, *command, &command_proc
|
2507
|
-
|
2527
|
+
sym =
|
2528
|
+
case sig
|
2529
|
+
when String
|
2530
|
+
sig.to_sym
|
2531
|
+
when Integer
|
2532
|
+
Signal.signame(sig)&.to_sym
|
2533
|
+
else
|
2534
|
+
sig
|
2535
|
+
end
|
2536
|
+
|
2537
|
+
case sig&.to_s&.to_sym
|
2508
2538
|
when :INT, :SIGINT
|
2509
2539
|
if defined?(SESSION) && SESSION.active? && SESSION.intercept_trap_sigint?
|
2510
2540
|
return SESSION.save_int_trap(command.empty? ? command_proc : command.first)
|
@@ -34,7 +34,7 @@ module DEBUGGER__
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def add iseq, src
|
37
|
-
#
|
37
|
+
# only manage loaded file names
|
38
38
|
if (path = (iseq.absolute_path || iseq.path)) && File.exist?(path)
|
39
39
|
if @loaded_file_map.has_key? path
|
40
40
|
return path, true # reloaded
|
@@ -49,7 +49,7 @@ module DEBUGGER__
|
|
49
49
|
lines = iseq.script_lines&.map(&:chomp)
|
50
50
|
line = iseq.first_line
|
51
51
|
if line > 1
|
52
|
-
|
52
|
+
[*([''] * (line - 1)), *lines]
|
53
53
|
else
|
54
54
|
lines
|
55
55
|
end
|
data/lib/debug/thread_client.rb
CHANGED
@@ -14,6 +14,7 @@ module DEBUGGER__
|
|
14
14
|
M_RESPOND_TO_P = method(:respond_to?).unbind
|
15
15
|
M_METHOD = method(:method).unbind
|
16
16
|
M_OBJECT_ID = method(:object_id).unbind
|
17
|
+
M_NAME = method(:name).unbind
|
17
18
|
|
18
19
|
module SkipPathHelper
|
19
20
|
def skip_path?(path)
|
@@ -468,10 +469,14 @@ module DEBUGGER__
|
|
468
469
|
if file_lines = frame.file_lines
|
469
470
|
frame_line = frame.location.lineno - 1
|
470
471
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
472
|
+
if CONFIG[:no_lineno]
|
473
|
+
lines = file_lines
|
474
|
+
else
|
475
|
+
lines = file_lines.map.with_index do |e, i|
|
476
|
+
cur = i == frame_line ? '=>' : ' '
|
477
|
+
line = colorize_dim('%4d|' % (i+1))
|
478
|
+
"#{cur}#{line} #{e}"
|
479
|
+
end
|
475
480
|
end
|
476
481
|
|
477
482
|
unless start_line
|
@@ -607,12 +612,17 @@ module DEBUGGER__
|
|
607
612
|
|
608
613
|
def get_consts expr = nil, only_self: false, &block
|
609
614
|
if expr && !expr.empty?
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
615
|
+
begin
|
616
|
+
_self = frame_eval(expr, re_raise: true)
|
617
|
+
rescue Exception => e
|
618
|
+
# ignore
|
614
619
|
else
|
615
|
-
|
620
|
+
if M_KIND_OF_P.bind_call(_self, Module)
|
621
|
+
iter_consts _self, &block
|
622
|
+
return
|
623
|
+
else
|
624
|
+
puts "#{_self.inspect} (by #{expr}) is not a Module."
|
625
|
+
end
|
616
626
|
end
|
617
627
|
elsif _self = current_frame&.self
|
618
628
|
cs = {}
|
@@ -1230,7 +1240,15 @@ module DEBUGGER__
|
|
1230
1240
|
rescue SuspendReplay, SystemExit, Interrupt
|
1231
1241
|
raise
|
1232
1242
|
rescue Exception => e
|
1233
|
-
|
1243
|
+
STDERR.puts e.cause.inspect
|
1244
|
+
STDERR.puts e.inspect
|
1245
|
+
Thread.list.each{|th|
|
1246
|
+
STDERR.puts "@@@ #{th}"
|
1247
|
+
th.backtrace.each{|b|
|
1248
|
+
STDERR.puts " > #{b}"
|
1249
|
+
}
|
1250
|
+
}
|
1251
|
+
p ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace]
|
1234
1252
|
raise
|
1235
1253
|
ensure
|
1236
1254
|
@returning = false
|
@@ -1292,10 +1310,14 @@ module DEBUGGER__
|
|
1292
1310
|
frame._callee = b.eval('__callee__')
|
1293
1311
|
end
|
1294
1312
|
}
|
1295
|
-
|
1313
|
+
append(frames)
|
1296
1314
|
}
|
1297
1315
|
end
|
1298
1316
|
|
1317
|
+
def append frames
|
1318
|
+
@log << frames
|
1319
|
+
end
|
1320
|
+
|
1299
1321
|
def enable
|
1300
1322
|
unless @tp_recorder.enabled?
|
1301
1323
|
@log.clear
|
data/lib/debug/tracer.rb
CHANGED
@@ -54,6 +54,10 @@ module DEBUGGER__
|
|
54
54
|
@tracer.disable
|
55
55
|
end
|
56
56
|
|
57
|
+
def enabled?
|
58
|
+
@tracer.enabled?
|
59
|
+
end
|
60
|
+
|
57
61
|
def description
|
58
62
|
nil
|
59
63
|
end
|
@@ -85,11 +89,6 @@ module DEBUGGER__
|
|
85
89
|
end
|
86
90
|
end
|
87
91
|
|
88
|
-
def puts msg
|
89
|
-
@output.puts msg
|
90
|
-
@output.flush
|
91
|
-
end
|
92
|
-
|
93
92
|
def minfo tp
|
94
93
|
return "block{}" if tp.event == :b_call
|
95
94
|
|
data/lib/debug/version.rb
CHANGED
data/misc/README.md.erb
CHANGED
@@ -26,7 +26,7 @@ New debug.rb has several advantages:
|
|
26
26
|
* Support threads (almost done) and ractors (TODO).
|
27
27
|
* Support suspending and entering to the console debugging with `Ctrl-C` at most of timing.
|
28
28
|
* Show parameters on backtrace command.
|
29
|
-
* Support recording &
|
29
|
+
* Support recording & replay debugging.
|
30
30
|
|
31
31
|
# Installation
|
32
32
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: debug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Koichi Sasada
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: irb
|
@@ -66,6 +66,7 @@ files:
|
|
66
66
|
- lib/debug/color.rb
|
67
67
|
- lib/debug/config.rb
|
68
68
|
- lib/debug/console.rb
|
69
|
+
- lib/debug/dap_custom/traceInspector.rb
|
69
70
|
- lib/debug/frame_info.rb
|
70
71
|
- lib/debug/local.rb
|
71
72
|
- lib/debug/open.rb
|