Skip to content

Commit 8447c72

Browse files
Update documentation.
1 parent fa55874 commit 8447c72

File tree

13 files changed

+272
-474
lines changed

13 files changed

+272
-474
lines changed

context/fiber-debugging.md

Lines changed: 35 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ Scanning heap for Fiber objects...
2828
2929
Found 12 fiber(s):
3030
31-
Fiber #0: <VALUE:0x7f8a1c800000>
32-
Status: RESUMED
33-
Stack: 0x7f8a1d000000
31+
Fiber #0: <T_DATA@...> → <struct rb_fiber_struct@...>
32+
Status: SUSPENDED
33+
Stack: <void *@...>
34+
VM Stack: <VALUE *@...>
35+
CFP: <rb_control_frame_t@...>
3436
35-
Fiber #1: <VALUE:0x7f8a1c800100>
37+
Fiber #1: <T_DATA@...> → <struct rb_fiber_struct@...>
3638
Status: SUSPENDED
3739
...
3840
~~~
@@ -75,18 +77,18 @@ See Ruby-level call stacks for all fibers at once:
7577
(gdb) rb-fiber-scan-stack-trace-all
7678
Found 12 fiber(s)
7779
78-
Fiber #0: <VALUE:0x7f8a1c800000>
80+
Fiber #0: <T_DATA@...> → <struct rb_fiber_struct@...>
7981
Status: RESUMED
8082
[No backtrace - fiber is running]
8183
82-
Fiber #1: <VALUE:0x7f8a1c800100>
84+
Fiber #1: <T_DATA@...> → <struct rb_fiber_struct@...>
8385
Status: SUSPENDED
8486
/app/lib/connection.rb:123:in `read'
8587
/app/lib/connection.rb:89:in `receive'
8688
/app/lib/server.rb:56:in `handle_client'
8789
...
8890
89-
Fiber #5: <VALUE:0x7f8a1c800500>
91+
Fiber #5: <T_DATA@...> → <struct rb_fiber_struct@...>
9092
Status: SUSPENDED
9193
Exception: IOError: Connection reset
9294
/app/lib/connection.rb:45:in `write'
@@ -104,13 +106,20 @@ The most powerful feature: switch GDB's view to a fiber's stack (even in core du
104106
~~~
105107
(gdb) rb-fiber-scan-heap
106108
(gdb) rb-fiber-scan-switch 5
107-
Switched to Fiber #5
109+
Switching to Fiber #5: VALUE 0x...
110+
Switched to Fiber: <T_DATA@...> → <struct rb_fiber_struct@...>
108111
Status: SUSPENDED
109-
110-
Now you can use standard GDB commands with this fiber's context:
111-
rb-stack-trace # Show combined backtrace
112-
bt # Show C backtrace
113-
info locals # Show C local variables
112+
113+
Convenience variables set:
114+
$fiber = Current fiber VALUE
115+
$fiber_ptr = Current fiber pointer (struct rb_fiber_struct *)
116+
$ec = Execution context (rb_execution_context_t *)
117+
$errinfo = Exception being handled (VALUE)
118+
119+
Now try:
120+
bt # Show C backtrace of fiber
121+
rb-stack-trace # Show combined Ruby/C backtrace
122+
info locals # Show local variables
114123
~~~
115124

116125
After switching, all standard GDB commands work with the fiber's context:
@@ -145,147 +154,21 @@ Return to normal stack view:
145154

146155
## Analyzing Fiber State
147156

148-
### VM Stack Inspection
149-
150-
View the Ruby VM stack for a fiber:
151-
152-
~~~
153-
(gdb) rb-fiber-vm-stack 5
154-
VM Stack for Fiber #5:
155-
Base: 0x7f8a1c950000
156-
Size: 4096 VALUEs (32768 bytes)
157-
CFP: 0x7f8a1c951000
158-
~~~
159-
160-
### VM Control Frames
161-
162-
Walk through each Ruby method frame:
163-
164-
~~~
165-
(gdb) rb-fiber-vm-frames 5
166-
VM Control Frames for Fiber #5:
167-
...
168-
169-
Frame #0 (depth 45):
170-
CFP Address: 0x7f8a1c951000
171-
PC: 0x7f8a1c234500
172-
SP: 0x7f8a1c950100
173-
Location: /app/lib/connection.rb:123
174-
Method: read
175-
Frame Type: VM_FRAME_MAGIC_METHOD
176-
Stack Depth: 256 slots
177-
~~~
178-
179-
### Stack Top Values
180-
181-
See what's on top of the VM stack:
182-
183-
~~~
184-
(gdb) rb-fiber-stack-top 5 20
185-
VM Stack Top for Fiber #5:
186-
187-
Top 20 VALUE(s) on stack (newest first):
188-
189-
[ -1] 0x00007f8a1c888888 T_STRING "Hello"
190-
[ -2] 0x0000000000000015 Fixnum(10) Fixnum: 10
191-
[ -3] 0x00007f8a1c999999 T_HASH <hash:0x7f8a1c999999>
192-
...
193-
~~~
194-
195-
## Diagnosing Crashes
196-
197-
When Ruby crashes, find out why:
198-
199-
~~~
200-
(gdb) rb-diagnose-exit
201-
================================================================================
202-
DIAGNOSING RUBY EXIT/CRASH
203-
================================================================================
204-
205-
[1] Main Thread Exception:
206-
--------------------------------------------------------------------------------
207-
Main thread has exception: NoMethodError
208-
VALUE: 0x7f8a1c777777
209-
Use: rb-object-print (VALUE)0x7f8a1c777777
210-
211-
[2] Fibers with Exceptions:
212-
--------------------------------------------------------------------------------
213-
Fiber #5 (SUSPENDED): RuntimeError
214-
Fiber: 0x7f8a1c800500, errinfo: 0x7f8a1c666666
215-
Fiber #8 (SUSPENDED): IOError
216-
Fiber: 0x7f8a1c800800, errinfo: 0x7f8a1c555555
217-
218-
[3] Interrupt Flags:
219-
--------------------------------------------------------------------------------
220-
interrupt_flag: 0x00000002
221-
interrupt_mask: 0x00000000
222-
WARNING: Interrupts pending!
223-
- TRAP
224-
225-
[4] Signal Information (from core dump):
226-
--------------------------------------------------------------------------------
227-
Program terminated with signal SIGSEGV, Segmentation fault.
228-
...
229-
~~~
230-
231-
This comprehensive overview helps quickly identify the root cause.
232-
233-
## Advanced Techniques
234-
235-
### Finding Fibers by Stack Address
236-
237-
If you know a stack address, find the owning fiber:
157+
After switching to a fiber with `rb-fiber-scan-switch`, you can use standard GDB commands to inspect the fiber's state:
238158

239159
~~~
240-
(gdb) info frame
241-
... rsp = 0x7f8a1e000500 ...
242-
243-
(gdb) rb-fiber-from-stack 0x7f8a1e000000
244-
Searching for fiber with stack base 0x7f8a1e000000...
245-
246-
Found fiber: 0x7f8a1c800300
247-
Status: SUSPENDED
248-
Stack: base=0x7f8a1e000000, size=1048576
249-
~~~
250-
251-
### Searching Fibers by Function
252-
253-
Find which fibers are blocked in a specific C function:
254-
255-
~~~
256-
(gdb) rb-fiber-c-stack-search pthread_cond_wait
257-
Scanning 12 fiber(s)...
258-
259-
Match: Fiber #3 - found at 0x7f8a1e000450
260-
Match: Fiber #7 - found at 0x7f8a1e100780
261-
262-
Search complete: 2 fiber(s) matched.
263-
~~~
264-
265-
Use this to find all fibers waiting on locks or I/O.
266-
267-
### Debug Unwinder Issues
268-
269-
If fiber switching doesn't work as expected:
270-
160+
(gdb) rb-fiber-scan-switch 5
161+
(gdb) bt # Show C backtrace
162+
(gdb) frame <n> # Switch to specific frame
163+
(gdb) info locals # Show local variables
164+
(gdb) rb-object-print $errinfo # Print exception if present
271165
~~~
272-
(gdb) rb-fiber-debug-unwind 5
273-
Debug unwinding for Fiber #5: 0x7f8a1c800500
274-
275-
Coroutine context:
276-
fiber->context.stack_pointer = 0x7f8a1e000480
277166

278-
Saved registers on coroutine stack:
279-
[0x7f8a1e000480+0] = R15: 0x0000000000000000
280-
[0x7f8a1e000480+8] = R14: 0x00007f8a1c567890
281-
...
282-
[0x7f8a1e000480+48] = RIP: 0x00007f8a1ab12345
283-
284-
Validation:
285-
✓ RIP looks like a valid code address
286-
Symbol: fiber_setcontext + 123
287-
✓ RSP is within fiber's stack range
288-
~~~
167+
The fiber switch command sets up several convenience variables:
168+
- `$fiber` - The fiber VALUE
169+
- `$fiber_ptr` - Pointer to `struct rb_fiber_struct`
170+
- `$ec` - The fiber's execution context
171+
- `$errinfo` - Exception being handled (if any)
289172

290173
## Best Practices
291174

@@ -306,10 +189,10 @@ The cache persists throughout your GDB session.
306189
CREATED and TERMINATED fibers may not have valid saved contexts. The scan output shows status:
307190

308191
~~~
309-
Fiber #5: <VALUE:0x7f8a1c800500>
192+
Fiber #5: <T_DATA@...> → <struct rb_fiber_struct@...>
310193
Status: TERMINATED # Won't have useful context
311194
312-
Fiber #3: <VALUE:0x7f8a1c800300>
195+
Fiber #3: <T_DATA@...> → <struct rb_fiber_struct@...>
313196
Status: SUSPENDED # Good candidate for inspection
314197
~~~
315198

context/getting-started.md

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,62 @@
11
# Getting Started
22

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

55
## Installation
66

77
Install the gem:
88

99
~~~ bash
10-
$ gem install ruby-gdb
10+
$ gem install toolbox
1111
~~~
1212

1313
### Installing GDB Extensions
1414

15-
Install the extensions (automatically adds to `~/.gdbinit`):
15+
Install the GDB extensions (automatically adds to `~/.gdbinit`):
1616

1717
~~~ bash
18-
$ bake ruby:gdb:install
18+
$ bake toolbox:gdb:install
1919
~~~
2020

2121
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.
2222

2323
To install to a custom `.gdbinit` location:
2424

2525
~~~ bash
26-
$ bake ruby:gdb:install gdbinit=/path/to/custom/gdbinit
26+
$ bake toolbox:gdb:install gdbinit=/path/to/custom/gdbinit
27+
~~~
28+
29+
### Installing LLDB Extensions
30+
31+
Install the LLDB extensions (automatically adds to `~/.lldbinit`):
32+
33+
~~~ bash
34+
$ bake toolbox:lldb:install
35+
~~~
36+
37+
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.
38+
39+
To install to a custom `.lldbinit` location:
40+
41+
~~~ bash
42+
$ bake toolbox:lldb:install lldbinit=/path/to/custom/lldbinit
2743
~~~
2844

2945
### Verifying Installation
3046

31-
Check installation status:
47+
Check GDB installation status:
3248

3349
~~~ bash
34-
$ bake ruby:gdb:info
35-
Ruby GDB Extensions v0.1.0
50+
$ bake toolbox:gdb:info
51+
Ruby Toolbox GDB Extensions v0.1.0
52+
Status: ✓ Installed
53+
~~~
54+
55+
Check LLDB installation status:
56+
57+
~~~ bash
58+
$ bake toolbox:lldb:info
59+
Ruby Toolbox LLDB Extensions v0.1.0
3660
Status: ✓ Installed
3761
~~~
3862

@@ -45,10 +69,16 @@ Recursively print Ruby hash and array structures...
4569

4670
### Uninstalling
4771

48-
To remove the extensions:
72+
To remove the GDB extensions:
73+
74+
~~~ bash
75+
$ bake toolbox:gdb:uninstall
76+
~~~
77+
78+
To remove the LLDB extensions:
4979

5080
~~~ bash
51-
$ bake ruby:gdb:uninstall
81+
$ bake toolbox:lldb:uninstall
5282
~~~
5383

5484
This removes the source line from your `~/.gdbinit`.
@@ -135,9 +165,9 @@ Ruby hashes and arrays can contain nested structures:
135165

136166
~~~
137167
(gdb) rb-object-print $some_hash --depth 2
138-
<T_HASH@0x7f8a1c999999>
168+
<T_HASH@...>
139169
[ 0] K: <T_SYMBOL> :name
140-
V: <T_STRING@0x7f8a1c888888> 'Alice'
170+
V: <T_STRING@...> "Alice"
141171
[ 1] K: <T_SYMBOL> :age
142172
V: <T_FIXNUM> 30
143173
~~~

0 commit comments

Comments
 (0)