开发者

How to control gdb within C or Python code without the GDB Python API?

开发者 https://www.devze.com 2023-03-22 16:28 出处:网络
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 sol

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).


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:

Documentation

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.

Async

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.

Grammar

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.

Speed

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.

MI / CLI mapping

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.

Alternatives

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.


What about using http://www.noah.org/python/pexpect/ ? It is the python version of http://en.wikipedia.org/wiki/Expect which is very usefull for automating tasks with external commands.

0

精彩评论

暂无评论...
验证码 换一张
取 消