Skip to content

Instantly share code, notes, and snippets.

@pnomolos
Forked from fujin/Ruby GDB introspection
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pnomolos/03b803ac9b566ffe2c40 to your computer and use it in GitHub Desktop.
Save pnomolos/03b803ac9b566ffe2c40 to your computer and use it in GitHub Desktop.
Attaching to the process with GDB
Populate your .gdbinit and .gdb directories
In ~/.gdbinit:
define session-ruby
source ~/.gdb/ruby
end
Next, you need to download http://eigenclass.org/hiki.rb?c=plugin;plugin=attach_download;p=ruby+live+process+introspection;file_name=ruby
And place it in ~/.gdb/ruby.
$ mkdir -p ~/.gdb
$ wget 'http://eigenclass.org/hiki.rb?c=plugin;plugin=attach_download;p=ruby+live+process+introspection;file_name=ruby'
$ mv ruby ~/.gdb
Attach to the process, load the ruby helpers, and redirect stdout:
$ ps ax | grep ruby
845 s000 S+ 0:00.91 /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby /usr/bin/chef-indexer -l debug
932 s001 R+ 0:00.00 grep ruby
842 s002 S+ 0:00.44 /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby /usr/bin/stompserver
The important part here is the very first segment of the line (the PID).
$ gdb /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby 845
The first argument to gdb should be the full path to the ruby executable that is running the process.
Start your debug session
From above, you should see a bunch of output like this:
...
Loaded symbols for /srv/ruby/1.8.6/lib/ruby/1.8/i686-linux/nkf.so
0xbfffe402 in +kernel_vsyscall ()
And then you'll wind up at...
(gdb)
First things first, load up the ruby helpers.
(gdb) session-ruby
Then, redirect stdout to a file, so we can capture the output for later.
(gdb) redirect_stdout
Open up a second terminal, and you can watch the output from your debug session:
$ tail -f /tmp/ruby-debug.PID
Where PID above is equal to the PID you attached to with gdb.
Now that you are watching, flip back to your gdb session and..
Get some data
(gdb) eval "caller"
(gdb) rb_object_counts
(gdb) eval "total = ObjectSpace.each_object {|x| if x.class.to_s =~ /Puppet/; puts '---'; puts x.inspect; end }; puts \"---\nTotal Objects: #{total}\""
Or, for arrays only:
(gdb) eval "total = ObjectSpace.each_object(Array){|x| puts '---'; puts x.inspect }; puts \"---\nTotal Arrays: #{total}\""
You should see a stack trace, a long count of the number of objects in the system.
# taken from http://eigenclass.org/hiki.rb?ruby+live+process+introspection
###################
# #### RUBY STUFF
define eval
call(rb_p(rb_eval_string_protect($arg0,(int*)0)))
end
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 restore_stdout
call rb_eval_string("$stdout = $_old_stdout")
end
define rb_finish
call rb_eval_string_protect("set_trace_func lambda{|event, file, line, id, binding, classname| if /return/ =~ event; sleep 0; set_trace_func(nil) end}",(int*)0)
tbreak rb_f_sleep
cont
end
define rb_object_counts
call rb_eval_string_protect("counts = Hash.new{|h,k| h[k] = 0}; ObjectSpace.each_object{|o| counts[o.class] += 1}; counts.sort_by{|k,c| c}.reverse.each{|k,c| puts '%7d %s' % [c, k] } ",(int*)0)
end
define rb_locals
eval "local_variables.map{|x| puts '%s = %s' % [x, eval(x)]}; nil"
end
define rp
if ($arg0 & 0x1)
echo T_FIXNUM\n
print (long)$arg0 >> 1
else
if ($arg0 == 0)
echo T_FALSE\n
else
if ($arg0 == 2)
echo T_TRUE\n
else
if ($arg0 == 4)
echo T_NIL\n
else
if ($arg0 == 6)
echo T_UNDEF\n
else
if (($arg0 & 0xff) == 0x0e)
echo T_SYMBOL\n
output $arg0 >> 8
echo \n
call rb_id2name($arg0 >> 8)
else
set $rbasic = (struct RBasic*)$arg0
# output $rbasic
# echo \ =\
# output *$rbasic
# echo \n
set $flags = (*$rbasic).flags & 0x3f
if ($flags == 0x01)
echo T_NIL\n
echo impossible\n
else
if ($flags == 0x02)
echo T_OBJECT\n
print *(struct RObject*)$rbasic
else
if ($flags == 0x03)
echo T_CLASS\n
# rb_classname($arg0)
else
if ($flags == 0x04)
echo T_ICLASS\n
print *(struct RClass*)$rbasic
else
if ($flags == 0x05)
echo T_MODULE\n
print *(struct RClass*)$rbasic
else
if ($flags == 0x06)
echo T_FLOAT\n
print *(struct RFloat*)$rbasic
else
if ($flags == 0x07)
echo T_STRING\n
print *(struct RString*)$rbasic
else
if ($flags == 0x08)
echo T_REGEXP\n
print *(struct RRegexp*)$rbasic
else
if ($flags == 0x09)
echo T_ARRAY\n
print *(struct RArray*)$rbasic
else
if ($flags == 0x0a)
echo T_FIXNUM\n
echo impossible\n
else
if ($flags == 0x0b)
echo T_HASH\n
print *(struct RHash*)$rbasic
else
if ($flags == 0x0c)
echo T_STRUCT\n
print *(struct RStruct*)$rbasic
else
if ($flags == 0x0d)
echo T_BIGNUM\n
print *(struct RBignum*)$rbasic
else
if ($flags == 0x0e)
echo T_FILE\n
print *(struct RFile*)$rbasic
else
if ($flags == 0x20)
echo T_TRUE\n
echo impossible\n
else
if ($flags == 0x21)
echo T_FALSE\n
echo impossible\n
else
if ($flags == 0x22)
echo T_DATA\n
print *(struct RData*)$rbasic
else
if ($flags == 0x23)
echo T_MATCH\n
print *(struct RMatch*)$rbasic
else
if ($flags == 0x24)
echo T_SYMBOL\n
echo impossible\n
else
if ($flags == 0x3c)
echo T_UNDEF\n
echo impossible\n
else
if ($flags == 0x3d)
echo T_VARMAP\n
else
if ($flags == 0x3e)
echo T_SCOPE\n
else
if ($flags == 0x3f)
echo T_NODE\n
print (NODE*)$arg0
else
echo Unknown\n
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
document rp
ruby¤ÎÁȤ߹þ¤ß¥ª¥Ö¥¸¥§¥¯¥È¤òɽ¼¨¤¹¤ë
end
define nd_type
print nodetype($arg0)
end
document nd_type
ruby node ¤Î·¿¤òɽ¼¨
end
define nd_file
print ((NODE*)$arg0)->nd_file
end
document nd_file
node ¤Î¥½¡¼¥¹¥Õ¥¡¥¤¥ë̾¤òɽ¼¨
end
define nd_line
print nodeline($arg0)
end
document nd_line
node ¤Î¹ÔÈÖ¹æ¤òɽ¼¨
end
# ruby node ¤Î¥á¥ó¥Ð¤òɽ¼¨
define nd_head
print "u1.node"
what $arg0.u1.node
p $arg0.u1.node
end
define nd_alen
print "u2.argc"
what $arg0.u2.argc
p $arg0.u2.argc
end
define nd_next
print "u3.node"
what $arg0.u3.node
p $arg0.u3.node
end
define nd_cond
print "u1.node"
what $arg0.u1.node
p $arg0.u1.node
end
define nd_body
print "u2.node"
what $arg0.u2.node
p $arg0.u2.node
end
define nd_else
print "u3.node"
what $arg0.u3.node
p $arg0.u3.node
end
define nd_orig
print "u3.value"
what $arg0.u3.value
p $arg0.u3.value
end
define nd_resq
print "u2.node"
what $arg0.u2.node
p $arg0.u2.node
end
define nd_ensr
print "u3.node"
what $arg0.u3.node
p $arg0.u3.node
end
define nd_1st
print "u1.node"
what $arg0.u1.node
p $arg0.u1.node
end
define nd_2nd
print "u2.node"
what $arg0.u2.node
p $arg0.u2.node
end
define nd_stts
print "u1.node"
what $arg0.u1.node
p $arg0.u1.node
end
define nd_entry
print "u3.entry"
what $arg0.u3.entry
p $arg0.u3.entry
end
define nd_vid
print "u1.id"
what $arg0.u1.id
p $arg0.u1.id
end
define nd_cflag
print "u2.id"
what $arg0.u2.id
p $arg0.u2.id
end
define nd_cval
print "u3.value"
what $arg0.u3.value
p $arg0.u3.value
end
define nd_cnt
print "u3.cnt"
what $arg0.u3.cnt
p $arg0.u3.cnt
end
define nd_tbl
print "u1.tbl"
what $arg0.u1.tbl
p $arg0.u1.tbl
end
define nd_var
print "u1.node"
what $arg0.u1.node
p $arg0.u1.node
end
define nd_ibdy
print "u2.node"
what $arg0.u2.node
p $arg0.u2.node
end
define nd_iter
print "u3.node"
what $arg0.u3.node
p $arg0.u3.node
end
define nd_value
print "u2.node"
what $arg0.u2.node
p $arg0.u2.node
end
define nd_aid
print "u3.id"
what $arg0.u3.id
p $arg0.u3.id
end
define nd_lit
print "u1.value"
what $arg0.u1.value
p $arg0.u1.value
end
define nd_frml
print "u1.node"
what $arg0.u1.node
p $arg0.u1.node
end
define nd_rest
print "u2.argc"
what $arg0.u2.argc
p $arg0.u2.argc
end
define nd_opt
print "u1.node"
what $arg0.u1.node
p $arg0.u1.node
end
define nd_recv
print "u1.node"
what $arg0.u1.node
p $arg0.u1.node
end
define nd_mid
print "u2.id"
what $arg0.u2.id
p $arg0.u2.id
end
define nd_args
print "u3.node"
what $arg0.u3.node
p $arg0.u3.node
end
define nd_noex
print "u1.id"
what $arg0.u1.id
p $arg0.u1.id
end
define nd_defn
print "u3.node"
what $arg0.u3.node
p $arg0.u3.node
end
define nd_old
print "u1.id"
what $arg0.u1.id
p $arg0.u1.id
end
define nd_new
print "u2.id"
what $arg0.u2.id
p $arg0.u2.id
end
define nd_cfnc
print "u1.cfunc"
what $arg0.u1.cfunc
p $arg0.u1.cfunc
end
define nd_argc
print "u2.argc"
what $arg0.u2.argc
p $arg0.u2.argc
end
define nd_cname
print "u1.id"
what $arg0.u1.id
p $arg0.u1.id
end
define nd_super
print "u3.node"
what $arg0.u3.node
p $arg0.u3.node
end
define nd_modl
print "u1.id"
what $arg0.u1.id
p $arg0.u1.id
end
define nd_clss
print "u1.value"
what $arg0.u1.value
p $arg0.u1.value
end
define nd_beg
print "u1.node"
what $arg0.u1.node
p $arg0.u1.node
end
define nd_end
print "u2.node"
what $arg0.u2.node
p $arg0.u2.node
end
define nd_state
print "u3.state"
what $arg0.u3.state
p $arg0.u3.state
end
define nd_rval
print "u2.value"
what $arg0.u2.value
p $arg0.u2.value
end
define nd_nth
print "u2.argc"
what $arg0.u2.argc
p $arg0.u2.argc
end
define nd_tag
print "u1.id"
what $arg0.u1.id
p $arg0.u1.id
end
define nd_tval
print "u2.value"
what $arg0.u2.value
p $arg0.u2.value
end
define rb_p
call rb_p($arg0)
end
define rb_id2name
call rb_id2name($arg0)
end
define rb_classname
call classname($arg0)
rb_p $
p *(struct RClass*)$arg0
end
define rb_backtrace
call rb_backtrace()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment