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 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