debug 1.4.0 → 1.5.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 +124 -0
- data/Gemfile +1 -0
- data/README.md +16 -16
- data/Rakefile +5 -5
- data/debug.gemspec +6 -4
- data/ext/debug/debug.c +84 -0
- data/ext/debug/extconf.rb +11 -0
- data/lib/debug/breakpoint.rb +24 -35
- data/lib/debug/client.rb +9 -3
- data/lib/debug/console.rb +34 -13
- data/lib/debug/frame_info.rb +4 -5
- data/lib/debug/local.rb +1 -1
- data/lib/debug/server.rb +65 -27
- data/lib/debug/server_cdp.rb +369 -148
- data/lib/debug/server_dap.rb +72 -75
- data/lib/debug/session.rb +225 -114
- data/lib/debug/source_repository.rb +91 -51
- data/lib/debug/thread_client.rb +94 -42
- data/lib/debug/tracer.rb +3 -9
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +6 -6
- metadata +4 -13
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -24
- data/.github/ISSUE_TEMPLATE/custom.md +0 -10
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
- data/.github/pull_request_template.md +0 -9
- data/.github/workflows/ruby.yml +0 -34
- data/.gitignore +0 -12
- data/bin/console +0 -14
- data/bin/gentest +0 -30
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 121cdb1003971d234dbeb40878f693d06053fa32f28024c5d2a7c0e0fd6d3719
|
4
|
+
data.tar.gz: fd95c68d4bf99b38a83cef1a6851680bb9abb65d39fa9fc69a94d248295a5829
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4354a11670db6e0fd49e4b8151b268a08c7843c80ccd36b5c492cf5fabc7b42c6632939905b9912c81434f5513e36dac8378686b5d47c274248c523eea88a0c8
|
7
|
+
data.tar.gz: e22274473f567bed800c25d46a46d32adf263f070e8147cd71778ef9cbd95b8e239e2912b226892f032266a92322045a62e7f9c908f176e601a984e254acd2a7
|
data/CONTRIBUTING.md
CHANGED
@@ -249,6 +249,130 @@ Passes if `text` is not included in the last debugger log.
|
|
249
249
|
|
250
250
|
Passes if `text` is included in the debuggee log.
|
251
251
|
|
252
|
+
### Tests for DAP and CDP
|
253
|
+
|
254
|
+
Currently, there are 2 kinds of test frameworks for DAP and CDP.
|
255
|
+
|
256
|
+
1. Protocol-based tests
|
257
|
+
|
258
|
+
If you want to write protocol-based tests, you should use the test generator.
|
259
|
+
To run the test generator, you can enter `$ bin/gentest target.rb --open=vscode` in the terminal, VSCode will be executed.
|
260
|
+
Also, if you enter ``$ bin/gentest target.rb --open=chrome` there, Chrome will be executed.
|
261
|
+
If you need to modify existing tests, it is basically a good idea to regenerate them by the test generator instead of rewriting them directly.
|
262
|
+
Please refer to [the Microsoft "Debug Adapter Protocol" article](https://microsoft.github.io/debug-adapter-protocol/specification) to learn more about DAP formats.
|
263
|
+
Please refer to [Procol viewer for "Chrome DevTools Protocol"](https://chromedevtools.github.io/devtools-protocol/) to learn more about CDP formats.
|
264
|
+
|
265
|
+
2. High-level tests
|
266
|
+
|
267
|
+
High-level tests are designed to test both DAP and CDP for a single method.
|
268
|
+
You can write tests as follows:
|
269
|
+
**NOTE:** Use `req_terminate_debuggee` to finish debugging. You can't use any methods such as `req_continue`, `req_next` and so on.
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
require_relative '../support/test_case'
|
273
|
+
module DEBUGGER__
|
274
|
+
class BreakTest < TestCase
|
275
|
+
# PROGRAM is the target script.
|
276
|
+
PROGRAM = <<~RUBY
|
277
|
+
1| module Foo
|
278
|
+
2| class Bar
|
279
|
+
3| def self.a
|
280
|
+
4| "hello"
|
281
|
+
5| end
|
282
|
+
6| end
|
283
|
+
7| Bar.a
|
284
|
+
8| bar = Bar.new
|
285
|
+
9| end
|
286
|
+
RUBY
|
287
|
+
|
288
|
+
def test_break1
|
289
|
+
run_protocol_scenario PROGRAM do # Start debugging with DAP and CDP
|
290
|
+
req_add_breakpoint 5 # Set a breakpoint on line 5.
|
291
|
+
req_add_breakpoint 8 # Set a breakpoint on line 8.
|
292
|
+
req_continue # Resume the program.
|
293
|
+
assert_line_num 5 # Check if debugger stops at line 5.
|
294
|
+
req_continue # Resume the program.
|
295
|
+
assert_line_num 8 # Check if debugger stops at line 8.
|
296
|
+
req_terminate_debuggee # Terminate debugging.
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
```
|
302
|
+
|
303
|
+
#### API
|
304
|
+
|
305
|
+
- run_protocol_scenario program, dap: true, cdp: true, &scenario
|
306
|
+
|
307
|
+
Execute debugging `program` with `&scenario`. If you want to test it only for DAP, you can write as follows:
|
308
|
+
|
309
|
+
`run_protocol_scenario program, cdp: false ...`
|
310
|
+
|
311
|
+
- req_add_breakpoint(lineno, path: temp_file_path, cond: nil)
|
312
|
+
|
313
|
+
Sends request to rdbg to add a breakpoint.
|
314
|
+
|
315
|
+
- req_delete_breakpoint bpnum
|
316
|
+
|
317
|
+
Sends request to rdbg to delete a breakpoint.
|
318
|
+
|
319
|
+
- req_set_exception_breakpoints
|
320
|
+
|
321
|
+
Sends request to rdbg to set exception breakpoints.
|
322
|
+
|
323
|
+
- req_continue
|
324
|
+
|
325
|
+
Sends request to rdbg to resume the program.
|
326
|
+
|
327
|
+
- req_step
|
328
|
+
|
329
|
+
Sends request to rdbg to step into next method.
|
330
|
+
|
331
|
+
- req_next
|
332
|
+
|
333
|
+
Sends request to rdbg to step over next method.
|
334
|
+
|
335
|
+
- req_finish
|
336
|
+
|
337
|
+
Sends request to rdbg to step out of current method.
|
338
|
+
|
339
|
+
- req_step_back
|
340
|
+
|
341
|
+
Sends request to rdbg to step back from current method.
|
342
|
+
|
343
|
+
- req_terminate_debuggee
|
344
|
+
|
345
|
+
Sends request to rdbg to terminate the debuggee.
|
346
|
+
|
347
|
+
- assert_reattach
|
348
|
+
|
349
|
+
Passes if reattaching to rdbg is successful.
|
350
|
+
|
351
|
+
- assert_hover_result(expected, expression: nil)
|
352
|
+
|
353
|
+
Passes if result of `expression` is equal to `expected`.
|
354
|
+
|
355
|
+
- assert_repl_result(expected, expression: nil)
|
356
|
+
|
357
|
+
Passes if result of `expression` is equal to `expected`.
|
358
|
+
|
359
|
+
- assert_watch_result(expected, expression: nil)
|
360
|
+
|
361
|
+
Passes if result of `expression` is equal to `expected`.
|
362
|
+
|
363
|
+
- assert_line_num(expected)
|
364
|
+
|
365
|
+
Passes if `expected` is equal to the location where debugger stops.
|
366
|
+
|
367
|
+
- assert_locals_result(expected)
|
368
|
+
|
369
|
+
Passes if all of `expected` local variable entries match the ones returned by debugger.
|
370
|
+
|
371
|
+
An variable entry looks like this: `{ name: "bar", value: "nil", type: "NilClass" }`.
|
372
|
+
|
373
|
+
Please note that both `value` and `type` need to be strings.
|
374
|
+
|
375
|
+
|
252
376
|
## To Update README
|
253
377
|
|
254
378
|
This project generates `README.md` from the template `misc/README.md.erb`
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
[![Ruby](https://github.com/ruby/debug/actions/workflows/ruby.yml/badge.svg?branch=master)](https://github.com/ruby/debug/actions/workflows/ruby.yml?query=branch%3Amaster)
|
1
|
+
[![Ruby](https://github.com/ruby/debug/actions/workflows/ruby.yml/badge.svg?branch=master)](https://github.com/ruby/debug/actions/workflows/ruby.yml?query=branch%3Amaster) [![Protocol](https://github.com/ruby/debug/actions/workflows/protocol.yml/badge.svg)](https://github.com/ruby/debug/actions/workflows/protocol.yml)
|
2
2
|
|
3
3
|
# debug.rb
|
4
4
|
|
5
|
-
This library provides debugging functionality to Ruby.
|
5
|
+
This library provides debugging functionality to Ruby (MRI) 2.6 and later.
|
6
6
|
|
7
7
|
This debug.rb is replacement of traditional lib/debug.rb standard library which is implemented by `set_trace_func`.
|
8
8
|
New debug.rb has several advantages:
|
@@ -113,7 +113,7 @@ d => nil
|
|
113
113
|
5| binding.break
|
114
114
|
6| c = 3
|
115
115
|
7| d = 4
|
116
|
-
=> 8| binding.break # Again the program stops
|
116
|
+
=> 8| binding.break # Again the program stops here
|
117
117
|
9| p [a, b, c, d]
|
118
118
|
10|
|
119
119
|
11| __END__
|
@@ -358,6 +358,8 @@ Also `open` command allows opening the debug port.
|
|
358
358
|
|
359
359
|
#### VSCode integration
|
360
360
|
|
361
|
+
([vscode-rdbg v0.0.9](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) or later is required)
|
362
|
+
|
361
363
|
If you don't run a debuggee Ruby process on VSCode, you can attach with VSCode later with the following steps.
|
362
364
|
|
363
365
|
`rdbg --open=vscode` opens the debug port and tries to invoke the VSCode (`code` command).
|
@@ -417,7 +419,7 @@ Note that you can attach with `rdbg --attach` and continue REPL debugging.
|
|
417
419
|
|
418
420
|
#### Chrome DevTool integration
|
419
421
|
|
420
|
-
With `rdbg --open=chrome` command will
|
422
|
+
With `rdbg --open=chrome` command will show the following message.
|
421
423
|
|
422
424
|
```
|
423
425
|
$ rdbg target.rb --open=chrome
|
@@ -435,8 +437,6 @@ Also `open chrome` command works like `open vscode`.
|
|
435
437
|
|
436
438
|
For more information about how to use Chrome debugging, you might want to read [here](https://developer.chrome.com/docs/devtools/).
|
437
439
|
|
438
|
-
Note: If you want to maximize Chrome DevTools, click [Toggle Device Toolbar](https://developer.chrome.com/docs/devtools/device-mode/#viewport).
|
439
|
-
|
440
440
|
## Configuration
|
441
441
|
|
442
442
|
You can configure the debugger's behavior with debug commands and environment variables.
|
@@ -567,8 +567,8 @@ The `<...>` notation means the argument.
|
|
567
567
|
* break and run `<command>` before stopping.
|
568
568
|
* `b[reak] ... do: <command>`
|
569
569
|
* break and run `<command>`, and continue.
|
570
|
-
* `b[reak] ... path: <
|
571
|
-
* break if the
|
570
|
+
* `b[reak] ... path: <path>`
|
571
|
+
* break if the path matches to `<path>`. `<path>` can be a regexp with `/regexp/`.
|
572
572
|
* `b[reak] if: <expr>`
|
573
573
|
* break if: `<expr>` is true at any lines.
|
574
574
|
* Note that this feature is super slow.
|
@@ -580,8 +580,8 @@ The `<...>` notation means the argument.
|
|
580
580
|
* runs `<command>` before stopping.
|
581
581
|
* `catch ... do: <command>`
|
582
582
|
* stops and run `<command>`, and continue.
|
583
|
-
* `catch ... path: <
|
584
|
-
* stops if the exception is raised from a path
|
583
|
+
* `catch ... path: <path>`
|
584
|
+
* stops if the exception is raised from a `<path>`. `<path>` can be a regexp with `/regexp/`.
|
585
585
|
* `watch @ivar`
|
586
586
|
* Stop the execution when the result of current scope's `@ivar` is changed.
|
587
587
|
* Note that this feature is super slow.
|
@@ -591,8 +591,8 @@ The `<...>` notation means the argument.
|
|
591
591
|
* runs `<command>` before stopping.
|
592
592
|
* `watch ... do: <command>`
|
593
593
|
* stops and run `<command>`, and continue.
|
594
|
-
* `watch ... path: <
|
595
|
-
* stops if the
|
594
|
+
* `watch ... path: <path>`
|
595
|
+
* stops if the path matches `<path>`. `<path>` can be a regexp with `/regexp/`.
|
596
596
|
* `del[ete]`
|
597
597
|
* delete all breakpoints.
|
598
598
|
* `del[ete] <bpnum>`
|
@@ -631,8 +631,8 @@ The `<...>` notation means the argument.
|
|
631
631
|
* Show information about accessible constants except toplevel constants.
|
632
632
|
* `i[nfo] g[lobal[s]]`
|
633
633
|
* Show information about global variables
|
634
|
-
* `i[nfo] ...
|
635
|
-
* Filter the output with
|
634
|
+
* `i[nfo] ... /regexp/`
|
635
|
+
* Filter the output with `/regexp/`.
|
636
636
|
* `i[nfo] th[read[s]]`
|
637
637
|
* Show all threads (same as `th[read]`).
|
638
638
|
* `o[utline]` or `ls`
|
@@ -683,8 +683,8 @@ The `<...>` notation means the argument.
|
|
683
683
|
* Add an exception tracer. It indicates raising exceptions.
|
684
684
|
* `trace object <expr>`
|
685
685
|
* Add an object tracer. It indicates that an object by `<expr>` is passed as a parameter or a receiver on method call.
|
686
|
-
* `trace ...
|
687
|
-
* Indicates only matched events to
|
686
|
+
* `trace ... /regexp/`
|
687
|
+
* Indicates only matched events to `/regexp/`.
|
688
688
|
* `trace ... into: <file>`
|
689
689
|
* Save trace information into: `<file>`.
|
690
690
|
* `trace off <num>`
|
data/Rakefile
CHANGED
@@ -2,8 +2,6 @@ require "bundler/gem_tasks"
|
|
2
2
|
require "rake/testtask"
|
3
3
|
|
4
4
|
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.libs << "test"
|
6
|
-
t.libs << "lib"
|
7
5
|
t.test_files = FileList["test/**/*_test.rb"]
|
8
6
|
end
|
9
7
|
|
@@ -17,7 +15,6 @@ begin
|
|
17
15
|
rescue LoadError
|
18
16
|
end
|
19
17
|
|
20
|
-
|
21
18
|
task :default => [:clobber, :compile, 'README.md', :test]
|
22
19
|
|
23
20
|
file 'README.md' => ['lib/debug/session.rb', 'lib/debug/config.rb',
|
@@ -28,7 +25,10 @@ file 'README.md' => ['lib/debug/session.rb', 'lib/debug/config.rb',
|
|
28
25
|
puts 'README.md is updated.'
|
29
26
|
end
|
30
27
|
|
31
|
-
task :
|
32
|
-
|
28
|
+
task :test_protocol do
|
29
|
+
ENV['RUBY_DEBUG_PROTOCOL_TEST'] = '1'
|
33
30
|
end
|
34
31
|
|
32
|
+
Rake::TestTask.new(:test_protocol) do |t|
|
33
|
+
t.test_files = FileList["test/protocol/*_test.rb"]
|
34
|
+
end
|
data/debug.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.email = ["ko1@atdot.net"]
|
8
8
|
|
9
9
|
spec.summary = %q{Debugging functionality for Ruby}
|
10
|
-
spec.description = %q{Debugging functionality for Ruby. This is completely rewritten debug.rb which was contained by the
|
10
|
+
spec.description = %q{Debugging functionality for Ruby. This is completely rewritten debug.rb which was contained by the ancient Ruby versions.}
|
11
11
|
spec.homepage = "https://github.com/ruby/debug"
|
12
12
|
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
13
13
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
@@ -17,11 +17,13 @@ Gem::Specification.new do |spec|
|
|
17
17
|
|
18
18
|
# Specify which files should be added to the gem when it is released.
|
19
19
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
-
spec.files
|
21
|
-
`git ls-files -z`.split("\x0").reject
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
22
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
23
|
+
end
|
22
24
|
end
|
23
25
|
spec.bindir = "exe"
|
24
|
-
spec.executables = spec.files.grep(%r{
|
26
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
25
27
|
spec.require_paths = ["lib"]
|
26
28
|
spec.extensions = ['ext/debug/extconf.rb']
|
27
29
|
|
data/ext/debug/debug.c
CHANGED
@@ -118,11 +118,82 @@ create_method_added_tracker(VALUE self)
|
|
118
118
|
return rb_tracepoint_new(0, RUBY_EVENT_CALL, method_added_tracker, NULL);
|
119
119
|
}
|
120
120
|
|
121
|
+
// iseq
|
122
|
+
|
123
|
+
const struct rb_iseq *rb_iseqw_to_iseq(VALUE iseqw);
|
124
|
+
|
125
|
+
#ifdef HAVE_RB_ISEQ_TYPE
|
126
|
+
VALUE rb_iseq_type(const struct rb_iseq *);
|
127
|
+
|
128
|
+
static VALUE
|
129
|
+
iseq_type(VALUE iseqw)
|
130
|
+
{
|
131
|
+
const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw);
|
132
|
+
return rb_iseq_type(iseq);
|
133
|
+
}
|
134
|
+
#endif
|
135
|
+
|
136
|
+
#ifdef HAVE_RB_ISEQ_PARAMETERS
|
137
|
+
VALUE rb_iseq_parameters(const struct rb_iseq *, int is_proc);
|
138
|
+
|
139
|
+
static VALUE
|
140
|
+
iseq_parameters_symbols(VALUE iseqw)
|
141
|
+
{
|
142
|
+
const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw);
|
143
|
+
VALUE params = rb_iseq_parameters(iseq, 0);
|
144
|
+
VALUE ary = rb_ary_new();
|
145
|
+
|
146
|
+
static VALUE sym_ast, sym_astast, sym_amp;
|
147
|
+
|
148
|
+
if (sym_ast == 0) {
|
149
|
+
sym_ast = ID2SYM(rb_intern("*"));
|
150
|
+
sym_astast = ID2SYM(rb_intern("**"));
|
151
|
+
sym_amp = ID2SYM(rb_intern("&"));
|
152
|
+
}
|
153
|
+
|
154
|
+
for (long i=0; i<RARRAY_LEN(params); i++) {
|
155
|
+
VALUE e = RARRAY_AREF(params, i);
|
156
|
+
if (RARRAY_LEN(e) == 2) {
|
157
|
+
VALUE sym = RARRAY_AREF(e, 1);
|
158
|
+
if (sym != sym_ast &&
|
159
|
+
sym != sym_astast &&
|
160
|
+
sym != sym_amp) rb_ary_push(ary, RARRAY_AREF(e, 1));
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
return ary;
|
165
|
+
}
|
166
|
+
#endif
|
167
|
+
|
168
|
+
#ifdef HAVE_RB_ISEQ_CODE_LOCATION
|
169
|
+
void rb_iseq_code_location(const struct rb_iseq *, int *first_lineno, int *first_column, int *last_lineno, int *last_column);
|
170
|
+
|
171
|
+
static VALUE
|
172
|
+
iseq_first_line(VALUE iseqw)
|
173
|
+
{
|
174
|
+
const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw);
|
175
|
+
int line;
|
176
|
+
rb_iseq_code_location(iseq, &line, NULL, NULL, NULL);
|
177
|
+
return INT2NUM(line);
|
178
|
+
}
|
179
|
+
|
180
|
+
static VALUE
|
181
|
+
iseq_last_line(VALUE iseqw)
|
182
|
+
{
|
183
|
+
const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw);
|
184
|
+
int line;
|
185
|
+
rb_iseq_code_location(iseq, NULL, NULL, &line, NULL);
|
186
|
+
return INT2NUM(line);
|
187
|
+
}
|
188
|
+
#endif
|
189
|
+
|
121
190
|
void Init_iseq_collector(void);
|
122
191
|
|
123
192
|
void
|
124
193
|
Init_debug(void)
|
125
194
|
{
|
195
|
+
VALUE rb_mRubyVM = rb_const_get(rb_cObject, rb_intern("RubyVM"));
|
196
|
+
VALUE rb_cISeq = rb_const_get(rb_mRubyVM, rb_intern("InstructionSequence"));
|
126
197
|
rb_mDebugger = rb_const_get(rb_cObject, rb_intern("DEBUGGER__"));
|
127
198
|
rb_cFrameInfo = rb_const_get(rb_mDebugger, rb_intern("FrameInfo"));
|
128
199
|
|
@@ -134,5 +205,18 @@ Init_debug(void)
|
|
134
205
|
rb_define_singleton_method(rb_mDebugger, "frame_depth", frame_depth, 0);
|
135
206
|
rb_define_singleton_method(rb_mDebugger, "create_method_added_tracker", create_method_added_tracker, 0);
|
136
207
|
rb_define_const(rb_mDebugger, "SO_VERSION", rb_str_new2(RUBY_DEBUG_VERSION));
|
208
|
+
|
209
|
+
// iseq
|
210
|
+
#ifdef HAVE_RB_ISEQ_TYPE
|
211
|
+
rb_define_method(rb_cISeq, "type", iseq_type, 0);
|
212
|
+
#endif
|
213
|
+
#ifdef HAVE_RB_ISEQ_PARAMETERS
|
214
|
+
rb_define_method(rb_cISeq, "parameters_symbols", iseq_parameters_symbols, 0);
|
215
|
+
#endif
|
216
|
+
#ifdef HAVE_RB_ISEQ_CODE_LOCATION
|
217
|
+
rb_define_method(rb_cISeq, "first_line", iseq_first_line, 0);
|
218
|
+
rb_define_method(rb_cISeq, "last_line", iseq_last_line, 0);
|
219
|
+
#endif
|
220
|
+
|
137
221
|
Init_iseq_collector();
|
138
222
|
}
|
data/ext/debug/extconf.rb
CHANGED
@@ -1,4 +1,15 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
require_relative '../../lib/debug/version'
|
3
3
|
File.write("debug_version.h", "#define RUBY_DEBUG_VERSION \"#{DEBUGGER__::VERSION}\"\n")
|
4
|
+
|
5
|
+
have_func "rb_iseq_parameters(NULL, 0)",
|
6
|
+
[["VALUE rb_iseq_parameters(void *, int is_proc);"]]
|
7
|
+
|
8
|
+
have_func "rb_iseq_code_location(NULL, NULL, NULL, NULL, NULL)",
|
9
|
+
[["void rb_iseq_code_location(void *, int *first_lineno, int *first_column, int *last_lineno, int *last_column);"]]
|
10
|
+
|
11
|
+
# from Ruby 3.1
|
12
|
+
have_func "rb_iseq_type(NULL)",
|
13
|
+
[["VALUE rb_iseq_type(void *);"]]
|
14
|
+
|
4
15
|
create_makefile 'debug/debug'
|
data/lib/debug/breakpoint.rb
CHANGED
@@ -8,9 +8,13 @@ module DEBUGGER__
|
|
8
8
|
|
9
9
|
attr_reader :key
|
10
10
|
|
11
|
-
def initialize do_enable
|
11
|
+
def initialize cond, command, path, do_enable: true
|
12
12
|
@deleted = false
|
13
13
|
|
14
|
+
@cond = cond
|
15
|
+
@command = command
|
16
|
+
@path = path
|
17
|
+
|
14
18
|
setup
|
15
19
|
enable if do_enable
|
16
20
|
end
|
@@ -82,8 +86,11 @@ module DEBUGGER__
|
|
82
86
|
end
|
83
87
|
|
84
88
|
def skip_path?(path)
|
85
|
-
|
89
|
+
case @path
|
90
|
+
when Regexp
|
86
91
|
!path.match?(@path)
|
92
|
+
when String
|
93
|
+
!path.include?(@path)
|
87
94
|
else
|
88
95
|
super
|
89
96
|
end
|
@@ -108,7 +115,7 @@ module DEBUGGER__
|
|
108
115
|
@oneshot = oneshot
|
109
116
|
@key = [:iseq, @iseq.path, @iseq.first_lineno].freeze
|
110
117
|
|
111
|
-
super()
|
118
|
+
super(nil, nil, nil)
|
112
119
|
end
|
113
120
|
|
114
121
|
def setup
|
@@ -127,20 +134,17 @@ module DEBUGGER__
|
|
127
134
|
attr_reader :path, :line, :iseq
|
128
135
|
|
129
136
|
def initialize path, line, cond: nil, oneshot: false, hook_call: true, command: nil
|
130
|
-
@path = path
|
131
137
|
@line = line
|
132
|
-
@cond = cond
|
133
138
|
@oneshot = oneshot
|
134
139
|
@hook_call = hook_call
|
135
|
-
@command = command
|
136
140
|
@pending = false
|
137
141
|
|
138
142
|
@iseq = nil
|
139
143
|
@type = nil
|
140
144
|
|
141
|
-
@key = [
|
145
|
+
@key = [path, @line].freeze
|
142
146
|
|
143
|
-
super()
|
147
|
+
super(cond, command, path)
|
144
148
|
|
145
149
|
try_activate
|
146
150
|
@pending = !@iseq
|
@@ -216,7 +220,7 @@ module DEBUGGER__
|
|
216
220
|
nearest = nil # NearestISeq
|
217
221
|
|
218
222
|
ObjectSpace.each_iseq{|iseq|
|
219
|
-
if (iseq.absolute_path || iseq.path)
|
223
|
+
if DEBUGGER__.compare_path((iseq.absolute_path || iseq.path), self.path) &&
|
220
224
|
iseq.first_lineno <= self.line &&
|
221
225
|
iseq.type != :ensure # ensure iseq is copied (duplicated)
|
222
226
|
|
@@ -277,11 +281,7 @@ module DEBUGGER__
|
|
277
281
|
@key = [:catch, @pat].freeze
|
278
282
|
@last_exc = nil
|
279
283
|
|
280
|
-
|
281
|
-
@command = command
|
282
|
-
@path = path
|
283
|
-
|
284
|
-
super()
|
284
|
+
super(cond, command, path)
|
285
285
|
end
|
286
286
|
|
287
287
|
def setup
|
@@ -314,29 +314,28 @@ module DEBUGGER__
|
|
314
314
|
end
|
315
315
|
|
316
316
|
class CheckBreakpoint < Breakpoint
|
317
|
-
def initialize
|
318
|
-
@
|
319
|
-
@key = [:check, @expr].freeze
|
320
|
-
@path = path
|
317
|
+
def initialize cond:, command: nil, path: nil
|
318
|
+
@key = [:check, cond].freeze
|
321
319
|
|
322
|
-
super()
|
320
|
+
super(cond, command, path)
|
323
321
|
end
|
324
322
|
|
325
323
|
def setup
|
326
324
|
@tp = TracePoint.new(:line){|tp|
|
327
|
-
next if
|
328
|
-
next if tp.path.start_with? '<internal:'
|
325
|
+
next if SESSION.in_subsession? # TODO: Ractor support
|
329
326
|
next if ThreadClient.current.management?
|
330
327
|
next if skip_path?(tp.path)
|
331
328
|
|
332
|
-
if safe_eval tp.binding, @
|
329
|
+
if safe_eval tp.binding, @cond
|
333
330
|
suspend
|
334
331
|
end
|
335
332
|
}
|
336
333
|
end
|
337
334
|
|
338
335
|
def to_s
|
339
|
-
"#{generate_label("Check")}
|
336
|
+
s = "#{generate_label("Check")}"
|
337
|
+
s += super
|
338
|
+
s
|
340
339
|
end
|
341
340
|
end
|
342
341
|
|
@@ -348,10 +347,7 @@ module DEBUGGER__
|
|
348
347
|
|
349
348
|
@current = current
|
350
349
|
|
351
|
-
|
352
|
-
@command = command
|
353
|
-
@path = path
|
354
|
-
super()
|
350
|
+
super(cond, command, path)
|
355
351
|
end
|
356
352
|
|
357
353
|
def watch_eval(tp)
|
@@ -374,9 +370,6 @@ module DEBUGGER__
|
|
374
370
|
|
375
371
|
def setup
|
376
372
|
@tp = TracePoint.new(:line, :return, :b_return){|tp|
|
377
|
-
next if tp.path.start_with? __dir__
|
378
|
-
next if tp.path.start_with? '<internal:'
|
379
|
-
|
380
373
|
watch_eval(tp)
|
381
374
|
}
|
382
375
|
end
|
@@ -404,13 +397,10 @@ module DEBUGGER__
|
|
404
397
|
|
405
398
|
@klass = nil
|
406
399
|
@method = nil
|
407
|
-
@cond = cond
|
408
400
|
@cond_class = nil
|
409
|
-
@command = command
|
410
|
-
@path = path
|
411
401
|
@key = "#{klass_name}#{op}#{method_name}".freeze
|
412
402
|
|
413
|
-
super(false)
|
403
|
+
super(cond, command, path, do_enable: false)
|
414
404
|
end
|
415
405
|
|
416
406
|
def setup
|
@@ -419,7 +409,6 @@ module DEBUGGER__
|
|
419
409
|
next if @cond_class && !tp.self.kind_of?(@cond_class)
|
420
410
|
|
421
411
|
caller_location = caller_locations(2, 1).first.to_s
|
422
|
-
next if caller_location.start_with?(__dir__)
|
423
412
|
next if skip_path?(caller_location)
|
424
413
|
|
425
414
|
suspend
|
data/lib/debug/client.rb
CHANGED
@@ -18,6 +18,10 @@ module DEBUGGER__
|
|
18
18
|
case name
|
19
19
|
when 'gen-sockpath'
|
20
20
|
puts DEBUGGER__.create_unix_domain_socket_name
|
21
|
+
when 'gen-portpath'
|
22
|
+
port_path = File.join(DEBUGGER__.unix_domain_socket_dir, 'tcp_port')
|
23
|
+
File.unlink port_path if File.exist?(port_path)
|
24
|
+
puts port_path
|
21
25
|
when 'list-socks'
|
22
26
|
cleanup_unix_domain_sockets
|
23
27
|
puts list_connections
|
@@ -76,7 +80,7 @@ module DEBUGGER__
|
|
76
80
|
|
77
81
|
def cleanup_unix_domain_sockets
|
78
82
|
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*') do |file|
|
79
|
-
if
|
83
|
+
if File.socket?(file) && (/-(\d+)-\d+$/ =~ file || /-(\d+)$/ =~ file)
|
80
84
|
begin
|
81
85
|
Process.kill(0, $1.to_i)
|
82
86
|
rescue Errno::EPERM
|
@@ -88,7 +92,9 @@ module DEBUGGER__
|
|
88
92
|
end
|
89
93
|
|
90
94
|
def list_connections
|
91
|
-
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*')
|
95
|
+
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*').find_all do |path|
|
96
|
+
File.socket?(path)
|
97
|
+
end
|
92
98
|
end
|
93
99
|
end
|
94
100
|
|
@@ -175,7 +181,7 @@ module DEBUGGER__
|
|
175
181
|
trap(:SIGWINCH){
|
176
182
|
@width = IO.console_size[1]
|
177
183
|
}
|
178
|
-
rescue ArgumentError
|
184
|
+
rescue ArgumentError
|
179
185
|
@width = 80
|
180
186
|
end
|
181
187
|
|