GDB wrapper for Ruby

Posted by Jamis on September 25, 2006 @ 11:10 AM

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!

Posted in Announcements

Comments

Have something to add? Click here to leave a comment.

25 Sep 2006

1. Matt Todd said...

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.

2. Jon Leighton said...

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

3. Jamis said...

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.

4. Jon Leighton said...

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!