debug 1.0.0.beta7 → 1.0.0

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,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DEBUGGER__
4
- VERSION = "1.0.0.beta7"
4
+ VERSION = "1.0.0"
5
5
  end
data/misc/README.md.erb CHANGED
@@ -12,7 +12,7 @@ New debug.rb has several advantages:
12
12
  * UNIX domain socket
13
13
  * TCP/IP
14
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 methods
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,340 +20,447 @@ 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
 
26
27
  ```
27
- $ gem install debug --pre
28
+ $ gem install debug
28
29
  ```
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
- If you use Bundler, write the following line to your Gemfile. And use rdbg command with -c option.
33
+ If you use Bundler, write the following line to your Gemfile.
34
+
35
+ ```
36
+ gem "debug", ">= 1.0.0"
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
- ```
35
- gem "debug", ">= 1.0.0.beta"
149
+ (rdbg)
36
150
  ```
37
151
 
38
- ```
39
- $ rdbg -c bundle exec ruby target.rb
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).
153
+
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)
157
+
158
+ (rdbg) b 5 # set breakpoint at line 5
159
+ #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line)
160
+
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)
40
164
  ```
41
165
 
42
- # How to use
166
+ You can see that two breakpoints are registered. Let's continue the program by `continue` command.
43
167
 
44
- ## Invoke with debugger
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
45
179
 
46
- You can run ruby program on debugger with the local debug console or the remote debug console.
180
+ Stop by #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line)
47
181
 
48
- * (a) Run a ruby program with the local debug console
49
- * (b) Run a ruby program with the remote debug console by opening a network port
50
- * (b-1) Open with UNIX domain socket
51
- * (b-2) Open with TCP/IP port
182
+ (rdbg)
183
+ ```
52
184
 
53
- (b-1) is useful when you want to use debugging features after running the program.
54
- (b-2) is also useful when you don't have a ssh access for the Ruby process.
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.
55
188
 
56
- To use debugging feature, you can have 3 ways.
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
57
197
 
58
- * (1) Use `rdbg` command
59
- * (2) Use `ruby -r debug...` command line option
60
- * (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
61
208
 
62
- ### Local debug console
209
+ Stop by #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line)
63
210
 
64
- #### (1) Use `rdbg` command
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
65
218
 
66
- ```
67
- $ rdbg target.rb
68
- $ rdbg -- -r foo -e expr # -- is required to make clear rdbg options and ruby's options
219
+ (rdbg) continue
220
+ [1, 2, 3, 4]
69
221
  ```
70
222
 
71
- #### (2) Use `-r debug/run` command line option
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.
72
225
 
73
- ```
74
- $ ruby -r debug/run target.rb
75
- ```
226
+ ### Use `rdbg` with commands written in Ruby
76
227
 
77
- #### (3) Write `require 'debug...'` in .rb files
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.
78
229
 
79
- ```ruby
80
- # target.rb
81
- require 'debug/run' # start the debug console
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.
82
232
 
83
- # ... rest of program ...
84
- ```
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`
85
238
 
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`.
86
240
 
87
- ```
88
- $ ruby target.rb
89
- ```
241
+ NOTE: If you want to use bundler (`bundle` command), you need to write `gem debug` line in your `Gemfile`.
90
242
 
91
- When you run the program with the debug console, you will see the debug console prompt `(rdbg)`.
92
- The debuggee program (`target.rb`) is suspended at the beginning of `target.rb`.
243
+ ### Using VSCode
93
244
 
245
+ Like other languages, you can use this debugger on the VSCode.
94
246
 
95
- Alternatively, start the debugger at a specific location in your program using `binding.break` (`binding.b` for short).
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.
96
253
 
97
- ```ruby
98
- # target.rb
99
- require 'debug' # start the debugger
254
+ Please refer [Debugging in Visual Studio Code](https://code.visualstudio.com/docs/editor/debugging) for operations on VSCode.
100
255
 
101
- # ... program ...
256
+ You can configure the extension in `.vscode/launch.json`.
257
+ Please see the extension page for more details.
102
258
 
103
- binding.break # setup a breakpoint at this line
259
+ ## Remote debugging
104
260
 
105
- # ... rest of program ...
106
- ```
261
+ You can use this debugger as a remote debugger. For example, it will help the following situations:
107
262
 
108
- ```
109
- $ ruby target.rb
110
- ```
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).
268
+
269
+ You can run your application as a remote debuggee and the remote debugger console can attach to the debuggee anytime.
111
270
 
112
- You can type any debugger's command described bellow. "c" or "continue" resume the debuggee program.
113
- You can suspend the debuggee program and show the debug console with `Ctrl-C`.
271
+ ### Invoke as a remote debuggee
114
272
 
115
- The following example shows simple usage of the debug console. You can show the all variables
273
+ There are two ways to invoke a script as remote debuggee: Use `rdbg --open` and require `debug/open` (or `debug/open_nonstop`).
116
274
 
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...
117
284
  ```
118
- $ rdbg ~/src/rb/target.rb
119
285
 
120
- [1, 5] in /home/ko1/src/rb/target.rb
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).
287
+
288
+ You can connect to the debuggee with `rdbg --attach` command (`rdbg -A` for short).
289
+
290
+ ```shell
291
+ $ rdbg -A
292
+ [1, 7] in target.rb
121
293
  => 1| a = 1
122
294
  2| b = 2
123
295
  3| c = 3
124
- 4| p [a + b + c]
125
- 5|
126
- --> #0 /home/ko1/src/rb/target.rb:1:in `<main>'
296
+ 4| d = 4
297
+ 5| p [a, b, c, d]
298
+ 6|
299
+ 7| __END__
300
+ =>#0 <main> at target.rb:1
127
301
 
128
- (rdbg) info # Show all local variables
129
- %self => main
130
- a => nil
131
- b => nil
132
- c => nil
302
+ (rdbg:remote)
303
+ ```
133
304
 
134
- (rdbg) p a # Same as p(a)
135
- => nil
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.
136
306
 
137
- (rdbg) s # Step in ("s" is a short name of "step")
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.
138
308
 
139
- [1, 5] in /home/ko1/src/rb/target.rb
140
- 1| a = 1
141
- => 2| b = 2
142
- 3| c = 3
143
- 4| p [a + b + c]
144
- 5|
145
- --> #0 /home/ko1/src/rb/target.rb:2:in `<main>'
146
-
147
- (rdbg) <Enter> # Repeat the last command ("step")
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.
148
310
 
149
- [1, 5] in /home/ko1/src/rb/target.rb
150
- 1| a = 1
151
- 2| b = 2
152
- => 3| c = 3
153
- 4| p [a + b + c]
154
- 5|
155
- --> #0 /home/ko1/src/rb/target.rb:3:in `<main>'
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`.
156
312
 
157
- (rdbg) # Repeat the last command ("step")
313
+ To connect to the debuggee, you need to specify the port.
158
314
 
159
- [1, 5] in /home/ko1/src/rb/target.rb
160
- 1| a = 1
161
- 2| b = 2
162
- 3| c = 3
163
- => 4| p [a + b + c]
164
- 5|
165
- --> #0 /home/ko1/src/rb/target.rb:4:in `<main>'
166
-
167
- (rdbg) info # Show all local variables
168
- %self => main
169
- a => 1
170
- b => 2
171
- c => 3
172
-
173
- (rdbg) c # Continue the program ("c" is a short name of "continue")
174
- [6]
315
+ ```shell
316
+ $ rdbg --attach 12345
175
317
  ```
176
318
 
177
- ### Remote debug (1) UNIX domain socket
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.
178
321
 
179
- #### (1) Use `rdbg` command
322
+ #### `require 'debug/open'` in a program
180
323
 
181
- ```
182
- $ rdbg --open target.rb # or rdbg -O target.rb for shorthand
183
- Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-5042)
184
- ```
324
+ If you can modify the program, you can open debugging port by adding `require 'debug/open'` line in the program.
185
325
 
186
- #### (2) Use `-r debug/open` command line option
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.
187
330
 
188
- ```
189
- $ ruby -r debug/open target.rb
190
- Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-5042)
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.
332
+
333
+ ```shell
334
+ $ RUBY_DEBUG_PORT=12345 ruby target.rb
191
335
  ```
192
336
 
193
- #### (3) Write `require 'debug/open'` in .rb files
337
+ ## Configuration
194
338
 
195
- ```ruby
196
- # target.rb
197
- require 'debug/open' # open the debugger entry point by UNIX domain socket.
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.
198
341
 
199
- # or
342
+ ### Configuration list
200
343
 
201
- require 'debug/server' # introduce remote debugging feature
202
- DEBUGGER__.open # open the debugger entry point by UNIX domain socket.
203
- # or DEBUGGER__.open_unix to specify UNIX domain socket.
204
- ```
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.
205
345
 
206
346
  ```
207
- $ ruby target.rb
208
- Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-5042)
347
+ # configuration example
348
+ config set log_level INFO
349
+ config set no_color true
209
350
  ```
210
351
 
211
- It runs target.rb and accept debugger connection within UNIX domain socket.
212
- The debuggee process waits for debugger connection at the beginning of `target.rb` like that:
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 %>
356
+
357
+ ### Initial scripts
213
358
 
214
- ```
215
- $ rdbg -O ~/src/rb/target.rb
216
- DEBUGGER: Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-29828)
217
- DEBUGGER: wait for debugger connection...
218
- ```
359
+ If there is `~/.rdbgrc`, the file is loaded as an initial script (which contains debug commands) when the debug session is started.
219
360
 
220
- You can attach the program with the following 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).
221
363
 
222
- ```
223
- $ rdbg --attach # or rdbg -A for shorthand
224
-
225
- [1, 4] in /home/ko1/src/rb/target.rb
226
- 1| (1..).each do |i|
227
- => 2| sleep 0.5
228
- 3| p i
229
- 4| end
230
- --> #0 [C] /home/ko1/src/rb/target.rb:2:in `sleep'
231
- #1 /home/ko1/src/rb/target.rb:2:in `block in <main>' {|i=17|}
232
- #2 [C] /home/ko1/src/rb/target.rb:1:in `each'
233
- # and 1 frames (use `bt' command for all frames)
234
-
235
- (rdb)
236
- ```
364
+ Initial scripts are useful to write your favorite configurations.
365
+ For example, you can set break points with `break file:123` in `~/.rdbgrc`.
237
366
 
238
- and you can input any debug commands. `c` (or `continue`) continues the debuggee process.
367
+ If there are `~/.rdbgrc.rb` is available, it is also loaded as a ruby script at same timing.
239
368
 
240
- You can detach the debugger from the debugger process with `quit` command.
241
- 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).
369
+ ## Debug command on the debug console
242
370
 
243
- 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.
371
+ On the debug console, you can use the following debug commands.
244
372
 
245
- * Use `rdbg -n` option
246
- * Set the environment variable `RUBY_DEBUG_NONSTOP=1`
373
+ There are additional features:
247
374
 
248
- If you are running multiple debuggee processes, the attach command (`rdbg -A`) shows the options like that:
375
+ * `<expr>` without debug command is almost same as `pp <expr>`.
376
+ * If the input line `<expr>` does *NOT* start with any debug command, the line `<expr>` will be evaluated as a Ruby expression and the result will be printed with `pp` method. So that the input `foo.bar` is same as `pp foo.bar`.
377
+ * If `<expr>` is recognized as a debug command, of course it is not evaluated as a Ruby expression, but is executed as debug command. For example, you can not evaluate such single letter local variables `i`, `b`, `n`, `c` because they are single letter debug commands. Use `p i` instead.
378
+ * `Enter` without any input repeats the last command (useful when repeating `step`s).
379
+ * `Ctrl-D` is equal to `quit` command.
380
+ * [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing)
249
381
 
250
- ```
251
- $ rdbg --attach
252
- Please select a debug session:
253
- ruby-debug-ko1-19638
254
- ruby-debug-ko1-19603
255
- ```
382
+ You can use the following debug commands. Each command should be written in 1 line.
383
+ The `[...]` notation means this part can be eliminate. For example, `s[tep]` means `s` or `step` are valid command. `ste` is not valid.
384
+ The `<...>` notation means the argument.
256
385
 
257
- and you need to specify one (copy and paste the name):
386
+ <%= DEBUGGER__.help %>
258
387
 
259
- ```
260
- $ rdbg --attach ruby-debug-ko1-19638
261
- ```
388
+ ## Debugger API
262
389
 
263
- The socket file is located at
264
- * `RUBY_DEBUG_SOCK_DIR` environment variable if available.
265
- * `XDG_RUNTIME_DIR` environment variable if available.
266
- * `$HOME/.ruby-debug-sock` if `$HOME` is available.
390
+ ### Start debugging
267
391
 
268
- ### Remote debug (2) TCP/IP
392
+ #### Start by requiring a library
269
393
 
270
- You can open the TCP/IP port instead of using UNIX domain socket.
394
+ You can start debugging without `rdbg` command by requiring the following libraries:
271
395
 
272
- #### (1) Use `rdbg` command
396
+ * `require 'debug'`: Same as `rdbg --nonstop --no-sigint-hook`.
397
+ * `require 'debug/start'`: Same as `rdbg`.
398
+ * `require 'debug/open'`: Same as `rdbg --open`.
399
+ * `require 'debug/open_nonstop'`: Same as `rdbg --open --nonstop`.
273
400
 
274
- ```
275
- $ rdbg -O --port=12345 target.rb
276
- # or
277
- $ rdbg --open --port=12345 target.rb
278
- Debugger can attach via TCP/IP (localhost:12345)
279
- ```
401
+ You need to require one of them at the very beginning of the application.
402
+ Using `ruby -r` (for example `ruby -r debug/start target.rb`) is another way to invoke with debugger.
280
403
 
281
- #### (2) Use `-r debug/open` command line option
404
+ 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:
282
405
 
406
+ ```shell
407
+ $ ruby -r debug -e0
408
+ .../2.7.3/lib/ruby/2.7.0/x86_64-linux/continuation.so: warning: callcc is obsolete; use Fiber instead
409
+ Debug.rb
410
+ Emacs support available.
283
411
 
284
- ```
285
- $ RUBY_DEBUG_PORT=12345 ruby -r debug/open target.rb
286
- Debugger can attach via TCP/IP (localhost:12345)
412
+ .../2.7.3/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:162: if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?)
413
+ (rdb:1)
287
414
  ```
288
415
 
289
- #### (3) Write `require 'debug/open'` in .rb files
416
+ `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.
290
417
 
291
- ```ruby
292
- # target.rb
293
- require 'debug/open' # open the debugger entry point.
294
- ```
418
+ #### Start by method
295
419
 
296
- and run with environment variable RUBY_DEBUG_PORT
420
+ 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.
297
421
 
298
- ```
299
- $ RUBY_DEBUG_PORT=12345 ruby target.rb
300
- Debugger can attach via TCP/IP (localhost:12345)
301
- ```
422
+ * `DEBUGGER__.start(**kw)`: start debug session with local console.
423
+ * `DEBUGGER__.open(**kw)`: open debug port with configuration (without configurations open with UNIX domain socket)
424
+ * `DEBUGGER__.open_unix(**kw)`: open debug port with UNIX domain socket
425
+ * `DEBUGGER__.open_tcp(**kw)`: open debug port with TCP/IP
302
426
 
303
- or
427
+ For example:
304
428
 
305
429
  ```ruby
306
- # target.rb
307
- require 'debug/server' # introduce remote debugging feature
308
- DEBUGGER__.open(port: 12345)
309
- # or DEBUGGER__.open_tcp(port: 12345)
310
- ```
430
+ require 'debug/session'
431
+ DEBUGGER__.start(no_color: true, # disable colorize
432
+ log_level: 'INFO') # Change log_level to INFO
311
433
 
312
- ```
313
- $ ruby target.rb
314
- Debugger can attach via TCP/IP (localhost:12345)
434
+ ... # your application code
315
435
  ```
316
436
 
317
- 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.
437
+ ### `binding.break` method
318
438
 
319
- To attach the debuggee process, specify the port number (and hostname if needed) for the `rdbg --attach` (or `rdbg -A`) command.
439
+ `binding.break` (or `binding.b`) set breakpoints at written line. It also has several keywords.
440
+
441
+ If `do: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command and continue the program.
442
+ It is useful if you only want to call a debug command and don't want to stop there.
320
443
 
321
444
  ```
322
- $ rdbg --attach 12345
323
- $ rdbg --attach hostname 12345
445
+ def initialize
446
+ @a = 1
447
+ binding.b do: 'watch @a'
448
+ end
324
449
  ```
325
450
 
326
- ### Initial scripts
451
+ On this case, register a watch breakpoint for `@a` and continue to run.
327
452
 
328
- If there are `~/.rdbgrc`, the file is loaded as initial scripts which contains debugger commands at the beginning of debug session. `RUBY_DEBUG_INIT_SCRIPT` environment variable can specify the initial script file. You can write configurations in a file. For example, you can set break points with `break file:123` in `~/.rdbgrc`.
329
-
330
- If there are `~/.rdbgrc.rb` is available, it is loaded as a ruby script at same timing.
331
-
332
- ### Configurations
333
-
334
- You can configure debugger's setting with environment variables and `config` command.
335
- You can write any configuration into `~/.rdbgrc` like:
453
+ If `pre: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command, and keep suspend.
454
+ It is useful if you have operations before suspend.
336
455
 
337
456
  ```
338
- config set log_level INFO
339
- config set no_color true
457
+ def foo
458
+ binding.b pre: 'p bar()'
459
+ ...
460
+ end
340
461
  ```
341
- <% cat = nil; DEBUGGER__::CONFIG_SET.each do |key, (env, desc)| %>
342
- <% /\A(\w+): (.+)/ =~ desc; if cat != $1; cat = 1 %>
343
- * <%= $1 %>
344
- <% cat = $1; end %> * `<%= env %>` (`<%= key %>`): <%= $2 %><% end %>
345
462
 
346
- ## Debug command on the debug console
347
-
348
- * `Enter` repeats the last command (useful when repeating `step`s).
349
- * `Ctrl-D` is equal to `quit` command.
350
- * [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing)
351
-
352
- You can use the following debug commands. Each command should be written in 1 line.
353
- The `[...]` notation means this part can be eliminate. For example, `s[tep]` means `s` or `step` are valid command. `ste` is not valid.
354
- The `<...>` notation means the argument.
355
-
356
- <%= DEBUGGER__.help %>
463
+ On this case, you can see the result of `bar()` every time you stop there.
357
464
 
358
465
  ## rdbg command help
359
466
 
@@ -364,6 +471,7 @@ The `<...>` notation means the argument.
364
471
  # Contributing
365
472
 
366
473
  Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/debug.
474
+ This debugger is not mature so your feedback will help us.
367
475
 
368
476
  Please also check the [contributing guideline](/CONTRIBUTING.md).
369
477