debug 1.3.4 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/pull_request_template.md +9 -0
- data/CONTRIBUTING.md +39 -6
- data/README.md +34 -7
- data/bin/gentest +12 -4
- data/ext/debug/debug.c +4 -1
- data/lib/debug/breakpoint.rb +61 -11
- data/lib/debug/client.rb +57 -16
- data/lib/debug/color.rb +29 -19
- data/lib/debug/config.rb +6 -3
- data/lib/debug/console.rb +17 -3
- data/lib/debug/frame_info.rb +11 -16
- data/lib/debug/prelude.rb +2 -2
- data/lib/debug/server.rb +45 -77
- data/lib/debug/server_cdp.rb +590 -93
- data/lib/debug/server_dap.rb +231 -53
- data/lib/debug/session.rb +114 -52
- data/lib/debug/source_repository.rb +4 -6
- data/lib/debug/thread_client.rb +67 -48
- data/lib/debug/tracer.rb +1 -1
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +12 -4
- metadata +3 -2
data/lib/debug/frame_info.rb
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
|
3
3
|
module DEBUGGER__
|
4
4
|
FrameInfo = Struct.new(:location, :self, :binding, :iseq, :class, :frame_depth,
|
5
|
-
:has_return_value,
|
5
|
+
:has_return_value, :return_value,
|
6
6
|
:has_raised_exception, :raised_exception,
|
7
7
|
:show_line,
|
8
|
-
:_local_variables, :_callee # for recorder
|
8
|
+
:_local_variables, :_callee, # for recorder
|
9
|
+
:dupped_binding,
|
9
10
|
)
|
10
11
|
|
11
12
|
# extend FrameInfo with debug.so
|
@@ -31,7 +32,7 @@ module DEBUGGER__
|
|
31
32
|
use_short_path = CONFIG[:use_short_path]
|
32
33
|
|
33
34
|
case
|
34
|
-
when use_short_path && path.start_with?(dir = CONFIG["rubylibdir"] + '/')
|
35
|
+
when use_short_path && path.start_with?(dir = RbConfig::CONFIG["rubylibdir"] + '/')
|
35
36
|
path.sub(dir, '$(rubylibdir)/')
|
36
37
|
when use_short_path && Gem.path.any? do |gp|
|
37
38
|
path.start_with?(dir = gp + '/gems/')
|
@@ -110,7 +111,7 @@ module DEBUGGER__
|
|
110
111
|
|
111
112
|
def return_str
|
112
113
|
if self.binding && iseq && has_return_value
|
113
|
-
DEBUGGER__.
|
114
|
+
DEBUGGER__.safe_inspect(return_value, short: true)
|
114
115
|
end
|
115
116
|
end
|
116
117
|
|
@@ -118,19 +119,13 @@ module DEBUGGER__
|
|
118
119
|
"#{pretty_path}:#{location.lineno}"
|
119
120
|
end
|
120
121
|
|
121
|
-
private def make_binding
|
122
|
-
__newb__ = self.self.instance_eval('binding')
|
123
|
-
self.local_variables.each{|var, val|
|
124
|
-
__newb__.local_variable_set(var, val)
|
125
|
-
}
|
126
|
-
__newb__
|
127
|
-
end
|
128
|
-
|
129
122
|
def eval_binding
|
130
|
-
if b = self.
|
123
|
+
if b = self.dupped_binding
|
131
124
|
b
|
132
|
-
|
133
|
-
|
125
|
+
else
|
126
|
+
b = TOPLEVEL_BINDING unless b = self.binding
|
127
|
+
b = self.binding || TOPLEVEL_BINDING
|
128
|
+
self.dupped_binding = b.dup
|
134
129
|
end
|
135
130
|
end
|
136
131
|
|
@@ -160,7 +155,7 @@ module DEBUGGER__
|
|
160
155
|
vars = iseq.locals[0...argc]
|
161
156
|
vars.map{|var|
|
162
157
|
begin
|
163
|
-
{ name: var, value: DEBUGGER__.
|
158
|
+
{ name: var, value: DEBUGGER__.safe_inspect(local_variable_get(var), short: true) }
|
164
159
|
rescue NameError, TypeError
|
165
160
|
nil
|
166
161
|
end
|
data/lib/debug/prelude.rb
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
return if defined?(::DEBUGGER__)
|
4
4
|
|
5
|
+
# Put the following line in your login script (e.g. ~/.bash_profile) with modified path:
|
5
6
|
#
|
6
|
-
#
|
7
|
-
# export RUBYOPT="-r .../debug/prelude $(RUBYOPT)"
|
7
|
+
# export RUBYOPT="-r /path/to/debug/prelude $(RUBYOPT)"
|
8
8
|
#
|
9
9
|
module Kernel
|
10
10
|
def debugger(*a, up_level: 0, **kw)
|
data/lib/debug/server.rb
CHANGED
@@ -75,12 +75,7 @@ module DEBUGGER__
|
|
75
75
|
DEBUGGER__.warn "ReaderThreadError: #{e}"
|
76
76
|
pp e.backtrace
|
77
77
|
ensure
|
78
|
-
|
79
|
-
@sock = nil
|
80
|
-
@q_msg.close
|
81
|
-
@q_msg = nil
|
82
|
-
@q_ans.close
|
83
|
-
@q_ans = nil
|
78
|
+
cleanup_reader
|
84
79
|
end # accept
|
85
80
|
|
86
81
|
rescue Terminate
|
@@ -88,6 +83,15 @@ module DEBUGGER__
|
|
88
83
|
end
|
89
84
|
end
|
90
85
|
|
86
|
+
def cleanup_reader
|
87
|
+
DEBUGGER__.warn "Disconnected."
|
88
|
+
@sock = nil
|
89
|
+
@q_msg.close
|
90
|
+
@q_msg = nil
|
91
|
+
@q_ans.close
|
92
|
+
@q_ans = nil
|
93
|
+
end
|
94
|
+
|
91
95
|
def greeting
|
92
96
|
case g = @sock.gets
|
93
97
|
when /^version:\s+(.+)\s+width: (\d+) cookie:\s+(.*)$/
|
@@ -118,8 +122,8 @@ module DEBUGGER__
|
|
118
122
|
@repl = false
|
119
123
|
CONFIG.set_config no_color: true
|
120
124
|
|
121
|
-
@
|
122
|
-
@
|
125
|
+
@ws_server = UI_CDP::WebSocketServer.new(@sock)
|
126
|
+
@ws_server.handshake
|
123
127
|
else
|
124
128
|
raise "Greeting message error: #{g}"
|
125
129
|
end
|
@@ -180,7 +184,7 @@ module DEBUGGER__
|
|
180
184
|
|
181
185
|
def sigurg_overridden? prev_handler
|
182
186
|
case prev_handler
|
183
|
-
when "SYSTEM_DEFAULT"
|
187
|
+
when "SYSTEM_DEFAULT", "DEFAULT"
|
184
188
|
false
|
185
189
|
when Proc
|
186
190
|
if prev_handler.source_location[0] == __FILE__
|
@@ -193,10 +197,19 @@ module DEBUGGER__
|
|
193
197
|
end
|
194
198
|
end
|
195
199
|
|
200
|
+
begin
|
201
|
+
prev = trap(:SIGURG, nil)
|
202
|
+
trap(:SIGURG, prev)
|
203
|
+
TRAP_SIGNAL = :SIGURG
|
204
|
+
rescue ArgumentError
|
205
|
+
# maybe Windows?
|
206
|
+
TRAP_SIGNAL = :SIGINT
|
207
|
+
end
|
208
|
+
|
196
209
|
def setup_interrupt
|
197
|
-
prev_handler = trap(
|
210
|
+
prev_handler = trap(TRAP_SIGNAL) do
|
198
211
|
# $stderr.puts "trapped SIGINT"
|
199
|
-
ThreadClient.current.on_trap
|
212
|
+
ThreadClient.current.on_trap TRAP_SIGNAL
|
200
213
|
|
201
214
|
case prev_handler
|
202
215
|
when Proc
|
@@ -211,7 +224,7 @@ module DEBUGGER__
|
|
211
224
|
end
|
212
225
|
yield
|
213
226
|
ensure
|
214
|
-
trap(
|
227
|
+
trap(TRAP_SIGNAL, prev_handler)
|
215
228
|
end
|
216
229
|
|
217
230
|
attr_reader :reader_thread
|
@@ -299,7 +312,7 @@ module DEBUGGER__
|
|
299
312
|
|
300
313
|
def pause
|
301
314
|
# $stderr.puts "DEBUG: pause request"
|
302
|
-
Process.kill(
|
315
|
+
Process.kill(TRAP_SIGNAL, Process.pid)
|
303
316
|
end
|
304
317
|
|
305
318
|
def quit n
|
@@ -330,29 +343,37 @@ module DEBUGGER__
|
|
330
343
|
super()
|
331
344
|
end
|
332
345
|
|
346
|
+
def chrome_setup
|
347
|
+
require_relative 'server_cdp'
|
348
|
+
|
349
|
+
unless @chrome_pid = UI_CDP.setup_chrome(@addr)
|
350
|
+
DEBUGGER__.warn <<~EOS if CONFIG[:open_frontend] == 'chrome'
|
351
|
+
With Chrome browser, type the following URL in the address-bar:
|
352
|
+
|
353
|
+
devtools://devtools/bundled/inspector.html?ws=#{@addr}
|
354
|
+
|
355
|
+
EOS
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
333
359
|
def accept
|
334
360
|
retry_cnt = 0
|
335
361
|
super # for fork
|
336
362
|
|
337
363
|
begin
|
338
364
|
Socket.tcp_server_sockets @host, @port do |socks|
|
339
|
-
addr = socks[0].local_address.inspect_sockaddr # Change this part if `socks` are multiple.
|
365
|
+
@addr = socks[0].local_address.inspect_sockaddr # Change this part if `socks` are multiple.
|
340
366
|
rdbg = File.expand_path('../../exe/rdbg', __dir__)
|
341
367
|
|
342
|
-
DEBUGGER__.warn "Debugger can attach via TCP/IP (#{addr})"
|
368
|
+
DEBUGGER__.warn "Debugger can attach via TCP/IP (#{@addr})"
|
343
369
|
DEBUGGER__.info <<~EOS
|
344
370
|
With rdbg, use the following command line:
|
345
371
|
#
|
346
|
-
# #{rdbg} --attach #{addr.split(':').join(' ')}
|
372
|
+
# #{rdbg} --attach #{@addr.split(':').join(' ')}
|
347
373
|
#
|
348
374
|
EOS
|
349
375
|
|
350
|
-
|
351
|
-
With Chrome browser, type the following URL in the address-bar:
|
352
|
-
|
353
|
-
devtools://devtools/bundled/inspector.html?ws=#{addr}
|
354
|
-
|
355
|
-
EOS
|
376
|
+
chrome_setup if CONFIG[:open_frontend] == 'chrome'
|
356
377
|
|
357
378
|
Socket.accept_loop(socks) do |sock, client|
|
358
379
|
@client_addr = client
|
@@ -389,61 +410,8 @@ module DEBUGGER__
|
|
389
410
|
end
|
390
411
|
|
391
412
|
def vscode_setup
|
392
|
-
|
393
|
-
|
394
|
-
require 'fileutils'
|
395
|
-
|
396
|
-
dir = Dir.mktmpdir("ruby-debug-vscode-")
|
397
|
-
at_exit{
|
398
|
-
FileUtils.rm_rf dir
|
399
|
-
}
|
400
|
-
Dir.chdir(dir) do
|
401
|
-
Dir.mkdir('.vscode')
|
402
|
-
open('README.rb', 'w'){|f|
|
403
|
-
f.puts <<~MSG
|
404
|
-
# Wait for starting the attaching to the Ruby process
|
405
|
-
# This file will be removed at the end of the debuggee process.
|
406
|
-
#
|
407
|
-
# Note that vscode-rdbg extension is needed. Please install if you don't have.
|
408
|
-
MSG
|
409
|
-
}
|
410
|
-
open('.vscode/launch.json', 'w'){|f|
|
411
|
-
f.puts JSON.pretty_generate({
|
412
|
-
version: '0.2.0',
|
413
|
-
configurations: [
|
414
|
-
{
|
415
|
-
type: "rdbg",
|
416
|
-
name: "Attach with rdbg",
|
417
|
-
request: "attach",
|
418
|
-
rdbgPath: File.expand_path('../../exe/rdbg', __dir__),
|
419
|
-
debugPort: @sock_path,
|
420
|
-
autoAttach: true,
|
421
|
-
}
|
422
|
-
]
|
423
|
-
})
|
424
|
-
}
|
425
|
-
end
|
426
|
-
|
427
|
-
cmds = ['code', "#{dir}/", "#{dir}/README.rb"]
|
428
|
-
cmdline = cmds.join(' ')
|
429
|
-
ssh_cmdline = "code --remote ssh-remote+[SSH hostname] #{dir}/ #{dir}/README.rb"
|
430
|
-
|
431
|
-
STDERR.puts "Launching: #{cmdline}"
|
432
|
-
env = ENV.delete_if{|k, h| /RUBY/ =~ k}.to_h
|
433
|
-
|
434
|
-
unless system(env, *cmds)
|
435
|
-
DEBUGGER__.warn <<~MESSAGE
|
436
|
-
Can not invoke the command.
|
437
|
-
Use the command-line on your terminal (with modification if you need).
|
438
|
-
|
439
|
-
#{cmdline}
|
440
|
-
|
441
|
-
If your application is running on a SSH remote host, please try:
|
442
|
-
|
443
|
-
#{ssh_cmdline}
|
444
|
-
|
445
|
-
MESSAGE
|
446
|
-
end
|
413
|
+
require_relative 'server_dap'
|
414
|
+
UI_DAP.setup @sock_path
|
447
415
|
end
|
448
416
|
|
449
417
|
def accept
|