debug 1.0.0.beta5 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,242 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DEBUGGER__
4
+ class Tracer
5
+ include SkipPathHelper
6
+ include Color
7
+
8
+ def colorize(str, color)
9
+ # don't colorize trace sent into a file
10
+ if @into
11
+ str
12
+ else
13
+ super
14
+ end
15
+ end
16
+
17
+ attr_reader :type
18
+
19
+ def initialize ui, pattern: nil, into: nil
20
+ if /\ADEBUGGER__::(([A-Z][a-z]+?)[A-Z][a-z]+)/ =~ self.class.name
21
+ @name = $1
22
+ @type = $2.downcase
23
+ end
24
+
25
+ setup
26
+
27
+ if pattern
28
+ @pattern = Regexp.compile(pattern)
29
+ else
30
+ @pattern = nil
31
+ end
32
+
33
+ if @into = into
34
+ @output = File.open(into, 'w')
35
+ @output.puts "PID:#{Process.pid} #{self}"
36
+ else
37
+ @output = ui
38
+ end
39
+
40
+ enable
41
+ end
42
+
43
+ def header depth
44
+ "DEBUGGER (trace/#{@type}) \#th:#{Thread.current.instance_variable_get(:@__thread_client_id)} \#depth:#{'%-2d'%depth}"
45
+ end
46
+
47
+ def enable
48
+ @tracer.enable
49
+ end
50
+
51
+ def disable
52
+ @tracer.disable
53
+ end
54
+
55
+ def description
56
+ nil
57
+ end
58
+
59
+ def to_s
60
+ s = "#{@name}#{description} (#{@tracer.enabled? ? 'enabled' : 'disabled'})"
61
+ s += " with pattern #{@pattern.inspect}" if @pattern
62
+ s += " into: #{@into}" if @into
63
+ s
64
+ end
65
+
66
+ def skip? tp
67
+ if tp.path.start_with?(__dir__) ||
68
+ tp.path.start_with?('<internal:') ||
69
+ ThreadClient.current.management? ||
70
+ skip_path?(tp.path) ||
71
+ skip_with_pattern?(tp)
72
+ true
73
+ else
74
+ false
75
+ end
76
+ end
77
+
78
+ def skip_with_pattern?(tp)
79
+ @pattern && !tp.path.match?(@pattern)
80
+ end
81
+
82
+ def out tp, msg = nil, depth = caller.size - 1
83
+ location_str = colorize("#{tp.path}:#{tp.lineno}", [:GREEN])
84
+ buff = "#{header(depth)}#{msg} at #{location_str}"
85
+
86
+ if false # TODO: Ractor.main?
87
+ ThreadClient.current.on_trace self.object_id, buff
88
+ else
89
+ @output.puts buff
90
+ end
91
+ end
92
+
93
+ def puts msg
94
+ @output.puts msg
95
+ end
96
+
97
+ def minfo tp
98
+ klass = tp.defined_class
99
+
100
+ if klass.singleton_class?
101
+ "#{tp.self}.#{tp.method_id}"
102
+ else
103
+ "#{klass}\##{tp.method_id}"
104
+ end
105
+ end
106
+ end
107
+
108
+ class LineTracer < Tracer
109
+ def setup
110
+ @tracer = TracePoint.new(:line){|tp|
111
+ next if skip?(tp)
112
+ # pp tp.object_id, caller(0)
113
+ out tp
114
+ }
115
+ end
116
+ end
117
+
118
+ class CallTracer < Tracer
119
+ def setup
120
+ @tracer = TracePoint.new(:a_call, :a_return){|tp|
121
+ next if skip?(tp)
122
+
123
+ depth = caller.size
124
+ sp = ' ' * depth
125
+
126
+ call_identifier_str =
127
+ if tp.defined_class
128
+ minfo(tp)
129
+ else
130
+ "block"
131
+ end
132
+
133
+ call_identifier_str = colorize_blue(call_identifier_str)
134
+
135
+ case tp.event
136
+ when :call, :c_call, :b_call
137
+ depth += 1 if tp.event == :c_call
138
+ out tp, ">#{sp}#{call_identifier_str}", depth
139
+ when :return, :c_return, :b_return
140
+ depth += 1 if tp.event == :c_return
141
+ return_str = colorize_magenta(DEBUGGER__.short_inspect(tp.return_value))
142
+ out tp, "<#{sp}#{call_identifier_str} #=> #{return_str}", depth
143
+ end
144
+ }
145
+ end
146
+
147
+ def skip_with_pattern?(tp)
148
+ super && !tp.method_id&.match?(@pattern)
149
+ end
150
+ end
151
+
152
+ class ExceptionTracer < Tracer
153
+ def setup
154
+ @tracer = TracePoint.new(:raise) do |tp|
155
+ next if skip?(tp)
156
+
157
+ exc = tp.raised_exception
158
+
159
+ out tp, " #{colorize_magenta(exc.inspect)}"
160
+ rescue Exception => e
161
+ p e
162
+ end
163
+ end
164
+
165
+ def skip_with_pattern?(tp)
166
+ super && !tp.raised_exception.inspect.match?(@pattern)
167
+ end
168
+ end
169
+
170
+ class ObjectTracer < Tracer
171
+ def initialize ui, obj_id, obj_inspect, **kw
172
+ @obj_id = obj_id
173
+ @obj_inspect = obj_inspect
174
+ super(ui, **kw)
175
+ end
176
+
177
+ def description
178
+ " for #{@obj_inspect}"
179
+ end
180
+
181
+ def colorized_obj_inspect
182
+ colorize_magenta(@obj_inspect)
183
+ end
184
+
185
+ def setup
186
+ @tracer = TracePoint.new(:a_call){|tp|
187
+ next if skip?(tp)
188
+
189
+ if tp.self.object_id == @obj_id
190
+ klass = tp.defined_class
191
+ method = tp.method_id
192
+ method_info =
193
+ if klass.singleton_class?
194
+ if tp.self.is_a?(Class)
195
+ ".#{method} (#{klass}.#{method})"
196
+ else
197
+ ".#{method}"
198
+ end
199
+ else
200
+ "##{method} (#{klass}##{method})"
201
+ end
202
+
203
+ out tp, " #{colorized_obj_inspect} receives #{colorize_blue(method_info)}"
204
+ else
205
+ b = tp.binding
206
+ method_info = colorize_blue(minfo(tp))
207
+
208
+ tp.parameters.each{|type, name|
209
+ next unless name
210
+
211
+ colorized_name = colorize_cyan(name)
212
+
213
+ case type
214
+ when :req, :opt, :key, :keyreq
215
+ if b.local_variable_get(name).object_id == @obj_id
216
+ out tp, " #{colorized_obj_inspect} is used as a parameter #{colorized_name} of #{method_info}"
217
+ end
218
+ when :rest
219
+ next name == :"*"
220
+
221
+ ary = b.local_variable_get(name)
222
+ ary.each{|e|
223
+ if e.object_id == @obj_id
224
+ out tp, " #{colorized_obj_inspect} is used as a parameter in #{colorized_name} of #{method_info}"
225
+ end
226
+ }
227
+ when :keyrest
228
+ next if name == :'**'
229
+ h = b.local_variable_get(name)
230
+ h.each{|k, e|
231
+ if e.object_id == @obj_id
232
+ out tp, " #{colorized_obj_inspect} is used as a parameter in #{colorized_name} of #{method_info}"
233
+ end
234
+ }
235
+ end
236
+ }
237
+ end
238
+ }
239
+ end
240
+ end
241
+ end
242
+
data/lib/debug/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DEBUGGER__
2
- VERSION = "1.0.0.beta5"
4
+ VERSION = "1.0.0.rc1"
3
5
  end
data/lib/debug.rb CHANGED
@@ -1 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'debug/session'
4
+ DEBUGGER__::start no_sigint_hook: true, nonstop: true
data/misc/README.md.erb CHANGED
@@ -11,8 +11,8 @@ New debug.rb has several advantages:
11
11
  * Remote debugging: Support remote debugging natively.
12
12
  * UNIX domain socket
13
13
  * TCP/IP
14
- * VSCode/DAP integration (TODO)
15
- * Extensible: application can introduce debugging support with several methods
14
+ * VSCode/DAP integration ([VSCode rdbg Ruby Debugger - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg))
15
+ * Extensible: application can introduce debugging support with several ways:
16
16
  * By `rdbg` command
17
17
  * By loading libraries with `-r` command line option
18
18
  * By calling Ruby's method explicitly
@@ -20,6 +20,7 @@ New debug.rb has several advantages:
20
20
  * Support threads (almost done) and ractors (TODO).
21
21
  * Support suspending and entering to the console debugging with `Ctrl-C` at most of timing.
22
22
  * Show parameters on backtrace command.
23
+ * Support recording & reply debugging.
23
24
 
24
25
  # Installation
25
26
 
@@ -29,309 +30,432 @@ $ gem install debug --pre
29
30
 
30
31
  or specify `-Ipath/to/debug/lib` in `RUBYOPT` or each ruby command-line option, especially for debug this gem development.
31
32
 
32
- # How to use
33
+ If you use Bundler, write the following line to your Gemfile.
34
+
35
+ ```
36
+ gem "debug", ">= 1.0.0.rc"
37
+ ```
38
+
39
+ # HOW TO USE
40
+
41
+ To use a debugger, roughly you will do the following steps:
42
+
43
+ 1. Set breakpoints.
44
+ 2. Run a program with the debugger.
45
+ 3. At the breakpoint, enter the debugger console.
46
+ 4. Use debug commands.
47
+ * Query the program status (e.g. `p lvar` to see the local variable `lvar`).
48
+ * Control program flow (e.g. move to the another line with `step`, to the next line with `next`).
49
+ * Set another breakpoint (e.g. `catch Exception` to set a breakpoint when `Exception` is raised).
50
+ * Change the configuration (e.g. `config set no_color true` to disable coloring).
51
+ * Continue the program (`c` or `continue`) and goto 3.
52
+
53
+ ## Invoke with the debugger
54
+
55
+ There are several options for (1) and (2). Please choose your favorite way.
56
+
57
+ ### Modify source code as `binding.pry` and `binding.irb`
58
+
59
+ If you can modify the source code, you can use the debugger by adding `require 'debug'` line at the top of your program and putting `binding.break` method (`binding.b` for short) into lines where you want to stop as breakpoints like `binding.pry` and `binding.irb`.
60
+ After that, you run the program as usual and you will enter the debug console at breakpoints you inserted.
61
+
62
+ The following example shows the demonstration of `binding.break`.
63
+
64
+ ```shell
65
+ $ cat target.rb # Sample program
66
+ require 'debug'
67
+
68
+ a = 1
69
+ b = 2
70
+ binding.break # Program will stop here
71
+ c = 3
72
+ d = 4
73
+ binding.break # Program will stop here
74
+ p [a, b, c, d]
75
+
76
+ $ ruby target.rb # Run the program normally.
77
+ DEBUGGER: Session start (pid: 7604)
78
+ [1, 10] in target.rb
79
+ 1| require 'debug'
80
+ 2|
81
+ 3| a = 1
82
+ 4| b = 2
83
+ => 5| binding.break # Now you can see it stops at this line
84
+ 6| c = 3
85
+ 7| d = 4
86
+ 8| binding.break
87
+ 9| p [a, b, c, d]
88
+ 10|
89
+ =>#0 <main> at target.rb:5
90
+
91
+ (rdbg) info locals # You can show local variables
92
+ =>#0 <main> at target.rb:5
93
+ %self => main
94
+ a => 1
95
+ b => 2
96
+ c => nil
97
+ d => nil
98
+
99
+ (rdbg) continue # Continue the execution
100
+ [3, 11] in target.rb
101
+ 3| a = 1
102
+ 4| b = 2
103
+ 5| binding.break
104
+ 6| c = 3
105
+ 7| d = 4
106
+ => 8| binding.break # Again the program stops at here
107
+ 9| p [a, b, c, d]
108
+ 10|
109
+ 11| __END__
110
+ =>#0 <main> at target.rb:8
111
+
112
+ (rdbg) info locals # And you can see the updated local variables
113
+ =>#0 <main> at target.rb:8
114
+ %self => main
115
+ a => 1
116
+ b => 2
117
+ c => 3
118
+ d => 4
119
+
120
+ (rdbg) continue
121
+ [1, 2, 3, 4]
122
+ ```
123
+
124
+ ### Invoke the program from the debugger as a traditional debuggers
125
+
126
+ If you don't want to modify the source code, you can set breakpoints with a debug command `break` (`b` for short).
127
+ Using `rdbg` command to launch the program without any modifications, you can run the program with the debugger.
128
+
129
+ ```shell
130
+ $ cat target.rb # Sample program
131
+ a = 1
132
+ b = 2
133
+ c = 3
134
+ d = 4
135
+ p [a, b, c, d]
136
+
137
+ $ rdbg target.rb # run like `ruby target.rb`
138
+ DEBUGGER: Session start (pid: 7656)
139
+ [1, 7] in target.rb
140
+ => 1| a = 1
141
+ 2| b = 2
142
+ 3| c = 3
143
+ 4| d = 4
144
+ 5| p [a, b, c, d]
145
+ 6|
146
+ 7| __END__
147
+ =>#0 <main> at target.rb:1
33
148
 
34
- ## Invoke with debugger
149
+ (rdbg)
150
+ ```
35
151
 
36
- You can run ruby program on debugger with the local debug console or the remote debug console.
152
+ `rdbg` command suspends the program at the beginning of the given script (`target.rb` in this case) and you can use debug commands. `(rdbg)` is prompt. Let's set breakpoints on line 3 and line 5 with `break` command (`b` for short).
37
153
 
38
- * (a) Run a ruby program with the local debug console
39
- * (b) Run a ruby program with the remote debug console by opening a network port
40
- * (b-1) Open with UNIX domain socket
41
- * (b-2) Open with TCP/IP port
154
+ ```shell
155
+ (rdbg) break 3 # set breakpoint at line 3
156
+ #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line)
42
157
 
43
- (b-1) is useful when you want to use debugging features after running the program.
44
- (b-2) is also useful when you don't have a ssh access for the Ruby process.
158
+ (rdbg) b 5 # set breakpoint at line 5
159
+ #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line)
45
160
 
46
- To use debugging feature, you can have 3 ways.
161
+ (rdbg) break # show all registered breakpoints
162
+ #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line)
163
+ #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line)
164
+ ```
47
165
 
48
- * (1) Use `rdbg` command
49
- * (2) Use `ruby -r debug...` command line option
50
- * (3) Write `require 'debug...'` in .rb files
166
+ You can see that two breakpoints are registered. Let's continue the program by `continue` command.
51
167
 
52
- ### Local debug console
168
+ ```shell
169
+ (rdbg) continue
170
+ [1, 7] in target.rb
171
+ 1| a = 1
172
+ 2| b = 2
173
+ => 3| c = 3
174
+ 4| d = 4
175
+ 5| p [a, b, c, d]
176
+ 6|
177
+ 7| __END__
178
+ =>#0 <main> at target.rb:3
53
179
 
54
- #### (1) Use `rdbg` command
180
+ Stop by #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line)
55
181
 
56
- ```
57
- $ rdbg target.rb
58
- $ rdbg -- -r foo -e expr # -- is required to make clear rdbg options and ruby's options
182
+ (rdbg)
59
183
  ```
60
184
 
61
- #### (2) Use `-r debug/run` command line option
185
+ You can see that we can stop at line 3.
186
+ Let's see the local variables with `info` command, and continue.
187
+ You can also confirm that the program will suspend at line 5 and you can use `info` command again.
62
188
 
63
- ```
64
- $ ruby -r debug/run target.rb
65
- ```
189
+ ```shell
190
+ (rdbg) info
191
+ =>#0 <main> at target.rb:3
192
+ %self => main
193
+ a => 1
194
+ b => 2
195
+ c => nil
196
+ d => nil
66
197
 
67
- #### (3) Write `require 'debug...'` in .rb files
198
+ (rdbg) continue
199
+ [1, 7] in target.rb
200
+ 1| a = 1
201
+ 2| b = 2
202
+ 3| c = 3
203
+ 4| d = 4
204
+ => 5| p [a, b, c, d]
205
+ 6|
206
+ 7| __END__
207
+ =>#0 <main> at target.rb:5
68
208
 
69
- ```ruby
70
- # target.rb
71
- require 'debug/run' # start the debug console
209
+ Stop by #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line)
72
210
 
73
- # or
211
+ (rdbg) info
212
+ =>#0 <main> at target.rb:5
213
+ %self => main
214
+ a => 1
215
+ b => 2
216
+ c => 3
217
+ d => 4
74
218
 
75
- require 'debug/session' # introduce the functionality
76
- DEBUGGER__.console # and start the debug console
77
- # ... rest of program ...
219
+ (rdbg) continue
220
+ [1, 2, 3, 4]
78
221
  ```
79
222
 
80
- ```
81
- $ ruby target.rb
82
- ```
223
+ By the way, using `rdbg` command you can suspend your application with `C-c` (SIGINT) and enter the debug console.
224
+ It will help that if you want to know what the program is doing.
83
225
 
84
- When you run the program with the debug console, you will see the debug console prompt `(rdbg)`.
85
- The debuggee program (`target.rb`) is suspended at the beginning of `target.rb`.
226
+ ### Use `rdbg` with commands written in Ruby
86
227
 
87
- You can type any debugger's command described bellow. "c" or "continue" resume the debuggee program.
88
- You can suspend the debuggee program and show the debug console with `Ctrl-C`.
228
+ If you want to run a command written in Ruby like like `rake`, `rails`, `bundle`, `rspec` and so on, you can use `rdbg -c` option.
89
229
 
90
- The following example shows simple usage of the debug console. You can show the all variables
230
+ * Without `-c` option, `rdbg <name>` means that `<name>` is Ruby script and invoke it like `ruby <name>` with the debugger.
231
+ * With `-c` option, `rdbg -c <name>` means that `<name>` is command in `PATH` and simply invoke it with the debugger.
91
232
 
92
- ```
93
- $ rdbg ~/src/rb/target.rb
233
+ Examples:
234
+ * `rdbg -c -- rails server`
235
+ * `rdbg -c -- bundle exec ruby foo.rb`
236
+ * `rdbg -c -- bundle exec rake test`
237
+ * `rdbg -c -- ruby target.rb` is same as `rdbg target.rb`
94
238
 
95
- [1, 5] in /home/ko1/src/rb/target.rb
96
- => 1| a = 1
97
- 2| b = 2
98
- 3| c = 3
99
- 4| p [a + b + c]
100
- 5|
101
- --> #0 /home/ko1/src/rb/target.rb:1:in `<main>'
239
+ NOTE: `--` is needed to separate the command line options for `rdbg` and invoking command. For example, `rdbg -c rake -T` is recognized like `rdbg -c -T -- rake`. It should be `rdbg -c -- rake -T`.
102
240
 
103
- (rdbg) info # Show all local variables
104
- %self => main
105
- a => nil
106
- b => nil
107
- c => nil
241
+ NOTE: If you want to use bundler (`bundle` command), you need to write `gem debug` line in your `Gemfile`.
108
242
 
109
- (rdbg) p a # Same as p(a)
110
- => nil
243
+ ### Using VSCode
111
244
 
112
- (rdbg) s # Step in ("s" is a short name of "step")
245
+ Like other languages, you can use this debugger on the VSCode.
113
246
 
114
- [1, 5] in /home/ko1/src/rb/target.rb
115
- 1| a = 1
116
- => 2| b = 2
117
- 3| c = 3
118
- 4| p [a + b + c]
119
- 5|
120
- --> #0 /home/ko1/src/rb/target.rb:2:in `<main>'
247
+ 1. Install [VSCode rdbg Ruby Debugger - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg)
248
+ 2. Open `.rb` file (e.g. `target.rb`)
249
+ 3. Register breakpoints with "Toggle breakpoint" in Run menu (or type F9 key)
250
+ 4. Choose "Start debugging" in "Run" menu (or type F5 key)
251
+ 5. You will see a dialog "Debug command line" and you can choose your favorite command line your want to run.
252
+ 6. Chosen command line is invoked with `rdbg -c` and VSCode shows the details at breakpoints.
121
253
 
122
- (rdbg) <Enter> # Repeat the last command ("step")
254
+ Please refer [Debugging in Visual Studio Code](https://code.visualstudio.com/docs/editor/debugging) for operations on VSCode.
123
255
 
124
- [1, 5] in /home/ko1/src/rb/target.rb
125
- 1| a = 1
126
- 2| b = 2
127
- => 3| c = 3
128
- 4| p [a + b + c]
129
- 5|
130
- --> #0 /home/ko1/src/rb/target.rb:3:in `<main>'
256
+ You can configure the extension in `.vscode/launch.json`.
257
+ Please see the extension page for more details.
131
258
 
132
- (rdbg) # Repeat the last command ("step")
259
+ ## Remote debugging
133
260
 
134
- [1, 5] in /home/ko1/src/rb/target.rb
135
- 1| a = 1
136
- 2| b = 2
137
- 3| c = 3
138
- => 4| p [a + b + c]
139
- 5|
140
- --> #0 /home/ko1/src/rb/target.rb:4:in `<main>'
141
-
142
- (rdbg) info # Show all local variables
143
- %self => main
144
- a => 1
145
- b => 2
146
- c => 3
147
-
148
- (rdbg) c # Continue the program ("c" is a short name of "continue")
149
- [6]
150
- ```
261
+ You can use this debugger as a remote debugger. For example, it will help the following situations:
151
262
 
152
- ### Remote debug (1) UNIX domain socket
263
+ * Your application does not run on TTY and it is hard to use `binding.pry` or `binding.irb`.
264
+ * Your application is running on Docker container and there is no TTY.
265
+ * Your application is running as a daemon.
266
+ * Your application uses pipe for STDIN or STDOUT.
267
+ * Your application is running as a daemon and you want to query the running status (checking a backtrace and so on).
153
268
 
154
- #### (1) Use `rdbg` command
269
+ You can run your application as a remote debuggee and the remote debugger console can attach to the debuggee anytime.
155
270
 
156
- ```
157
- $ rdbg --open target.rb # or rdbg -O target.rb for shorthand
158
- Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-5042)
159
- ```
271
+ ### Invoke as a remote debuggee
160
272
 
161
- #### (2) Use `-r debug/open` command line option
273
+ There are two ways to invoke a script as remote debuggee: Use `rdbg --open` and require `debug/open` (or `debug/open_nonstop`).
162
274
 
163
- ```
164
- $ ruby -r debug/open target.rb
165
- Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-5042)
275
+ #### `rdbg --open` (or `rdbg -O` for short)
276
+
277
+ You can run a script with `rdbg --open target.rb` command and run a `target.rb` as a debuggee program. It also opens the network port and suspends at the beginning of `target.rb`.
278
+
279
+ ```shell
280
+ $ exe/rdbg --open target.rb
281
+ DEBUGGER: Session start (pid: 7773)
282
+ DEBUGGER: Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773)
283
+ DEBUGGER: wait for debugger connection...
166
284
  ```
167
285
 
168
- #### (3) Write `require 'debug/open'` in .rb files
286
+ By default, `rdbg --open` uses UNIX domain socket and generates path name automatically (`/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773` in this case).
169
287
 
170
- ```ruby
171
- # target.rb
172
- require 'debug/open' # open the debugger entry point by UNIX domain socket.
288
+ You can connect to the debuggee with `rdbg --attach` command (`rdbg -A` for short).
173
289
 
174
- # or
290
+ ```shell
291
+ $ rdbg -A
292
+ [1, 7] in target.rb
293
+ => 1| a = 1
294
+ 2| b = 2
295
+ 3| c = 3
296
+ 4| d = 4
297
+ 5| p [a, b, c, d]
298
+ 6|
299
+ 7| __END__
300
+ =>#0 <main> at target.rb:1
175
301
 
176
- require 'debug/server' # introduce remote debugging feature
177
- DEBUGGER__.open # open the debugger entry point by UNIX domain socket.
178
- # or DEBUGGER__.open_unix to specify UNIX domain socket.
302
+ (rdbg:remote)
179
303
  ```
180
304
 
181
- ```
182
- $ ruby target.rb
183
- Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-5042)
184
- ```
305
+ If there is no other opening ports on the default directory, `rdbg --attach` command chooses the only one opening UNIX domain socket and connect to it. If there are more files, you need to specify the file.
185
306
 
186
- It runs target.rb and accept debugger connection within UNIX domain socket.
187
- The debuggee process waits for debugger connection at the beginning of `target.rb` like that:
307
+ When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program and so on) like local debug console. When an debuggee program exits, the remote console will also terminate.
188
308
 
189
- ```
190
- $ rdbg -O ~/src/rb/target.rb
191
- DEBUGGER: Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-29828)
192
- DEBUGGER: wait for debugger connection...
193
- ```
309
+ NOTE: If you use `quit` command, only remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command.
194
310
 
195
- You can attach the program with the following command:
311
+ If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`.
196
312
 
197
- ```
198
- $ rdbg --attach # or rdbg -A for shorthand
199
-
200
- [1, 4] in /home/ko1/src/rb/target.rb
201
- 1| (1..).each do |i|
202
- => 2| sleep 0.5
203
- 3| p i
204
- 4| end
205
- --> #0 [C] /home/ko1/src/rb/target.rb:2:in `sleep'
206
- #1 /home/ko1/src/rb/target.rb:2:in `block in <main>' {|i=17|}
207
- #2 [C] /home/ko1/src/rb/target.rb:1:in `each'
208
- # and 1 frames (use `bt' command for all frames)
209
-
210
- (rdb)
313
+ To connect to the debuggee, you need to specify the port.
314
+
315
+ ```shell
316
+ $ rdbg --attach 12345
211
317
  ```
212
318
 
213
- and you can input any debug commands. `c` (or `continue`) continues the debuggee process.
319
+ If you want to choose the host to bind, you can use `--host` option.
320
+ Note that all messages communicated between the debugger and the debuggee are *NOT* encrypted so please use remote debugging carefully.
214
321
 
215
- You can detach the debugger from the debugger process with `quit` command.
216
- You can re-connect to the debuggee process by `rdbg -A` command again, and the debuggee process suspends the execution (and debugger can input any debug commands).
322
+ #### `require 'debug/open'` in a program
217
323
 
218
- If you don't want to stop the debuggee process at the beginning of debuggee process (`target.rb`), you can use the following to specify "non-stop" option.
324
+ If you can modify the program, you can open debugging port by adding `require 'debug/open'` line in the program.
219
325
 
220
- * Use `rdbg -n` option
221
- * Set the environment variable `RUBY_DEBUG_NONSTOP=1`
326
+ If you don't want to stop the program at the beginning, you can also use `require 'debug/open_nonstop'`.
327
+ Using `debug/open_nonstop` is useful if you want to open a backdoor to the application.
328
+ However, it is also danger because it can become another vulnerability.
329
+ Please use it carefully.
222
330
 
223
- If you are running multiple debuggee processes, the attach command (`rdbg -A`) shows the options like that:
331
+ By default, UNIX domain socket is used for the debugging port. To use TCP/IP, you can set the `RUBY_DEBUG_PORT` environment variable.
224
332
 
333
+ ```shell
334
+ $ RUBY_DEBUG_PORT=12345 ruby target.rb
225
335
  ```
226
- $ rdbg --attach
227
- Please select a debug session:
228
- ruby-debug-ko1-19638
229
- ruby-debug-ko1-19603
230
- ```
231
336
 
232
- and you need to specify one (copy and paste the name):
337
+ ## Configuration
338
+
339
+ You can configure the debugger's behavior with debug commands and environment variables.
340
+ When the debug session is started, initial scripts are loaded so you can put your favorite configurations in the initial scripts.
341
+
342
+ ### Configuration list
343
+
344
+ You can configure debugger's behavior with environment variables and `config` command. Each configuration has environment variable and the name which can be specified by `config` command.
233
345
 
234
346
  ```
235
- $ rdbg --attach ruby-debug-ko1-19638
347
+ # configuration example
348
+ config set log_level INFO
349
+ config set no_color true
236
350
  ```
237
351
 
238
- The socket file is located at
239
- * `RUBY_DEBUG_SOCK_DIR` environment variable if available.
240
- * `XDG_RUNTIME_DIR` environment variable if available.
241
- * `$HOME/.ruby-debug-sock` if `$HOME` is available.
352
+ <% cat = nil; DEBUGGER__::CONFIG_SET.each do |key, (env, desc)| %>
353
+ <% /\A(\w+): (.+)/ =~ desc; if cat != $1; cat = 1 %>
354
+ * <%= $1 %>
355
+ <% cat = $1; end %> * `<%= env %>` (`<%= key %>`): <%= $2 %><% end %>
242
356
 
243
- ### Remote debug (2) TCP/IP
357
+ ### Initial scripts
244
358
 
245
- You can open the TCP/IP port instead of using UNIX domain socket.
359
+ If there is `~/.rdbgrc`, the file is loaded as an initial script (which contains debug commands) when the debug session is started.
246
360
 
247
- #### (1) Use `rdbg` command
361
+ * `RUBY_DEBUG_INIT_SCRIPT` environment variable can specify the initial script file.
362
+ * You can specify the initial script with `rdbg -x initial_script` (like gdb's `-x` option).
248
363
 
249
- ```
250
- $ rdbg -O --port=12345 target.rb
251
- # or
252
- $ rdbg --open --port=12345 target.rb
253
- Debugger can attach via TCP/IP (localhost:12345)
254
- ```
364
+ Initial scripts are useful to write your favorite configurations.
365
+ For example, you can set break points with `break file:123` in `~/.rdbgrc`.
255
366
 
256
- #### (2) Use `-r debug/open` command line option
367
+ If there are `~/.rdbgrc.rb` is available, it is also loaded as a ruby script at same timing.
257
368
 
369
+ ## Debug command on the debug console
258
370
 
259
- ```
260
- $ RUBY_DEBUG_PORT=12345 ruby -r debug/open target.rb
261
- Debugger can attach via TCP/IP (localhost:12345)
262
- ```
371
+ On the debug console, you can use the following debug commands.
263
372
 
264
- #### (3) Write `require 'debug/open'` in .rb files
373
+ * `Enter` repeats the last command (useful when repeating `step`s).
374
+ * `Ctrl-D` is equal to `quit` command.
375
+ * [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing)
265
376
 
266
- ```ruby
267
- # target.rb
268
- require 'debug/open' # open the debugger entry point.
269
- ```
377
+ You can use the following debug commands. Each command should be written in 1 line.
378
+ The `[...]` notation means this part can be eliminate. For example, `s[tep]` means `s` or `step` are valid command. `ste` is not valid.
379
+ The `<...>` notation means the argument.
270
380
 
271
- and run with environment variable RUBY_DEBUG_PORT
381
+ <%= DEBUGGER__.help %>
272
382
 
273
- ```
274
- $ RUBY_DEBUG_PORT=12345 ruby target.rb
275
- Debugger can attach via TCP/IP (localhost:12345)
276
- ```
383
+ ## Debugger API
277
384
 
278
- or
385
+ ### Start debugging
279
386
 
280
- ```ruby
281
- # target.rb
282
- require 'debug/server' # introduce remote debugging feature
283
- DEBUGGER__.open(port: 12345)
284
- # or DEBUGGER__.open_tcp(port: 12345)
285
- ```
387
+ #### Start by requiring a library
286
388
 
287
- ```
288
- $ ruby target.rb
289
- Debugger can attach via TCP/IP (localhost:12345)
290
- ```
389
+ You can start debugging without `rdbg` command by requiring the following libraries:
291
390
 
292
- You can also specify the host with the `RUBY_DEBUG_HOST` environment variable. And also `DEBUGGER__.open` method accepts a `host:` keyword parameter. If the host is not given, `localhost` will be used.
391
+ * `require 'debug'`: Same as `rdbg --nonstop --no-sigint-hook`.
392
+ * `require 'debug/start'`: Same as `rdbg`.
393
+ * `require 'debug/open'`: Same as `rdbg --open`.
394
+ * `require 'debug/open_nonstop'`: Same as `rdbg --open --nonstop`.
293
395
 
294
- To attach the debuggee process, specify the port number (and hostname if needed) for the `rdbg --attach` (or `rdbg -A`) command.
396
+ You need to require one of them at the very beginning of the application.
397
+ Using `ruby -r` (for example `ruby -r debug/start target.rb`) is another way to invoke with debugger.
295
398
 
296
- ```
297
- $ rdbg --attach 12345
298
- $ rdbg --attach hostname 12345
399
+ NOTE: Until Ruby 3.0, there is old `lib/debug.rb` standard library. So that if this gem is not installed, or if `Gemfile` missed to list this gem and `bundle exec` is used, you will see the following output:
400
+
401
+ ```shell
402
+ $ ruby -r debug -e0
403
+ .../2.7.3/lib/ruby/2.7.0/x86_64-linux/continuation.so: warning: callcc is obsolete; use Fiber instead
404
+ Debug.rb
405
+ Emacs support available.
406
+
407
+ .../2.7.3/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:162: if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?)
408
+ (rdb:1)
299
409
  ```
300
410
 
301
- ### Initial scripts
411
+ `lib/debug.rb` was not maintained well in recent years, and the purpose of this library is to rewrite old `lib/debug.rb` with recent techniques.
302
412
 
303
- If there are `.rdbgrc` files are there at the current directory and the home directory, files are loaded as initial scripts which contains debugger commands. `RUBY_DEBUG_INIT_SCRIPT` environment variable can specify the initial script file.
413
+ #### Start by method
304
414
 
305
- Initial scripts are evaluated at the first suspend timing (generally, it is the beginning of the target script). For example, you can set break points with `break file:123`.
415
+ After loading `debug/session`, you can start debug session with the following methods. They are convenient if you want to specify debug configurations in your program.
306
416
 
307
- If there are `.rdbgrc.rb` files at the current directory and the home directory, files are loaded as a ruby script at the initializing timing.
417
+ * `DEBUGGER__.start(**kw)`: start debug session with local console.
418
+ * `DEBUGGER__.open(**kw)`: open debug port with configuration (without configurations open with UNIX domain socket)
419
+ * `DEBUGGER__.open_unix(**kw)`: open debug port with UNIX domain socket
420
+ * `DEBUGGER__.open_tcp(**kw)`: open debug port with TCP/IP
308
421
 
309
- ### Environment variables
422
+ For example:
310
423
 
311
- You can control debuggee's behavior with environment variables:
424
+ ```ruby
425
+ require 'debug/session'
426
+ DEBUGGER__.start(no_color: true, # disable colorize
427
+ log_level: 'INFO') # Change log_level to INFO
312
428
 
313
- * `RUBY_DEBUG_NONSTOP`: 1 for nonstop at the beginning of program.
314
- * `RUBY_DEBUG_INIT_SCRIPT`: Initial script path loaded at the first stop.
315
- * `RUBY_DEBUG_COMMANDS`: Debug commands invoked at the first stop. Commands should be separated by ';;'.
316
- * `RUBY_DEBUG_SHOW_SRC_LINES`: Show n lines source code on breakpoint (default: 10 lines).
317
- * `RUBY_DEBUG_SHOW_FRAMES`: Show n frames on breakpoint (default: 2 frames).
318
- * Remote debugging
319
- * `RUBY_DEBUG_PORT`: TCP/IP remote debugging: port to open.
320
- * `RUBY_DEBUG_HOST`: TCP/IP remote debugging: host (localhost if not given) to open.
321
- * `RUBY_DEBUG_SOCK_PATH`: UNIX Domain Socket remote debugging: socket path to open.
322
- * `RUBY_DEBUG_SOCK_DIR`: UNIX Domain Socket remote debugging: socket directory to open.
429
+ ... # your application code
430
+ ```
323
431
 
324
- ## Debug command on the debug console
432
+ ### `binding.break` method
325
433
 
326
- * `Enter` repeats the last command (useful when repeating `step`s).
327
- * `Ctrl-D` is equal to `quit` command.
328
- * [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing)
434
+ `binding.break` (or `binding.b`) set breakpoints at written line. It also has several keywords.
329
435
 
330
- You can use the following debug commands. Each command should be written in 1 line.
331
- The `[...]` notation means this part can be eliminate. For example, `s[tep]` means `s` or `step` are valid command. `ste` is not valid.
332
- The `<...>` notation means the argument.
436
+ If `do: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command and continue the program.
437
+ It is useful if you only want to call a debug command and don't want to stop there.
333
438
 
334
- <%= DEBUGGER__.help %>
439
+ ```
440
+ def initialize
441
+ @a = 1
442
+ binding.b do: 'watch @a'
443
+ end
444
+ ```
445
+
446
+ On this case, register a watch breakpoint for `@a` and continue to run.
447
+
448
+ If `pre: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command, and keep suspend.
449
+ It is useful if you have operations before suspend.
450
+
451
+ ```
452
+ def foo
453
+ binding.b pre: 'p bar()'
454
+ ...
455
+ end
456
+ ```
457
+
458
+ On this case, you can see the result of `bar()` every time you stop there.
335
459
 
336
460
  ## rdbg command help
337
461
 
@@ -342,6 +466,7 @@ The `<...>` notation means the argument.
342
466
  # Contributing
343
467
 
344
468
  Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/debug.
469
+ This debugger is not mature so your feedback will help us.
345
470
 
346
471
  Please also check the [contributing guideline](/CONTRIBUTING.md).
347
472