debug 1.3.4 → 1.4.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/.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
|