15

我正在尝试使用 gdb 创建一个小单元测试,用于由OpenOCD控制的嵌入式 mcu (这使我可以通过 gdb 服务器控制我的目标)。

所以我想用gdb的一些脚本来自动化这个。

我想为 gdb 编写某种或多或少的脚本:

  1. 添加几个断点
  2. 启动程序
  3. 当我们停止时,它在哪里停止(获取帧信息)
  4. 辞职。

有任何想法吗?

关于如何在 python gdb 脚本中执行此操作的示例会很好。

谢谢约翰


注意

假设我们有这个基本结构,或多或少进入 test_failed() 或 test_success() 取决于函数 start_test() 返回的内容。

void test_failed() {    
    while(1);    
}

void test_success() {    
    while(1);    
}

int main(void) {    
    int status = start_test();    

    if( status > 0 ) {    
        test_failed();    
    }    
    test_success();

    while(1);    
}

在 gdb 中手动执行此操作非常困难,

(gdb) break test_success
Breakpoint 1 at 0x20: file src/main.c, line 9.
(gdb) break test_failed
Breakpoint 2 at 0x18: file src/main.c, line 5.
(gdb) cont
Continuing.

Breakpoint 1, test_success () at src/main.c:9
9       while(1);
(gdb) frame
#0  test_success () at src/main.c:9
9       while(1);
(gdb) 

因此,我尝试的下一步是将这些 gdb 命令添加到 gdb 启动脚本中,该脚本或多或少看起来像这样。

break test_success
break test_failed
target remote localhost:3333
cont 
frame

并开始

arm-none-eabi-gdb --batch --command=commands.gdb main.elf

而这种作品,但它不是很好。我如何使用 gdb 似乎支持的“新的和酷的”python 脚本来做到这一点。

4

4 回答 4

11

仅供参考,最近的 gdb 版本可以在 Python 中编写脚本。您可以从 gdb 命令行调用 python 代码。这打开了一个全新的世界,请查看相关文档。从命令行运行:

 dnf/yum/apt-get install gdb-doc
 info gdb extending python

如果您不喜欢基于文本的信息浏览器,这里有一个(在众多?)替代图形浏览器:

yelp 'info:gdb' # , go to "Extending"

这是一个示例 gdb-python 脚本。它将 gdb 附加到第一个正在运行的“your_program”。

#!/usr/bin/python

import subprocess
import string

def backquotes(cmdwords):
        output = subprocess.Popen(cmdwords, stdout=subprocess.PIPE).communicate()[0]
        return output.strip()

pid = backquotes(['pgrep', 'your_program'])

gdb.execute("attach " + str(pid))
于 2010-11-10T00:25:34.560 回答
10

我目前正在使用的简化示例:

class DebugPrintingBreakpoint(gdb.Breakpoint):
    debugging_IDs = frozenset({37, 153, 420})
    def stop(self):
        top = gdb.newest_frame()
        someVector = top.read_var('aVectorVar')
        # Access the begin() & end() pointer of std::vector in GNU Standard C++ lib
        first = someVector['_M_impl']['_M_start']
        last = someVector['_M_impl']['_M_finish']
        values = []
        while first != last:
            values.append(int(first.dereference()['intID']))
            first = first + 1
        if not set(values) & debugging_IDs:
            return False # skip: none of the items we're looking for can be found by ID in the vector on the stack
        print("Found other accompanying IDs: {}".format(values))
        return True # drop to gdb's prompt
# Ensure shared libraries are loaded already
gdb.execute("start")
# Set our breakpoint, which happens to reside in some shared lib, hence the "start" previously
DebugPrintingBreakpoint("source.cpp:42")
gdb.execute("continue")

您可以像这样从 gdb 的提示符处执行此脚本:

(gdb) source script.py

或者从命令行:

$ gdb --command script.py ./executable.elf

有关更多信息,请参阅完整的GDB Python API 文档

于 2014-08-15T09:13:00.040 回答
3

好的,我在问这个问题时找到了答案……而且这真的很简单。

如果您希望它们以特定顺序执行,则不应同时使用“--command”和“--eval”!

更可预测的方法是将所有内容都放在 commands.gdb 文件中并忽略 --eval。

所以它变成了这样:

arm-none-eabi-gdb --batch --command=commands.gdb main.elf

commands.gdb 看起来像这样:

break test_success
break test_failed
target remote localhost:3333
cont 
frame

但是用python之类的东西来做这件事可能会好得多。

于 2010-10-31T08:27:49.313 回答
1

只是想指出一些我在回到这个话题时感到困惑的事情(注意,我目前使用的是 Ubuntu 14.04,GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1):

首先,有一些关于它“可以作为解释器调用gdb”的参考资料:

#!/usr/bin/gbd -P...意思是,可以用 shebang 行或编写一个脚本文本文件#!/usr/bin/gbd --python,然后在其中编写 Python 代码,然后使其可执行chmod +x pygdbscript,然后运行./pygdbscript;...但就像在这篇文章中一样:

...,gdb: unrecognized option '--python'如果我尝试这样的事情,我会明白的。显然这个选项是/曾经是一些“弓箭手”分支的一个特性gdb?!


因此,为了在 中运行 Python 脚本gdb,实际上有两种方法:

  • 用扩展名命名你的脚本文件.py;在这里说test.py
def Something():
  print("hello from python")

Something()
gdb.execute("quit");

请注意,在这种情况下,您只需编写纯 Python 代码;你不需要import gdb为了访问gdb对象。您可以使用以下任一方式运行:

gdb -x test.py
gdb -x=test.py
gdb --command test.py
gdb --command=test.py
gdb -command test.py
gdb -command=test.py

...这似乎是等效的,因为其中任何一个的结果都是相同的打印输出,在gdb脚本指示退出之前:

$ gdb -x=test.py
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1
...
For help, type "help".
Type "apropos word" to search for commands related to "word".
hello from python

请注意,对于这种情况,类似的名称也test.gdb.py将被解释为纯 Python 脚本,此后以.py.

  • 您的脚本命名为其他任何名称- 只要它以扩展名结尾.py;在这里说test.pygdb
python
def Something():
  print("hello from python")

Something()
gdb.execute("quit");
end

在这种情况下,gdb将脚本解释为gdb脚本,即带有gdb命令 - 这意味着,无论您想在此处编写的任何 Python 代码,都必须以“ python”作为起始行,“ end”在 Python 末尾代码。同样,它会被这些等效调用中的任何一个调用:

gdb -x test.pygdb
gdb -x=test.pygdb
gdb --command test.pygdb
gdb --command=test.pygdb
gdb -command test.pygdb
gdb -command=test.pygdb

...然后输出与前一种情况相同(因为它运行的是相同的 Python 脚本):

$ gdb -x test.pygdb 
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1
...
hello from python

并响应 OP:如果 OP 中的 C 代码在/tmp/myprog.c-int start_test() { return rand() % 50; }顶部添加,否则将无法编译 - ,并与 with gcc -g myprog.c -o myprog.exeinto一起编译/tmp/myprog.exe;那么你可以使用这样的myprog.gdb.py脚本:

# need to specify the executable file which we debug (in this case, not from command line)
# here `gdb` command `file` is used - it does not have a Python equivalent (https://sourceware.org/gdb/onlinedocs/gdb/Objfiles-In-Python.html#index-Objfile_002eframe_005ffilters)
# so we must use gdb.execute:

myexefile="/tmp/myprog.exe"
print("""
### myprog.gdb.py is running: """ + myexefile + """ - and adding breakpoints:
""")

gdb.execute("file " + myexefile)
gdb.execute("set pagination off")

ax = gdb.Breakpoint("test_success")
bx = gdb.Breakpoint("test_failed")

gdb.execute("run")

# here the program will break, so we can do:

print("""
### myprog.gdb.py after the break - current stack frame:
""")

current_frame_at_break = gdb.selected_frame()
print(current_frame_at_break) # instead of gdb.execute("frame")

print("""
### myprog.gdb.py - backtrace:
""")

gdb.execute("backtrace 2")

print("""
### myprog.gdb.py - go to frame that called current frame:
""")

parent_frame = current_frame_at_break.older()
print(parent_frame)
status_var = parent_frame.read_var("status")
print("status_var is: ", status_var)

...然后使用以下命令运行此脚本:

$ gdb -x myprog.gdb.py
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1
....
For help, type "help".
Type "apropos word" to search for commands related to "word".

### myprog.gdb.py is running: /tmp/myprog.exe - and adding breakpoints:

Breakpoint 1 at 0x400565: file myprog.c, line 8.
Breakpoint 2 at 0x40055f: file myprog.c, line 4.

Breakpoint 2, test_failed () at myprog.c:4
4       while(1);    

### myprog.gdb.py after the break - current stack frame:

{stack=0x7fffffffdc70,code=0x40055b,!special}

### myprog.gdb.py - backtrace:

#0  test_failed () at myprog.c:4
#1  0x000000000040058c in main () at myprog.c:15

### myprog.gdb.py - go to frame that called current frame:

{stack=0x7fffffffdc90,code=0x400567,!special}
status_var is: 33
(gdb) 

注意,在这个脚本结束时,(gdb)交互提示仍然存在,在这里可以正常使用;如果您不需要交互式提示,您可以gdb.execute("quit");像上面的脚本一样强制gdb退出,而不是在脚本执行结束时退出。

此外,有关在 gdb Python 中子类化断点类的示例,请参阅如何在 GDB 中的断点处打印当前源代码行,仅此而已?

于 2017-10-17T17:19:35.533 回答