debug 1.5.0 → 1.6.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/CONTRIBUTING.md +79 -11
- data/README.md +39 -16
- data/Rakefile +25 -7
- data/debug.gemspec +1 -1
- data/exe/rdbg +7 -3
- data/ext/debug/debug.c +0 -22
- data/ext/debug/extconf.rb +18 -7
- data/lib/debug/breakpoint.rb +68 -33
- data/lib/debug/client.rb +12 -2
- data/lib/debug/config.rb +55 -24
- data/lib/debug/console.rb +9 -3
- data/lib/debug/frame_info.rb +31 -24
- data/lib/debug/server.rb +44 -17
- data/lib/debug/server_cdp.rb +5 -5
- data/lib/debug/server_dap.rb +221 -115
- data/lib/debug/session.rb +227 -129
- data/lib/debug/source_repository.rb +13 -0
- data/lib/debug/thread_client.rb +161 -64
- data/lib/debug/tracer.rb +4 -3
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +28 -8
- metadata +5 -6
- data/lib/debug/bp.vim +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb9c418ee481ed3b473973d522bb811949f6123501709d3385d9b2bf2a46d993
|
4
|
+
data.tar.gz: d0036bac1930ec7e920e9faeb66556a4a9132342ed604a909e15f9d02b4d6963
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9cb09ddeee150eac35f5f3044106f482e54e16b41cee4ab6d0678fa92a2c1aefad350412bdc00997892733cf0a58312372d3f40c0f22d5262223de46f31cd9b
|
7
|
+
data.tar.gz: 68a846cc25aca6aab1429b3b36da57977c7c5671b21e9c6381f6d0b6d5fe7d28979fac53d1958da4de00c10445722a3fe1e386a871ee8b5638b3bf541cbf19ad
|
data/CONTRIBUTING.md
CHANGED
@@ -14,15 +14,27 @@ If you spot any problem, please open an issue.
|
|
14
14
|
### Run all tests
|
15
15
|
|
16
16
|
```bash
|
17
|
-
$ rake
|
17
|
+
$ rake test_all
|
18
|
+
```
|
19
|
+
|
20
|
+
### Run all console tests
|
21
|
+
|
22
|
+
```bash
|
23
|
+
$ rake test_console
|
24
|
+
```
|
25
|
+
|
26
|
+
### Run all protocol (DAP & CDP) tests
|
27
|
+
|
28
|
+
```bash
|
29
|
+
$ rake test_protocol
|
18
30
|
```
|
19
31
|
|
20
32
|
### Run specific test(s)
|
21
33
|
|
22
34
|
|
23
35
|
```bash
|
24
|
-
$ ruby test/
|
25
|
-
$ ruby test/
|
36
|
+
$ ruby test/console/break_test.rb # run all tests in the specified file
|
37
|
+
$ ruby test/console/break_test.rb -h # to see all the test options
|
26
38
|
```
|
27
39
|
|
28
40
|
## Generate Tests
|
@@ -316,9 +328,30 @@ Sends request to rdbg to add a breakpoint.
|
|
316
328
|
|
317
329
|
Sends request to rdbg to delete a breakpoint.
|
318
330
|
|
319
|
-
- req_set_exception_breakpoints
|
331
|
+
- req_set_exception_breakpoints(breakpoints)
|
332
|
+
|
333
|
+
Sends request to rdbg to set exception breakpoints. e.g.
|
320
334
|
|
321
|
-
|
335
|
+
```rb
|
336
|
+
req_set_exception_breakpoints([{ name: "RuntimeError", condition: "a == 1" }])
|
337
|
+
```
|
338
|
+
|
339
|
+
Please note that `setExceptionBreakpoints` resets all exception breakpoints in every request.
|
340
|
+
|
341
|
+
So the following code will only set breakpoint for `Exception`.
|
342
|
+
|
343
|
+
```rb
|
344
|
+
req_set_exception_breakpoints([{ name: "RuntimeError" }])
|
345
|
+
req_set_exception_breakpoints([{ name: "Exception" }])
|
346
|
+
```
|
347
|
+
|
348
|
+
This means you can also use
|
349
|
+
|
350
|
+
```rb
|
351
|
+
req_set_exception_breakpoints([])
|
352
|
+
```
|
353
|
+
|
354
|
+
to clear all exception breakpoints.
|
322
355
|
|
323
356
|
- req_continue
|
324
357
|
|
@@ -348,17 +381,35 @@ Sends request to rdbg to terminate the debuggee.
|
|
348
381
|
|
349
382
|
Passes if reattaching to rdbg is successful.
|
350
383
|
|
351
|
-
- assert_hover_result(expected, expression
|
384
|
+
- assert_hover_result(expected, expression)
|
385
|
+
|
386
|
+
Passes if result of `expression` matches `expected`.
|
387
|
+
|
388
|
+
`expected` need to be a Hash object as follows:
|
389
|
+
|
390
|
+
`assert_hover_result({value: '2', type: 'Integer'}, 'a')`
|
391
|
+
|
392
|
+
NOTE: `value` and `type` need to be strings.
|
393
|
+
|
394
|
+
- assert_repl_result(expected, expression)
|
395
|
+
|
396
|
+
Passes if result of `expression` matches `expected`.
|
397
|
+
|
398
|
+
`expected` need to be a Hash object as follows:
|
352
399
|
|
353
|
-
|
400
|
+
`assert_repl_result({value: '2', type: 'Integer'}, 'a')`
|
354
401
|
|
355
|
-
|
402
|
+
NOTE: `value` and `type` need to be strings.
|
356
403
|
|
357
|
-
|
404
|
+
- assert_watch_result(expected, expression)
|
358
405
|
|
359
|
-
|
406
|
+
Passes if result of `expression` matches `expected`.
|
360
407
|
|
361
|
-
|
408
|
+
`expected` need to be a Hash object as follows:
|
409
|
+
|
410
|
+
`assert_watch_result({value: '2', type: 'Integer'}, 'a')`
|
411
|
+
|
412
|
+
NOTE: `value` and `type` need to be strings.
|
362
413
|
|
363
414
|
- assert_line_num(expected)
|
364
415
|
|
@@ -372,6 +423,23 @@ An variable entry looks like this: `{ name: "bar", value: "nil", type: "NilClass
|
|
372
423
|
|
373
424
|
Please note that both `value` and `type` need to be strings.
|
374
425
|
|
426
|
+
- assert_threads_result(expected)
|
427
|
+
|
428
|
+
Passes if both conditions are true:
|
429
|
+
|
430
|
+
1. The number of expected patterns matches the number of threads.
|
431
|
+
2. Every pattern matches a thread name. Notice that the order of threads info is not guaranteed.
|
432
|
+
|
433
|
+
Example:
|
434
|
+
|
435
|
+
```
|
436
|
+
assert_threads_result(
|
437
|
+
[
|
438
|
+
/\.rb:\d:in `<main>'/,
|
439
|
+
/\.rb:\d:in `block in foo'/
|
440
|
+
]
|
441
|
+
)
|
442
|
+
```
|
375
443
|
|
376
444
|
## To Update README
|
377
445
|
|
data/README.md
CHANGED
@@ -9,11 +9,15 @@ New debug.rb has several advantages:
|
|
9
9
|
|
10
10
|
* Fast: No performance penalty on non-stepping mode and non-breakpoints.
|
11
11
|
* [Remote debugging](#remote-debugging): Support remote debugging natively.
|
12
|
-
* UNIX domain socket
|
12
|
+
* UNIX domain socket (UDS)
|
13
13
|
* TCP/IP
|
14
|
-
* Integration with rich debugger
|
15
|
-
|
16
|
-
|
14
|
+
* Integration with rich debugger frontends
|
15
|
+
|
16
|
+
Frontend | [Console](https://github.com/ruby/debug#invoke-as-a-remote-debuggee) | [VSCode](https://github.com/ruby/debug#vscode-integration) | [Chrome DevTool](#chrome-devtool-integration) |
|
17
|
+
---|---|---|---|
|
18
|
+
Connection | UDS, TCP/IP | UDS, TCP/IP | TCP/IP |
|
19
|
+
Requirement | No | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome |
|
20
|
+
|
17
21
|
* Extensible: application can introduce debugging support with several ways:
|
18
22
|
* By `rdbg` command
|
19
23
|
* By loading libraries with `-r` command line option
|
@@ -38,6 +42,9 @@ If you use Bundler, write the following line to your Gemfile.
|
|
38
42
|
gem "debug", ">= 1.0.0"
|
39
43
|
```
|
40
44
|
|
45
|
+
(The version constraint is important; `debug < 1.0.0` is an older,
|
46
|
+
abandoned gem that is completely different from this product.)
|
47
|
+
|
41
48
|
# HOW TO USE
|
42
49
|
|
43
50
|
To use a debugger, roughly you will do the following steps:
|
@@ -134,7 +141,7 @@ d => 4
|
|
134
141
|
### Invoke the program from the debugger as a traditional debuggers
|
135
142
|
|
136
143
|
If you don't want to modify the source code, you can set breakpoints with a debug command `break` (`b` for short).
|
137
|
-
Using `rdbg` command to launch the program without any modifications, you can run the program with the debugger.
|
144
|
+
Using `rdbg` command (or `bundle exec rdbg`) to launch the program without any modifications, you can run the program with the debugger.
|
138
145
|
|
139
146
|
```shell
|
140
147
|
$ cat target.rb # Sample program
|
@@ -280,7 +287,12 @@ You can run your application as a remote debuggee and the remote debugger consol
|
|
280
287
|
|
281
288
|
### Invoke as a remote debuggee
|
282
289
|
|
283
|
-
There are
|
290
|
+
There are multiple ways to run your program as a debuggee:
|
291
|
+
|
292
|
+
Stop at program start | [`rdbg` option](https://github.com/ruby/debug#rdbg---open-or-rdbg--o-for-short) | [require](https://github.com/ruby/debug#require-debugopen-in-a-program) | [debugger API](https://github.com/ruby/debug#start-by-method)
|
293
|
+
---|---|---|---|
|
294
|
+
Yes | `rdbg --open` | `require "debug/open"` | `DEBUGGER__.open`
|
295
|
+
No | `rdbg --open --nonstop` | `require "debug/open_nonstop"` | `DEBUGGER__.open(nonstop: true)`
|
284
296
|
|
285
297
|
#### `rdbg --open` (or `rdbg -O` for short)
|
286
298
|
|
@@ -456,35 +468,38 @@ config set no_color true
|
|
456
468
|
|
457
469
|
* UI
|
458
470
|
* `RUBY_DEBUG_LOG_LEVEL` (`log_level`): Log level same as Logger (default: WARN)
|
459
|
-
* `RUBY_DEBUG_SHOW_SRC_LINES` (`show_src_lines`): Show n lines source code on breakpoint (default: 10
|
460
|
-
* `RUBY_DEBUG_SHOW_FRAMES` (`show_frames`): Show n frames on breakpoint (default: 2
|
461
|
-
* `RUBY_DEBUG_USE_SHORT_PATH` (`use_short_path`): Show shorten PATH (like $(Gem)/foo.rb)
|
471
|
+
* `RUBY_DEBUG_SHOW_SRC_LINES` (`show_src_lines`): Show n lines source code on breakpoint (default: 10)
|
472
|
+
* `RUBY_DEBUG_SHOW_FRAMES` (`show_frames`): Show n frames on breakpoint (default: 2)
|
473
|
+
* `RUBY_DEBUG_USE_SHORT_PATH` (`use_short_path`): Show shorten PATH (like $(Gem)/foo.rb) (default: false)
|
462
474
|
* `RUBY_DEBUG_NO_COLOR` (`no_color`): Do not use colorize (default: false)
|
463
475
|
* `RUBY_DEBUG_NO_SIGINT_HOOK` (`no_sigint_hook`): Do not suspend on SIGINT (default: false)
|
464
476
|
* `RUBY_DEBUG_NO_RELINE` (`no_reline`): Do not use Reline library (default: false)
|
477
|
+
* `RUBY_DEBUG_NO_HINT` (`no_hint`): Do not show the hint on the REPL (default: false)
|
465
478
|
|
466
479
|
* CONTROL
|
467
|
-
* `RUBY_DEBUG_SKIP_PATH` (`skip_path`): Skip showing/entering frames for given paths
|
480
|
+
* `RUBY_DEBUG_SKIP_PATH` (`skip_path`): Skip showing/entering frames for given paths
|
468
481
|
* `RUBY_DEBUG_SKIP_NOSRC` (`skip_nosrc`): Skip on no source code lines (default: false)
|
469
482
|
* `RUBY_DEBUG_KEEP_ALLOC_SITE` (`keep_alloc_site`): Keep allocation site and p, pp shows it (default: false)
|
470
483
|
* `RUBY_DEBUG_POSTMORTEM` (`postmortem`): Enable postmortem debug (default: false)
|
471
484
|
* `RUBY_DEBUG_FORK_MODE` (`fork_mode`): Control which process activates a debugger after fork (both/parent/child) (default: both)
|
472
|
-
* `RUBY_DEBUG_SIGDUMP_SIG` (`sigdump_sig`): Sigdump signal (default:
|
485
|
+
* `RUBY_DEBUG_SIGDUMP_SIG` (`sigdump_sig`): Sigdump signal (default: false)
|
473
486
|
|
474
487
|
* BOOT
|
475
|
-
* `RUBY_DEBUG_NONSTOP` (`nonstop`): Nonstop mode
|
476
|
-
* `RUBY_DEBUG_STOP_AT_LOAD` (`stop_at_load`): Stop at just loading location
|
488
|
+
* `RUBY_DEBUG_NONSTOP` (`nonstop`): Nonstop mode (default: false)
|
489
|
+
* `RUBY_DEBUG_STOP_AT_LOAD` (`stop_at_load`): Stop at just loading location (default: false)
|
477
490
|
* `RUBY_DEBUG_INIT_SCRIPT` (`init_script`): debug command script path loaded at first stop
|
478
491
|
* `RUBY_DEBUG_COMMANDS` (`commands`): debug commands invoked at first stop. commands should be separated by ';;'
|
479
|
-
* `RUBY_DEBUG_NO_RC` (`no_rc`): ignore loading ~/.rdbgrc(.rb)
|
492
|
+
* `RUBY_DEBUG_NO_RC` (`no_rc`): ignore loading ~/.rdbgrc(.rb) (default: false)
|
480
493
|
* `RUBY_DEBUG_HISTORY_FILE` (`history_file`): history file (default: ~/.rdbg_history)
|
481
|
-
* `RUBY_DEBUG_SAVE_HISTORY` (`save_history`): maximum save history lines (default:
|
494
|
+
* `RUBY_DEBUG_SAVE_HISTORY` (`save_history`): maximum save history lines (default: 10000)
|
482
495
|
|
483
496
|
* REMOTE
|
484
497
|
* `RUBY_DEBUG_PORT` (`port`): TCP/IP remote debugging: port
|
485
|
-
* `RUBY_DEBUG_HOST` (`host`): TCP/IP remote debugging: host (
|
498
|
+
* `RUBY_DEBUG_HOST` (`host`): TCP/IP remote debugging: host (default: 127.0.0.1)
|
486
499
|
* `RUBY_DEBUG_SOCK_PATH` (`sock_path`): UNIX Domain Socket remote debugging: socket path
|
487
500
|
* `RUBY_DEBUG_SOCK_DIR` (`sock_dir`): UNIX Domain Socket remote debugging: socket directory
|
501
|
+
* `RUBY_DEBUG_LOCAL_FS_MAP` (`local_fs_map`): Specify local fs map
|
502
|
+
* `RUBY_DEBUG_SKIP_BP` (`skip_bp`): Skip breakpoints if no clients are attached (default: false)
|
488
503
|
* `RUBY_DEBUG_COOKIE` (`cookie`): Cookie for negotiation
|
489
504
|
* `RUBY_DEBUG_OPEN_FRONTEND` (`open_frontend`): frontend used by open command (vscode, chrome, default: rdbg).
|
490
505
|
* `RUBY_DEBUG_CHROME_PATH` (`chrome_path`): Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64))
|
@@ -492,6 +507,14 @@ config set no_color true
|
|
492
507
|
* OBSOLETE
|
493
508
|
* `RUBY_DEBUG_PARENT_ON_FORK` (`parent_on_fork`): Keep debugging parent process on fork (default: false)
|
494
509
|
|
510
|
+
There are other environment variables:
|
511
|
+
|
512
|
+
* `NO_COLOR`: If the value is set, set `RUBY_DEBUG_NO_COLOR` ([NO_COLOR: disabling ANSI color output in various Unix commands](https://no-color.org/)).
|
513
|
+
* `RUBY_DEBUG_ENABLE`: If the value is `0`, do not enable debug.gem feature.
|
514
|
+
* `RUBY_DEBUG_ADDED_RUBYOPT`: Remove this value from `RUBYOPT` at first. This feature helps loading debug.gem with `RUBYOPT='-r debug/...'` and you don't want to derive it to child processes. In this case you can set `RUBY_DEBUG_ADDED_RUBYOPT='-r debug/...'` (same value) and this string will be deleted from `RUBYOPT` at first.
|
515
|
+
* `RUBY_DEBUG_EDITOR` or `EDITOR`: An editor used by `edit` debug command.
|
516
|
+
* `RUBY_DEBUG_BB`: Define `Kernel#bb` method which is alias of `Kernel#debugger`.
|
517
|
+
|
495
518
|
### Initial scripts
|
496
519
|
|
497
520
|
If there is `~/.rdbgrc`, the file is loaded as an initial script (which contains debug commands) when the debug session is started.
|
data/Rakefile
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rake/testtask"
|
3
3
|
|
4
|
-
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
6
|
-
end
|
7
|
-
|
8
4
|
begin
|
9
5
|
require "rake/extensiontask"
|
10
6
|
task :build => :compile
|
@@ -15,7 +11,7 @@ begin
|
|
15
11
|
rescue LoadError
|
16
12
|
end
|
17
13
|
|
18
|
-
task :default => [:clobber, :compile, 'README.md', :
|
14
|
+
task :default => [:clobber, :compile, 'README.md', :check_readme, :test_console]
|
19
15
|
|
20
16
|
file 'README.md' => ['lib/debug/session.rb', 'lib/debug/config.rb',
|
21
17
|
'exe/rdbg', 'misc/README.md.erb'] do
|
@@ -25,10 +21,32 @@ file 'README.md' => ['lib/debug/session.rb', 'lib/debug/config.rb',
|
|
25
21
|
puts 'README.md is updated.'
|
26
22
|
end
|
27
23
|
|
28
|
-
task :
|
29
|
-
|
24
|
+
task :check_readme do
|
25
|
+
require_relative 'lib/debug/session'
|
26
|
+
require 'erb'
|
27
|
+
current_readme = File.read("README.md")
|
28
|
+
generated_readme = ERB.new(File.read('misc/README.md.erb')).result
|
29
|
+
|
30
|
+
if current_readme != generated_readme
|
31
|
+
fail <<~MSG
|
32
|
+
The content of README.md doesn't match its template and/or source.
|
33
|
+
Please apply the changes to info source (e.g. command comments) or the template and run 'rake README.md' to update README.md.
|
34
|
+
MSG
|
35
|
+
end
|
30
36
|
end
|
31
37
|
|
38
|
+
desc "Run all debugger console related tests"
|
39
|
+
Rake::TestTask.new(:test_console) do |t|
|
40
|
+
t.test_files = FileList["test/console/*_test.rb", "test/support/*_test.rb"]
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Run all debugger protocols (CAP & DAP) related tests"
|
32
44
|
Rake::TestTask.new(:test_protocol) do |t|
|
33
45
|
t.test_files = FileList["test/protocol/*_test.rb"]
|
34
46
|
end
|
47
|
+
|
48
|
+
task test: 'test_console' do
|
49
|
+
warn '`rake test` doesn\'t run protocol tests. Use `rake test-all` to test all.'
|
50
|
+
end
|
51
|
+
|
52
|
+
task test_all: [:test_console, :test_protocol]
|
data/debug.gemspec
CHANGED
@@ -28,5 +28,5 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.extensions = ['ext/debug/extconf.rb']
|
29
29
|
|
30
30
|
spec.add_dependency "irb", ">= 1.3.6" # for its color_printer class, which was added after 1.3
|
31
|
-
spec.add_dependency "reline", ">= 0.
|
31
|
+
spec.add_dependency "reline", ">= 0.3.1"
|
32
32
|
end
|
data/exe/rdbg
CHANGED
@@ -3,7 +3,9 @@
|
|
3
3
|
require_relative '../lib/debug/config'
|
4
4
|
config = DEBUGGER__::Config::parse_argv(ARGV)
|
5
5
|
|
6
|
-
|
6
|
+
# mode is not an actual configuration option
|
7
|
+
# it's only used to carry the result of parse_argv here
|
8
|
+
case config.delete(:mode)
|
7
9
|
when :start
|
8
10
|
require 'rbconfig'
|
9
11
|
|
@@ -12,13 +14,15 @@ when :start
|
|
12
14
|
cmd = config[:command] ? ARGV.shift : (ENV['RUBY'] || RbConfig.ruby)
|
13
15
|
|
14
16
|
env = ::DEBUGGER__::Config.config_to_env_hash(config)
|
15
|
-
env['RUBYOPT']
|
17
|
+
rubyopt = env['RUBYOPT']
|
18
|
+
env['RUBY_DEBUG_ADDED_RUBYOPT'] = added = "-r #{libpath}/#{start_mode}"
|
19
|
+
env['RUBYOPT'] = "#{added} #{rubyopt}"
|
16
20
|
|
17
21
|
exec(env, cmd, *ARGV)
|
18
22
|
|
19
23
|
when :attach
|
20
24
|
require_relative "../lib/debug/client"
|
21
|
-
::DEBUGGER__::CONFIG.
|
25
|
+
::DEBUGGER__::CONFIG.set_config **config
|
22
26
|
|
23
27
|
begin
|
24
28
|
if ARGV.empty? && config[:port]
|
data/ext/debug/debug.c
CHANGED
@@ -97,27 +97,6 @@ frame_depth(VALUE self)
|
|
97
97
|
return INT2FIX(RARRAY_LEN(bt));
|
98
98
|
}
|
99
99
|
|
100
|
-
static void
|
101
|
-
method_added_tracker(VALUE tpval, void *ptr)
|
102
|
-
{
|
103
|
-
rb_trace_arg_t *arg = rb_tracearg_from_tracepoint(tpval);
|
104
|
-
VALUE mid = rb_tracearg_callee_id(arg);
|
105
|
-
|
106
|
-
if (RB_UNLIKELY(mid == ID2SYM(rb_intern("method_added")) ||
|
107
|
-
mid == ID2SYM(rb_intern("singleton_method_added")))) {
|
108
|
-
VALUE args[] = {
|
109
|
-
tpval,
|
110
|
-
};
|
111
|
-
rb_funcallv(rb_mDebugger, rb_intern("method_added"), 1, args);
|
112
|
-
}
|
113
|
-
}
|
114
|
-
|
115
|
-
static VALUE
|
116
|
-
create_method_added_tracker(VALUE self)
|
117
|
-
{
|
118
|
-
return rb_tracepoint_new(0, RUBY_EVENT_CALL, method_added_tracker, NULL);
|
119
|
-
}
|
120
|
-
|
121
100
|
// iseq
|
122
101
|
|
123
102
|
const struct rb_iseq *rb_iseqw_to_iseq(VALUE iseqw);
|
@@ -203,7 +182,6 @@ Init_debug(void)
|
|
203
182
|
rb_gc_register_mark_object(rb_cFrameInfo);
|
204
183
|
rb_define_singleton_method(rb_mDebugger, "capture_frames", capture_frames, 1);
|
205
184
|
rb_define_singleton_method(rb_mDebugger, "frame_depth", frame_depth, 0);
|
206
|
-
rb_define_singleton_method(rb_mDebugger, "create_method_added_tracker", create_method_added_tracker, 0);
|
207
185
|
rb_define_const(rb_mDebugger, "SO_VERSION", rb_str_new2(RUBY_DEBUG_VERSION));
|
208
186
|
|
209
187
|
// iseq
|
data/ext/debug/extconf.rb
CHANGED
@@ -2,14 +2,25 @@ require 'mkmf'
|
|
2
2
|
require_relative '../../lib/debug/version'
|
3
3
|
File.write("debug_version.h", "#define RUBY_DEBUG_VERSION \"#{DEBUGGER__::VERSION}\"\n")
|
4
4
|
|
5
|
-
have_func "rb_iseq_parameters(NULL, 0)",
|
6
|
-
[["VALUE rb_iseq_parameters(void *, int is_proc);"]]
|
7
5
|
|
8
|
-
|
9
|
-
|
6
|
+
if defined? RubyVM
|
7
|
+
$defs << '-DHAVE_RB_ISEQ_PARAMETERS'
|
8
|
+
$defs << '-DHAVE_RB_ISEQ_CODE_LOCATION'
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
if RUBY_VERSION >= '3.1.0'
|
11
|
+
$defs << '-DHAVE_RB_ISEQ_TYPE'
|
12
|
+
end
|
13
|
+
else
|
14
|
+
# not on MRI
|
15
|
+
|
16
|
+
have_func "rb_iseq_parameters(NULL, 0)",
|
17
|
+
[["VALUE rb_iseq_parameters(void *, int is_proc);"]]
|
18
|
+
|
19
|
+
have_func "rb_iseq_code_location(NULL, NULL, NULL, NULL, NULL)",
|
20
|
+
[["void rb_iseq_code_location(void *, int *first_lineno, int *first_column, int *last_lineno, int *last_column);"]]
|
21
|
+
# from Ruby 3.1
|
22
|
+
have_func "rb_iseq_type(NULL)",
|
23
|
+
[["VALUE rb_iseq_type(void *);"]]
|
24
|
+
end
|
14
25
|
|
15
26
|
create_makefile 'debug/debug'
|
data/lib/debug/breakpoint.rb
CHANGED
@@ -131,9 +131,17 @@ module DEBUGGER__
|
|
131
131
|
end
|
132
132
|
|
133
133
|
class LineBreakpoint < Breakpoint
|
134
|
-
attr_reader :path, :line, :iseq
|
134
|
+
attr_reader :path, :line, :iseq, :cond, :oneshot, :hook_call, :command
|
135
135
|
|
136
|
-
def
|
136
|
+
def self.copy bp, root_iseq
|
137
|
+
nbp = LineBreakpoint.new bp.path, bp.line,
|
138
|
+
cond: bp.cond, oneshot: bp.oneshot, hook_call: bp.hook_call,
|
139
|
+
command: bp.command, skip_activate: true
|
140
|
+
nbp.try_activate root_iseq
|
141
|
+
nbp
|
142
|
+
end
|
143
|
+
|
144
|
+
def initialize path, line, cond: nil, oneshot: false, hook_call: true, command: nil, skip_activate: false
|
137
145
|
@line = line
|
138
146
|
@oneshot = oneshot
|
139
147
|
@hook_call = hook_call
|
@@ -146,7 +154,7 @@ module DEBUGGER__
|
|
146
154
|
|
147
155
|
super(cond, command, path)
|
148
156
|
|
149
|
-
try_activate
|
157
|
+
try_activate unless skip_activate
|
150
158
|
@pending = !@iseq
|
151
159
|
end
|
152
160
|
|
@@ -206,7 +214,7 @@ module DEBUGGER__
|
|
206
214
|
when events.include?(:RUBY_EVENT_END)
|
207
215
|
activate(iseq, :end, line)
|
208
216
|
else
|
209
|
-
# not
|
217
|
+
# not activated
|
210
218
|
end
|
211
219
|
end
|
212
220
|
|
@@ -216,42 +224,56 @@ module DEBUGGER__
|
|
216
224
|
|
217
225
|
NearestISeq = Struct.new(:iseq, :line, :events)
|
218
226
|
|
219
|
-
def
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
227
|
+
def iterate_iseq root_iseq
|
228
|
+
if root_iseq
|
229
|
+
is = [root_iseq]
|
230
|
+
while iseq = is.pop
|
231
|
+
yield iseq
|
232
|
+
iseq.each_child do |child_iseq|
|
233
|
+
is << child_iseq
|
234
|
+
end
|
235
|
+
end
|
236
|
+
else
|
237
|
+
ObjectSpace.each_iseq do |iseq|
|
238
|
+
if DEBUGGER__.compare_path((iseq.absolute_path || iseq.path), self.path) &&
|
239
|
+
iseq.first_lineno <= self.line &&
|
240
|
+
iseq.type != :ensure # ensure iseq is copied (duplicated)
|
241
|
+
yield iseq
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
226
246
|
|
227
|
-
|
228
|
-
|
247
|
+
def try_activate root_iseq = nil
|
248
|
+
nearest = nil # NearestISeq
|
249
|
+
iterate_iseq root_iseq do |iseq|
|
250
|
+
iseq.traceable_lines_norec(line_events = {})
|
251
|
+
lines = line_events.keys.sort
|
229
252
|
|
230
|
-
|
231
|
-
|
232
|
-
|
253
|
+
if !lines.empty? && lines.last >= line
|
254
|
+
nline = lines.bsearch{|l| line <= l}
|
255
|
+
events = line_events[nline]
|
233
256
|
|
234
|
-
|
257
|
+
next if events == [:RUBY_EVENT_B_CALL]
|
235
258
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
259
|
+
if @hook_call &&
|
260
|
+
events.include?(:RUBY_EVENT_CALL) &&
|
261
|
+
self.line == iseq.first_lineno
|
262
|
+
nline = iseq.first_lineno
|
263
|
+
end
|
241
264
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
end
|
265
|
+
if !nearest || ((line - nline).abs < (line - nearest.line).abs)
|
266
|
+
nearest = NearestISeq.new(iseq, nline, events)
|
267
|
+
else
|
268
|
+
if @hook_call && nearest.iseq.first_lineno <= iseq.first_lineno
|
269
|
+
if (nearest.line > line && !nearest.events.include?(:RUBY_EVENT_CALL)) ||
|
270
|
+
(events.include?(:RUBY_EVENT_CALL))
|
271
|
+
nearest = NearestISeq.new(iseq, nline, events)
|
250
272
|
end
|
251
273
|
end
|
252
274
|
end
|
253
275
|
end
|
254
|
-
|
276
|
+
end
|
255
277
|
|
256
278
|
if nearest
|
257
279
|
activate_exact nearest.iseq, nearest.events, nearest.line
|
@@ -326,12 +348,25 @@ module DEBUGGER__
|
|
326
348
|
next if ThreadClient.current.management?
|
327
349
|
next if skip_path?(tp.path)
|
328
350
|
|
329
|
-
if safe_eval
|
351
|
+
if need_suspend? safe_eval(tp.binding, @cond)
|
330
352
|
suspend
|
331
353
|
end
|
332
354
|
}
|
333
355
|
end
|
334
356
|
|
357
|
+
private def need_suspend? cond_result
|
358
|
+
map = ThreadClient.current.check_bp_fulfillment_map
|
359
|
+
if cond_result
|
360
|
+
if map[self]
|
361
|
+
false
|
362
|
+
else
|
363
|
+
map[self] = true
|
364
|
+
end
|
365
|
+
else
|
366
|
+
map[self] = false
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
335
370
|
def to_s
|
336
371
|
s = "#{generate_label("Check")}"
|
337
372
|
s += super
|
@@ -386,7 +421,7 @@ module DEBUGGER__
|
|
386
421
|
end
|
387
422
|
|
388
423
|
class MethodBreakpoint < Breakpoint
|
389
|
-
attr_reader :sig_method_name, :method
|
424
|
+
attr_reader :sig_method_name, :method, :klass
|
390
425
|
|
391
426
|
def initialize b, klass_name, op, method_name, cond: nil, command: nil, path: nil
|
392
427
|
@sig_klass_name = klass_name
|
data/lib/debug/client.rb
CHANGED
@@ -121,7 +121,10 @@ module DEBUGGER__
|
|
121
121
|
@width = IO.console_size[1]
|
122
122
|
@width = 80 if @width == 0
|
123
123
|
|
124
|
-
send "version: #{VERSION}
|
124
|
+
send "version: #{VERSION} " +
|
125
|
+
"width: #{@width} " +
|
126
|
+
"cookie: #{CONFIG[:cookie] || '-'} " +
|
127
|
+
"nonstop: #{CONFIG[:nonstop] ? 'true' : 'false'}"
|
125
128
|
end
|
126
129
|
|
127
130
|
def deactivate
|
@@ -173,6 +176,8 @@ module DEBUGGER__
|
|
173
176
|
end
|
174
177
|
|
175
178
|
def connect
|
179
|
+
pre_commands = (CONFIG[:commands] || '').split(';;')
|
180
|
+
|
176
181
|
trap(:SIGINT){
|
177
182
|
send "pause"
|
178
183
|
}
|
@@ -199,7 +204,12 @@ module DEBUGGER__
|
|
199
204
|
prev_trap = trap(:SIGINT, 'DEFAULT')
|
200
205
|
|
201
206
|
begin
|
202
|
-
|
207
|
+
if pre_commands.empty?
|
208
|
+
line = readline
|
209
|
+
else
|
210
|
+
line = pre_commands.shift
|
211
|
+
puts "(rdbg:remote:command) #{line}"
|
212
|
+
end
|
203
213
|
rescue Interrupt
|
204
214
|
retry
|
205
215
|
ensure
|