How to script gdb (with python)? Example add breakpoints, run, what breakpoint did we hit?
我正在尝试使用gdb创建一个小单元测试,
适用于由OpenOCD控制的嵌入式MCU(可通过gdb服务器控制目标)。
所以我想用一些gdb脚本来自动化它。
我想为gdb编写某种或多或少的脚本:
有任何想法吗?
关于如何在python gdb脚本中执行此操作的示例将是不错的。
谢谢
约翰
注意:
假设我们有这个基本结构,
或多或少都进入了test_failed()或test_success()
取决于函数start_test()返回的内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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中手动执行此操作非常困难,
1 2 3 4 5 6 7 8 9 10 11 12 13 | (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启动脚本中。
1 2 3 4 5 | break test_success break test_failed target remote localhost:3333 cont frame |
然后开始
1 | arm-none-eabi-gdb --batch --command=commands.gdb main.elf |
这种工作,但不是很好。
如何使用"新颖而又酷"的python脚本来做到这一点,
该gdb似乎支持。
仅供参考,最新的gdb版本可在Python中编写脚本。您可以从gdb命令行调用python代码。这将打开一个全新的世界,请查看相关文档。从命令行运行:
1 2 | dnf/yum/apt-get install gdb-doc info gdb extending python |
如果您不喜欢基于文本的信息浏览器,则可以使用以下一种图形浏览器:
1 | yelp 'info:gdb' # , go to"Extending" |
这是一个示例gdb-python脚本。它将gdb附加到运行的第一个" your_program"上。
1 2 3 4 5 6 7 8 9 10 11 12 | #!/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)) |
我目前正在使用的简化示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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的提示符处执行以下脚本:
1 | (gdb) source script.py |
或从命令行:
1 | $ gdb --command script.py ./executable.elf |
有关更多信息,请参见完整的GDB Python API文档。
好的,我在问问题时找到了答案……这确实很简单。
如果希望它们以特定顺序执行,则不应同时使用" --command"和" --eval"!
一种更可预测的方法是将所有内容都放入commands.gdb文件中,并忽略--eval。
这样就变成了这样的东西:
1 | arm-none-eabi-gdb --batch --command=commands.gdb main.elf |
命令.gdb如下所示:
1 2 3 4 5 | break test_success break test_failed target remote localhost:3333 cont frame |
但是用python之类的东西来做这件事可能会更好。
只是想记下我每次回到该主题时都会感到困惑的地方(请注意,我当前使用的是Ubuntu 14.04,GNU gdb(Ubuntu 7.7.1-0ubuntu5?14.04.3)7.7.1):
首先,有关于它"可以调用
- 9.编写gdb脚本-独立性的悬崖(http://tromey.com/blog/?p=548)
- http://blog.scottt.tw/2012/01/exploring-gdb-python-api-with-ipython_31.html
...的意思是,将用shebang行
- GDB-缺少" --python"参数? /新手专区/ Arch Linux论坛
...,如果我尝试类似的操作,则会得到
因此,为了在
-
用扩展名
.py 命名脚本文件;在这里说test.py :
1 2 3 4 5 | def Something(): print("hello from python") Something() gdb.execute("quit"); |
注意,在这种情况下,您只需要编写简单的Python代码即可;并且您不需要
1 2 3 4 5 6 | gdb -x test.py gdb -x=test.py gdb --command test.py gdb --command=test.py gdb -command test.py gdb -command=test.py |
...似乎是等效的,因为在脚本指示
1 2 3 4 5 6 | $ 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 |
请注意,在这种情况下,
-
为脚本命名,只要不以
.py 扩展名结尾即可;在这里说test.pygdb :
1 2 3 4 5 6 7 | python def Something(): print("hello from python") Something() gdb.execute("quit"); end |
在这种情况下,
1 2 3 4 5 6 | 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脚本):
1 2 3 4 | $ gdb -x test.pygdb GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1 ... hello from python |
并响应OP:如果OP中的C代码在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | # 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) |
...然后使用以下命令运行此脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | $ 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 Python中对断点类进行子类化的示例,请参见如何在GDB中的断点处打印当前源代码行,而没有其他内容?