ToolboxGuidesGetting Started

Getting Started

This guide explains how to install and use Toolbox for debugging Ruby programs and core dumps with GDB or LLDB.

Installation

Install the gem:

$ gem install toolbox

Installing GDB Extensions

Install the GDB extensions (automatically adds to ~/.gdbinit):

$ bake -g toolbox toolbox:gdb:install

This adds a single line to your ~/.gdbinit that sources the extensions from the gem's data directory. The extensions will then load automatically every time you start GDB.

To install to a custom .gdbinit location:

$ bake -g toolbox toolbox:gdb:install gdbinit=/path/to/custom/gdbinit

Installing LLDB Extensions

Install the LLDB extensions (automatically adds to ~/.lldbinit):

$ bake -g toolbox toolbox:lldb:install

This adds a command script import line to your ~/.lldbinit that loads the extensions from the gem's data directory. The extensions will then load automatically every time you start LLDB.

To install to a custom .lldbinit location:

$ bake -g toolbox toolbox:lldb:install lldbinit=/path/to/custom/lldbinit

Verifying Installation

Check GDB installation status:

$ bake -g toolbox toolbox:gdb:info
Ruby Toolbox GDB Extensions v0.1.0
Status: ✓ Installed

Check LLDB installation status:

$ bake -g toolbox toolbox:lldb:info
Ruby Toolbox LLDB Extensions v0.1.0
Status: ✓ Installed

Test that extensions load automatically:

$ gdb --batch -ex "help rb-object-print"
Recursively print Ruby hash and array structures...

Uninstalling

To remove the GDB extensions:

$ bake -g toolbox toolbox:gdb:uninstall

To remove the LLDB extensions:

$ bake -g toolbox toolbox:lldb:uninstall

This removes the source line from your ~/.gdbinit or ~/.lldbinit.

Core Concepts

Ruby GDB provides specialized commands for debugging Ruby at multiple levels:

  • Context Setup (rb-context) - Get current execution context and set up convenience variables
  • Object Inspection (rb-object-print) - View Ruby objects, hashes, arrays, and structs with proper formatting
  • Fiber Debugging (rb-fiber-*) - Scan heap for fibers, inspect state, and switch contexts
  • Stack Analysis (rb-stack-trace) - Examine combined VM (Ruby) and C (native) stack frames
  • Heap Navigation (rb-heap-scan) - Scan the Ruby heap to find objects by type

Quick Start

Debugging a Running Process

Start your Ruby program under GDB:

$ gdb --args ruby my_script.rb

Set a breakpoint and run:

(gdb) break rb_vm_exec
(gdb) run

Once stopped, use Ruby debugging commands:

(gdb) rb-stack-trace                     # Show combined Ruby/C backtrace
(gdb) rb-fiber-scan-heap                 # Scan heap for fibers
(gdb) rb-heap-scan --type RUBY_T_STRING --limit 5  # Find strings

Debugging a Core Dump

When your Ruby program crashes, you can analyze the core dump:

$ gdb ruby core.dump

Diagnose the issue (extensions load automatically if installed):

(gdb) rb-fiber-scan-heap                 # Scan heap for all fibers
(gdb) rb-fiber-scan-stack-trace-all      # Show backtraces for all fibers
(gdb) rb-fiber-scan-switch 0             # Switch to main fiber
(gdb) rb-object-print $errinfo --depth 2 # Print exception (now $errinfo is set)
(gdb) rb-heap-scan --type RUBY_T_HASH --limit 10  # Find hashes

Common Workflows

Inspecting Exception Objects

When a Ruby exception occurs, you can inspect it in detail:

(gdb) break rb_exc_raise
(gdb) run
(gdb) rb-context
(gdb) rb-object-print $errinfo --depth 2

This shows the exception class, message, and any nested structures. The rb-context command displays the current execution context and sets up $ec, $cfp, and $errinfo convenience variables.

Debugging Fiber Issues

When working with fibers, you often need to see what each fiber is doing:

(gdb) rb-fiber-scan-heap                # Scan heap for all fibers
(gdb) rb-fiber-scan-stack-trace-all     # Show backtraces for all fibers  
(gdb) rb-fiber-scan-switch 5            # Switch GDB to fiber #5's context
(gdb) rb-stack-trace                    # Now shows fiber's combined backtrace

Examining Complex Data Structures

Ruby hashes and arrays can contain nested structures:

(gdb) rb-object-print $some_hash --depth 2
<T_HASH@...>
[   0] K: <T_SYMBOL> :name
       V: <T_STRING@...> "Alice"
[   1] K: <T_SYMBOL> :age
       V: <T_FIXNUM> 30

The --depth flag controls how deep to recurse into nested objects.

Requirements

  • GDB with Python support (GDB 7.0+) or LLDB with Python support.
  • Ruby 3.3+ recommended.

Platform Support

  • Linux: Full support with all features (GDB or LLDB).
  • macOS:
    • Ruby head: Full support.
    • Ruby 3.4.x: Limited support (see below).
  • BSD: Should work similar to Linux (untested).

macOS + Ruby 3.4.x Limitation

On macOS with LLDB and Ruby <= 3.4.x, some commands including rb-fiber-scan-heap will not work due to a dsymutil bug that drops struct RTypedData from debug symbols. This appears fixed in ruby-head.

Workarounds:

  • Use Ruby head: ruby-install ruby-head -- CFLAGS="-g -O0"
  • Use GDB instead of LLDB (works with Ruby 3.4.x)
  • Other commands like rb-object-print, rb-stack-trace, rb-context work fine