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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 121cdb1003971d234dbeb40878f693d06053fa32f28024c5d2a7c0e0fd6d3719
4
- data.tar.gz: fd95c68d4bf99b38a83cef1a6851680bb9abb65d39fa9fc69a94d248295a5829
3
+ metadata.gz: cb9c418ee481ed3b473973d522bb811949f6123501709d3385d9b2bf2a46d993
4
+ data.tar.gz: d0036bac1930ec7e920e9faeb66556a4a9132342ed604a909e15f9d02b4d6963
5
5
  SHA512:
6
- metadata.gz: 4354a11670db6e0fd49e4b8151b268a08c7843c80ccd36b5c492cf5fabc7b42c6632939905b9912c81434f5513e36dac8378686b5d47c274248c523eea88a0c8
7
- data.tar.gz: e22274473f567bed800c25d46a46d32adf263f070e8147cd71778ef9cbd95b8e239e2912b226892f032266a92322045a62e7f9c908f176e601a984e254acd2a7
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 test
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/debug/bp_test.rb # run all tests in the specified file
25
- $ ruby test/debug/bp_test.rb -h # to see all the test options
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
- Sends request to rdbg to set exception breakpoints.
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: nil)
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
- Passes if result of `expression` is equal to `expected`.
400
+ `assert_repl_result({value: '2', type: 'Integer'}, 'a')`
354
401
 
355
- - assert_repl_result(expected, expression: nil)
402
+ NOTE: `value` and `type` need to be strings.
356
403
 
357
- Passes if result of `expression` is equal to `expected`.
404
+ - assert_watch_result(expected, expression)
358
405
 
359
- - assert_watch_result(expected, expression: nil)
406
+ Passes if result of `expression` matches `expected`.
360
407
 
361
- Passes if result of `expression` is equal to `expected`.
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 frontend
15
- * VSCode/DAP ([VSCode rdbg Ruby Debugger - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg))
16
- * Chrome DevTools
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 two ways to invoke a script as remote debuggee: Use `rdbg --open` and require `debug/open` (or `debug/open_nonstop`).
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 lines)
460
- * `RUBY_DEBUG_SHOW_FRAMES` (`show_frames`): Show n frames on breakpoint (default: 2 frames)
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 (default: [])
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: disabled)
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: 10,000)
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 (localhost if not given)
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', :test]
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 :test_protocol do
29
- ENV['RUBY_DEBUG_PROTOCOL_TEST'] = '1'
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.2.7"
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
- case config[:mode]
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'] = "-r #{libpath}/#{start_mode}"
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.update 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
- 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);"]]
6
+ if defined? RubyVM
7
+ $defs << '-DHAVE_RB_ISEQ_PARAMETERS'
8
+ $defs << '-DHAVE_RB_ISEQ_CODE_LOCATION'
10
9
 
11
- # from Ruby 3.1
12
- have_func "rb_iseq_type(NULL)",
13
- [["VALUE rb_iseq_type(void *);"]]
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'
@@ -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 initialize path, line, cond: nil, oneshot: false, hook_call: true, command: nil
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 actiavated
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 try_activate
220
- nearest = nil # NearestISeq
221
-
222
- ObjectSpace.each_iseq{|iseq|
223
- if DEBUGGER__.compare_path((iseq.absolute_path || iseq.path), self.path) &&
224
- iseq.first_lineno <= self.line &&
225
- iseq.type != :ensure # ensure iseq is copied (duplicated)
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
- iseq.traceable_lines_norec(line_events = {})
228
- lines = line_events.keys.sort
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
- if !lines.empty? && lines.last >= line
231
- nline = lines.bsearch{|l| line <= l}
232
- events = line_events[nline]
253
+ if !lines.empty? && lines.last >= line
254
+ nline = lines.bsearch{|l| line <= l}
255
+ events = line_events[nline]
233
256
 
234
- next if events == [:RUBY_EVENT_B_CALL]
257
+ next if events == [:RUBY_EVENT_B_CALL]
235
258
 
236
- if @hook_call &&
237
- events.include?(:RUBY_EVENT_CALL) &&
238
- self.line == iseq.first_lineno
239
- nline = iseq.first_lineno
240
- end
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
- if !nearest || ((line - nline).abs < (line - nearest.line).abs)
243
- nearest = NearestISeq.new(iseq, nline, events)
244
- else
245
- if @hook_call && nearest.iseq.first_lineno <= iseq.first_lineno
246
- if (nearest.line > line && !nearest.events.include?(:RUBY_EVENT_CALL)) ||
247
- (events.include?(:RUBY_EVENT_CALL))
248
- nearest = NearestISeq.new(iseq, nline, events)
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 tp.binding, @cond
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} width: #{@width} cookie: #{CONFIG[:cookie]}"
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
- line = readline
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