如何在没有GDB Python API的情况下在C或Python代码中控制gdb?

时间:2022-08-27 04:45:25

I am trying to write a program in python or c that can debug c code by using gdb.

我试图在python或c中编写一个程序,可以使用gdb调试c代码。

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.

我已经阅读了Tom和Invoke的解决方案并从Python控制GDB。但它们或多或少是在python中编写脚本gdb的解决方案。由于我将使用arm-gdb来调试嵌入式程序,我无法在我的gdb中启用python脚本。

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

我的目标是创建一个gdb的高级抽象。例如,启动gdb,设置一些断点并在我的代码中继续。我还阅读了一些材料gdb / mi界面。但有谁能告诉我如何使用gdb / mi接口创建一个gdb进程并从c / python代码与gdb进行通信? (幸运的是我的arm-gdb支持gdb / mi接口)。

3 个解决方案

#1


5  

As promised in the comments above, I have published my (early, incomplete, almost certainly buggy) ruby work to http://github.com/mcarpenter/rubug.

正如上面评论中所承诺的那样,我已将我的(早期,不完整,几乎肯定是错误的)ruby工作发布到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).

这是一个例子(你可以在examples / breakpoint中找到它)。函数check_for_crash是一个回调,可以在调用factorial的程序运行后调用。断点采用一个函数名称(fac;前导冒号只表示这是一个ruby符号,这里的所有意图和目的都是一个轻量级字符串)。

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

警告你,代码可能是......狡猾的,这是公平的。目前(这是我停止的地方)没什么用(在我的工作中途进行gdb更新之后,请参阅下面的语法)。

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

考虑到写入的时间你应该选择ruby1.8,如果你有选择的话(我当时没有进入1.9并且可能存在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 ....

通过树梢http://treetop.rubyforge.org(PEG解析器)进行响应的解析。用新鲜的眼睛看着语法,我确信它可以简化。您将需要使用gem install安装此(以及任何其他所需的宝石)....

Some more tips if you do Pythonize:

如果你做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.

外部“使用GDB进行调试”很少(第22章)。我抛出这个PDF而且只是ch。 22作为单独的文件进入存储库的docs部分。

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.

该协议是异步的(起初我认为这是命令/响应类型协议,这是一个错误)。如果我要重新实现它,我可能会使用像事件机器或libevent这样的东西而不是滚动我自己的select()循环。

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":

语法有点......令人困惑。虽然文档(27.2.2)声明响应“由零个或多个带外记录组成,可选地,由单个结果记录组成”:

`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:

你应该知道,因为任何时候都可以到达套接字上的read()显然可以返回async / result / more async / terminator(!)。例如,我用我当前的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的自动模糊测试,二进制检查等感兴趣。为此,GDB / MI太慢(在调试器中启动程序的成本)。因人而异。

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 CLI命令集中有一些内容我无法看到如何使用MI命令实现。我有这样的骨架代码:

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.

(对于我们非MI-expert-but-gdb知识渊博的用户,我认为这很好而且清晰。)我现在不能记住那些有问题的东西(自从我看到它以来已经过了一年多)但是如果那些神经元发射了,我会回来更新它。

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.

当我第一次开始这条路时,我发现Jamis Buck发布了一篇博文:http://weblog.jamisbuck.org/2006/9/25/gdb-wrapper-for-ruby这包含了一个在popen中的gdb命令行会话(这让我有点畏缩。特别是人们可能会认为它很脆弱,因为gdb不能保证CLI输出的稳定性。您可能(或可能不)更喜欢这种方法。

If you're on windows then PyDbg / PeiMei may be of interest: http://code.google.com/p/paimei/

如果你在Windows上,那么PyDbg / PeiMei可能会引起关注: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.

您可能也喜欢“灰帽子Python:黑客Python编程”(Seitz)这本书。同样,大多数基于Windows,但可能会鼓舞人心。

#2


1  

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.

您列出的链接更多是“从GDB调用Python”,但您要问的是如何从Python或C调用GDB.GDB / MI接口绝对是最佳选择。 Eclipse,Emacs和KDevelop使用GDB / MI来抽象调试接口。我个人使用KDevelop为ARM,AVR和H8S提供了三种不同的交叉编译gdb版本。 MI协议旨在由软件解析,因此语法非常规则。

A Google search yielded a Python GDB wrapper that should get you started.

谷歌搜索产生了一个Python GDB包装器,可以帮助您入门。

#3


0  

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.

使用http://www.noah.org/python/pexpect/怎么样?它是http://en.wikipedia.org/wiki/Expect的python版本,对于使用外部命令自动执行任务非常有用。

#1


5  

As promised in the comments above, I have published my (early, incomplete, almost certainly buggy) ruby work to http://github.com/mcarpenter/rubug.

正如上面评论中所承诺的那样,我已将我的(早期,不完整,几乎肯定是错误的)ruby工作发布到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).

这是一个例子(你可以在examples / breakpoint中找到它)。函数check_for_crash是一个回调,可以在调用factorial的程序运行后调用。断点采用一个函数名称(fac;前导冒号只表示这是一个ruby符号,这里的所有意图和目的都是一个轻量级字符串)。

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

警告你,代码可能是......狡猾的,这是公平的。目前(这是我停止的地方)没什么用(在我的工作中途进行gdb更新之后,请参阅下面的语法)。

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

考虑到写入的时间你应该选择ruby1.8,如果你有选择的话(我当时没有进入1.9并且可能存在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 ....

通过树梢http://treetop.rubyforge.org(PEG解析器)进行响应的解析。用新鲜的眼睛看着语法,我确信它可以简化。您将需要使用gem install安装此(以及任何其他所需的宝石)....

Some more tips if you do Pythonize:

如果你做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.

外部“使用GDB进行调试”很少(第22章)。我抛出这个PDF而且只是ch。 22作为单独的文件进入存储库的docs部分。

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.

该协议是异步的(起初我认为这是命令/响应类型协议,这是一个错误)。如果我要重新实现它,我可能会使用像事件机器或libevent这样的东西而不是滚动我自己的select()循环。

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":

语法有点......令人困惑。虽然文档(27.2.2)声明响应“由零个或多个带外记录组成,可选地,由单个结果记录组成”:

`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:

你应该知道,因为任何时候都可以到达套接字上的read()显然可以返回async / result / more async / terminator(!)。例如,我用我当前的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的自动模糊测试,二进制检查等感兴趣。为此,GDB / MI太慢(在调试器中启动程序的成本)。因人而异。

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 CLI命令集中有一些内容我无法看到如何使用MI命令实现。我有这样的骨架代码:

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.

(对于我们非MI-expert-but-gdb知识渊博的用户,我认为这很好而且清晰。)我现在不能记住那些有问题的东西(自从我看到它以来已经过了一年多)但是如果那些神经元发射了,我会回来更新它。

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.

当我第一次开始这条路时,我发现Jamis Buck发布了一篇博文:http://weblog.jamisbuck.org/2006/9/25/gdb-wrapper-for-ruby这包含了一个在popen中的gdb命令行会话(这让我有点畏缩。特别是人们可能会认为它很脆弱,因为gdb不能保证CLI输出的稳定性。您可能(或可能不)更喜欢这种方法。

If you're on windows then PyDbg / PeiMei may be of interest: http://code.google.com/p/paimei/

如果你在Windows上,那么PyDbg / PeiMei可能会引起关注: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.

您可能也喜欢“灰帽子Python:黑客Python编程”(Seitz)这本书。同样,大多数基于Windows,但可能会鼓舞人心。

#2


1  

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.

您列出的链接更多是“从GDB调用Python”,但您要问的是如何从Python或C调用GDB.GDB / MI接口绝对是最佳选择。 Eclipse,Emacs和KDevelop使用GDB / MI来抽象调试接口。我个人使用KDevelop为ARM,AVR和H8S提供了三种不同的交叉编译gdb版本。 MI协议旨在由软件解析,因此语法非常规则。

A Google search yielded a Python GDB wrapper that should get you started.

谷歌搜索产生了一个Python GDB包装器,可以帮助您入门。

#3


0  

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.

使用http://www.noah.org/python/pexpect/怎么样?它是http://en.wikipedia.org/wiki/Expect的python版本,对于使用外部命令自动执行任务非常有用。