[or-cvs] r10626: added ruby gdb-wrapper (in topf/trunk: lib utils)
benedikt at seul.org
benedikt at seul.org
Sun Jun 17 00:58:43 UTC 2007
Author: benedikt
Date: 2007-06-16 20:58:42 -0400 (Sat, 16 Jun 2007)
New Revision: 10626
Added:
topf/trunk/lib/gdb.rb
topf/trunk/utils/gdb-test.rb
Log:
added ruby gdb-wrapper
Added: topf/trunk/lib/gdb.rb
===================================================================
--- topf/trunk/lib/gdb.rb (rev 0)
+++ topf/trunk/lib/gdb.rb 2007-06-17 00:58:42 UTC (rev 10626)
@@ -0,0 +1,129 @@
+# gdb.rb -- a simple wrapper around the GDB console to make inspecting
+# ruby processes less painful.
+#
+# Author: Jamis Buck <jamis at 37signals.com>
+#
+# This library is in the public domain. You are free to use it, modify
+# it, redistribute it, or ignore it, as you wish, with absolutely no
+# restrictions.
+#
+# The GDB module provides a "raw", low-level, language-independent
+# interface to GDB (GDB::Interface) as well as a higher-level
+# interface specifically for Ruby programs (GDB::Ruby). Theoretically,
+# GDB::Interface could be extended to support other languages
+# than Ruby.
+
+module GDB
+ # The basic interface for wrapping GDB. You could concievably use this
+ # to interace with arbitrary remote processes, though it is best used
+ # by extending it to add platform-specific functionality.
+ class Interface
+ # Creates a new GDB::Interface that connects to process-id and
+ # executable.
+ def initialize(options)
+ prompt = "gdb -q "
+
+ prompt << "-c " << options[:core] if options[:core]
+ prompt << " " << options[:executable] if options[:executable]
+ prompt << " " << options[:pid] if options[:pid]
+ prompt << " 2>&1"
+ @gdb = IO.popen(prompt, "r+")
+ read_to_prompt
+ end
+
+ # Returns the (32-bit) integer at the given address
+ def int_at(address)
+ command("x/1dw #{address}").first.split(/:/).last.to_i
+ end
+
+ # Returns the string located at the given address
+ def string_at(address)
+ command("x/1s *#{address}").first.match(/"(.*)"/)[1]
+ end
+
+ # Returns the (8-bit) double precision floating point value at
+ # the given address.
+ def double_at(address)
+ command("x/1fg #{address}").first.split(/:/).last.to_f
+ end
+
+ # Executes the given command and returns the output as an array
+ # of lines. The command must be in GDB's syntax. If $gdb_verbose
+ # is true, this will print the command to STDOUT as well.
+ def command(cmd)
+ puts "(gdb) #{cmd}" if $gdb_verbose
+ @gdb.puts(cmd.strip)
+ read_to_prompt
+ end
+
+ # Call a C function. The +function+ parameter must include any
+ # parameters, all of which must be in valid C syntax. +opts+
+ # should include a <code>:return</code> key, which indicates
+ # what the expected return type of the function is:
+ #
+ # * <code>:int</code>
+ # * <code>:string</code>
+ # * <code>:void</code>
+ #
+ # Currently, the default is <code>:void</code>. The method
+ # returns a value of the expected type.
+ def call(function, opts={})
+ cast = case opts[:return]
+ when :int then "int"
+ when :string then "char*"
+ when nil, :void then "void"
+ else Kernel.raise "unsupported return type #{opts[:return].inspect}"
+ end
+
+ result = command("call (#{cast})#{function}")
+
+ case opts[:return]
+ when :int
+ if md = result.first.match(/= (-?\d+)/)
+ md[1].to_i
+ else
+ Kernel.raise "couldn't match integer result from #{result.inspect}"
+ end
+ when :string then result.first.match(/"(.*)"/)[1]
+ else nil
+ end
+ end
+
+ # Reads all lines emitted by GDB until a recognized prompt is encountered.
+ # Currently recognized prompts are:
+ #
+ # * "(gdb) "
+ # * " >"
+ #
+ # If your version of GDB uses a different kind of prompt, you should
+ # modify this method to include it.
+ #
+ # This method returns the lines read as an array. If $gdb_verbose is
+ # true, the lines will be echoed to STDOUT.
+ def read_to_prompt
+ lines = []
+ line = ""
+ while result = IO.select([@gdb])
+ next if result.empty?
+ c = @gdb.read(1)
+ break if c.nil?
+ line << c
+ break if line == "(gdb) " || line == " >"
+ if line[-1] == ?\n
+ lines << line
+ line = ""
+ end
+ end
+ puts lines.map { |l| "> #{l}" } if $gdb_verbose
+ lines
+ end
+
+ # A convenience method for executing GDB commands. Any unrecognized
+ # message is packaged up and invoked by GDB.
+ def method_missing(sym, *args)
+ cmd = sym.to_s
+ cmd << " #{args.join(' ')}" unless args.empty?
+ command(cmd)
+ end
+ end
+end
Added: topf/trunk/utils/gdb-test.rb
===================================================================
--- topf/trunk/utils/gdb-test.rb (rev 0)
+++ topf/trunk/utils/gdb-test.rb 2007-06-17 00:58:42 UTC (rev 10626)
@@ -0,0 +1,20 @@
+require '../lib/gdb'
+
+# simple testcode that prints registers and backtrace of a given core file
+
+raise "please supply core file as argument" if !ARGV[0]
+
+options = {
+ :core => ARGV[0]
+}
+
+gdb = GDB::Interface.new(options)
+
+gdb.info("registers").each { |line|
+ puts line
+}
+gdb.backtrace.each {|line|
+ puts line
+}
+
+gdb.quit
More information about the tor-commits
mailing list