debug 1.3.1 → 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 +43 -12
- data/README.md +38 -11
- data/bin/gentest +12 -4
- data/ext/debug/debug.c +5 -2
- data/lib/debug/breakpoint.rb +61 -11
- data/lib/debug/client.rb +57 -16
- data/lib/debug/color.rb +30 -20
- 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 +47 -77
- data/lib/debug/server_cdp.rb +605 -94
- data/lib/debug/server_dap.rb +256 -57
- data/lib/debug/session.rb +146 -54
- 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 +16 -8
- metadata +3 -2
data/lib/debug/console.rb
CHANGED
|
@@ -34,6 +34,12 @@ module DEBUGGER__
|
|
|
34
34
|
load_history_if_not_loaded
|
|
35
35
|
commands = DEBUGGER__.commands
|
|
36
36
|
|
|
37
|
+
prev_completion_proc = Reline.completion_proc
|
|
38
|
+
prev_output_modifier_proc = Reline.output_modifier_proc
|
|
39
|
+
prev_prompt_proc = Reline.prompt_proc
|
|
40
|
+
|
|
41
|
+
Reline.prompt_proc = nil
|
|
42
|
+
|
|
37
43
|
Reline.completion_proc = -> given do
|
|
38
44
|
buff = Reline.line_buffer
|
|
39
45
|
Reline.completion_append_character= ' '
|
|
@@ -72,6 +78,13 @@ module DEBUGGER__
|
|
|
72
78
|
colorize_code(buff.chomp) + colorize(" # ruby", [:DIM])
|
|
73
79
|
end
|
|
74
80
|
end
|
|
81
|
+
|
|
82
|
+
yield
|
|
83
|
+
|
|
84
|
+
ensure
|
|
85
|
+
Reline.completion_proc = prev_completion_proc
|
|
86
|
+
Reline.output_modifier_proc = prev_output_modifier_proc
|
|
87
|
+
Reline.prompt_proc = prev_prompt_proc
|
|
75
88
|
end
|
|
76
89
|
|
|
77
90
|
private def get_command line
|
|
@@ -84,8 +97,9 @@ module DEBUGGER__
|
|
|
84
97
|
end
|
|
85
98
|
|
|
86
99
|
def readline prompt
|
|
87
|
-
readline_setup prompt
|
|
88
|
-
|
|
100
|
+
readline_setup prompt do
|
|
101
|
+
Reline.readmultiline(prompt, true){ true }
|
|
102
|
+
end
|
|
89
103
|
end
|
|
90
104
|
|
|
91
105
|
def history
|
|
@@ -145,7 +159,7 @@ module DEBUGGER__
|
|
|
145
159
|
FH = "# Today's OMIKUJI: "
|
|
146
160
|
|
|
147
161
|
def read_history_file
|
|
148
|
-
if history && File.
|
|
162
|
+
if history && File.exist?(path = history_file)
|
|
149
163
|
f = (['', 'DAI-', 'CHU-', 'SHO-'].map{|e| e+'KICHI'}+['KYO']).sample
|
|
150
164
|
["#{FH}#{f}".dup] + File.readlines(path)
|
|
151
165
|
else
|
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+(.*)$/
|
|
@@ -116,8 +120,10 @@ module DEBUGGER__
|
|
|
116
120
|
|
|
117
121
|
self.extend(UI_CDP)
|
|
118
122
|
@repl = false
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
CONFIG.set_config no_color: true
|
|
124
|
+
|
|
125
|
+
@ws_server = UI_CDP::WebSocketServer.new(@sock)
|
|
126
|
+
@ws_server.handshake
|
|
121
127
|
else
|
|
122
128
|
raise "Greeting message error: #{g}"
|
|
123
129
|
end
|
|
@@ -178,7 +184,7 @@ module DEBUGGER__
|
|
|
178
184
|
|
|
179
185
|
def sigurg_overridden? prev_handler
|
|
180
186
|
case prev_handler
|
|
181
|
-
when "SYSTEM_DEFAULT"
|
|
187
|
+
when "SYSTEM_DEFAULT", "DEFAULT"
|
|
182
188
|
false
|
|
183
189
|
when Proc
|
|
184
190
|
if prev_handler.source_location[0] == __FILE__
|
|
@@ -191,10 +197,19 @@ module DEBUGGER__
|
|
|
191
197
|
end
|
|
192
198
|
end
|
|
193
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
|
+
|
|
194
209
|
def setup_interrupt
|
|
195
|
-
prev_handler = trap(
|
|
210
|
+
prev_handler = trap(TRAP_SIGNAL) do
|
|
196
211
|
# $stderr.puts "trapped SIGINT"
|
|
197
|
-
ThreadClient.current.on_trap
|
|
212
|
+
ThreadClient.current.on_trap TRAP_SIGNAL
|
|
198
213
|
|
|
199
214
|
case prev_handler
|
|
200
215
|
when Proc
|
|
@@ -209,7 +224,7 @@ module DEBUGGER__
|
|
|
209
224
|
end
|
|
210
225
|
yield
|
|
211
226
|
ensure
|
|
212
|
-
trap(
|
|
227
|
+
trap(TRAP_SIGNAL, prev_handler)
|
|
213
228
|
end
|
|
214
229
|
|
|
215
230
|
attr_reader :reader_thread
|
|
@@ -297,7 +312,7 @@ module DEBUGGER__
|
|
|
297
312
|
|
|
298
313
|
def pause
|
|
299
314
|
# $stderr.puts "DEBUG: pause request"
|
|
300
|
-
Process.kill(
|
|
315
|
+
Process.kill(TRAP_SIGNAL, Process.pid)
|
|
301
316
|
end
|
|
302
317
|
|
|
303
318
|
def quit n
|
|
@@ -328,29 +343,37 @@ module DEBUGGER__
|
|
|
328
343
|
super()
|
|
329
344
|
end
|
|
330
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
|
+
|
|
331
359
|
def accept
|
|
332
360
|
retry_cnt = 0
|
|
333
361
|
super # for fork
|
|
334
362
|
|
|
335
363
|
begin
|
|
336
364
|
Socket.tcp_server_sockets @host, @port do |socks|
|
|
337
|
-
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.
|
|
338
366
|
rdbg = File.expand_path('../../exe/rdbg', __dir__)
|
|
339
367
|
|
|
340
|
-
DEBUGGER__.warn "Debugger can attach via TCP/IP (#{addr})"
|
|
368
|
+
DEBUGGER__.warn "Debugger can attach via TCP/IP (#{@addr})"
|
|
341
369
|
DEBUGGER__.info <<~EOS
|
|
342
370
|
With rdbg, use the following command line:
|
|
343
371
|
#
|
|
344
|
-
# #{rdbg} --attach #{addr.split(':').join(' ')}
|
|
372
|
+
# #{rdbg} --attach #{@addr.split(':').join(' ')}
|
|
345
373
|
#
|
|
346
374
|
EOS
|
|
347
375
|
|
|
348
|
-
|
|
349
|
-
With Chrome browser, type the following URL in the address-bar:
|
|
350
|
-
|
|
351
|
-
devtools://devtools/bundled/inspector.html?ws=#{addr}
|
|
352
|
-
|
|
353
|
-
EOS
|
|
376
|
+
chrome_setup if CONFIG[:open_frontend] == 'chrome'
|
|
354
377
|
|
|
355
378
|
Socket.accept_loop(socks) do |sock, client|
|
|
356
379
|
@client_addr = client
|
|
@@ -387,61 +410,8 @@ module DEBUGGER__
|
|
|
387
410
|
end
|
|
388
411
|
|
|
389
412
|
def vscode_setup
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
require 'fileutils'
|
|
393
|
-
|
|
394
|
-
dir = Dir.mktmpdir("ruby-debug-vscode-")
|
|
395
|
-
at_exit{
|
|
396
|
-
FileUtils.rm_rf dir
|
|
397
|
-
}
|
|
398
|
-
Dir.chdir(dir) do
|
|
399
|
-
Dir.mkdir('.vscode')
|
|
400
|
-
open('README.rb', 'w'){|f|
|
|
401
|
-
f.puts <<~MSG
|
|
402
|
-
# Wait for starting the attaching to the Ruby process
|
|
403
|
-
# This file will be removed at the end of the debuggee process.
|
|
404
|
-
#
|
|
405
|
-
# Note that vscode-rdbg extension is needed. Please install if you don't have.
|
|
406
|
-
MSG
|
|
407
|
-
}
|
|
408
|
-
open('.vscode/launch.json', 'w'){|f|
|
|
409
|
-
f.puts JSON.pretty_generate({
|
|
410
|
-
version: '0.2.0',
|
|
411
|
-
configurations: [
|
|
412
|
-
{
|
|
413
|
-
type: "rdbg",
|
|
414
|
-
name: "Attach with rdbg",
|
|
415
|
-
request: "attach",
|
|
416
|
-
rdbgPath: File.expand_path('../../exe/rdbg', __dir__),
|
|
417
|
-
debugPort: @sock_path,
|
|
418
|
-
autoAttach: true,
|
|
419
|
-
}
|
|
420
|
-
]
|
|
421
|
-
})
|
|
422
|
-
}
|
|
423
|
-
end
|
|
424
|
-
|
|
425
|
-
cmds = ['code', "#{dir}/", "#{dir}/README.rb"]
|
|
426
|
-
cmdline = cmds.join(' ')
|
|
427
|
-
ssh_cmdline = "code --remote ssh-remote+[SSH hostname] #{dir}/ #{dir}/README.rb"
|
|
428
|
-
|
|
429
|
-
STDERR.puts "Launching: #{cmdline}"
|
|
430
|
-
env = ENV.delete_if{|k, h| /RUBY/ =~ k}.to_h
|
|
431
|
-
|
|
432
|
-
unless system(env, *cmds)
|
|
433
|
-
DEBUGGER__.warn <<~MESSAGE
|
|
434
|
-
Can not invoke the command.
|
|
435
|
-
Use the command-line on your terminal (with modification if you need).
|
|
436
|
-
|
|
437
|
-
#{cmdline}
|
|
438
|
-
|
|
439
|
-
If your application is running on a SSH remote host, please try:
|
|
440
|
-
|
|
441
|
-
#{ssh_cmdline}
|
|
442
|
-
|
|
443
|
-
MESSAGE
|
|
444
|
-
end
|
|
413
|
+
require_relative 'server_dap'
|
|
414
|
+
UI_DAP.setup @sock_path
|
|
445
415
|
end
|
|
446
416
|
|
|
447
417
|
def accept
|