debug 1.7.2 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|