debug 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|