The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
"Inspecting a live Ruby process", easier if you cheat.

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Eigen Class

Posts: 358
Nickname: eigenclass
Registered: Oct, 2005

Eigenclass is a hardcore Ruby blog.
"Inspecting a live Ruby process", easier if you cheat. Posted: Sep 23, 2006 5:27 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Eigen Class.
Original Post: "Inspecting a live Ruby process", easier if you cheat.
Feed Title: Eigenclass
Feed URL: http://feeds.feedburner.com/eigenclass
Feed Description: Ruby stuff --- trying to stay away from triviality.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Eigen Class
Latest Posts From Eigenclass

Advertisement

Are you still adding printf/puts calls and restarting your app to figure what went wrong? Sometimes, the problem is hard to reproduce, or you only discover it in production. You've got a process that exhibits the bug, but you didn't run it under ruby-debug, so there's no choice but kill it and reproduce after adding some code to inspect your program, right?

Sure not. Jamis Buck blogged about how to use GDB to inspect a live Ruby process, and showed how to get a stack-trace using Ruby's C API and some GDB scripting:

(gdb) set $ary = (int)backtrace(-1)
(gdb) set $count = *($ary+8)
(gdb) set $index = 0
(gdb) while $index < $count
>  x/1s *((int)rb_ary_entry($ary, $index)+12)
>  set $index = $index + 1
>end

But it gets much easier than that. How about this:

(gdb) eval "caller"

or

(gdb) eval "local_variables"

Once you've opened that door, you get a full-powered Ruby interpreter inside GDB. Ruby's introspection capabilities do the rest. Local variables, instance variables, classes, methods, Ruby threads, object counts... evil eval can bring us pretty far. You can find the scripts to turn GDB into a sort of IRB that can attach to running processes below.

A synthetic example

For the sake of illustration, let's take this trivial program:


def foo
  a = 1
  bar + a
end

def bar
  a = 2
  b = 2
  baz + 1
end

def baz
  c = 232
  c + gets.to_i
end

puts "foo returned #{foo}"

$ gdb ruby 
GNU gdb 6.1-debian
...
(gdb) attach 13658
Attaching to program: /home/batsman/usr/bin/ruby, process 13525
...
0xa7ec526e in read () from /lib/tls/libc.so.6
(gdb) 

I don't want to pollute gdb with lots of commands, so I've put the Ruby magic in a separate script that can be loaded with

(gdb) session-ruby

(I also have a session-asm that imports a number of commands useful for low-level inspection.)

At this point, I could just

 (gdb) eval "caller"

but that would #p() the caller's result in the stdout from the process being examined. So I first redirect $stdout with another command:

 (gdb) redirect_stdout
 $1 = 2
 (gdb) eval "caller"

This way, the result from eval is put in /tmp/ruby-debug.PID, and I get:

 $ tail /tmp/ruby-debug.13658 
 ["foo.rb:16:in `baz'", "foo.rb:11:in `bar'", "foo.rb:5:in `foo'",
 "foo.rb:19"]

Basic introspection

The stacktrace tells me where I am, but there's more much information available:

 (gdb) rb_object_counts
   220  String
   183  Class
    16  Module
    12  Array
     5  Float
     3  Bignum
     3  IO
     3  Object
     2  File
     1  Proc
     1  SystemStackError
     1  Binding
     1  fatal
     1  Thread
     1  ThreadGroup
     1  NoMemoryError
     1  Hash
(gdb) local_variables
["c"]

The last result might look surprising. How come there's a (Ruby) local variable, if we're running a method implemented in C (rb_f_gets)? It seems ruby doesn't get out of its way to overwrite the (Ruby) frame info when it calls a C method, so the data you get corresponds to the enclosing Ruby method.

Running until the end of the current method (aka "finish")


Read more...

Read: "Inspecting a live Ruby process", easier if you cheat.

Topic: Why we focus on solutions, not products Previous Topic   Next Topic Topic: MySQL Query Analyzer Rails Plugin

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use