I am trying to write a program in python or c that can debug c code by using gdb.
I've read the solution of Tom and Invoke and control GDB from Python. But they are more or less a solution for scripting gdb in python. Since I am going to use an arm-gdb to debug embedded program, I cannot enable python scripting in my gdb.
My goal is to create a high-level abstraction of gdb. For example, launch gdb, set some breakpoints and continue within my code. I also read some material gdb/mi interface. But could anyone tell me how to use gdb/mi interface to create a gdb process and communicate with gdb from c/python code? (Luckily my arm-gdb supports gdb/mi interface).
Pretty much anything that can be done at the GDB command line can be done with a breakpoint from Python. You can attach commands to a breakpoint, make it conditional, ignore a certain number of hits, make the breakpoint specific to a thread or process, and all of the things you can do from the command line.
Python in gdb We can access a dynamic python runtime from within gdb by simply calling python. The python code only runs when you press Control D. Another way to run your script is to import them as “new gdb commands”. This is the most useful way to use python for gdb, but it does require some boilerplate to start.
Without an argument, the python-interactive command can be used to start an interactive Python prompt. To return to GDB, type the EOF character (e.g., Ctrl-D on an empty prompt). The python command can be used to evaluate Python code.
It is often useful to do ' display/i $pc ' when stepping by machine instructions. This makes GDB automatically display the next instruction to be executed, each time your program stops.
As promised in the comments above, I have published my (early, incomplete, almost certainly buggy) ruby work to http://github.com/mcarpenter/rubug.
Here's an example (you can find this in
examples/breakpoint
). Function check_for_crash
is a callback that may be invoked
after the program called factorial
is set running. The breakpoint takes a function name
(fac
; the leading colon just indicates that this is a
ruby symbol which to all intents and purposes here is a lightweight
string).
EXE = 'factorial'
def check_for_crash(gdb, event)
case event.type
when :command_response
raise RuntimeError, 'oops' unless
[ :done, :running ].include? event.response.result
when :breakpoint
puts 'Breakpoint reached'
pp event
gdb.continue
when :exit
puts 'Exit'
gdb.stop_event_loop
exit
end
end
gdb = Rubug::Gdb.new
resp = gdb.file EXE
gdb.register_callback(method :check_for_crash)
gdb.break(:fac)
gdb.run '5 > /dev/null'
gdb.start_event_loop
It is only fair to warn you that the code may be... crufty. Currently (this is where I stopped) nothing much works (subsequent to a gdb update midway through my work, see Grammar below).
There are a bunch of examples in the directory of the same name that might prove helpful however. To (attempt to!) run them, you will need to do something like this:
rake clean
rake grammar
rake make
cd examples/simple_fuzzer
ruby -I ../../lib -r rubygems simple_fuzzer.rb
Given the time that this was written you should probably go with a ruby1.8 if you have the choice (I wasn't into 1.9 at the time and there are probably string encoding issues under 1.9).
Parsing of responses is performed by treetop
http://treetop.rubyforge.org, a PEG parser. Looking at the grammar with
fresh eyes I'm sure that it could be simplified. You will need to install this
(and any other required gems) using gem install ...
.
Some more tips if you do Pythonize:
There is little outside "Debugging with GDB" (ch. 22). I've thrown this PDF and just ch. 22 as a separate file into the docs section of the repository.
The protocol is asynrchronous (at first I assumed this was
command/response type protocol, this was a mistake). If I were to
re-implement this I'd probably use something like event machine or
libevent rather than rolling my own select()
loop.
The grammar is a little... confusing. Although the documentation (27.2.2) states that a response "consists of zero or more out of band records followed, optionally, by a single result record":
`output -> ( out-of-band-record )* [ result-record ] "(gdb)" nl`
you should be aware that since anything can arrive at any time a read()
on the socket can apparently return async/result/more
async/terminator(!). For example, I see this with my current gdb:
=thread-group-started,id="i1",pid="1086"
=thread-created,id="1",group-id="i1"
^running
*running,thread-id="all"
(gdb)
The line starting ^
is a result record, all others are async (then
the terminator). This seems like a fairly significant flaw in the
specification.
My main focus is security and I was interested in MI for automated fuzzing, binary inspection, etc. For this purpose GDB/MI is too slow (cost of starting the program in the debugger). YMMV.
There were some things in the standard gdb CLI command set that I could not see how to implement using MI commands. I have skeleton code for something like this:
gdb = Gdb::MI.new
gdb.cli(:file, '/bin/ls')
gdb.cli(:set, :args, '> /dev/null')
gdb.cli(:run)
gdb.cli(:quit)
(which is nice and clear, I think, for us non-MI-expert-but-gdb-knowledgeable users). I can't now remember what those problematic things were (it's over a year since I looked at this) but if those neurons do fire I'll come back and update this.
When I first started out on this road I found a blog posting from Jamis Buck: http://weblog.jamisbuck.org/2006/9/25/gdb-wrapper-for-ruby This wraps a gdb command line session in popen() which made me wince a little. In particular one might expect it to be brittle since gdb makes no guarantees about the stability of the CLI output. You may (or may not) prefer this approach.
If you're on windows then PyDbg / PeiMei may be of interest: http://code.google.com/p/paimei/
You might also like the book Grey Hat Python: Python Programming for Hackers (Seitz). Again, mostly windows based but might prove inspirational.
The links you listed are more of "invoking Python from GDB", but you're asking how to invoke GDB from Python or C. The GDB/MI interface is definately the way to go. Eclipse, Emacs, and KDevelop use GDB/MI to abstract the debugging interface. I've personally used KDevelop with three different cross-compiled gdb versions for ARM, AVR and H8S. The MI protocol is designed to be parsed by software, so the syntax is very regular.
A Google search yielded a Python GDB wrapper that should get you started.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With