[![Ruby](https://github.com/ruby/debug/actions/workflows/ruby.yml/badge.svg?branch=master)](https://github.com/ruby/debug/actions/workflows/ruby.yml?query=branch%3Amaster)
# debug.rb
This library provides debugging functionality to Ruby.
This debug.rb is replacement of traditional lib/debug.rb standard library which is implemented by `set_trace_func`.
New debug.rb has several advantages:
* Fast: No performance penalty on non-stepping mode and non-breakpoints.
* [Remote debugging](#remote-debugging): Support remote debugging natively.
* UNIX domain socket
* TCP/IP
* Integration with rich debugger frontend
* VSCode/DAP ([VSCode rdbg Ruby Debugger - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg))
* Chrome DevTools
* Extensible: application can introduce debugging support with several ways:
* By `rdbg` command
* By loading libraries with `-r` command line option
* By calling Ruby's method explicitly
* Misc
* Support threads (almost done) and ractors (TODO).
* Support suspending and entering to the console debugging with `Ctrl-C` at most of timing.
* Show parameters on backtrace command.
* Support recording & reply debugging.
# Installation
```
$ gem install debug
```
or specify `-Ipath/to/debug/lib` in `RUBYOPT` or each ruby command-line option, especially for debug this gem development.
If you use Bundler, write the following line to your Gemfile.
```
gem "debug", ">= 1.0.0"
```
# HOW TO USE
To use a debugger, roughly you will do the following steps:
1. Set breakpoints.
2. Run a program with the debugger.
3. At the breakpoint, enter the debugger console.
4. Use debug commands.
* [Evaluate Ruby expressions](#evaluate) (e.g. `p lvar` to see the local variable `lvar`).
* [Query the program status](#information) (e.g. `info` to see information about the current frame).
* [Control program flow](#control-flow) (e.g. move to the another line with `step`, to the next line with `next`).
* [Set another breakpoint](#breakpoint) (e.g. `catch Exception` to set a breakpoint that'll be triggered when `Exception` is raised).
* [Activate tracing in your program](#trace) (e.g. `trace call` to trace method calls).
* [Change the configuration](#configuration-1) (e.g. `config set no_color true` to disable coloring).
* Continue the program (`c` or `continue`) and goto 3.
## Invoke with the debugger
There are several options for (1) and (2). Please choose your favorite way.
### Modify source code with [`binding.break`](#bindingbreak-method) (similar to `binding.pry` or `binding.irb`)
If you can modify the source code, you can use the debugger by adding `require 'debug'` at the top of your program and putting [`binding.break`](#bindingbreak-method) method into lines where you want to stop as breakpoints like `binding.pry` and `binding.irb`.
You can also use its 2 aliases in the same way:
- `binding.b`
- `debugger`
After that, run the program as usual and you will enter the debug console at breakpoints you inserted.
The following example shows the demonstration of [`binding.break`](#bindingbreak-method).
```shell
$ cat target.rb # Sample program
require 'debug'
a = 1
b = 2
binding.break # Program will stop here
c = 3
d = 4
binding.break # Program will stop here
p [a, b, c, d]
$ ruby target.rb # Run the program normally.
DEBUGGER: Session start (pid: 7604)
[1, 10] in target.rb
1| require 'debug'
2|
3| a = 1
4| b = 2
=> 5| binding.break # Now you can see it stops at this line
6| c = 3
7| d = 4
8| binding.break
9| p [a, b, c, d]
10|
=>#0 <main> at target.rb:5
(rdbg) info locals # You can show local variables
=>#0 <main> at target.rb:5
%self => main
a => 1
b => 2
c => nil
d => nil
(rdbg) continue # Continue the execution
[3, 11] in target.rb
3| a = 1
4| b = 2
5| binding.break
6| c = 3
7| d = 4
=> 8| binding.break # Again the program stops at here
9| p [a, b, c, d]
10|
11| __END__
=>#0 <main> at target.rb:8
(rdbg) info locals # And you can see the updated local variables
=>#0 <main> at target.rb:8
%self => main
a => 1
b => 2
c => 3
d => 4
(rdbg) continue
[1, 2, 3, 4]
```
### Invoke the program from the debugger as a traditional debuggers
If you don't want to modify the source code, you can set breakpoints with a debug command `break` (`b` for short).
Using `rdbg` command to launch the program without any modifications, you can run the program with the debugger.
```shell
$ cat target.rb # Sample program
a = 1
b = 2
c = 3
d = 4
p [a, b, c, d]
$ rdbg target.rb # run like `ruby target.rb`
DEBUGGER: Session start (pid: 7656)
[1, 7] in target.rb
=> 1| a = 1
2| b = 2
3| c = 3
4| d = 4
5| p [a, b, c, d]
6|
7| __END__
=>#0 <main> at target.rb:1
(rdbg)
```
`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).
```shell
(rdbg) break 3 # set breakpoint at line 3
#0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line)
(rdbg) b 5 # set breakpoint at line 5
#1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line)
(rdbg) break # show all registered breakpoints
#0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line)
#1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line)
```
You can see that two breakpoints are registered. Let's continue the program by `continue` command.
```shell
(rdbg) continue
[1, 7] in target.rb
1| a = 1
2| b = 2
=> 3| c = 3
4| d = 4
5| p [a, b, c, d]
6|
7| __END__
=>#0 <main> at target.rb:3
Stop by #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line)
(rdbg)
```
You can see that we can stop at line 3.
Let's see the local variables with `info` command, and continue.
You can also confirm that the program will suspend at line 5 and you can use `info` command again.
```shell
(rdbg) info
=>#0 <main> at target.rb:3
%self => main
a => 1
b => 2
c => nil
d => nil
(rdbg) continue
[1, 7] in target.rb
1| a = 1
2| b = 2
3| c = 3
4| d = 4
=> 5| p [a, b, c, d]
6|
7| __END__
=>#0 <main> at target.rb:5
Stop by #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line)
(rdbg) info
=>#0 <main> at target.rb:5
%self => main
a => 1
b => 2
c => 3
d => 4
(rdbg) continue
[1, 2, 3, 4]
```
By the way, using `rdbg` command you can suspend your application with `C-c` (SIGINT) and enter the debug console.
It will help that if you want to know what the program is doing.
### Use `rdbg` with commands written in Ruby
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.
* Without `-c` option, `rdbg <name>` means that `<name>` is Ruby script and invoke it like `ruby <name>` with the debugger.
* With `-c` option, `rdbg -c <name>` means that `<name>` is command in `PATH` and simply invoke it with the debugger.
Examples:
* `rdbg -c -- rails server`
* `rdbg -c -- bundle exec ruby foo.rb`
* `rdbg -c -- bundle exec rake test`
* `rdbg -c -- ruby target.rb` is same as `rdbg target.rb`
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`.
NOTE: If you want to use bundler (`bundle` command), you need to write `gem debug` line in your `Gemfile`.
### Using VSCode
Like other l