---
title: Using GDB to Inspect a Running Ruby Process
teaser:
tags: web,ruby,unix
author: Jon Yurek
published_on: 2013-04-05
---

> This job shouldn't be taking this long!

That's not a great thing to have to say, is it? However, I bet you've said it
before and may not have immediately know why.

With liberal use of `puts` and maybe `pry`, you can figure out what a problem
_might_ be next time you run it, but sometimes you need to figure out what that
problem is right now.

As it turns out, and I know this is a shocker, Ruby processes are just regular
processes. They can be debugged with `gdb`.

Having recently had the need to find out why a job of mine was running
particularly slowly, I found out about this lovely tool the hard way: frantic
googling. I found some very useful functions for gdb in [a blog post by Rasmus
on Ruby callstacks][1].

```ruby
define redirect_stdout
  call rb_eval_string("$_old_stdout, $stdout = $stdout,
    File.open('/tmp/ruby-debug.' + Process.pid.to_s, 'a'); $stdout.sync = true")
end

define ruby_eval
  call(rb_p(rb_eval_string_protect($arg0,(int*)0)))
end
```

How to use these:

1. Start up `gdb` by running `gdb /path/to/ruby PID`, where `/path/to/ruby` is
   the full path to the actual ruby binary and `PID` is the process ID of the
   ruby you want to check out.
1. Paste those functions above into the gdb prompt (you might also want to store
   them in `~/.gdbinit` for later).
1. Run `redirect_stdout`, which will put all the ruby output into a file called
   `/tmp/ruby-debug.PID` where `PID` in this case if the process id of gdb --
   not terribly important, but a differentiator in case you do this a lot.
1. Run commands via `ruby_eval('Kernel.caller')` and `object_id` and things like
   that. You should be able to get local variables from wherever you broke into
   the program.

These `ruby_eval` commands will output into the tempfile that `redirect_stdout`
created, so you'll need to `tail -f` that file in a different console. Now, with
that small headache over with, you can see exactly where your program is and if
there is a stupid loop where you forgot to check a boundary condition, or what
thing you're doing with a regular expression on where you should have just used
`String#index`.

[1]: http://rrn.dk/running-ruby-process-callstack
