Object Inspection
This guide explains how to use rb-object-print to inspect Ruby objects, hashes, arrays, and structs in GDB.
Why Object Inspection Matters
When debugging Ruby programs or analyzing core dumps, you often need to inspect complex data structures that are difficult to read in their raw memory representation. Standard GDB commands show pointer addresses and raw memory, but not the logical structure of Ruby objects.
Use rb-object-print when you need:
- Understand exception objects: See the full exception hierarchy, message, and backtrace data
- Inspect fiber storage: View thread-local data and fiber-specific variables
- Debug data corruption: Check the contents of hashes and arrays for unexpected values
- Analyze VM state: Examine objects on the VM stack without manual pointer arithmetic
Basic Usage
The rb-object-print command recursively prints Ruby objects in a human-readable format.
Syntax
rb-object-print <expression> [--depth N] [--debug]
Where:
<expression>: Any GDB expression that evaluates to a Ruby VALUE--depth N: Maximum recursion depth (default: 1)--debug: Enable diagnostic output for troubleshooting
Simple Values
Print immediate values and special constants:
(gdb) rb-object-print 0 # <T_FALSE>
(gdb) rb-object-print 8 # <T_NIL>
(gdb) rb-object-print 20 # <T_TRUE>
(gdb) rb-object-print 85 # <T_FIXNUM> 42
These work without any Ruby process running, making them useful for learning and testing.
Expressions
Use any valid GDB expression:
(gdb) rb-object-print $ec->errinfo # Exception object
(gdb) rb-object-print $ec->cfp->sp[-1] # Top of VM stack
(gdb) rb-object-print $ec->storage # Fiber storage hash
(gdb) rb-object-print (VALUE)0x00007f8a12345678 # Object at specific address
Inspecting Hashes
Ruby hashes have two internal representations (ST table and AR table). The command automatically detects and displays both:
Small Hashes (AR Table)
For hashes with fewer than 8 entries, Ruby uses an array-based implementation:
(gdb) rb-object-print $some_hash
<T_HASH@...>
[ 0] K: <T_SYMBOL> :name
V: <T_STRING@...> "Alice"
[ 1] K: <T_SYMBOL> :age
V: <T_FIXNUM> 30
[ 2] K: <T_SYMBOL> :active
V: <T_TRUE>
Large Hashes (ST Table)
For larger hashes, Ruby uses a hash table (output format is similar):
(gdb) rb-object-print $large_hash
<T_HASH@...>
[ 0] K: <T_SYMBOL> :user_id
V: <T_FIXNUM> 12345
[ 1] K: <T_SYMBOL> :session_data
V: <T_STRING@...> "..."
...
Controlling Depth
Prevent overwhelming output from deeply nested structures:
(gdb) rb-object-print $nested_hash --depth 1 # Only top level
<T_HASH@...>
[ 0] K: <T_SYMBOL> :data
V: <T_HASH@...> # Nested hash not expanded
(gdb) rb-object-print $nested_hash --depth 2 # Expand one level
<T_HASH@...>
[ 0] K: <T_SYMBOL> :data
V: <T_HASH@...>
[ 0] K: <T_SYMBOL> :nested_key
V: <T_STRING@...> "value"
At depth 1, nested structures show their type and address but aren't expanded. Increase depth to expand them.
Inspecting Arrays
Arrays also have two representations based on size:
Arrays
Arrays display their elements with type information:
(gdb) rb-object-print $array
<T_ARRAY@...>
[ 0] <T_FIXNUM> 1
[ 1] <T_FIXNUM> 2
[ 2] <T_FIXNUM> 3
For arrays with nested objects:
(gdb) rb-object-print $array --depth 2
<T_ARRAY@...>
[ 0] <T_STRING@...> "first item"
[ 1] <T_HASH@...>
[ 0] K: <T_SYMBOL> :key
V: <T_FIXNUM> 123
...
Inspecting Structs
Ruby Struct objects work similarly to arrays:
(gdb) rb-object-print $struct_instance
<T_STRUCT@...>
[ 0] <T_STRING@...> "John"
[ 1] <T_FIXNUM> 25
[ 2] <T_STRING@...> "Engineer"
[ 3] <T_TRUE>
Practical Examples
Debugging Exception in Fiber
When a fiber has an exception, inspect it:
(gdb) rb-fiber-scan-heap
(gdb) rb-fiber-scan-switch 5 # Switch to fiber #5
(gdb) rb-object-print $errinfo --depth 3
This reveals the full exception structure including any nested causes. After switching to a fiber, $errinfo and $ec convenience variables are automatically set.
Inspecting Method Arguments
Break at a method and examine arguments on the stack:
(gdb) break some_method
(gdb) run
(gdb) rb-object-print $ec->cfp->sp[-1] # Last argument
(gdb) rb-object-print $ec->cfp->sp[-2] # Second-to-last argument
Examining Fiber Storage
Thread-local variables are stored in fiber storage:
(gdb) rb-fiber-scan-heap
(gdb) rb-fiber-scan-switch 0
(gdb) rb-object-print $ec->storage --depth 2
This shows all thread-local variables and their values.
Debugging with --debug Flag
When rb-object-print doesn't show what you expect, use --debug:
(gdb) rb-object-print $suspicious_value --debug
DEBUG: Evaluated '$suspicious_value' to 0x7f8a1c567890
DEBUG: Loaded constant RUBY_T_MASK = 31
DEBUG: Object at 0x7f8a1c567890 with flags=0x20040005, type=0x5
...
This shows:
- How the expression was evaluated
- What constants were loaded
- Object type detection logic
- Any errors encountered
Use this to troubleshoot:
- Unexpected output format
- Missing nested structures
- Type detection issues
- Access errors