debug 1.7.2 → 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/README.md +3 -0
- data/lib/debug/config.rb +1 -0
- data/lib/debug/dap_custom/traceInspector.rb +336 -0
- data/lib/debug/frame_info.rb +9 -0
- data/lib/debug/server_cdp.rb +9 -11
- data/lib/debug/server_dap.rb +188 -159
- data/lib/debug/session.rb +18 -1
- data/lib/debug/thread_client.rb +24 -10
- data/lib/debug/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39fceaae982c712433b6bf0bc855328c5d923524658a399926e7a032f5d7cdbf
|
4
|
+
data.tar.gz: 4f80f39348e0cd46882bd54e04398342c3d124133aa15edcc57a18f1a20fe449
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67a369a45e2debb29dbb42fcbc32d36e1c40467249d657f45caa8a04a5fb3521a10c91860a3f3407caaa8f97cf81ad35f8a3e5ac83a124b99811d82363afe2cf
|
7
|
+
data.tar.gz: b29458d948196114b7cb5c7c182decca2685495b96707d904674714a2256a46bd0244efdde5d1ada8a460d881dff7ad4acafaa2c433c6e0eddbcf928425f6748
|
data/README.md
CHANGED
@@ -476,6 +476,7 @@ config set no_color true
|
|
476
476
|
* `RUBY_DEBUG_NO_SIGINT_HOOK` (`no_sigint_hook`): Do not suspend on SIGINT (default: false)
|
477
477
|
* `RUBY_DEBUG_NO_RELINE` (`no_reline`): Do not use Reline library (default: false)
|
478
478
|
* `RUBY_DEBUG_NO_HINT` (`no_hint`): Do not show the hint on the REPL (default: false)
|
479
|
+
* `RUBY_DEBUG_NO_LINENO` (`no_lineno`): Do not show line numbers (default: false)
|
479
480
|
|
480
481
|
* CONTROL
|
481
482
|
* `RUBY_DEBUG_SKIP_PATH` (`skip_path`): Skip showing/entering frames for given paths
|
@@ -908,6 +909,8 @@ Attach mode:
|
|
908
909
|
'rdbg -A host port' tries to connect to host:port via TCP/IP.
|
909
910
|
|
910
911
|
Other options:
|
912
|
+
-v Show version number
|
913
|
+
--version Show version number and exit
|
911
914
|
-h, --help Print help
|
912
915
|
--util=NAME Utility mode (used by tools)
|
913
916
|
--stop-at-load Stop immediately when the debugging feature is loaded.
|
data/lib/debug/config.rb
CHANGED
@@ -21,6 +21,7 @@ module DEBUGGER__
|
|
21
21
|
no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT", :bool, "false"],
|
22
22
|
no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"],
|
23
23
|
no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"],
|
24
|
+
no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"],
|
24
25
|
|
25
26
|
# control setting
|
26
27
|
skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path],
|
@@ -0,0 +1,336 @@
|
|
1
|
+
module DEBUGGER__
|
2
|
+
module DAP_TraceInspector
|
3
|
+
class MultiTracer < Tracer
|
4
|
+
def initialize ui, evts, trace_params, max_log_size: nil, **kw
|
5
|
+
@evts = evts
|
6
|
+
@log = []
|
7
|
+
@trace_params = trace_params
|
8
|
+
if max_log_size
|
9
|
+
@max_log_size = max_log_size
|
10
|
+
else
|
11
|
+
@max_log_size = 50000
|
12
|
+
end
|
13
|
+
@dropped_trace_cnt = 0
|
14
|
+
super(ui, **kw)
|
15
|
+
@type = 'multi'
|
16
|
+
@name = 'TraceInspector'
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :dropped_trace_cnt
|
20
|
+
attr_reader :log
|
21
|
+
|
22
|
+
def setup
|
23
|
+
@tracer = TracePoint.new(*@evts){|tp|
|
24
|
+
next if skip?(tp)
|
25
|
+
|
26
|
+
case tp.event
|
27
|
+
when :call, :c_call, :b_call
|
28
|
+
if @trace_params
|
29
|
+
params = parameters_info tp
|
30
|
+
end
|
31
|
+
append(call_trace_log(tp, params: params))
|
32
|
+
when :return, :c_return, :b_return
|
33
|
+
return_str = DEBUGGER__.safe_inspect(tp.return_value, short: true, max_length: 4096)
|
34
|
+
append(call_trace_log(tp, return_str: return_str))
|
35
|
+
when :line
|
36
|
+
append(line_trace_log(tp))
|
37
|
+
end
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def parameters_info tp
|
42
|
+
b = tp.binding
|
43
|
+
tp.parameters.map{|_type, name|
|
44
|
+
begin
|
45
|
+
{ name: name, value: DEBUGGER__.safe_inspect(b.local_variable_get(name), short: true, max_length: 4096) }
|
46
|
+
rescue NameError, TypeError
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
}.compact
|
50
|
+
end
|
51
|
+
|
52
|
+
def call_identifier_str tp
|
53
|
+
if tp.defined_class
|
54
|
+
minfo(tp)
|
55
|
+
else
|
56
|
+
"block"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def append log
|
61
|
+
if @log.size >= @max_log_size
|
62
|
+
@dropped_trace_cnt += 1
|
63
|
+
@log.shift
|
64
|
+
end
|
65
|
+
@log << log
|
66
|
+
end
|
67
|
+
|
68
|
+
def call_trace_log tp, return_str: nil, params: nil
|
69
|
+
log = {
|
70
|
+
depth: DEBUGGER__.frame_depth,
|
71
|
+
name: call_identifier_str(tp),
|
72
|
+
threadId: Thread.current.instance_variable_get(:@__thread_client_id),
|
73
|
+
location: {
|
74
|
+
path: tp.path,
|
75
|
+
line: tp.lineno
|
76
|
+
}
|
77
|
+
}
|
78
|
+
log[:returnValue] = return_str if return_str
|
79
|
+
log[:parameters] = params if params && params.size > 0
|
80
|
+
log
|
81
|
+
end
|
82
|
+
|
83
|
+
def line_trace_log tp
|
84
|
+
{
|
85
|
+
depth: DEBUGGER__.frame_depth,
|
86
|
+
threadId: Thread.current.instance_variable_get(:@__thread_client_id),
|
87
|
+
location: {
|
88
|
+
path: tp.path,
|
89
|
+
line: tp.lineno
|
90
|
+
}
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
def skip? tp
|
95
|
+
super || !@evts.include?(tp.event)
|
96
|
+
end
|
97
|
+
|
98
|
+
def skip_with_pattern?(tp)
|
99
|
+
super && !tp.method_id&.match?(@pattern)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class Custom_Recorder < ThreadClient::Recorder
|
104
|
+
def initialize max_log_size: nil
|
105
|
+
if max_log_size
|
106
|
+
@max_log_size = max_log_size
|
107
|
+
else
|
108
|
+
@max_log_size = 50000
|
109
|
+
end
|
110
|
+
@dropped_trace_cnt = 0
|
111
|
+
super()
|
112
|
+
end
|
113
|
+
|
114
|
+
attr_accessor :dropped_trace_cnt
|
115
|
+
|
116
|
+
def append frames
|
117
|
+
if @log.size >= @max_log_size
|
118
|
+
@dropped_trace_cnt += 1
|
119
|
+
@log.shift
|
120
|
+
end
|
121
|
+
@log << frames
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
module Custom_UI_DAP
|
126
|
+
def custom_dap_request_rdbgTraceInspector(req)
|
127
|
+
@q_msg << req
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
module Custom_Session
|
132
|
+
def process_trace_cmd req
|
133
|
+
cmd = req.dig('arguments', 'subCommand')
|
134
|
+
case cmd
|
135
|
+
when 'enable'
|
136
|
+
events = req.dig('arguments', 'events')
|
137
|
+
evts = []
|
138
|
+
trace_params = false
|
139
|
+
filter = req.dig('arguments', 'filterRegExp')
|
140
|
+
max_log_size = req.dig('arguments', 'maxLogSize')
|
141
|
+
events.each{|evt|
|
142
|
+
case evt
|
143
|
+
when 'traceLine'
|
144
|
+
evts << :line
|
145
|
+
when 'traceCall'
|
146
|
+
evts << :call
|
147
|
+
evts << :b_call
|
148
|
+
when 'traceReturn'
|
149
|
+
evts << :return
|
150
|
+
evts << :b_return
|
151
|
+
when 'traceParams'
|
152
|
+
trace_params = true
|
153
|
+
when 'traceClanguageCall'
|
154
|
+
evts << :c_call
|
155
|
+
when 'traceClanguageReturn'
|
156
|
+
evts << :c_return
|
157
|
+
else
|
158
|
+
raise "unknown trace type #{evt}"
|
159
|
+
end
|
160
|
+
}
|
161
|
+
add_tracer MultiTracer.new @ui, evts, trace_params, max_log_size: max_log_size, pattern: filter
|
162
|
+
@ui.respond req, {}
|
163
|
+
when 'disable'
|
164
|
+
if t = find_multi_trace
|
165
|
+
t.disable
|
166
|
+
end
|
167
|
+
@ui.respond req, {}
|
168
|
+
when 'collect'
|
169
|
+
logs = []
|
170
|
+
if t = find_multi_trace
|
171
|
+
logs = t.log
|
172
|
+
if t.dropped_trace_cnt > 0
|
173
|
+
@ui.puts "Return #{logs.size} traces and #{t.dropped_trace_cnt} traces are dropped"
|
174
|
+
else
|
175
|
+
@ui.puts "Return #{logs.size} traces"
|
176
|
+
end
|
177
|
+
t.dropped_trace_cnt = 0
|
178
|
+
end
|
179
|
+
@ui.respond req, logs: logs
|
180
|
+
else
|
181
|
+
raise "Unknown trace sub command #{cmd}"
|
182
|
+
end
|
183
|
+
return :retry
|
184
|
+
end
|
185
|
+
|
186
|
+
def find_multi_trace
|
187
|
+
@tracers.values.each{|t|
|
188
|
+
if t.type == 'multi'
|
189
|
+
return t
|
190
|
+
end
|
191
|
+
}
|
192
|
+
return nil
|
193
|
+
end
|
194
|
+
|
195
|
+
def process_record_cmd req
|
196
|
+
cmd = req.dig('arguments', 'subCommand')
|
197
|
+
case cmd
|
198
|
+
when 'enable'
|
199
|
+
@tc << [:dap, :rdbgTraceInspector, req]
|
200
|
+
when 'disable'
|
201
|
+
@tc << [:dap, :rdbgTraceInspector, req]
|
202
|
+
when 'step'
|
203
|
+
tid = req.dig('arguments', 'threadId')
|
204
|
+
count = req.dig('arguments', 'count')
|
205
|
+
if tc = find_waiting_tc(tid)
|
206
|
+
@ui.respond req, {}
|
207
|
+
tc << [:step, :in, count]
|
208
|
+
else
|
209
|
+
fail_response req
|
210
|
+
end
|
211
|
+
when 'stepBack'
|
212
|
+
tid = req.dig('arguments', 'threadId')
|
213
|
+
count = req.dig('arguments', 'count')
|
214
|
+
if tc = find_waiting_tc(tid)
|
215
|
+
@ui.respond req, {}
|
216
|
+
tc << [:step, :back, count]
|
217
|
+
else
|
218
|
+
fail_response req
|
219
|
+
end
|
220
|
+
when 'collect'
|
221
|
+
tid = req.dig('arguments', 'threadId')
|
222
|
+
if tc = find_waiting_tc(tid)
|
223
|
+
tc << [:dap, :rdbgTraceInspector, req]
|
224
|
+
else
|
225
|
+
fail_response req
|
226
|
+
end
|
227
|
+
else
|
228
|
+
raise "Unknown record sub command #{cmd}"
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def custom_dap_request_rdbgTraceInspector(req)
|
233
|
+
cmd = req.dig('arguments', 'command')
|
234
|
+
case cmd
|
235
|
+
when 'trace'
|
236
|
+
process_trace_cmd req
|
237
|
+
when 'record'
|
238
|
+
process_record_cmd req
|
239
|
+
else
|
240
|
+
raise "Unknown command #{cmd}"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def custom_dap_request_event_rdbgTraceInspector(req, result)
|
245
|
+
cmd = req.dig('arguments', 'command')
|
246
|
+
case cmd
|
247
|
+
when 'record'
|
248
|
+
process_event_record_cmd(req, result)
|
249
|
+
else
|
250
|
+
raise "Unknown command #{cmd}"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def process_event_record_cmd(req, result)
|
255
|
+
cmd = req.dig('arguments', 'subCommand')
|
256
|
+
case cmd
|
257
|
+
when 'enable'
|
258
|
+
@ui.respond req, {}
|
259
|
+
when 'disable'
|
260
|
+
@ui.respond req, {}
|
261
|
+
when 'collect'
|
262
|
+
cnt = result.delete :dropped_trace_cnt
|
263
|
+
if cnt > 0
|
264
|
+
@ui.puts "Return #{result[:logs].size} traces and #{cnt} traces are dropped"
|
265
|
+
else
|
266
|
+
@ui.puts "Return #{result[:logs].size} traces"
|
267
|
+
end
|
268
|
+
@ui.respond req, result
|
269
|
+
else
|
270
|
+
raise "Unknown command #{cmd}"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
module Custom_ThreadClient
|
276
|
+
def custom_dap_request_rdbgTraceInspector(req)
|
277
|
+
cmd = req.dig('arguments', 'command')
|
278
|
+
case cmd
|
279
|
+
when 'record'
|
280
|
+
process_record_cmd(req)
|
281
|
+
else
|
282
|
+
raise "Unknown command #{cmd}"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def process_record_cmd(req)
|
287
|
+
cmd = req.dig('arguments', 'subCommand')
|
288
|
+
case cmd
|
289
|
+
when 'enable'
|
290
|
+
size = req.dig('arguments', 'maxLogSize')
|
291
|
+
@recorder = Custom_Recorder.new max_log_size: size
|
292
|
+
@recorder.enable
|
293
|
+
event! :protocol_result, :rdbgTraceInspector, req
|
294
|
+
when 'disable'
|
295
|
+
if @recorder&.enabled?
|
296
|
+
@recorder.disable
|
297
|
+
end
|
298
|
+
@recorder = nil
|
299
|
+
event! :protocol_result, :rdbgTraceInspector, req
|
300
|
+
when 'collect'
|
301
|
+
logs = []
|
302
|
+
log_index = nil
|
303
|
+
trace_cnt = 0
|
304
|
+
unless @recorder.nil?
|
305
|
+
log_index = @recorder.log_index
|
306
|
+
@recorder.log.each{|frames|
|
307
|
+
crt_frame = frames[0]
|
308
|
+
log = {
|
309
|
+
name: crt_frame.name,
|
310
|
+
location: {
|
311
|
+
path: crt_frame.location.path,
|
312
|
+
line: crt_frame.location.lineno,
|
313
|
+
},
|
314
|
+
depth: crt_frame.frame_depth
|
315
|
+
}
|
316
|
+
if params = crt_frame.iseq_parameters_info
|
317
|
+
log[:parameters] = params
|
318
|
+
end
|
319
|
+
if return_str = crt_frame.return_str
|
320
|
+
log[:returnValue] = return_str
|
321
|
+
end
|
322
|
+
logs << log
|
323
|
+
}
|
324
|
+
trace_cnt = @recorder.dropped_trace_cnt
|
325
|
+
@recorder.dropped_trace_cnt = 0
|
326
|
+
end
|
327
|
+
event! :protocol_result, :rdbgTraceInspector, req, logs: logs, stoppedIndex: log_index, dropped_trace_cnt: trace_cnt
|
328
|
+
else
|
329
|
+
raise "Unknown command #{cmd}"
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
::DEBUGGER__::SESSION.extend_feature session: Custom_Session, thread_client: Custom_ThreadClient, ui: Custom_UI_DAP
|
335
|
+
end
|
336
|
+
end
|
data/lib/debug/frame_info.rb
CHANGED
@@ -147,6 +147,15 @@ module DEBUGGER__
|
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
|
+
def iseq_parameters_info
|
151
|
+
case frame_type
|
152
|
+
when :block, :method
|
153
|
+
parameters_info
|
154
|
+
else
|
155
|
+
nil
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
150
159
|
def parameters_info
|
151
160
|
vars = iseq.parameters_symbols
|
152
161
|
vars.map{|var|
|
data/lib/debug/server_cdp.rb
CHANGED
@@ -849,27 +849,25 @@ module DEBUGGER__
|
|
849
849
|
unless s_id = @scr_id_map[path]
|
850
850
|
s_id = (@scr_id_map.size + 1).to_s
|
851
851
|
@scr_id_map[path] = s_id
|
852
|
+
lineno = 0
|
853
|
+
src = ''
|
852
854
|
if path && File.exist?(path)
|
853
855
|
src = File.read(path)
|
856
|
+
@src_map[s_id] = src
|
857
|
+
lineno = src.lines.count
|
854
858
|
end
|
855
|
-
@
|
856
|
-
end
|
857
|
-
if src = @src_map[s_id]
|
858
|
-
lineno = src.lines.count
|
859
|
-
else
|
860
|
-
lineno = 0
|
861
|
-
end
|
862
|
-
frame[:location][:scriptId] = s_id
|
863
|
-
frame[:functionLocation][:scriptId] = s_id
|
864
|
-
@ui.fire_event 'Debugger.scriptParsed',
|
859
|
+
@ui.fire_event 'Debugger.scriptParsed',
|
865
860
|
scriptId: s_id,
|
866
|
-
url:
|
861
|
+
url: path,
|
867
862
|
startLine: 0,
|
868
863
|
startColumn: 0,
|
869
864
|
endLine: lineno,
|
870
865
|
endColumn: 0,
|
871
866
|
executionContextId: 1,
|
872
867
|
hash: src.hash.inspect
|
868
|
+
end
|
869
|
+
frame[:location][:scriptId] = s_id
|
870
|
+
frame[:functionLocation][:scriptId] = s_id
|
873
871
|
|
874
872
|
frame[:scopeChain].each {|s|
|
875
873
|
oid = s.dig(:object, :objectId)
|
data/lib/debug/server_dap.rb
CHANGED
@@ -274,198 +274,225 @@ module DEBUGGER__
|
|
274
274
|
retry
|
275
275
|
end
|
276
276
|
|
277
|
+
def load_extensions req
|
278
|
+
if exts = req.dig('arguments', 'rdbgExtensions')
|
279
|
+
exts.each{|ext|
|
280
|
+
require_relative "dap_custom/#{File.basename(ext)}"
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
if scripts = req.dig('arguments', 'rdbgInitialScripts')
|
285
|
+
scripts.each do |script|
|
286
|
+
begin
|
287
|
+
eval(script)
|
288
|
+
rescue Exception => e
|
289
|
+
puts e.message
|
290
|
+
puts e.backtrace.inspect
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
277
296
|
def process
|
278
297
|
while req = recv_request
|
279
|
-
|
280
|
-
|
298
|
+
process_request(req)
|
299
|
+
end
|
300
|
+
ensure
|
301
|
+
send_event :terminated unless @sock.closed?
|
302
|
+
end
|
281
303
|
|
282
|
-
|
304
|
+
def process_request req
|
305
|
+
raise "not a request: #{req.inspect}" unless req['type'] == 'request'
|
306
|
+
args = req.dig('arguments')
|
283
307
|
|
284
|
-
|
285
|
-
when 'launch'
|
286
|
-
send_response req
|
287
|
-
# `launch` runs on debuggee on the same file system
|
288
|
-
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true
|
289
|
-
@nonstop = true
|
308
|
+
case req['command']
|
290
309
|
|
291
|
-
|
292
|
-
|
293
|
-
|
310
|
+
## boot/configuration
|
311
|
+
when 'launch'
|
312
|
+
send_response req
|
313
|
+
# `launch` runs on debuggee on the same file system
|
314
|
+
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true
|
315
|
+
@nonstop = true
|
294
316
|
|
295
|
-
|
296
|
-
@nonstop = true
|
297
|
-
else
|
298
|
-
@nonstop = false
|
299
|
-
end
|
317
|
+
load_extensions req
|
300
318
|
|
301
|
-
|
302
|
-
|
319
|
+
when 'attach'
|
320
|
+
send_response req
|
321
|
+
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap')
|
303
322
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
threadId: 1, # maybe ...
|
310
|
-
allThreadsStopped: true
|
311
|
-
end
|
312
|
-
end
|
323
|
+
if req.dig('arguments', 'nonstop') == true
|
324
|
+
@nonstop = true
|
325
|
+
else
|
326
|
+
@nonstop = false
|
327
|
+
end
|
313
328
|
|
314
|
-
|
315
|
-
req_path = args.dig('source', 'path')
|
316
|
-
path = UI_DAP.local_to_remote_path(req_path)
|
317
|
-
if path
|
318
|
-
SESSION.clear_line_breakpoints path
|
319
|
-
|
320
|
-
bps = []
|
321
|
-
args['breakpoints'].each{|bp|
|
322
|
-
line = bp['line']
|
323
|
-
if cond = bp['condition']
|
324
|
-
bps << SESSION.add_line_breakpoint(path, line, cond: cond)
|
325
|
-
else
|
326
|
-
bps << SESSION.add_line_breakpoint(path, line)
|
327
|
-
end
|
328
|
-
}
|
329
|
-
send_response req, breakpoints: (bps.map do |bp| {verified: true,} end)
|
330
|
-
else
|
331
|
-
send_response req, success: false, message: "#{req_path} is not available"
|
332
|
-
end
|
329
|
+
load_extensions req
|
333
330
|
|
334
|
-
|
335
|
-
|
331
|
+
when 'configurationDone'
|
332
|
+
send_response req
|
336
333
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
nil
|
347
|
-
end
|
348
|
-
{
|
349
|
-
verified: !bp.nil?,
|
350
|
-
message: bp.inspect,
|
351
|
-
}
|
352
|
-
}
|
334
|
+
if @nonstop
|
335
|
+
@q_msg << 'continue'
|
336
|
+
else
|
337
|
+
if SESSION.in_subsession?
|
338
|
+
send_event 'stopped', reason: 'pause',
|
339
|
+
threadId: 1, # maybe ...
|
340
|
+
allThreadsStopped: true
|
341
|
+
end
|
342
|
+
end
|
353
343
|
|
354
|
-
|
344
|
+
when 'setBreakpoints'
|
345
|
+
req_path = args.dig('source', 'path')
|
346
|
+
path = UI_DAP.local_to_remote_path(req_path)
|
347
|
+
if path
|
348
|
+
SESSION.clear_line_breakpoints path
|
349
|
+
|
350
|
+
bps = []
|
351
|
+
args['breakpoints'].each{|bp|
|
352
|
+
line = bp['line']
|
353
|
+
if cond = bp['condition']
|
354
|
+
bps << SESSION.add_line_breakpoint(path, line, cond: cond)
|
355
|
+
else
|
356
|
+
bps << SESSION.add_line_breakpoint(path, line)
|
357
|
+
end
|
358
|
+
}
|
359
|
+
send_response req, breakpoints: (bps.map do |bp| {verified: true,} end)
|
360
|
+
else
|
361
|
+
send_response req, success: false, message: "#{req_path} is not available"
|
362
|
+
end
|
355
363
|
|
356
|
-
|
357
|
-
|
364
|
+
when 'setFunctionBreakpoints'
|
365
|
+
send_response req
|
366
|
+
|
367
|
+
when 'setExceptionBreakpoints'
|
368
|
+
process_filter = ->(filter_id, cond = nil) {
|
369
|
+
bp =
|
370
|
+
case filter_id
|
371
|
+
when 'any'
|
372
|
+
SESSION.add_catch_breakpoint 'Exception', cond: cond
|
373
|
+
when 'RuntimeError'
|
374
|
+
SESSION.add_catch_breakpoint 'RuntimeError', cond: cond
|
375
|
+
else
|
376
|
+
nil
|
377
|
+
end
|
378
|
+
{
|
379
|
+
verified: !bp.nil?,
|
380
|
+
message: bp.inspect,
|
358
381
|
}
|
382
|
+
}
|
383
|
+
|
384
|
+
SESSION.clear_catch_breakpoints 'Exception', 'RuntimeError'
|
359
385
|
|
360
|
-
|
361
|
-
process_filter.call(
|
386
|
+
filters = args.fetch('filters').map {|filter_id|
|
387
|
+
process_filter.call(filter_id)
|
362
388
|
}
|
363
389
|
|
364
|
-
|
390
|
+
filters += args.fetch('filterOptions', {}).map{|bp_info|
|
391
|
+
process_filter.call(bp_info['filterId'], bp_info['condition'])
|
392
|
+
}
|
365
393
|
|
366
|
-
|
367
|
-
terminate = args.fetch("terminateDebuggee", false)
|
394
|
+
send_response req, breakpoints: filters
|
368
395
|
|
369
|
-
|
370
|
-
|
396
|
+
when 'disconnect'
|
397
|
+
terminate = args.fetch("terminateDebuggee", false)
|
371
398
|
|
372
|
-
|
373
|
-
|
374
|
-
@q_msg << 'kill!'
|
375
|
-
else
|
376
|
-
@q_msg << 'continue'
|
377
|
-
end
|
378
|
-
else
|
379
|
-
if terminate
|
380
|
-
@q_msg << 'kill!'
|
381
|
-
pause
|
382
|
-
end
|
383
|
-
end
|
399
|
+
SESSION.clear_all_breakpoints
|
400
|
+
send_response req
|
384
401
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
begin
|
391
|
-
@session.check_postmortem
|
392
|
-
@q_msg << 'n'
|
393
|
-
send_response req
|
394
|
-
rescue PostmortemError
|
395
|
-
send_response req,
|
396
|
-
success: false, message: 'postmortem mode',
|
397
|
-
result: "'Next' is not supported while postmortem mode"
|
398
|
-
end
|
399
|
-
when 'stepIn'
|
400
|
-
begin
|
401
|
-
@session.check_postmortem
|
402
|
-
@q_msg << 's'
|
403
|
-
send_response req
|
404
|
-
rescue PostmortemError
|
405
|
-
send_response req,
|
406
|
-
success: false, message: 'postmortem mode',
|
407
|
-
result: "'stepIn' is not supported while postmortem mode"
|
402
|
+
if SESSION.in_subsession?
|
403
|
+
if terminate
|
404
|
+
@q_msg << 'kill!'
|
405
|
+
else
|
406
|
+
@q_msg << 'continue'
|
408
407
|
end
|
409
|
-
|
410
|
-
|
411
|
-
@
|
412
|
-
|
413
|
-
send_response req
|
414
|
-
rescue PostmortemError
|
415
|
-
send_response req,
|
416
|
-
success: false, message: 'postmortem mode',
|
417
|
-
result: "'stepOut' is not supported while postmortem mode"
|
408
|
+
else
|
409
|
+
if terminate
|
410
|
+
@q_msg << 'kill!'
|
411
|
+
pause
|
418
412
|
end
|
419
|
-
|
413
|
+
end
|
414
|
+
|
415
|
+
## control
|
416
|
+
when 'continue'
|
417
|
+
@q_msg << 'c'
|
418
|
+
send_response req, allThreadsContinued: true
|
419
|
+
when 'next'
|
420
|
+
begin
|
421
|
+
@session.check_postmortem
|
422
|
+
@q_msg << 'n'
|
420
423
|
send_response req
|
421
|
-
|
422
|
-
|
424
|
+
rescue PostmortemError
|
425
|
+
send_response req,
|
426
|
+
success: false, message: 'postmortem mode',
|
427
|
+
result: "'Next' is not supported while postmortem mode"
|
428
|
+
end
|
429
|
+
when 'stepIn'
|
430
|
+
begin
|
431
|
+
@session.check_postmortem
|
432
|
+
@q_msg << 's'
|
423
433
|
send_response req
|
424
|
-
|
425
|
-
when 'reverseContinue'
|
434
|
+
rescue PostmortemError
|
426
435
|
send_response req,
|
427
|
-
success: false, message: '
|
428
|
-
result: "
|
429
|
-
|
430
|
-
|
436
|
+
success: false, message: 'postmortem mode',
|
437
|
+
result: "'stepIn' is not supported while postmortem mode"
|
438
|
+
end
|
439
|
+
when 'stepOut'
|
440
|
+
begin
|
441
|
+
@session.check_postmortem
|
442
|
+
@q_msg << 'fin'
|
443
|
+
send_response req
|
444
|
+
rescue PostmortemError
|
445
|
+
send_response req,
|
446
|
+
success: false, message: 'postmortem mode',
|
447
|
+
result: "'stepOut' is not supported while postmortem mode"
|
448
|
+
end
|
449
|
+
when 'terminate'
|
450
|
+
send_response req
|
451
|
+
exit
|
452
|
+
when 'pause'
|
453
|
+
send_response req
|
454
|
+
Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid)
|
455
|
+
when 'reverseContinue'
|
456
|
+
send_response req,
|
457
|
+
success: false, message: 'cancelled',
|
458
|
+
result: "Reverse Continue is not supported. Only \"Step back\" is supported."
|
459
|
+
when 'stepBack'
|
460
|
+
@q_msg << req
|
431
461
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
}
|
462
|
+
## query
|
463
|
+
when 'threads'
|
464
|
+
send_response req, threads: SESSION.managed_thread_clients.map{|tc|
|
465
|
+
{ id: tc.id,
|
466
|
+
name: tc.name,
|
438
467
|
}
|
468
|
+
}
|
439
469
|
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
470
|
+
when 'evaluate'
|
471
|
+
expr = req.dig('arguments', 'expression')
|
472
|
+
if /\A\s*,(.+)\z/ =~ expr
|
473
|
+
dbg_expr = $1.strip
|
474
|
+
dbg_expr.split(';;') { |cmd| @q_msg << cmd }
|
445
475
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
@q_msg << req
|
451
|
-
end
|
452
|
-
when 'stackTrace',
|
453
|
-
'scopes',
|
454
|
-
'variables',
|
455
|
-
'source',
|
456
|
-
'completions'
|
476
|
+
send_response req,
|
477
|
+
result: "(rdbg:command) #{dbg_expr}",
|
478
|
+
variablesReference: 0
|
479
|
+
else
|
457
480
|
@q_msg << req
|
481
|
+
end
|
482
|
+
when 'stackTrace',
|
483
|
+
'scopes',
|
484
|
+
'variables',
|
485
|
+
'source',
|
486
|
+
'completions'
|
487
|
+
@q_msg << req
|
458
488
|
|
489
|
+
else
|
490
|
+
if respond_to? mid = "custom_dap_request_#{req['command']}"
|
491
|
+
__send__ mid, req
|
459
492
|
else
|
460
|
-
|
461
|
-
__send__ mid, req
|
462
|
-
else
|
463
|
-
raise "Unknown request: #{req.inspect}"
|
464
|
-
end
|
493
|
+
raise "Unknown request: #{req.inspect}"
|
465
494
|
end
|
466
495
|
end
|
467
|
-
ensure
|
468
|
-
send_event :terminated unless @sock.closed?
|
469
496
|
end
|
470
497
|
|
471
498
|
## called by the SESSION thread
|
@@ -625,6 +652,7 @@ module DEBUGGER__
|
|
625
652
|
expr = req.dig('arguments', 'expression')
|
626
653
|
|
627
654
|
if find_waiting_tc(tid)
|
655
|
+
restart_all_threads
|
628
656
|
request_tc [:dap, :evaluate, req, fid, expr, context]
|
629
657
|
else
|
630
658
|
fail_response req
|
@@ -701,6 +729,7 @@ module DEBUGGER__
|
|
701
729
|
register_vars result[:variables], tid
|
702
730
|
@ui.respond req, result
|
703
731
|
when :evaluate
|
732
|
+
stop_all_threads
|
704
733
|
message = result.delete :message
|
705
734
|
if message
|
706
735
|
@ui.respond req, success: false, message: message
|
@@ -867,7 +896,7 @@ module DEBUGGER__
|
|
867
896
|
}
|
868
897
|
when String
|
869
898
|
vars = [
|
870
|
-
variable('#
|
899
|
+
variable('#length', obj.length),
|
871
900
|
variable('#encoding', obj.encoding),
|
872
901
|
]
|
873
902
|
printed_str = value_inspect(obj)
|
@@ -1014,7 +1043,7 @@ module DEBUGGER__
|
|
1014
1043
|
klass = M_CLASS.bind_call(obj)
|
1015
1044
|
|
1016
1045
|
begin
|
1017
|
-
klass
|
1046
|
+
M_NAME.bind_call(klass) || klass.to_s
|
1018
1047
|
rescue Exception => e
|
1019
1048
|
"<Error: #{e.message} (#{e.backtrace.first}>"
|
1020
1049
|
end
|
data/lib/debug/session.rb
CHANGED
@@ -1993,6 +1993,13 @@ module DEBUGGER__
|
|
1993
1993
|
def after_fork_parent
|
1994
1994
|
@ui.after_fork_parent
|
1995
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
|
1996
2003
|
end
|
1997
2004
|
|
1998
2005
|
class ProcessGroup
|
@@ -2517,7 +2524,17 @@ module DEBUGGER__
|
|
2517
2524
|
|
2518
2525
|
module TrapInterceptor
|
2519
2526
|
def trap sig, *command, &command_proc
|
2520
|
-
|
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
|
2521
2538
|
when :INT, :SIGINT
|
2522
2539
|
if defined?(SESSION) && SESSION.active? && SESSION.intercept_trap_sigint?
|
2523
2540
|
return SESSION.save_int_trap(command.empty? ? command_proc : command.first)
|
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 = {}
|
@@ -1300,10 +1310,14 @@ module DEBUGGER__
|
|
1300
1310
|
frame._callee = b.eval('__callee__')
|
1301
1311
|
end
|
1302
1312
|
}
|
1303
|
-
|
1313
|
+
append(frames)
|
1304
1314
|
}
|
1305
1315
|
end
|
1306
1316
|
|
1317
|
+
def append frames
|
1318
|
+
@log << frames
|
1319
|
+
end
|
1320
|
+
|
1307
1321
|
def enable
|
1308
1322
|
unless @tp_recorder.enabled?
|
1309
1323
|
@log.clear
|
data/lib/debug/version.rb
CHANGED
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: 2023-
|
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
|