debug 1.0.0.beta6 → 1.0.0.beta7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +82 -16
- data/TODO.md +0 -6
- data/lib/debug/breakpoint.rb +43 -43
- data/lib/debug/client.rb +1 -0
- data/lib/debug/color.rb +8 -4
- data/lib/debug/config.rb +75 -32
- data/lib/debug/console.rb +6 -2
- data/lib/debug/session.rb +178 -40
- data/lib/debug/thread_client.rb +61 -24
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +30 -12
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d545d212530685e0eaf7163bc0b2517befd0edfdc1b083c64ecab6bfcb6958b8
|
4
|
+
data.tar.gz: 6662febf1dccfbc0e7e4ec785578fb5eac2a076fa488a4a3a814582f80fa940f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3173551c5ada6fb2f7f71656a5762b6a6a6cc541d80d371532abfe1e03188f81ffb397df1a2c8d743c34983e27c5abe6e33ae8d8188502960501801af3aa9ea3
|
7
|
+
data.tar.gz: 59c84ef76b01d8630b764784d68edb7b1e25e2c336cab56a74e23add5f606f14c3dfe2d6cdd9fe3779e328ca8873317d5d7b56a8e5a7951ecc3a081c20c309d8
|
data/README.md
CHANGED
@@ -83,6 +83,7 @@ require 'debug/run' # start the debug console
|
|
83
83
|
# ... rest of program ...
|
84
84
|
```
|
85
85
|
|
86
|
+
|
86
87
|
```
|
87
88
|
$ ruby target.rb
|
88
89
|
```
|
@@ -90,6 +91,24 @@ $ ruby target.rb
|
|
90
91
|
When you run the program with the debug console, you will see the debug console prompt `(rdbg)`.
|
91
92
|
The debuggee program (`target.rb`) is suspended at the beginning of `target.rb`.
|
92
93
|
|
94
|
+
|
95
|
+
Alternatively, start the debugger at a specific location in your program using `binding.break` (`binding.b` for short).
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
# target.rb
|
99
|
+
require 'debug' # start the debugger
|
100
|
+
|
101
|
+
# ... program ...
|
102
|
+
|
103
|
+
binding.break # setup a breakpoint at this line
|
104
|
+
|
105
|
+
# ... rest of program ...
|
106
|
+
```
|
107
|
+
|
108
|
+
```
|
109
|
+
$ ruby target.rb
|
110
|
+
```
|
111
|
+
|
93
112
|
You can type any debugger's command described bellow. "c" or "continue" resume the debuggee program.
|
94
113
|
You can suspend the debuggee program and show the debug console with `Ctrl-C`.
|
95
114
|
|
@@ -310,20 +329,41 @@ If there are `~/.rdbgrc`, the file is loaded as initial scripts which contains d
|
|
310
329
|
|
311
330
|
If there are `~/.rdbgrc.rb` is available, it is loaded as a ruby script at same timing.
|
312
331
|
|
313
|
-
###
|
332
|
+
### Configurations
|
314
333
|
|
315
|
-
You can
|
334
|
+
You can configure debugger's setting with environment variables and `config` command.
|
335
|
+
You can write any configuration into `~/.rdbgrc` like:
|
336
|
+
|
337
|
+
```
|
338
|
+
config set log_level INFO
|
339
|
+
config set no_color true
|
340
|
+
```
|
316
341
|
|
317
|
-
|
318
|
-
*
|
319
|
-
* `
|
320
|
-
* `RUBY_DEBUG_SHOW_SRC_LINES
|
321
|
-
* `RUBY_DEBUG_SHOW_FRAMES
|
322
|
-
*
|
323
|
-
* `
|
324
|
-
* `
|
325
|
-
* `
|
326
|
-
* `
|
342
|
+
|
343
|
+
* UI
|
344
|
+
* `RUBY_DEBUG_LOG_LEVEL` (`log_level`): Log level same as Logger (default: WARN)
|
345
|
+
* `RUBY_DEBUG_SHOW_SRC_LINES` (`show_src_lines`): Show n lines source code on breakpoint (default: 10 lines)
|
346
|
+
* `RUBY_DEBUG_SHOW_FRAMES` (`show_frames`): Show n frames on breakpoint (default: 2 frames)
|
347
|
+
* `RUBY_DEBUG_SHOW_INFO_LINES` (`show_info_lines`): Show n lines on info command (default: 10 lines, 0 for unlimited)
|
348
|
+
* `RUBY_DEBUG_USE_SHORT_PATH` (`use_short_path`): Show shoten PATH (like $(Gem)/foo.rb)
|
349
|
+
* `RUBY_DEBUG_SKIP_NOSRC` (`skip_nosrc`): Skip on no source code lines (default: false)
|
350
|
+
* `RUBY_DEBUG_SKIP_PATH` (`skip_path`): Skip showing frames for given paths (default: [])
|
351
|
+
* `RUBY_DEBUG_NO_COLOR` (`no_color`): Do not use colorize (default: false)
|
352
|
+
* `RUBY_DEBUG_NO_SIGINT_HOOK` (`no_sigint_hook`): Do not suspend on SIGINT (default: false)
|
353
|
+
|
354
|
+
* BOOT
|
355
|
+
* `RUBY_DEBUG_NONSTOP` (`nonstop`): Nonstop mode
|
356
|
+
* `RUBY_DEBUG_INIT_SCRIPT` (`init_script`): debug command script path loaded at first stop
|
357
|
+
* `RUBY_DEBUG_COMMANDS` (`commands`): debug commands invoked at first stop. commands should be separated by ';;'
|
358
|
+
* `RUBY_DEBUG_NO_RC` (`no_rc`): ignore loading ~/.rdbgrc(.rb)
|
359
|
+
* `RUBY_DEBUG_HISTORY` (`history`): save and load history file (default: ~/.rdbg_history)
|
360
|
+
|
361
|
+
* REMOTE
|
362
|
+
* `RUBY_DEBUG_PORT` (`port`): TCP/IP remote debugging: port
|
363
|
+
* `RUBY_DEBUG_HOST` (`host`): TCP/IP remote debugging: host (localhost if not given)
|
364
|
+
* `RUBY_DEBUG_SOCK_PATH` (`sock_path`): UNIX Domain Socket remote debugging: socket path
|
365
|
+
* `RUBY_DEBUG_SOCK_DIR` (`sock_dir`): UNIX Domain Socket remote debugging: socket directory
|
366
|
+
* `RUBY_DEBUG_COOKIE` (`cookie`): Cookie for negotiation
|
327
367
|
|
328
368
|
## Debug command on the debug console
|
329
369
|
|
@@ -366,10 +406,14 @@ The `<...>` notation means the argument.
|
|
366
406
|
* Set breakpoint on the method `<class>#<name>`.
|
367
407
|
* `b[reak] <expr>.<name>`
|
368
408
|
* Set breakpoint on the method `<expr>.<name>`.
|
369
|
-
* `b[reak] ... if <expr>`
|
409
|
+
* `b[reak] ... if: <expr>`
|
370
410
|
* break if `<expr>` is true at specified location.
|
371
|
-
* `b[reak]
|
372
|
-
* break
|
411
|
+
* `b[reak] ... pre: <command>`
|
412
|
+
* break and run `<command>` before stopping.
|
413
|
+
* `b[reak] ... do: <command>`
|
414
|
+
* break and run `<command>`, and continue.
|
415
|
+
* `b[reak] if: <expr>`
|
416
|
+
* break if: `<expr>` is true at any lines.
|
373
417
|
* Note that this feature is super slow.
|
374
418
|
* `catch <Error>`
|
375
419
|
* Set breakpoint on raising `<Error>`.
|
@@ -385,6 +429,12 @@ The `<...>` notation means the argument.
|
|
385
429
|
|
386
430
|
* `bt` or `backtrace`
|
387
431
|
* Show backtrace (frame) information.
|
432
|
+
* `bt <num>` or `backtrace <num>`
|
433
|
+
* Only shows first `<num>` frames.
|
434
|
+
* `bt /regexp/` or `backtrace /regexp/`
|
435
|
+
* Only shows frames with method name or location info that matches `/regexp/`.
|
436
|
+
* `bt <num> /regexp/` or `backtrace <num> /regexp/`
|
437
|
+
* Only shows first `<num>` frames with method name or location info that matches `/regexp/`.
|
388
438
|
* `l[ist]`
|
389
439
|
* Show current frame's source code.
|
390
440
|
* Next `list` command shows the successor lines.
|
@@ -442,6 +492,19 @@ The `<...>` notation means the argument.
|
|
442
492
|
* `th[read] <thnum>`
|
443
493
|
* Switch thread specified by `<thnum>`.
|
444
494
|
|
495
|
+
### Configuration
|
496
|
+
|
497
|
+
* `config`
|
498
|
+
* Show all configuration with description.
|
499
|
+
* `config <name>`
|
500
|
+
* Show current configuration of <name>.
|
501
|
+
* `config set <name> <val>` or `config <name> = <val>`
|
502
|
+
* Set <name> to <val>.
|
503
|
+
* `config append <name> <val>` or `config <name> << <val>`
|
504
|
+
* Append `<val>` to `<name>` if it is an array.
|
505
|
+
* `config unset <name>`
|
506
|
+
* Set <name> to default.
|
507
|
+
|
445
508
|
### Help
|
446
509
|
|
447
510
|
* `h[elp]`
|
@@ -457,7 +520,7 @@ exe/rdbg [options] -- [debuggee options]
|
|
457
520
|
|
458
521
|
Debug console mode:
|
459
522
|
-n, --nonstop Do not stop at the beginning of the script.
|
460
|
-
-e
|
523
|
+
-e DEBUG_COMMAND Execute debug command at the beginning of the script.
|
461
524
|
-x, --init-script=FILE Execute debug command in the FILE.
|
462
525
|
--no-rc Ignore ~/.rdbgrc
|
463
526
|
--no-color Disable colorize
|
@@ -477,6 +540,9 @@ Debug console mode:
|
|
477
540
|
|
478
541
|
'rdbg target.rb foo bar' starts like 'ruby target.rb foo bar'.
|
479
542
|
'rdbg -- -r foo -e bar' starts like 'ruby -r foo -e bar'.
|
543
|
+
'rdbg -c rake test' starts like 'rake test'.
|
544
|
+
'rdbg -c -- rake test -t' starts like 'rake test -t'.
|
545
|
+
'rdbg -c bundle exec rake test' starts like 'bundle exec rake test'.
|
480
546
|
'rdbg -O target.rb foo bar' starts and accepts attaching with UNIX domain socket.
|
481
547
|
'rdbg -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234.
|
482
548
|
'rdbg -O --port 1234 -- -r foo -e bar' starts accepts attaching with TCP/IP localhost:1234.
|
data/TODO.md
CHANGED
@@ -2,14 +2,11 @@
|
|
2
2
|
|
3
3
|
## Basic functionality
|
4
4
|
|
5
|
-
* VScode DAP support
|
6
5
|
* Support Ractors
|
7
6
|
* Signal (SIGINT) support
|
8
|
-
* Remote connection with openssl
|
9
7
|
|
10
8
|
## UI
|
11
9
|
|
12
|
-
* Coloring
|
13
10
|
* Interactive breakpoint setting
|
14
11
|
* irb integration
|
15
12
|
* Web browser integrated UI
|
@@ -28,6 +25,3 @@
|
|
28
25
|
|
29
26
|
## Tests
|
30
27
|
|
31
|
-
* Test framework
|
32
|
-
* Tests for commands
|
33
|
-
* Tests for remote debugging
|
data/lib/debug/breakpoint.rb
CHANGED
@@ -49,15 +49,22 @@ module DEBUGGER__
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def suspend
|
52
|
+
if @command
|
53
|
+
provider, pre_cmds, do_cmds = @command
|
54
|
+
nonstop = true if do_cmds
|
55
|
+
cmds = [*pre_cmds&.split(';;'), *do_cmds&.split(';;')]
|
56
|
+
SESSION.add_preset_commands provider, cmds, kick: false, continue: nonstop
|
57
|
+
end
|
58
|
+
|
52
59
|
ThreadClient.current.on_breakpoint @tp, self
|
53
60
|
end
|
54
61
|
|
55
62
|
def to_s
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
63
|
+
s = ''.dup
|
64
|
+
s << " if: #{@cond}" if defined?(@cond) && @cond
|
65
|
+
s << " pre: #{@command[1]}" if defined?(@command) && @command && @command[1]
|
66
|
+
s << " do: #{@command[2]}" if defined?(@command) && @command && @command[2]
|
67
|
+
s
|
61
68
|
end
|
62
69
|
|
63
70
|
def description
|
@@ -68,27 +75,24 @@ module DEBUGGER__
|
|
68
75
|
false
|
69
76
|
end
|
70
77
|
|
71
|
-
|
72
|
-
include Color
|
78
|
+
include Color
|
73
79
|
|
74
|
-
|
75
|
-
|
76
|
-
end
|
80
|
+
def generate_label(name)
|
81
|
+
colorize(" BP - #{name} ", [:YELLOW, :BOLD, :REVERSE])
|
77
82
|
end
|
78
83
|
end
|
79
84
|
|
80
85
|
class LineBreakpoint < Breakpoint
|
81
|
-
LABEL = generate_label("Line")
|
82
|
-
PENDING_LABEL = generate_label("Line (pending)")
|
83
|
-
|
84
86
|
attr_reader :path, :line, :iseq
|
85
87
|
|
86
|
-
def initialize path, line, cond: nil, oneshot: false, hook_call: true
|
88
|
+
def initialize path, line, cond: nil, oneshot: false, hook_call: true, command: nil
|
87
89
|
@path = path
|
88
90
|
@line = line
|
89
91
|
@cond = cond
|
90
92
|
@oneshot = oneshot
|
91
93
|
@hook_call = hook_call
|
94
|
+
@command = command
|
95
|
+
@pending = false
|
92
96
|
|
93
97
|
@iseq = nil
|
94
98
|
@type = nil
|
@@ -96,23 +100,21 @@ module DEBUGGER__
|
|
96
100
|
@key = [@path, @line].freeze
|
97
101
|
|
98
102
|
super()
|
103
|
+
|
99
104
|
try_activate
|
105
|
+
@pending = !@iseq
|
100
106
|
end
|
101
107
|
|
102
108
|
def setup
|
103
109
|
return unless @type
|
104
110
|
|
105
|
-
|
106
|
-
|
107
|
-
delete if @oneshot
|
108
|
-
suspend
|
109
|
-
end
|
110
|
-
else
|
111
|
-
@tp = TracePoint.new(@type) do |tp|
|
111
|
+
@tp = TracePoint.new(@type) do |tp|
|
112
|
+
if @cond
|
112
113
|
next unless safe_eval tp.binding, @cond
|
113
|
-
delete if @oneshot
|
114
|
-
suspend
|
115
114
|
end
|
115
|
+
delete if @oneshot
|
116
|
+
|
117
|
+
suspend
|
116
118
|
end
|
117
119
|
end
|
118
120
|
|
@@ -138,9 +140,12 @@ module DEBUGGER__
|
|
138
140
|
|
139
141
|
@key = [@path, @line].freeze
|
140
142
|
SESSION.rehash_bps
|
141
|
-
|
142
143
|
setup
|
143
144
|
enable
|
145
|
+
|
146
|
+
if @pending && !@oneshot
|
147
|
+
DEBUGGER__.warn "#{self} is activated."
|
148
|
+
end
|
144
149
|
end
|
145
150
|
|
146
151
|
def activate_exact iseq, events, line
|
@@ -162,7 +167,6 @@ module DEBUGGER__
|
|
162
167
|
end
|
163
168
|
|
164
169
|
def duplicable?
|
165
|
-
# only binding.bp or DEBUGGER__.console are duplicable
|
166
170
|
@oneshot
|
167
171
|
end
|
168
172
|
|
@@ -214,9 +218,9 @@ module DEBUGGER__
|
|
214
218
|
oneshot = @oneshot ? " (oneshot)" : ""
|
215
219
|
|
216
220
|
if @iseq
|
217
|
-
"#{
|
221
|
+
"#{generate_label("Line")} #{@path}:#{@line} (#{@type})#{oneshot}" + super
|
218
222
|
else
|
219
|
-
"#{
|
223
|
+
"#{generate_label("Line (pending)")} #{@path}:#{@line}#{oneshot}" + super
|
220
224
|
end
|
221
225
|
end
|
222
226
|
|
@@ -226,7 +230,6 @@ module DEBUGGER__
|
|
226
230
|
end
|
227
231
|
|
228
232
|
class CatchBreakpoint < Breakpoint
|
229
|
-
LABEL = generate_label("Catch")
|
230
233
|
attr_reader :last_exc
|
231
234
|
|
232
235
|
def initialize pat
|
@@ -240,7 +243,9 @@ module DEBUGGER__
|
|
240
243
|
def setup
|
241
244
|
@tp = TracePoint.new(:raise){|tp|
|
242
245
|
exc = tp.raised_exception
|
246
|
+
next if SystemExit === exc
|
243
247
|
should_suspend = false
|
248
|
+
|
244
249
|
exc.class.ancestors.each{|cls|
|
245
250
|
if @pat === cls.name
|
246
251
|
should_suspend = true
|
@@ -253,7 +258,7 @@ module DEBUGGER__
|
|
253
258
|
end
|
254
259
|
|
255
260
|
def to_s
|
256
|
-
"#{
|
261
|
+
"#{generate_label("Catch")} #{@pat.inspect}"
|
257
262
|
end
|
258
263
|
|
259
264
|
def description
|
@@ -262,8 +267,6 @@ module DEBUGGER__
|
|
262
267
|
end
|
263
268
|
|
264
269
|
class CheckBreakpoint < Breakpoint
|
265
|
-
LABEL = generate_label("Check")
|
266
|
-
|
267
270
|
def initialize expr
|
268
271
|
@expr = expr.freeze
|
269
272
|
@key = [:check, @expr].freeze
|
@@ -285,13 +288,11 @@ module DEBUGGER__
|
|
285
288
|
end
|
286
289
|
|
287
290
|
def to_s
|
288
|
-
"#{
|
291
|
+
"#{generate_label("Check")} #{@expr}"
|
289
292
|
end
|
290
293
|
end
|
291
294
|
|
292
295
|
class WatchIVarBreakpoint < Breakpoint
|
293
|
-
LABEL = generate_label("Watch")
|
294
|
-
|
295
296
|
def initialize ivar, object, current
|
296
297
|
@ivar = ivar.to_sym
|
297
298
|
@object = object
|
@@ -332,17 +333,14 @@ module DEBUGGER__
|
|
332
333
|
else
|
333
334
|
"#{@current}"
|
334
335
|
end
|
335
|
-
"#{
|
336
|
+
"#{generate_label("Watch")} #{@object} #{@ivar} = #{value_str}"
|
336
337
|
end
|
337
338
|
end
|
338
339
|
|
339
340
|
class MethodBreakpoint < Breakpoint
|
340
|
-
LABEL = generate_label("Method")
|
341
|
-
PENDING_LABEL = generate_label("Method (pending)")
|
342
|
-
|
343
341
|
attr_reader :sig_method_name, :method
|
344
342
|
|
345
|
-
def initialize b, klass_name, op, method_name, cond
|
343
|
+
def initialize b, klass_name, op, method_name, cond, command: nil
|
346
344
|
@sig_klass_name = klass_name
|
347
345
|
@sig_op = op
|
348
346
|
@sig_method_name = method_name
|
@@ -351,6 +349,7 @@ module DEBUGGER__
|
|
351
349
|
@klass = nil
|
352
350
|
@method = nil
|
353
351
|
@cond = cond
|
352
|
+
@command = command
|
354
353
|
@key = "#{klass_name}#{op}#{method_name}".freeze
|
355
354
|
|
356
355
|
super(false)
|
@@ -391,13 +390,14 @@ module DEBUGGER__
|
|
391
390
|
try_enable
|
392
391
|
end
|
393
392
|
|
394
|
-
def try_enable
|
393
|
+
def try_enable added: false
|
395
394
|
eval_class_name
|
396
395
|
search_method
|
397
396
|
|
398
397
|
begin
|
399
398
|
retried = false
|
400
399
|
@tp.enable(target: @method)
|
400
|
+
DEBUGGER__.warn "#{self} is activated." if added
|
401
401
|
|
402
402
|
rescue ArgumentError
|
403
403
|
raise if retried
|
@@ -418,7 +418,7 @@ module DEBUGGER__
|
|
418
418
|
retry
|
419
419
|
end
|
420
420
|
rescue Exception
|
421
|
-
raise unless
|
421
|
+
raise unless added
|
422
422
|
end
|
423
423
|
|
424
424
|
def sig
|
@@ -427,9 +427,9 @@ module DEBUGGER__
|
|
427
427
|
|
428
428
|
def to_s
|
429
429
|
if @method
|
430
|
-
"#{
|
430
|
+
"#{generate_label("Method")} #{sig} at #{@method.source_location.join(':')}"
|
431
431
|
else
|
432
|
-
"#{
|
432
|
+
"#{generate_label("Method (pending)")} #{sig}"
|
433
433
|
end + super
|
434
434
|
end
|
435
435
|
end
|
data/lib/debug/client.rb
CHANGED
data/lib/debug/color.rb
CHANGED
@@ -24,8 +24,12 @@ module DEBUGGER__
|
|
24
24
|
end
|
25
25
|
|
26
26
|
if defined? IRB::ColorPrinter.pp
|
27
|
-
def color_pp obj
|
28
|
-
|
27
|
+
def color_pp obj, width = SESSION.width
|
28
|
+
if !CONFIG[:no_color]
|
29
|
+
IRB::ColorPrinter.pp(obj, "".dup, width)
|
30
|
+
else
|
31
|
+
obj.pretty_inspect
|
32
|
+
end
|
29
33
|
end
|
30
34
|
else
|
31
35
|
def color_pp obj
|
@@ -33,8 +37,8 @@ module DEBUGGER__
|
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
36
|
-
def colored_inspect obj
|
37
|
-
if !
|
40
|
+
def colored_inspect obj, no_color: false
|
41
|
+
if !no_color
|
38
42
|
color_pp obj
|
39
43
|
else
|
40
44
|
obj.pretty_inspect
|
data/lib/debug/config.rb
CHANGED
@@ -30,52 +30,80 @@ module DEBUGGER__
|
|
30
30
|
create_unix_domain_socket_name_prefix(base_dir) + "-#{Process.pid}"
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
# boot setting
|
35
|
-
nonstop: 'RUBY_DEBUG_NONSTOP', # Nonstop mode ('1' is nonstop)
|
36
|
-
init_script: 'RUBY_DEBUG_INIT_SCRIPT', # debug command script path loaded at first stop
|
37
|
-
commands: 'RUBY_DEBUG_COMMANDS', # debug commands invoked at first stop. commands should be separated by ';;'
|
38
|
-
no_rc: 'RUBY_DEBUG_NO_RC', # ignore loading ~/.rdbgrc(.rb)
|
39
|
-
|
33
|
+
CONFIG_SET = {
|
40
34
|
# UI setting
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
35
|
+
log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger (default: WARN)", :loglevel],
|
36
|
+
show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint (default: 10 lines)", :int],
|
37
|
+
show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint (default: 2 frames)", :int],
|
38
|
+
show_info_lines:['RUBY_DEBUG_SHOW_INFO_LINES',"UI: Show n lines on info command (default: 10 lines, 0 for unlimited)", :int],
|
39
|
+
use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shoten PATH (like $(Gem)/foo.rb)", :bool],
|
40
|
+
skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "UI: Skip on no source code lines (default: false)", :bool],
|
41
|
+
skip_path: ['RUBY_DEBUG_SKIP_PATH', "UI: Skip showing frames for given paths (default: [])", :path],
|
42
|
+
no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize (default: false)", :bool],
|
43
|
+
no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT (default: false)", :bool],
|
44
|
+
|
45
|
+
# boot setting
|
46
|
+
nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool],
|
47
|
+
init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"],
|
48
|
+
commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. commands should be separated by ';;'"],
|
49
|
+
no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool],
|
50
|
+
history: ['RUBY_DEBUG_HISTORY', "BOOT: save and load history file (default: ~/.rdbg_history)"],
|
48
51
|
|
49
52
|
# remote setting
|
50
|
-
port:
|
51
|
-
host:
|
52
|
-
sock_path:
|
53
|
-
sock_dir:
|
54
|
-
cookie:
|
53
|
+
port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"],
|
54
|
+
host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host (localhost if not given)"],
|
55
|
+
sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"],
|
56
|
+
sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"],
|
57
|
+
cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"],
|
55
58
|
}.freeze
|
56
59
|
|
60
|
+
CONFIG_MAP = CONFIG_SET.map{|k, (ev, desc)| [k, ev]}.to_h.freeze
|
61
|
+
|
57
62
|
def self.config_to_env_hash config
|
58
63
|
CONFIG_MAP.each_with_object({}){|(key, evname), env|
|
59
64
|
env[evname] = config[key].to_s if config[key]
|
60
65
|
}
|
61
66
|
end
|
62
67
|
|
68
|
+
def self.parse_config_value name, valstr
|
69
|
+
return valstr unless valstr.kind_of? String
|
70
|
+
|
71
|
+
case CONFIG_SET[name][2]
|
72
|
+
when :bool
|
73
|
+
case valstr
|
74
|
+
when '1', 'true', 'TRUE', 'T'
|
75
|
+
true
|
76
|
+
else
|
77
|
+
false
|
78
|
+
end
|
79
|
+
when :int
|
80
|
+
valstr.to_i
|
81
|
+
when :loglevel
|
82
|
+
if DEBUGGER__::LOG_LEVELS[s = valstr.to_sym]
|
83
|
+
s
|
84
|
+
else
|
85
|
+
raise "Unknown loglevel: #{valstr}"
|
86
|
+
end
|
87
|
+
when :path # array of String
|
88
|
+
valstr.split(/:/).map{|e|
|
89
|
+
if /\A\/(.+)\/\z/ =~ e
|
90
|
+
Regexp.compile $1
|
91
|
+
else
|
92
|
+
e
|
93
|
+
end
|
94
|
+
}
|
95
|
+
else
|
96
|
+
valstr
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
63
100
|
def self.parse_argv argv
|
64
101
|
config = {
|
65
102
|
mode: :start,
|
66
103
|
}
|
67
104
|
CONFIG_MAP.each{|key, evname|
|
68
105
|
if val = ENV[evname]
|
69
|
-
|
70
|
-
case val
|
71
|
-
when '1', 'true', 'TRUE', 'T'
|
72
|
-
config[key] = true
|
73
|
-
else
|
74
|
-
config[key] = false
|
75
|
-
end
|
76
|
-
else
|
77
|
-
config[key] = val
|
78
|
-
end
|
106
|
+
config[key] = parse_config_value(key, val)
|
79
107
|
end
|
80
108
|
}
|
81
109
|
return config if !argv || argv.empty?
|
@@ -93,7 +121,7 @@ module DEBUGGER__
|
|
93
121
|
config[:nonstop] = '1'
|
94
122
|
end
|
95
123
|
|
96
|
-
o.on('-e
|
124
|
+
o.on('-e DEBUG_COMMAND', 'Execute debug command at the beginning of the script.') do |cmd|
|
97
125
|
config[:commands] ||= ''
|
98
126
|
config[:commands] += cmd + ';;'
|
99
127
|
end
|
@@ -141,6 +169,9 @@ module DEBUGGER__
|
|
141
169
|
o.separator ''
|
142
170
|
o.separator " '#{rdbg} target.rb foo bar' starts like 'ruby target.rb foo bar'."
|
143
171
|
o.separator " '#{rdbg} -- -r foo -e bar' starts like 'ruby -r foo -e bar'."
|
172
|
+
o.separator " '#{rdbg} -c rake test' starts like 'rake test'."
|
173
|
+
o.separator " '#{rdbg} -c -- rake test -t' starts like 'rake test -t'."
|
174
|
+
o.separator " '#{rdbg} -c bundle exec rake test' starts like 'bundle exec rake test'."
|
144
175
|
o.separator " '#{rdbg} -O target.rb foo bar' starts and accepts attaching with UNIX domain socket."
|
145
176
|
o.separator " '#{rdbg} -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234."
|
146
177
|
o.separator " '#{rdbg} -O --port 1234 -- -r foo -e bar' starts accepts attaching with TCP/IP localhost:1234."
|
@@ -191,10 +222,22 @@ module DEBUGGER__
|
|
191
222
|
def self.set_config kw
|
192
223
|
kw.each{|k, v|
|
193
224
|
if CONFIG_MAP[k]
|
194
|
-
CONFIG[k] = v # TODO: ractor support
|
225
|
+
CONFIG[k] = parse_config_value(k, v) # TODO: ractor support
|
195
226
|
else
|
196
|
-
raise "
|
227
|
+
raise "Unknown configuration: #{k}"
|
197
228
|
end
|
198
229
|
}
|
199
230
|
end
|
231
|
+
|
232
|
+
def self.append_config key, val
|
233
|
+
if CONFIG_SET[key]
|
234
|
+
if CONFIG_SET[key][2] == :path
|
235
|
+
CONFIG[key] = [*CONFIG[key], *parse_config_value(key, val)];
|
236
|
+
else
|
237
|
+
raise "not an Array type: #{key}"
|
238
|
+
end
|
239
|
+
else
|
240
|
+
raise "Unknown configuration: #{key}"
|
241
|
+
end
|
242
|
+
end
|
200
243
|
end
|
data/lib/debug/console.rb
CHANGED
@@ -26,7 +26,11 @@ module DEBUGGER__
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def width
|
29
|
-
IO.console_size[1]
|
29
|
+
if (w = IO.console_size[1]) == 0 # for tests PTY
|
30
|
+
80
|
31
|
+
else
|
32
|
+
w
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
32
36
|
def quit n
|
@@ -36,7 +40,7 @@ module DEBUGGER__
|
|
36
40
|
def ask prompt
|
37
41
|
setup_interrupt do
|
38
42
|
print prompt
|
39
|
-
(gets || '').strip
|
43
|
+
($stdin.gets || '').strip
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
data/lib/debug/session.rb
CHANGED
@@ -101,6 +101,10 @@ module DEBUGGER__
|
|
101
101
|
@tp_thread_begin.enable
|
102
102
|
end
|
103
103
|
|
104
|
+
def active?
|
105
|
+
@ui ? true : false
|
106
|
+
end
|
107
|
+
|
104
108
|
def reset_ui ui
|
105
109
|
@ui.close
|
106
110
|
@ui = ui
|
@@ -172,8 +176,11 @@ module DEBUGGER__
|
|
172
176
|
end
|
173
177
|
end
|
174
178
|
ensure
|
179
|
+
@tp_load_script.disable
|
180
|
+
@tp_thread_begin.disable
|
175
181
|
@bps.each{|k, bp| bp.disable}
|
176
182
|
@th_clients.each{|th, thc| thc.close}
|
183
|
+
@ui = nil
|
177
184
|
end
|
178
185
|
|
179
186
|
def add_preset_commands name, cmds, kick: true, continue: true
|
@@ -337,10 +344,14 @@ module DEBUGGER__
|
|
337
344
|
# * Set breakpoint on the method `<class>#<name>`.
|
338
345
|
# * `b[reak] <expr>.<name>`
|
339
346
|
# * Set breakpoint on the method `<expr>.<name>`.
|
340
|
-
# * `b[reak] ... if <expr>`
|
347
|
+
# * `b[reak] ... if: <expr>`
|
341
348
|
# * break if `<expr>` is true at specified location.
|
342
|
-
# * `b[reak]
|
343
|
-
# * break
|
349
|
+
# * `b[reak] ... pre: <command>`
|
350
|
+
# * break and run `<command>` before stopping.
|
351
|
+
# * `b[reak] ... do: <command>`
|
352
|
+
# * break and run `<command>`, and continue.
|
353
|
+
# * `b[reak] if: <expr>`
|
354
|
+
# * break if: `<expr>` is true at any lines.
|
344
355
|
# * Note that this feature is super slow.
|
345
356
|
when 'b', 'break'
|
346
357
|
if arg == nil
|
@@ -428,8 +439,25 @@ module DEBUGGER__
|
|
428
439
|
|
429
440
|
# * `bt` or `backtrace`
|
430
441
|
# * Show backtrace (frame) information.
|
442
|
+
# * `bt <num>` or `backtrace <num>`
|
443
|
+
# * Only shows first `<num>` frames.
|
444
|
+
# * `bt /regexp/` or `backtrace /regexp/`
|
445
|
+
# * Only shows frames with method name or location info that matches `/regexp/`.
|
446
|
+
# * `bt <num> /regexp/` or `backtrace <num> /regexp/`
|
447
|
+
# * Only shows first `<num>` frames with method name or location info that matches `/regexp/`.
|
431
448
|
when 'bt', 'backtrace'
|
432
|
-
|
449
|
+
case arg
|
450
|
+
when /\A(\d+)\z/
|
451
|
+
@tc << [:show, :backtrace, arg.to_i, nil]
|
452
|
+
when /\A\/(.*)\/\z/
|
453
|
+
pattern = $1
|
454
|
+
@tc << [:show, :backtrace, nil, Regexp.compile(pattern)]
|
455
|
+
when /\A(\d+)\s+\/(.*)\/\z/
|
456
|
+
max, pattern = $1, $2
|
457
|
+
@tc << [:show, :backtrace, max.to_i, Regexp.compile(pattern)]
|
458
|
+
else
|
459
|
+
@tc << [:show, :backtrace, nil, nil]
|
460
|
+
end
|
433
461
|
|
434
462
|
# * `l[ist]`
|
435
463
|
# * Show current frame's source code.
|
@@ -609,6 +637,21 @@ module DEBUGGER__
|
|
609
637
|
end
|
610
638
|
return :retry
|
611
639
|
|
640
|
+
### Configuration
|
641
|
+
# * `config`
|
642
|
+
# * Show all configuration with description.
|
643
|
+
# * `config <name>`
|
644
|
+
# * Show current configuration of <name>.
|
645
|
+
# * `config set <name> <val>` or `config <name> = <val>`
|
646
|
+
# * Set <name> to <val>.
|
647
|
+
# * `config append <name> <val>` or `config <name> << <val>`
|
648
|
+
# * Append `<val>` to `<name>` if it is an array.
|
649
|
+
# * `config unset <name>`
|
650
|
+
# * Set <name> to default.
|
651
|
+
when 'config'
|
652
|
+
config_command arg
|
653
|
+
return :retry
|
654
|
+
|
612
655
|
### Help
|
613
656
|
|
614
657
|
# * `h[elp]`
|
@@ -640,6 +683,73 @@ module DEBUGGER__
|
|
640
683
|
return :retry
|
641
684
|
end
|
642
685
|
|
686
|
+
def config_show key
|
687
|
+
key = key.to_sym
|
688
|
+
if CONFIG_SET[key]
|
689
|
+
v = CONFIG[key]
|
690
|
+
kv = "#{key} = #{v.nil? ? '(default)' : v.inspect}"
|
691
|
+
desc = CONFIG_SET[key][1]
|
692
|
+
line = "%-30s \# %s" % [kv, desc]
|
693
|
+
if line.size > SESSION.width
|
694
|
+
@ui.puts "\# #{desc}\n#{kv}"
|
695
|
+
else
|
696
|
+
@ui.puts line
|
697
|
+
end
|
698
|
+
else
|
699
|
+
@ui.puts "Unknown configuration: #{key}. 'config' shows all configurations."
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
def config_set key, val, append: false
|
704
|
+
if CONFIG_SET[key = key.to_sym]
|
705
|
+
begin
|
706
|
+
if append
|
707
|
+
DEBUGGER__.append_config(key, val)
|
708
|
+
else
|
709
|
+
DEBUGGER__.set_config({key => val})
|
710
|
+
end
|
711
|
+
rescue => e
|
712
|
+
@ui.puts e.message
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
config_show key
|
717
|
+
end
|
718
|
+
|
719
|
+
def config_command arg
|
720
|
+
case arg
|
721
|
+
when nil
|
722
|
+
CONFIG_SET.each do |k, _|
|
723
|
+
config_show k
|
724
|
+
end
|
725
|
+
|
726
|
+
when /\Aunset\s+(.+)\z/
|
727
|
+
if CONFIG_SET[key = $1.to_sym]
|
728
|
+
DEBUGGER__.set_config({key => nil})
|
729
|
+
end
|
730
|
+
config_show key
|
731
|
+
|
732
|
+
when /\A(\w+)\s*=\s*(.+)\z/
|
733
|
+
config_set $1, $2
|
734
|
+
|
735
|
+
when /\A\s*set\s+(\w+)\s+(.+)\z/
|
736
|
+
config_set $1, $2
|
737
|
+
|
738
|
+
when /\A(\w+)\s*<<\s*(.+)\z/
|
739
|
+
config_set $1, $2, append: true
|
740
|
+
|
741
|
+
when /\A\s*append\s+(\w+)\s+(.+)\z/
|
742
|
+
config_set $1, $2
|
743
|
+
|
744
|
+
when /\A(\w+)\z/
|
745
|
+
config_show $1
|
746
|
+
|
747
|
+
else
|
748
|
+
@ui.puts "Can not parse parameters: #{arg}"
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
|
643
753
|
def cancel_auto_continue
|
644
754
|
if @preset_command&.auto_continue
|
645
755
|
@preset_command.auto_continue = false
|
@@ -762,29 +872,37 @@ module DEBUGGER__
|
|
762
872
|
end
|
763
873
|
end
|
764
874
|
|
765
|
-
|
766
|
-
arg.strip!
|
875
|
+
BREAK_KEYWORDS = %w(if: do: pre:).freeze
|
767
876
|
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
877
|
+
def parse_break arg
|
878
|
+
mode = :sig
|
879
|
+
expr = Hash.new{|h, k| h[k] = []}
|
880
|
+
arg.split(' ').each{|w|
|
881
|
+
if BREAK_KEYWORDS.any?{|pat| w == pat}
|
882
|
+
mode = w[0..-2].to_sym
|
883
|
+
else
|
884
|
+
expr[mode] << w
|
885
|
+
end
|
886
|
+
}
|
887
|
+
expr.default_proc = nil
|
888
|
+
expr.transform_values{|v| v.join(' ')}
|
889
|
+
end
|
890
|
+
|
891
|
+
def repl_add_breakpoint arg
|
892
|
+
expr = parse_break arg.strip
|
893
|
+
cond = expr[:if]
|
894
|
+
cmd = ['break', expr[:pre], expr[:do]] if expr[:pre] || expr[:do]
|
777
895
|
|
778
|
-
case sig
|
896
|
+
case expr[:sig]
|
779
897
|
when /\A(\d+)\z/
|
780
|
-
add_line_breakpoint @tc.location.path, $1.to_i, cond:
|
898
|
+
add_line_breakpoint @tc.location.path, $1.to_i, cond: expr[:if], command: cmd
|
781
899
|
when /\A(.+)[:\s+](\d+)\z/
|
782
|
-
add_line_breakpoint $1, $2.to_i, cond:
|
900
|
+
add_line_breakpoint $1, $2.to_i, cond: expr[:if], command: cmd
|
783
901
|
when /\A(.+)([\.\#])(.+)\z/
|
784
|
-
@tc << [:breakpoint, :method, $1, $2, $3,
|
902
|
+
@tc << [:breakpoint, :method, $1, $2, $3, expr[:if], cmd]
|
785
903
|
return :noretry
|
786
904
|
when nil
|
787
|
-
add_check_breakpoint
|
905
|
+
add_check_breakpoint expr[:if]
|
788
906
|
else
|
789
907
|
@ui.puts "Unknown breakpoint format: #{arg}"
|
790
908
|
@ui.puts
|
@@ -908,6 +1026,7 @@ module DEBUGGER__
|
|
908
1026
|
## event
|
909
1027
|
|
910
1028
|
def on_load iseq, src
|
1029
|
+
DEBUGGER__.info "Load #{iseq.absolute_path || iseq.path}"
|
911
1030
|
@sr.add iseq, src
|
912
1031
|
|
913
1032
|
pending_line_breakpoints do |bp|
|
@@ -920,6 +1039,9 @@ module DEBUGGER__
|
|
920
1039
|
# breakpoint management
|
921
1040
|
|
922
1041
|
def add_breakpoint bp
|
1042
|
+
# don't repeat commands that add breakpoints
|
1043
|
+
@repl_prev_line = nil
|
1044
|
+
|
923
1045
|
if @bps.has_key? bp.key
|
924
1046
|
unless bp.duplicable?
|
925
1047
|
@ui.puts "duplicated breakpoint: #{bp}"
|
@@ -928,9 +1050,6 @@ module DEBUGGER__
|
|
928
1050
|
else
|
929
1051
|
@bps[bp.key] = bp
|
930
1052
|
end
|
931
|
-
|
932
|
-
# don't repeat commands that add breakpoints
|
933
|
-
@repl_prev_line = nil
|
934
1053
|
end
|
935
1054
|
|
936
1055
|
def rehash_bps
|
@@ -1001,7 +1120,7 @@ module DEBUGGER__
|
|
1001
1120
|
when MethodBreakpoint
|
1002
1121
|
if bp.method.nil?
|
1003
1122
|
if bp.sig_method_name == mid.to_s
|
1004
|
-
bp.try_enable(
|
1123
|
+
bp.try_enable(added: true)
|
1005
1124
|
end
|
1006
1125
|
end
|
1007
1126
|
|
@@ -1139,20 +1258,18 @@ module DEBUGGER__
|
|
1139
1258
|
# ::DEBUGGER__.add_catch_breakpoint 'RuntimeError'
|
1140
1259
|
|
1141
1260
|
Binding.module_eval do
|
1142
|
-
def
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
# false -> stop
|
1148
|
-
SESSION.add_preset_commands 'binding.bp(command:)', cmds,
|
1149
|
-
kick: false,
|
1150
|
-
continue: nonstop == false ? false : true
|
1261
|
+
def break pre: nil, do: nil
|
1262
|
+
return unless SESSION.active?
|
1263
|
+
|
1264
|
+
if pre || (do_expr = binding.local_variable_get(:do))
|
1265
|
+
cmds = ['binding.break', pre, do_expr]
|
1151
1266
|
end
|
1152
1267
|
|
1153
|
-
::DEBUGGER__.add_line_breakpoint __FILE__, __LINE__ + 1, oneshot: true
|
1268
|
+
::DEBUGGER__.add_line_breakpoint __FILE__, __LINE__ + 1, oneshot: true, command: cmds
|
1154
1269
|
true
|
1155
1270
|
end
|
1271
|
+
alias b break
|
1272
|
+
# alias bp break
|
1156
1273
|
end
|
1157
1274
|
|
1158
1275
|
load_rc
|
@@ -1262,12 +1379,33 @@ module DEBUGGER__
|
|
1262
1379
|
end
|
1263
1380
|
end
|
1264
1381
|
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1382
|
+
LOG_LEVELS = {
|
1383
|
+
UNKNOWN: 0,
|
1384
|
+
FATAL: 1,
|
1385
|
+
ERROR: 2,
|
1386
|
+
WARN: 3,
|
1387
|
+
INFO: 4,
|
1388
|
+
}.freeze
|
1389
|
+
|
1390
|
+
def self.warn msg
|
1391
|
+
log :WARN, msg
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
def self.info msg
|
1395
|
+
log :INFO, msg
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
def self.log level, msg
|
1399
|
+
lv = LOG_LEVELS[level]
|
1400
|
+
config_lv = LOG_LEVELS[CONFIG[:log_level] || :WARN]
|
1401
|
+
|
1402
|
+
if lv <= config_lv
|
1403
|
+
if level == :WARN
|
1404
|
+
# :WARN on debugger is general information
|
1405
|
+
STDERR.puts "DEBUGGER: #{msg}"
|
1406
|
+
else
|
1407
|
+
STDERR.puts "DEBUGGER (#{level}): #{msg}"
|
1408
|
+
end
|
1271
1409
|
end
|
1272
1410
|
end
|
1273
1411
|
end
|
data/lib/debug/thread_client.rb
CHANGED
@@ -69,11 +69,11 @@ module DEBUGGER__
|
|
69
69
|
@q_cmd = q_cmd
|
70
70
|
@step_tp = nil
|
71
71
|
@output = []
|
72
|
-
@src_lines_on_stop = (::DEBUGGER__::CONFIG[:show_src_lines] || 10).to_i
|
73
|
-
@show_frames_on_stop = (::DEBUGGER__::CONFIG[:show_frames] || 2).to_i
|
74
72
|
@frame_formatter = method(:default_frame_formatter)
|
75
73
|
@var_map = {} # { thread_local_var_id => obj } for DAP
|
76
74
|
set_mode nil
|
75
|
+
|
76
|
+
::DEBUGGER__.info("Thread \##{@id} is created.")
|
77
77
|
end
|
78
78
|
|
79
79
|
def name
|
@@ -167,8 +167,8 @@ module DEBUGGER__
|
|
167
167
|
end
|
168
168
|
|
169
169
|
if event != :pause
|
170
|
-
show_src max_lines:
|
171
|
-
show_frames
|
170
|
+
show_src max_lines: (::DEBUGGER__::CONFIG[:show_src_lines] || 10)
|
171
|
+
show_frames ::DEBUGGER__::CONFIG[:show_frames] || 2
|
172
172
|
|
173
173
|
if bp
|
174
174
|
event! :suspend, :breakpoint, bp.key
|
@@ -304,20 +304,39 @@ module DEBUGGER__
|
|
304
304
|
end
|
305
305
|
end
|
306
306
|
|
307
|
+
def puts_variable_info label, obj
|
308
|
+
info = "#{colorize_cyan(label)} => #{colored_inspect(obj)}".lines
|
309
|
+
w = SESSION.width
|
310
|
+
max_inspect_lines = CONFIG[:show_inspect_lines] || 10
|
311
|
+
|
312
|
+
if (max_inspect_lines > 0 && (info.size > max_inspect_lines)) || info.any?{|l| l.size > w}
|
313
|
+
info = "#{colorize_cyan(label)} => #{colored_inspect(obj, no_color: true)}".lines
|
314
|
+
if max_inspect_lines > 0 && info.size > max_inspect_lines
|
315
|
+
info = info.first(max_inspect_lines - 2) +
|
316
|
+
["...(#{info.size - (max_inspect_lines - 1)} lines)\n" + info.last]
|
317
|
+
end
|
318
|
+
info.map!{|l|
|
319
|
+
l.length > w ? l[0..(w-4)] + '...' : l
|
320
|
+
}
|
321
|
+
end
|
322
|
+
|
323
|
+
puts info
|
324
|
+
end
|
325
|
+
|
307
326
|
def show_locals
|
308
327
|
if s = current_frame&.self
|
309
|
-
|
328
|
+
puts_variable_info '%self', s
|
310
329
|
end
|
311
330
|
if current_frame&.has_return_value
|
312
|
-
|
331
|
+
puts_variable_info '%return', current_frame.return_value
|
313
332
|
end
|
314
333
|
if current_frame&.has_raised_exception
|
315
|
-
|
334
|
+
puts_variable_info "%raised", current_frame.raised_exception
|
316
335
|
end
|
317
336
|
if b = current_frame&.binding
|
318
337
|
b.local_variables.each{|loc|
|
319
338
|
value = b.local_variable_get(loc)
|
320
|
-
|
339
|
+
puts_variable_info loc, value
|
321
340
|
}
|
322
341
|
end
|
323
342
|
end
|
@@ -326,11 +345,15 @@ module DEBUGGER__
|
|
326
345
|
if s = current_frame&.self
|
327
346
|
s.instance_variables.each{|iv|
|
328
347
|
value = s.instance_variable_get(iv)
|
329
|
-
|
348
|
+
puts_variable_info iv, value
|
330
349
|
}
|
331
350
|
end
|
332
351
|
end
|
333
352
|
|
353
|
+
def instance_eval_for_cmethod frame_self, src
|
354
|
+
frame_self.instance_eval(src)
|
355
|
+
end
|
356
|
+
|
334
357
|
def frame_eval src, re_raise: false
|
335
358
|
begin
|
336
359
|
@success_last_eval = false
|
@@ -341,7 +364,7 @@ module DEBUGGER__
|
|
341
364
|
b.eval(src, "(rdbg)/#{f}")
|
342
365
|
else
|
343
366
|
frame_self = current_frame.self
|
344
|
-
frame_self
|
367
|
+
instance_eval_for_cmethod(frame_self, src)
|
345
368
|
end
|
346
369
|
@success_last_eval = true
|
347
370
|
result
|
@@ -359,21 +382,35 @@ module DEBUGGER__
|
|
359
382
|
end
|
360
383
|
end
|
361
384
|
|
362
|
-
def frame_str(i)
|
385
|
+
def frame_str(i, frame: @target_frames[i])
|
363
386
|
cur_str = (@current_frame_index == i ? '=>' : ' ')
|
364
387
|
prefix = "#{cur_str}##{i}"
|
365
|
-
frame = @target_frames[i]
|
366
388
|
frame_string = @frame_formatter.call(frame)
|
367
389
|
"#{prefix}\t#{frame_string}"
|
368
390
|
end
|
369
391
|
|
370
|
-
def show_frames max =
|
371
|
-
if
|
372
|
-
|
373
|
-
|
392
|
+
def show_frames max = nil, pattern = nil
|
393
|
+
if @target_frames && (max ||= @target_frames.size) > 0
|
394
|
+
frames = []
|
395
|
+
@target_frames.each_with_index{|f, i|
|
396
|
+
next if pattern && !(f.name.match?(pattern) || f.location_str.match?(pattern))
|
397
|
+
next if CONFIG[:skip_path] && CONFIG[:skip_path].any?{|pat|
|
398
|
+
case pat
|
399
|
+
when String
|
400
|
+
f.location_str.start_with?(pat)
|
401
|
+
when Regexp
|
402
|
+
f.location_str.match?(pat)
|
403
|
+
end
|
404
|
+
}
|
405
|
+
|
406
|
+
frames << [i, f]
|
407
|
+
}
|
408
|
+
|
409
|
+
size = frames.size
|
374
410
|
max.times{|i|
|
375
|
-
break
|
376
|
-
|
411
|
+
break unless frames[i]
|
412
|
+
index, frame = frames[i]
|
413
|
+
puts frame_str(index, frame: frame)
|
377
414
|
}
|
378
415
|
puts " # and #{size - max} frames (use `bt' command for all frames)" if max < size
|
379
416
|
end
|
@@ -404,8 +441,8 @@ module DEBUGGER__
|
|
404
441
|
def make_breakpoint args
|
405
442
|
case args.first
|
406
443
|
when :method
|
407
|
-
klass_name, op, method_name, cond = args[1..]
|
408
|
-
bp = MethodBreakpoint.new(current_frame.binding, klass_name, op, method_name, cond)
|
444
|
+
klass_name, op, method_name, cond, cmd = args[1..]
|
445
|
+
bp = MethodBreakpoint.new(current_frame.binding, klass_name, op, method_name, cond, command: cmd)
|
409
446
|
begin
|
410
447
|
bp.enable
|
411
448
|
rescue Exception => e
|
@@ -493,8 +530,7 @@ module DEBUGGER__
|
|
493
530
|
when :pp
|
494
531
|
result = frame_eval(eval_src)
|
495
532
|
puts "=> "
|
496
|
-
|
497
|
-
puts out
|
533
|
+
puts color_pp(result, SESSION.width)
|
498
534
|
when :call
|
499
535
|
result = frame_eval(eval_src)
|
500
536
|
when :display, :try_display
|
@@ -549,7 +585,8 @@ module DEBUGGER__
|
|
549
585
|
|
550
586
|
case type
|
551
587
|
when :backtrace
|
552
|
-
|
588
|
+
max_lines, pattern = *args
|
589
|
+
show_frames max_lines, pattern
|
553
590
|
|
554
591
|
when :list
|
555
592
|
show_src(update_line: true, **(args.first || {}))
|
@@ -603,7 +640,7 @@ module DEBUGGER__
|
|
603
640
|
rescue SystemExit
|
604
641
|
raise
|
605
642
|
rescue Exception => e
|
606
|
-
pp [__FILE__
|
643
|
+
pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace]
|
607
644
|
raise
|
608
645
|
ensure
|
609
646
|
set_mode nil
|
data/lib/debug/version.rb
CHANGED
data/misc/README.md.erb
CHANGED
@@ -83,6 +83,7 @@ require 'debug/run' # start the debug console
|
|
83
83
|
# ... rest of program ...
|
84
84
|
```
|
85
85
|
|
86
|
+
|
86
87
|
```
|
87
88
|
$ ruby target.rb
|
88
89
|
```
|
@@ -90,6 +91,24 @@ $ ruby target.rb
|
|
90
91
|
When you run the program with the debug console, you will see the debug console prompt `(rdbg)`.
|
91
92
|
The debuggee program (`target.rb`) is suspended at the beginning of `target.rb`.
|
92
93
|
|
94
|
+
|
95
|
+
Alternatively, start the debugger at a specific location in your program using `binding.break` (`binding.b` for short).
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
# target.rb
|
99
|
+
require 'debug' # start the debugger
|
100
|
+
|
101
|
+
# ... program ...
|
102
|
+
|
103
|
+
binding.break # setup a breakpoint at this line
|
104
|
+
|
105
|
+
# ... rest of program ...
|
106
|
+
```
|
107
|
+
|
108
|
+
```
|
109
|
+
$ ruby target.rb
|
110
|
+
```
|
111
|
+
|
93
112
|
You can type any debugger's command described bellow. "c" or "continue" resume the debuggee program.
|
94
113
|
You can suspend the debuggee program and show the debug console with `Ctrl-C`.
|
95
114
|
|
@@ -310,20 +329,19 @@ If there are `~/.rdbgrc`, the file is loaded as initial scripts which contains d
|
|
310
329
|
|
311
330
|
If there are `~/.rdbgrc.rb` is available, it is loaded as a ruby script at same timing.
|
312
331
|
|
313
|
-
###
|
332
|
+
### Configurations
|
314
333
|
|
315
|
-
You can
|
334
|
+
You can configure debugger's setting with environment variables and `config` command.
|
335
|
+
You can write any configuration into `~/.rdbgrc` like:
|
316
336
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
*
|
325
|
-
* `RUBY_DEBUG_SOCK_PATH`: UNIX Domain Socket remote debugging: socket path to open.
|
326
|
-
* `RUBY_DEBUG_SOCK_DIR`: UNIX Domain Socket remote debugging: socket directory to open.
|
337
|
+
```
|
338
|
+
config set log_level INFO
|
339
|
+
config set no_color true
|
340
|
+
```
|
341
|
+
<% cat = nil; DEBUGGER__::CONFIG_SET.each do |key, (env, desc)| %>
|
342
|
+
<% /\A(\w+): (.+)/ =~ desc; if cat != $1; cat = 1 %>
|
343
|
+
* <%= $1 %>
|
344
|
+
<% cat = $1; end %> * `<%= env %>` (`<%= key %>`): <%= $2 %><% end %>
|
327
345
|
|
328
346
|
## Debug command on the debug console
|
329
347
|
|
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.0.0.
|
4
|
+
version: 1.0.0.beta7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Koichi Sasada
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
11
|
+
date: 2021-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: irb
|