The Buckblog

assorted ramblings by Jamis Buck

GDB wrapper for Ruby

25 September 2006 — 2-minute read

In his usual inimitable fashion, _why raised his hand in the comments to Inspecting a live ruby process and asked “I wonder if this could be wrapped up into an extension?” Intriguing idea!

I played around with it a bit over the weekend, and came up with a relatively simple script that wraps the GDB console, using popen to communicate with it from Ruby. It lets you do some fun stuff, but it’s still kind of fragile. I’m releasing it into the public domain, in the hopes that someone will take the idea and run with it, since I don’t really have any more time to play with it.

You can grab it here.

Basic usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
require 'gdb'

# create a new GDB::Ruby instance and attach it to
# pid 12345
gdb = GDB::Ruby.new(12345)

# print the (ruby) backtrace of the remote process
gdb.backtrace.each { |line| puts line }

# show the current local variables, and their values
p gdb.local_variables

# evaluate arbitrary ruby code in the remote process
p gdb.eval('%(pid #{$$})')

# show how many instances of each class exist in the
# remote process
p gdb.object_space

# raise an exception in the remote process
gdb.raise Exception, "go boom!"

# close the connection to the remote process
gdb.quit

As I said, it’s a little fragile; it doesn’t really do much in the way of error handling. Also, I’ve noticed that it will occassionally kill the process it attaches to (I suspect some bad interaction with garbage collection, but I haven’t dug much into it). For the curious, it uses the C API to work its magic, rather than the eval-based approach described by Mauricio. A more robust implementation could possibly be created using eval.

So, forgive the unoriginal name and the spotty implementation. It’s a fun experiment, nonetheless. Let me know what you think!

Reader Comments

I did a little hack to trap INT and start up gdb on the current process... Check it out: http://pastie.caboo.se/14613 M.T.
I did the obvious and hooked it into IRB: http://dev.turnipspatch.com/trac/browser/rgdb/trunk Example: $ rgdb 10500 Attaching GDB to process id 10500 irb(main):001:0> @gdb.local_variables However, I'm not getting any success with you code actually working on my machine :(. Any ideas about this: http://pastie.caboo.se/14829 ? Cheers
Jon, My implementation of the call function isn't expecting negative integers to be returned. :( My bad. The following patch should make it happier:
1
2
3
4
5

103c103
<           if md = result.first.match(/= (\d+)/)
---
>           if md = result.first.match(/= (-?\d+)/)
I'll also update the gdb.rb script I'm linking to.

Nice one. I've updated the file in my SVN repo and added in a README file.

If anyone else wants to improve gdb.rb feel free to use my irb stuff too. I'm probably not the guy to do it as I know bugger all about GDB!