如何在C或Python代码中控制gdb,而不使用GDB Python API?

14
我正在尝试用Python或C编写一个程序,可以通过使用gdb来调试C代码。
我已经阅读了Tom的解决方案从Python调用和控制GDB。但它们多少都是在Python中脚本化gdb的解决方案。由于我将使用arm-gdb来调试嵌入式程序,因此无法在我的gdb中启用Python脚本。
我的目标是创建gdb的高级抽象。例如,启动gdb,在我的代码中设置一些断点并继续执行。我还阅读了一些关于gdb / mi接口的材料。但是否有人可以告诉我如何使用gdb / mi接口创建gdb进程,并从C / Python代码中与gdb通信?(幸运的是,我的arm-gdb支持gdb / mi接口)。

我有一个未发布的 Ruby 库(不是 Python 或 C,抱歉),可以实现这个功能... 这是一个已经被放弃但仍然能够使用的项目(GDB MI 消息抽象和解析器/构建器、CLI/库调用映射等)。如果有用的话,我可以发布出来。 - Martin Carpenter
@Martin,如果您能够发布它,那将非常好,这样我就可以将其作为参考...感谢您的努力。 - Penny
好的,我会进行一些挖掘 :) 并发布一个带有链接的答案。 - Martin Carpenter
为什么不直接使用libptrace呢? - Alexander Oh
3个回答

5

如前述评论中所承诺的,我已将我(初期、不完整、几乎肯定存在错误)的 Ruby 代码发布于 http://github.com/mcarpenter/rubug

这里是一个示例(可以在 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

我需要提醒您的是,代码可能会...比较混乱。目前(这也是我停下来的地方),很少有东西能够正常工作(在我的工作中途进行gdb更新之后,见下文语法)。

然而,在相同名称的目录中有一堆示例可能会对您有所帮助。要(尝试!)运行它们,您需要执行类似于以下内容的操作:

rake clean
rake grammar
rake make 
cd examples/simple_fuzzer
ruby -I ../../lib -r rubygems simple_fuzzer.rb

考虑到这篇文章的写作时间,如果可以选择的话,你应该使用ruby1.8(我当时还不熟悉1.9,并且在1.9下可能存在字符串编码问题)。
响应解析由treetop http://treetop.rubyforge.org,一个PEG解析器执行。重新审视语法后,我相信它可以被简化。您需要使用gem install ...安装它(以及其他所需的gems)。
如果您想要Pythonize,请注意以下几点:

文档

除了“使用GDB进行调试”(第22章)之外,几乎没有其他内容。我已经将这个PDF和仅有的第22章作为单独的文件放入存储库的docs部分。

异步

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

语法

语法有点...令人困惑。尽管文档(27.2.2)指出响应“由零个或多个带外记录组成,后跟一个可选的结果记录”:

`output -> ( out-of-band-record )* [ result-record ] "(gdb)" nl`

你需要知道的是,由于任何东西都可以随时到达,因此套接字上的read() 可以明显地返回异步/结果/更多异步/终止符号(!)。例如,我在当前的gdb中看到了这个现象:

=thread-group-started,id="i1",pid="1086"
=thread-created,id="1",group-id="i1"
^running
*running,thread-id="all"
(gdb)

^开头的行是结果记录,其他所有行都是异步的(然后是终止符)。这似乎是规范中相当重要的缺陷。

速度

我的主要关注点是安全性,我对MI用于自动化模糊测试、二进制检查等方面很感兴趣。但是,为了启动调试器中的程序,GDB/MI太慢了。你的情况可能不同。

MI / CLI 映射

在标准的gdb CLI命令集中,有一些东西我无法通过MI命令来实现。我已经写了类似以下代码的框架:

gdb = Gdb::MI.new
gdb.cli(:file, '/bin/ls')
gdb.cli(:set, :args, '> /dev/null')
gdb.cli(:run)
gdb.cli(:quit)

这对于我们非MI专家但具备gdb知识的用户来说,非常清晰易懂。

我现在记不起那些有问题的东西是什么了(自从我看到这个已经过去一年了),但如果那些神经元确实发射了,我会回来更新这个。

替代方案

当我开始这条路时,我发现了Jamis Buck的一篇博客文章: http://weblog.jamisbuck.org/2006/9/25/gdb-wrapper-for-ruby 这将一个gdb命令行会话包装在popen()中,这让我有点担心。特别是因为gdb不保证CLI输出的稳定性,因此可能(也可能不)更喜欢这种方法。

如果您使用的是Windows,则PyDbg / PeiMei可能会引起您的兴趣:http://code.google.com/p/paimei/

你可能也会喜欢这本书 Grey Hat Python: Python Programming for Hackers (Seitz)。再次强调,大多数内容基于Windows平台,但可能会给你带来灵感。


2
你列出的链接更多是关于“从GDB调用Python”,但你正在询问如何从Python或C中调用GDB。 GDB/MI 接口绝对是正确的选择。Eclipse、Emacs和KDevelop使用GDB/MI抽象调试接口。我个人使用过KDevelop,为ARM、AVR和H8S编译了三个不同版本的gdb。MI协议旨在被软件解析,因此语法非常规则。

通过谷歌搜索可以找到一个Python GDB包装器,应该可以帮助你入门。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接