debug 1.0.0.beta6 → 1.0.0.beta7
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/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
|