• Stars
    star
    1,114
  • Rank 41,670 (Top 0.9 %)
  • Language
    Ruby
  • License
    BSD 2-Clause "Sim...
  • Created over 5 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Debugging functionality for Ruby

Ruby Protocol

debug.rb

This library provides debugging functionality to Ruby (MRI) 2.7 and later.

This debug.rb is the 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: Support remote debugging natively.

  • Extensible: application can introduce debugging support in 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 & replay 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"

(The version constraint is important; debug < 1.0.0 is an older, abandoned gem that is completely different from this product.)

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.

Invoke with the debugger

There are several options for (1) and (2). Please choose your favorite way.

Modify source code with binding.break (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 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.

$ 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 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 (or bundle exec rdbg) to launch the program without any modifications, you can run the program with the debugger.

$ 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).

(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 using the continue command.

(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 the info command, and continue. You can also confirm that the program will suspend at line 5 and you can use the info command again.

(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 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 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 a command in PATH and simply invokes 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 languages, you can use this debugger on the VSCode.

  1. Install VSCode rdbg Ruby Debugger - Visual Studio Marketplace
  2. Open .rb file (e.g. target.rb)
  3. Register breakpoints with "Toggle breakpoint" in the Run menu (or type F9 key)
  4. Choose "Start debugging" in "Run" menu (or type F5 key)
  5. You will see a dialog "Debug command line" and you can choose your favorite command line you want to run.
  6. Chosen command line is invoked with rdbg -c, and VSCode shows the details at breakpoints.

Please refer to Debugging in Visual Studio Code for operations on VSCode.

You can configure the extension in .vscode/launch.json. Please see the extension page for more details.

Remote debugging

You can use this debugger as a remote debugger. For example, it will help in the following situations:

  • Your application does not run on TTY, and it is hard to use binding.pry or binding.irb.
    • Your application is running on a Docker container, and there is no TTY.
    • Your application is running as a daemon.
    • Your application uses pipe for STDIN or STDOUT.
  • Your application is running as a daemon and you want to query the running status (checking a backtrace and so on).

You can run your application as a remote debuggee, and the remote debugger console can attach to the debuggee anytime.

Invoke as a remote debuggee

There are multiple ways to run your program as a debuggee:

Stop at program start rdbg option require debugger API
Yes rdbg --open require "debug/open" DEBUGGER__.open
No rdbg --open --nonstop require "debug/open_nonstop" DEBUGGER__.open(nonstop: true)

rdbg --open (or rdbg -O for short)

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.

$ exe/rdbg --open target.rb
DEBUGGER: Session start (pid: 7773)
DEBUGGER: Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773)
DEBUGGER: wait for debugger connection...

By default, rdbg --open uses UNIX domain socket and generates the path name automatically (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773 in this case).

You can connect to the debuggee with rdbg --attach command (rdbg -A for short).

$ rdbg -A
[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:remote)

If there are no other opening ports on the default directory, rdbg --attach command chooses the only one opening UNIX domain socket and connects to it. If there are more files, you need to specify the file.

When rdbg --attach connects to the debuggee, you can use any debug commands (set breakpoints, continue the program, and so on) like the local debug console. When a debuggee program exits, the remote console will also terminate.

NOTE: If you use the quit command, only the 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.

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.

To connect to the debuggee, you need to specify the port.

$ rdbg --attach 12345

If you want to choose the host to bind, you can use --host option. Note that all messages communicated between the debugger and the debuggee are NOT encrypted so please use remote debugging carefully.

require 'debug/open' in a program

If you can modify the program, you can open the debugging port by adding require 'debug/open' line in the program.

If you don't want to stop the program at the beginning, you can also use require 'debug/open_nonstop'. Using debug/open_nonstop is useful if you want to open a backdoor to the application. However, it is also dangerous because it can become another vulnerability. Please use it carefully.

By default, UNIX domain socket is used for the debugging port. To use TCP/IP, you can set the RUBY_DEBUG_PORT environment variable.

$ RUBY_DEBUG_PORT=12345 ruby target.rb

Integration with external debugger frontend

You can attach with external debugger frontend with VSCode and Chrome.

$ rdbg --open=[frontend] target.rb

will open a debug port and [frontend] can attach to the port.

Also open command allows opening the debug port.

VSCode integration

(vscode-rdbg v0.0.9 or later is required)

If you don't run a debuggee Ruby process on VSCode, you can attach it to VSCode later with the following steps.

rdbg --open=vscode opens the debug port and tries to invoke the VSCode (code command).

$ rdbg --open=vscode target.rb
DEBUGGER: Debugger can attach via UNIX domain socket (/tmp/ruby-debug-sock-1000/ruby-debug-ko1-27706)
DEBUGGER: wait for debugger connection...
Launching: code /tmp/ruby-debug-vscode-20211014-27706-gd7e85/ /tmp/ruby-debug-vscode-20211014-27706-gd7e85/README.rb
DEBUGGER: Connected.

And it tries to invoke the new VSCode window and VSCode starts attaching to the debuggee Ruby program automatically.

You can also use open vscode command in REPL.

$ rdbg target.rb
[1, 8] in target.rb
     1|
=>   2| p a = 1
     3| p b = 2
     4| p c = 3
     5| p d = 4
     6| p e = 5
     7|
     8| __END__
=>#0    <main> at target.rb:2
(rdbg) open vscode    # command
DEBUGGER: wait for debugger connection...
DEBUGGER: Debugger can attach via UNIX domain socket (/tmp/ruby-debug-sock-1000/ruby-debug-ko1-28337)
Launching: code /tmp/ruby-debug-vscode-20211014-28337-kg9dm/ /tmp/ruby-debug-vscode-20211014-28337-kg9dm/README.rb
DEBUGGER: Connected.

If the machine which runs the Ruby process doesn't have a code command, the following message will be shown:

(rdbg) open vscode
DEBUGGER: wait for debugger connection...
DEBUGGER: Debugger can attach via UNIX domain socket (/tmp/ruby-debug-sock-1000/ruby-debug-ko1-455)
Launching: code /tmp/ruby-debug-vscode-20211014-455-gtjpwi/ /tmp/ruby-debug-vscode-20211014-455-gtjpwi/README.rb
DEBUGGER: Can not invoke the command.
Use the command-line on your terminal (with modification if you need).

  code /tmp/ruby-debug-vscode-20211014-455-gtjpwi/ /tmp/ruby-debug-vscode-20211014-455-gtjpwi/README.rb

If your application is running on a SSH remote host, please try:

  code --remote ssh-remote+[SSH hostname] /tmp/ruby-debug-vscode-20211014-455-gtjpwi/ /tmp/ruby-debug-vscode-20211014-455-gtjpwi/README.rb

and try to use the proposed commands.

Note that you can attach with rdbg --attach and continue REPL debugging.

Chrome DevTool integration

With rdbg --open=chrome command will show the following message.

$ rdbg target.rb --open=chrome
DEBUGGER: Debugger can attach via TCP/IP (127.0.0.1:43633)
DEBUGGER: With Chrome browser, type the following URL in the address-bar:

   devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef

DEBUGGER: wait for debugger connection...

Type devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef in the address bar on Chrome browser, and you can continue the debugging with chrome browser.

Also open chrome command works like open vscode.

For more information about how to use Chrome debugging, you might want to read here.

Configuration

You can configure the debugger's behavior with debug commands and environment variables. When the debug session is started, initial scripts are loaded so you can put your favorite configurations in the initial scripts.

Configuration list

You can configure the debugger's behavior with environment variables and config command. Each configuration has an environment variable and a name which can be specified by config command.

# configuration example
config set log_level INFO
config set no_color true
  • UI

    • RUBY_DEBUG_LOG_LEVEL (log_level): Log level same as Logger (default: WARN)
    • RUBY_DEBUG_SHOW_SRC_LINES (show_src_lines): Show n lines source code on breakpoint (default: 10)
    • RUBY_DEBUG_SHOW_EVALEDSRC (show_evaledsrc): Show actually evaluated source (default: false)
    • RUBY_DEBUG_SHOW_FRAMES (show_frames): Show n frames on breakpoint (default: 2)
    • RUBY_DEBUG_USE_SHORT_PATH (use_short_path): Show shorten PATH (like $(Gem)/foo.rb) (default: false)
    • RUBY_DEBUG_NO_COLOR (no_color): Do not use colorize (default: false)
    • RUBY_DEBUG_NO_SIGINT_HOOK (no_sigint_hook): Do not suspend on SIGINT (default: false)
    • RUBY_DEBUG_NO_RELINE (no_reline): Do not use Reline library (default: false)
    • RUBY_DEBUG_NO_HINT (no_hint): Do not show the hint on the REPL (default: false)
    • RUBY_DEBUG_NO_LINENO (no_lineno): Do not show line numbers (default: false)
    • RUBY_DEBUG_IRB_CONSOLE (irb_console): Use IRB as the console (default: false)
  • CONTROL

    • RUBY_DEBUG_SKIP_PATH (skip_path): Skip showing/entering frames for given paths
    • RUBY_DEBUG_SKIP_NOSRC (skip_nosrc): Skip on no source code lines (default: false)
    • RUBY_DEBUG_KEEP_ALLOC_SITE (keep_alloc_site): Keep allocation site and p, pp shows it (default: false)
    • RUBY_DEBUG_POSTMORTEM (postmortem): Enable postmortem debug (default: false)
    • RUBY_DEBUG_FORK_MODE (fork_mode): Control which process activates a debugger after fork (both/parent/child) (default: both)
    • RUBY_DEBUG_SIGDUMP_SIG (sigdump_sig): Sigdump signal (default: false)
  • BOOT

    • RUBY_DEBUG_NONSTOP (nonstop): Nonstop mode (default: false)
    • RUBY_DEBUG_STOP_AT_LOAD (stop_at_load): Stop at just loading location (default: false)
    • RUBY_DEBUG_INIT_SCRIPT (init_script): debug command script path loaded at first stop
    • RUBY_DEBUG_COMMANDS (commands): debug commands invoked at first stop. Commands should be separated by ;;
    • RUBY_DEBUG_NO_RC (no_rc): ignore loading ~/.rdbgrc(.rb) (default: false)
    • RUBY_DEBUG_HISTORY_FILE (history_file): history file (default: ~/.rdbg_history)
    • RUBY_DEBUG_SAVE_HISTORY (save_history): maximum save history lines (default: 10000)
  • REMOTE

    • RUBY_DEBUG_OPEN (open): Open remote port (same as rdbg --open option)
    • RUBY_DEBUG_PORT (port): TCP/IP remote debugging: port
    • RUBY_DEBUG_HOST (host): TCP/IP remote debugging: host (default: 127.0.0.1)
    • RUBY_DEBUG_SOCK_PATH (sock_path): UNIX Domain Socket remote debugging: socket path
    • RUBY_DEBUG_SOCK_DIR (sock_dir): UNIX Domain Socket remote debugging: socket directory
    • RUBY_DEBUG_LOCAL_FS_MAP (local_fs_map): Specify local fs map
    • RUBY_DEBUG_SKIP_BP (skip_bp): Skip breakpoints if no clients are attached (default: false)
    • RUBY_DEBUG_COOKIE (cookie): Cookie for negotiation
    • RUBY_DEBUG_SESSION_NAME (session_name): Session name for differentiating multiple sessions
    • RUBY_DEBUG_CHROME_PATH (chrome_path): Platform dependent path of Chrome (For more information, See here)
  • OBSOLETE

    • RUBY_DEBUG_PARENT_ON_FORK (parent_on_fork): Keep debugging parent process on fork (default: false)

There are other environment variables:

  • NO_COLOR: If the value is set, set RUBY_DEBUG_NO_COLOR (NO_COLOR: disabling ANSI color output in various Unix commands).
  • RUBY_DEBUG_ENABLE: If the value is 0, do not enable debug.gem feature.
  • 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.
  • RUBY_DEBUG_EDITOR or EDITOR: An editor used by edit debug command.
  • RUBY_DEBUG_BB: Define Kernel#bb method which is alias of Kernel#debugger.

Initial scripts

If there is ~/.rdbgrc, the file is loaded as an initial script (which contains debug commands) when the debug session is started.

  • RUBY_DEBUG_INIT_SCRIPT environment variable can specify the initial script file.
  • You can specify the initial script with rdbg -x initial_script (like gdb's -x option).

Initial scripts are useful to write your favorite configurations. For example, you can set breakpoints with break file:123 in ~/.rdbgrc.

If there are ~/.rdbgrc.rb is available, it is also loaded as a ruby script at same timing.

Debug command on the debug console

On the debug console, you can use the following debug commands.

There are additional features:

  • <expr> without debug command is almost the same as pp <expr>.
    • 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 the same as pp foo.bar.
    • 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.
    • So the author (Koichi Sasada) recommends using p, pp or eval command to evaluate the Ruby expression every time.
  • Enter without any input repeats the last command (useful when repeating steps) for some commands.
  • Ctrl-D is equal to quit command.
  • debug command compare sheet - Google Sheets

You can use the following debug commands. Each command should be written in 1 line. The [...] notation means this part can be eliminated. For example, s[tep] means s or step is a valid command. ste is not valid. The <...> notation means the argument.

Control flow

  • s[tep]
    • Step in. Resume the program until next breakable point.
  • s[tep] <n>
    • Step in, resume the program at <n>th breakable point.
  • n[ext]
    • Step over. Resume the program until next line.
  • n[ext] <n>
    • Step over, same as step <n>.
  • fin[ish]
    • Finish this frame. Resume the program until the current frame is finished.
  • fin[ish] <n>
    • Finish <n>th frames.
  • u[ntil]
    • Similar to next command, but only stop later lines or the end of the current frame.
    • Similar to gdb's advance command.
  • u[ntil] <[file:]line>
    • Run til the program reaches given location or the end of the current frame.
  • u[ntil] <name>
    • Run til the program invokes a method <name>. <name> can be a regexp with /name/.
  • c or cont or continue
    • Resume the program.
  • q[uit] or Ctrl-D
    • Finish debugger (with the debuggee process on non-remote debugging).
  • q[uit]!
    • Same as q[uit] but without the confirmation prompt.
  • kill
    • Stop the debuggee process with Kernel#exit!.
  • kill!
    • Same as kill but without the confirmation prompt.
  • sigint
    • Execute SIGINT handler registered by the debuggee.
    • Note that this command should be used just after stop by SIGINT.

Breakpoint

  • b[reak]
    • Show all breakpoints.
  • b[reak] <line>
    • Set breakpoint on <line> at the current frame's file.
  • b[reak] <file>:<line> or <file> <line>
    • Set breakpoint on <file>:<line>.
  • b[reak] <class>#<name>
    • Set breakpoint on the method <class>#<name>.
  • b[reak] <expr>.<name>
    • Set breakpoint on the method <expr>.<name>.
  • b[reak] ... if: <expr>
    • break if <expr> is true at specified location.
  • b[reak] ... pre: <command>
    • break and run <command> before stopping.
  • b[reak] ... do: <command>
    • break and run <command>, and continue.
  • b[reak] ... path: <path>
    • break if the path matches to <path>. <path> can be a regexp with /regexp/.
  • b[reak] if: <expr>
    • break if: <expr> is true at any lines.
    • Note that this feature is super slow.
  • catch <Error>
    • Set breakpoint on raising <Error>.
  • catch ... if: <expr>
    • stops only if <expr> is true as well.
  • catch ... pre: <command>
    • runs <command> before stopping.
  • catch ... do: <command>
    • stops and run <command>, and continue.
  • catch ... path: <path>
    • stops if the exception is raised from a <path>. <path> can be a regexp with /regexp/.
  • watch @ivar
    • Stop the execution when the result of current scope's @ivar is changed.
    • Note that this feature is super slow.
  • watch ... if: <expr>
    • stops only if <expr> is true as well.
  • watch ... pre: <command>
    • runs <command> before stopping.
  • watch ... do: <command>
    • stops and run <command>, and continue.
  • watch ... path: <path>
    • stops if the path matches <path>. <path> can be a regexp with /regexp/.
  • del[ete]
    • delete all breakpoints.
  • del[ete] <bpnum>
    • delete specified breakpoint.

Information

  • bt or backtrace
    • Show backtrace (frame) information.
  • bt <num> or backtrace <num>
    • Only shows first <num> frames.
  • bt /regexp/ or backtrace /regexp/
    • Only shows frames with method name or location info that matches /regexp/.
  • bt <num> /regexp/ or backtrace <num> /regexp/
    • Only shows first <num> frames with method name or location info that matches /regexp/.
  • l[ist]
    • Show current frame's source code.
    • Next list command shows the successor lines.
  • l[ist] -
    • Show predecessor lines as opposed to the list command.
  • l[ist] <start> or l[ist] <start>-<end>
    • Show current frame's source code from the line to if given.
  • whereami
    • Show the current frame with source code.
  • edit
    • Open the current file on the editor (use EDITOR environment variable).
    • Note that edited file will not be reloaded.
  • edit <file>
    • Open on the editor.
  • i[nfo]
    • Show information about current frame (local/instance variables and defined constants).
  • i[nfo]
    • info has the following sub-commands.
    • Sub-commands can be specified with few letters which is unambiguous, like l for 'locals'.
  • i[nfo] l or locals or local_variables
    • Show information about the current frame (local variables)
    • It includes self as %self and a return value as _return.
  • i[nfo] i or ivars or instance_variables
    • Show information about instance variables about self.
    • info ivars <expr> shows the instance variables of the result of <expr>.
  • i[nfo] c or consts or constants
    • Show information about accessible constants except toplevel constants.
    • info consts <expr> shows the constants of a class/module of the result of <expr>
  • i[nfo] g or globals or global_variables
    • Show information about global variables
  • i[nfo] th or threads
    • Show all threads (same as th[read]).
  • i[nfo] b or breakpoints or w or watchpoints
    • Show all breakpoints and watchpoints.
  • i[nfo] ... /regexp/
    • Filter the output with /regexp/.
  • o[utline] or ls
    • Show you available methods, constants, local variables, and instance variables in the current scope.
  • o[utline] <expr> or ls <expr>
    • Show you available methods and instance variables of the given object.
    • If the object is a class/module, it also lists its constants.
  • display
    • Show display setting.
  • display <expr>
    • Show the result of <expr> at every suspended timing.
  • undisplay
    • Remove all display settings.
  • undisplay <displaynum>
    • Remove a specified display setting.

Frame control

  • f[rame]
    • Show the current frame.
  • f[rame] <framenum>
    • Specify a current frame. Evaluation are run on specified frame.
  • up
    • Specify the upper frame.
  • down
    • Specify the lower frame.

Evaluate

  • p <expr>
    • Evaluate like p <expr> on the current frame.
  • pp <expr>
    • Evaluate like pp <expr> on the current frame.
  • eval <expr>
    • Evaluate <expr> on the current frame.
  • irb
    • Activate and switch to irb:rdbg console

Trace

  • trace
    • Show available tracers list.
  • trace line
    • Add a line tracer. It indicates line events.
  • trace call
    • Add a call tracer. It indicate call/return events.
  • trace exception
    • Add an exception tracer. It indicates raising exceptions.
  • trace object <expr>
    • Add an object tracer. It indicates that an object by <expr> is passed as a parameter or a receiver on method call.
  • trace ... /regexp/
    • Indicates only matched events to /regexp/.
  • trace ... into: <file>
    • Save trace information into: <file>.
  • trace off <num>
    • Disable tracer specified by <num> (use trace command to check the numbers).
  • trace off [line|call|pass]
    • Disable all tracers. If <type> is provided, disable specified type tracers.
  • record
    • Show recording status.
  • record [on|off]
    • Start/Stop recording.
  • step back
    • Start replay. Step back with the last execution log.
    • s[tep] does stepping forward with the last log.
  • step reset
    • Stop replay .

Thread control

  • th[read]
    • Show all threads.
  • th[read] <thnum>
    • Switch thread specified by <thnum>.

Configuration

  • config
    • Show all configuration with description.
  • config <name>
    • Show current configuration of .
  • config set <name> <val> or config <name> = <val>
    • Set to .
  • config append <name> <val> or config <name> << <val>
    • Append <val> to <name> if it is an array.
  • config unset <name>
    • Set to default.
  • source <file>
    • Evaluate lines in <file> as debug commands.
  • open
    • open debuggee port on UNIX domain socket and wait for attaching.
    • Note that open command is EXPERIMENTAL.
  • open [<host>:]<port>
    • open debuggee port on TCP/IP with given [<host>:]<port> and wait for attaching.
  • open vscode
    • open debuggee port for VSCode and launch VSCode if available.
  • open chrome
    • open debuggee port for Chrome and wait for attaching.

Help

  • h[elp]
    • Show help for all commands.
  • h[elp] <command>
    • Show help for the given command.

Using IRB as the Debug Console

Starting from version v1.9, you can now use IRB as the debug console. This integration brings additional features such as:

  • Autocompletion
  • Support for multi-line input
  • Access to commands not available in debug, like show_source or show_doc
  • Configurable command aliases

To switch to the IRB console, simply use the irb command in the debug console.

Once activated, you'll notice the prompt changes to:

irb:rdbg(main):001>

If you want to make IRB the default console for all sessions, configure the irb_console setting by either:

  • Setting the RUBY_DEBUG_IRB_CONSOLE=true environment variable
  • Or adding config set irb_console 1 to your ~/.rdbgrc

To disable the IRB console in the current session, execute config set irb_console 0 in the console.

Debugger API

Start debugging

Start by requiring a library

You can start debugging without rdbg command by requiring the following libraries:

  • require 'debug': Same as rdbg --nonstop --no-sigint-hook.
  • require 'debug/start': Same as rdbg.
  • require 'debug/open': Same as rdbg --open.
  • require 'debug/open_nonstop': Same as rdbg --open --nonstop.

You need to require one of them at the very beginning of the application. Using ruby -r (for example ruby -r debug/start target.rb) is another way to invoke with debugger.

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:

$ ruby -r debug -e0
.../2.7.3/lib/ruby/2.7.0/x86_64-linux/continuation.so: warning: callcc is obsolete; use Fiber instead
Debug.rb
Emacs support available.

.../2.7.3/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:162:    if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?)
(rdb:1)

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.

Start by method

After loading debug/session, you can start a debug session with the following methods. They are convenient if you want to specify debug configurations in your program.

  • DEBUGGER__.start(**kw): start debug session with local console.
  • DEBUGGER__.open(**kw): open debug port with configuration (without configurations open with UNIX domain socket)
  • DEBUGGER__.open_unix(**kw): open debug port with UNIX domain socket
  • DEBUGGER__.open_tcp(**kw): open debug port with TCP/IP

For example:

require 'debug/session'
DEBUGGER__.start(no_color: true,    # disable colorize
                 log_level: 'INFO') # Change log_level to INFO

... # your application code

binding.break method

binding.break (or binding.b) set breakpoints at the written line. It also has several keywords.

If do: 'command' is specified, the debugger suspends the program, runs the command as a debug command, and continues the program. It is useful if you only want to call a debug command and don't want to stop there.

def initialize
  @a = 1
  binding.b do: 'info \n watch @a'
end

In this case, execute the info command then register a watch breakpoint for @a and continue to run. You can also use ;; instead of \n to separate your commands.

If pre: 'command' is specified, the debugger suspends the program and runs the command as a debug command, and keeps suspended. It is useful if you have operations before suspend.

def foo
  binding.b pre: 'p bar()'
  ...
end

In this case, you can see the result of bar() every time you stop there.

rdbg command help

exe/rdbg [options] -- [debuggee options]

Debug console mode:
    -n, --nonstop                    Do not stop at the beginning of the script.
    -e DEBUG_COMMAND                 Execute debug command at the beginning of the script.
    -x, --init-script=FILE           Execute debug command in the FILE.
        --no-rc                      Ignore ~/.rdbgrc
        --no-color                   Disable colorize
        --no-sigint-hook             Disable to trap SIGINT
    -c, --command                    Enable command mode.
                                     The first argument should be a command name in $PATH.
                                     Example: 'rdbg -c bundle exec rake test'

    -O, --open=[FRONTEND]            Start remote debugging with opening the network port.
                                     If TCP/IP options are not given, a UNIX domain socket will be used.
                                     If FRONTEND is given, prepare for the FRONTEND.
                                     Now rdbg, vscode and chrome is supported.
        --sock-path=SOCK_PATH        UNIX Domain socket path
        --port=PORT                  Listening TCP/IP port
        --host=HOST                  Listening TCP/IP host
        --cookie=COOKIE              Set a cookie for connection
        --session-name=NAME          Session name

  Debug console mode runs Ruby program with the debug console.

  'rdbg target.rb foo bar'                starts like 'ruby target.rb foo bar'.
  'rdbg -- -r foo -e bar'                 starts like 'ruby -r foo -e bar'.
  'rdbg -c rake test'                     starts like 'rake test'.
  'rdbg -c -- rake test -t'               starts like 'rake test -t'.
  'rdbg -c bundle exec rake test'         starts like 'bundle exec rake test'.
  'rdbg -O target.rb foo bar'             starts and accepts attaching with UNIX domain socket.
  'rdbg -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234.
  'rdbg -O --port 1234 -- -r foo -e bar'  starts accepts attaching with TCP/IP localhost:1234.
  'rdbg target.rb -O chrome --port 1234'  starts and accepts connecting from Chrome Devtools with localhost:1234.

Attach mode:
    -A, --attach                     Attach to debuggee process.

  Attach mode attaches the remote debug console to the debuggee process.

  'rdbg -A'           tries to connect via UNIX domain socket.
                      If there are multiple processes are waiting for the
                      debugger connection, list possible debuggee names.
  'rdbg -A path'      tries to connect via UNIX domain socket with given path name.
  'rdbg -A port'      tries to connect to localhost:port via TCP/IP.
  'rdbg -A host port' tries to connect to host:port via TCP/IP.

Other options:
    -v                               Show version number
        --version                    Show version number and exit
    -h, --help                       Print help
        --util=NAME                  Utility mode (used by tools)
        --stop-at-load               Stop immediately when the debugging feature is loaded.

NOTE
  All messages communicated between a debugger and a debuggee are *NOT* encrypted.
  Please use the remote debugging feature carefully.

Additional Resources

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/debug. This debugger is not mature so your feedback will help us.

Please also check the contributing guideline.

Acknowledgement

More Repositories

1

ruby

The Ruby Programming Language
Ruby
20,732
star
2

rake

A make-like build utility for Ruby.
Ruby
2,336
star
3

rbs

Type Signature for Ruby
Ruby
1,952
star
4

did_you_mean

The gem that has been saving people from typos since 2014
Ruby
1,871
star
5

www.ruby-lang.org

Source of the https://www.ruby-lang.org website.
Ruby
856
star
6

prism

Prism Ruby parser
C
840
star
7

rdoc

RDoc produces HTML and online documentation for Ruby projects.
Ruby
833
star
8

setup-ruby

An action to download a prebuilt Ruby and add it to the PATH in 5 seconds
JavaScript
798
star
9

typeprof

An experimental type-level Ruby interpreter for testing and understanding Ruby code
Ruby
746
star
10

ruby.wasm

ruby.wasm is a collection of WebAssembly ports of the CRuby.
Ruby
676
star
11

spec

The Ruby Spec Suite aka ruby/spec
Ruby
556
star
12

psych

A libyaml wrapper for Ruby
Ruby
543
star
13

racc

Racc is an LALR(1) parser generator. It is written in Ruby itself, and generates ruby programs.
Yacc
535
star
14

irb

interactive Ruby
Ruby
383
star
15

syntax_suggest

Searching for unexpected `end` syntax errors takes a lot of time. Let this gem do it for you!
Ruby
344
star
16

curses

Ruby binding for curses, ncurses, and PDCurses. Formerly part of the ruby standard library.
C
292
star
17

gem_rbs_collection

A collection of RBS for gems.
Ruby
262
star
18

reline

The compatible library with the API of Ruby's stdlib 'readline'
Ruby
256
star
19

webrick

HTTP server toolkit
Ruby
246
star
20

openssl

Provides SSL, TLS and general purpose cryptography.
C
240
star
21

TryRuby

This 4th iteration of TryRuby is a website where you can learn the Ruby language.
Ruby
226
star
22

power_assert

Power Assert for Ruby
Ruby
187
star
23

lrama

Pure Ruby LALR parser generator
Ruby
184
star
24

rss

RSS reading and writing
Ruby
182
star
25

vscode-rdbg

VSCode Ruby rdbg Debugger
TypeScript
176
star
26

csv

CSV Reading and Writing
Ruby
159
star
27

drb

Distributed object system for Ruby
Ruby
154
star
28

fiddle

A libffi wrapper for Ruby.
Ruby
147
star
29

error_highlight

The gem enhances Exception#message by adding a short explanation where the exception is raised
Ruby
145
star
30

benchmark

The Benchmark module provides methods for benchmarking Ruby code, giving detailed reports on the time taken for each task.
Ruby
136
star
31

rexml

REXML is an XML toolkit for Ruby
Ruby
130
star
32

timeout

Timeout provides a way to auto-terminate a potentially long-running operation if it hasn't finished in a fixed amount of time.
Ruby
128
star
33

bigdecimal

Arbitrary-precision decimal floating-point number library for Ruby
C
118
star
34

tk

Tk interface module using tcltklib
Ruby
115
star
35

ostruct

OpenStruct implementation
Ruby
106
star
36

logger

simple logging utility
Ruby
103
star
37

erb

An easy to use but powerful templating system for Ruby
Ruby
103
star
38

net-http

Net::HTTP provides a rich library which can be used to build HTTP user-agents.
Ruby
84
star
39

open3

Open3 gives you access to stdin, stdout, and stderr when running other programs.
Ruby
79
star
40

dev-meeting-log

78
star
41

docker-images

Ruby Docker Images
Ruby
74
star
42

tracer

Outputs a source level execution trace of a Ruby program.
Ruby
71
star
43

all-ruby

Run various versions of ruby command
Ruby
71
star
44

uri

URI is a module providing classes to handle Uniform Resource Identifiers
Ruby
69
star
45

pstore

PStore implements a file based persistence mechanism based on a Hash.
Ruby
67
star
46

date

A subclass of Object includes Comparable module for handling dates.
C
66
star
47

strscan

Provides lexical scanning operations on a String.
C
66
star
48

ipaddr

A class to manipulate an IP address
Ruby
62
star
49

ruby2_keywords

Shim library for Module#ruby2_keywords
Ruby
61
star
50

fileutils

Several file utility methods for copying, moving, removing, etc.
Ruby
60
star
51

mspec

RSpec-like test runner for the Ruby Spec Suite
Ruby
57
star
52

shell

Shell implements an idiomatic Ruby interface for common UNIX shell commands
Ruby
57
star
53

matrix

An implementation of Matrix and Vector classes
Ruby
56
star
54

net-telnet

Provides telnet client functionality.
Ruby
56
star
55

iconv

iconv wrapper
C
54
star
56

net-imap

Ruby client api for Internet Message Access Protocol
Ruby
53
star
57

io-console

add console capabilities to IO instance
Ruby
51
star
58

docs.ruby-lang.org

Source of the docs.ruby-lang.org site
Ruby
48
star
59

digest

Provides a framework for message digest libraries.
C
48
star
60

optparse

OptionParser is a class for command-line option analysis.
Ruby
47
star
61

net-smtp

This library provides functionality to send internet mail via SMTP, the Simple Mail Transfer Protocol.
Ruby
44
star
62

zlib

Ruby interface for the zlib compression/decompression library
C
43
star
63

securerandom

Interface for secure random number generator
Ruby
42
star
64

chkbuild

Continuous Integration tool, mainly for Ruby
Ruby
41
star
65

open-uri

OpenURI is an easy-to-use wrapper for Net::HTTP, Net::HTTPS and Net::FTP.
Ruby
41
star
66

forwardable

Provides delegation of specified methods to a designated object
Ruby
40
star
67

xmlrpc

The Ruby standard library package 'xmlrpc'
Ruby
35
star
68

resolv

A thread-aware DNS resolver library written in Ruby
Ruby
32
star
69

prime

Prime numbers and factorization library.
Ruby
32
star
70

cgi

CGI is a large class, providing several categories of methods, many of which are mixed in from other modules.
Ruby
32
star
71

stringio

Pseudo `IO` class from/to `String`.
Java
31
star
72

rubyci

The Ruby CI for chkbuild
Ruby
31
star
73

gserver

GServer implements a generic server
Ruby
31
star
74

ruby-builder

A repository building Ruby/JRuby/TruffleRuby releases to be used in GitHub Actions
Ruby
31
star
75

observer

The Observer pattern provides a simple mechanism for one object to inform a set of interested third-party objects when its state changes.
Ruby
29
star
76

snap.ruby

Ruby snap
HTML
29
star
77

tempfile

A utility class for managing temporary files.
Ruby
26
star
78

etc

Provides access to information typically stored in UNIX /etc directory.
C
26
star
79

profile

Ruby
26
star
80

net-ftp

This class implements the File Transfer Protocol.
Ruby
24
star
81

singleton

The Singleton module implements the Singleton pattern.
Ruby
24
star
82

yaml

This module provides a Ruby interface for data serialization in YAML format.
Ruby
24
star
83

net-protocol

The abstruct interface for net-* client.
Ruby
24
star
84

play-ruby

Ruby Playground Website
TypeScript
24
star
85

pathname

Pathname represents the name of a file or directory on the filesystem, but not the file itself.
Ruby
22
star
86

actions

Ruby
22
star
87

sdbm

Provides a simple file-based key-value store with String keys and values.
C
22
star
88

un

Utilities to replace common UNIX commands
Ruby
21
star
89

set

This library provides the Set class, which deals with a collection of unordered values with no duplicates.
Ruby
21
star
90

ruby-dev-builder

CRuby Dev Builds for GitHub Actions
Ruby
20
star
91

syck

Syck from stdlib turned in to a gem
C
20
star
92

pp

Provides a PrettyPrinter for Ruby objects
Ruby
19
star
93

English

Ruby
19
star
94

base64

Support for encoding and decoding binary data using a Base64 representation
Ruby
18
star
95

git.ruby-lang.org

Manifest for the Ruby git server
Ruby
17
star
96

net-pop

This library provides functionality for retrieving email via POP3, the Post Office Protocol version 3. For details of POP3
Ruby
17
star
97

repl_type_completor

Ruby
17
star
98

delegate

This library provides three different ways to delegate method calls to an object.
Ruby
17
star
99

rbs_json_schema

Generate RBS files from JSON Schema
Ruby
16
star
100

vscode-typeprof

TypeScript
16
star