I would like to be able to set a breakpoint in GDB, and have it run to that point - and in the process, print out lines it has "stepped through".
Here is an example, based on this simple file with a main
and a function, and two breakpoints for each:
$ cat > test.c <<EOF
#include "stdio.h"
int count=0;
void doFunction(void) {
// two steps forward
count += 2;
// one step back
count--;
}
int main(void) {
// some pointless init commands;
count = 1;
count += 2;
count = 0;
//main loop
while(1) {
doFunction();
printf("%d\n", count);
}
}
EOF
$ gcc -g -Wall test.c -o test.exe
$ chmod +x test.exe
$ gdb -se test.exe
...
Reading symbols from /path/to/test.exe...done.
(gdb) b main
Breakpoint 1 at 0x80483ec: file test.c, line 14.
(gdb) b doFunction
Breakpoint 2 at 0x80483c7: file test.c, line 7.
To start the session, I need to run ( r
) the program, which will then stop at first breakpoint ( main
):
(gdb) r
Starting program: /path/to/test.exe
Breakpoint 1, main () at test.c:14
14 count = 1;
(gdb)
At this point - I can, for instance, hit continue ( c
); and the process will run through, not outputing anything, and break at the requested line:
(gdb) c
Continuing.
Breakpoint 2, doFunction () at test.c:7
7 count += 2;
(gdb)
On the other hand, instead of continue - I can go line by line, either by using step ( s
) or next ( n
); for instance:
14 count = 1;
(gdb) n
15 count += 2;
(gdb) s
16 count = 0;
(gdb) s
19 doFunction();
(gdb) s
Breakpoint 2, doFunction () at test.c:7
7 count += 2;
(gdb) s
9 count--;
(gdb) s
10 }
(gdb) s
main () at test.c:20
20 printf("%d\n", count);
(gdb) s
...
(gdb) s
_IO_vfprintf_internal (s=Cannot access memory at address 0xe5853361
) at vfprintf.c:210
210 vfprintf.c: No such file or directory.
in vfprintf.c
(gdb) s
245 in vfprintf.c
(gdb) s
210 in vfprintf.c
(gdb) n
245 in vfprintf.c
...
(gdb) n
2006 in vfprintf.c
(gdb) n
__printf (format=0x80484f0 "%d\n") at printf.c:39
39 printf.c: No such file or directory.
in printf.c
(gdb) n
main () at test.c:21
21 }
(gdb) n
19 doFunction();
(gdb) n
Breakpoint 2, doFunction () at test.c:7
7 count += 2;
(gdb)
Anyways, I am aware that I can keep Enter pressed, and the last entered command (step or next) will repeat (left a bit longer session in the second case, to show that 'next' remains on same level, 'step' steps inside the functions being called). However, as it can be seen, depending on whether step or next runs, it may take a while until a result is reached - and so, I don't want to sit for 10 minutes with my hand stuck on the Enter button :)
So, my question is - can I somehow instruct gdb
to run to 'breakpoint 2' without further user intervention - while printing out the lines it goes through, as if step (or next) was pressed?
6条答案
按热度按时间cunj1qz11#
好吧,这并不容易--但我想我有点明白了:)我经历了一堆失败的尝试(发布了here);相关代码如下。
基本上,“next/step until breakpoint”中的问题是,如果调试器被停止(在一个步骤),如何确定你是否“在”一个断点上。还要注意,我使用的是GDB 7.2- 1ubuntu 11(Ubuntu 11.04的当前版本)。所以,它是这样的:
gdb.execute("CMDSTR", toString=True)
命令-这似乎正是捕获输出所需要的:“* 默认情况下,命令生成的任何输出都将发送到gdb的标准输出。如果to_string参数为True,则输出将由gdb.execute收集并作为字符串[1]返回 *"!gdb.execute
;这里失败-因为这个:subprocess.Popen
GDB程序,同时替换它的stdin和stdout;然后从那里继续控制GDB(pygdb-sub.py)-这也失败了...(* 显然,因为我没有正确重定向stdin/out *)source
),当gdb.execute
应该被调用时,它将在内部分叉到一个pty,以便捕获它的输出(pygdb-fork.gdb,pygdb-fork.py)...这 * 几乎 * 起作用了-因为有字符串返回;但广发银行发现有些不对劲:“[tcsetpgrp在下级终端中失败:不允许操作]",并且后续返回字符串似乎没有更改。最后,行之有效的方法是:临时将GDB输出从
gdb.execute
重定向到RAM中的日志文件(Linux:/dev/shm
)的值;然后从Python中阅读回、解析并打印它-- Python还处理一个简单的while循环,一直执行到断点。具有讽刺意味的是-大多数这些错误,导致这个解决方案通过重定向日志文件,实际上是最近修复的SVN;这意味着这些将在不久的将来传播到发行版,人们将能够直接使用
gdb.execute("CMDSTR", toString=True)
:/然而,由于我现在不能冒险从源代码构建GDB(可能会遇到新的不兼容问题),这对我来说也足够好了:)以下是相关文件(部分文件也在pygdb-fork.gdb、pygdb-fork.py中):
pygdb-logg.gdb
为:pygdb-logg.py
为:基本上,
pygdb-logg.gdb
加载pygdb-logg.py
python脚本,为nextUntilBreakpoint
设置别名nub
,并初始化会话--其他一切都由python脚本处理。...就像我想要它:P只是不知道它有多可靠(* 以及是否有可能在
avr-gdb
中使用,这是我需要它的原因:)编辑:Ubuntu 11.04中avr-gdb的当前版本为6.4,该版本无法识别python命令:(*)希望这能帮到你们
干杯!干杯!
这里有些参考资料:
parse_and_eval
gone? - Stack Overflowzynd9foi2#
在gdb中这样做怎么样,使用一个命令文件。根据需要更改文件参数和循环计数。
run.gdb:
jljoyd4f3#
基于@sdaau的答案(http://www.mail-archive.com/gdb@gnu.org/msg00031.html)中的链接,我创建了自己的脚本,简单地不断发送's'并阅读gdb的输出,同时将输出打印到文本文件和终端,当然,我的脚本可以修改以满足其他人的需要,但是,我希望我所做的修改应该适合大多数人的需要。
http://www.codeground.net/coding/gdb-step-into-all-lines-to-get-full-application-flow/
bn31dyow4#
作为一个新的答案,因为前面的已经被占用了:)基本上,如果重点是观察源代码(和/或汇编)行的执行,因为程序正在运行-作为动机,我经常在寻找“* 自动打印输出 *”-那么,基本上,一个非常快速的方法是使用GDB TUI模式;我引述:
c - gdb行为:值优化输出-堆栈溢出#1354762
使用GDB TUI模式。当我键入减号和回车键时,我的GDB副本会启用它。然后键入C-x 2(即按住Control并按X,释放两者,然后按2)。这将把它放入拆分源代码和反汇编显示。然后使用stepi和nexti一次移动一条机器指令。使用C-x o在TUI窗口之间切换。
这里的技巧是,即使你点击了
continue
-这个时间源也会在TUI上显示和指示;并在程序运行时执行以下操作:...这对我来说避免了许多情况,我必须在“自动单步执行上下文”中编写断点脚本(尽管仍然存在这样的情况)..有关TUI的文档:TUI - Debugging with GDB
干杯!干杯!
vc9ivgsu5#
实际上,我有一个带有Python-GDB扩展的Github repo,它做的事情与您所描述的完全相同,但功能更多。
您可以直接克隆存储库:
并在GDB内部使用以下命令将python脚本提供给GDB:
(如有必要,请更改python脚本路径)
现在,您可以使用以下命令运行代码的每一行,直到出现断点:
这里的“somefile.c:100”是一个起始断点,“somefile.c:200”是最后一个断点。
“--args”指定程序的一组参数(如果没有参数,可以省略它)。
使用此扩展,您还可以多次运行代码(使用'-r'选项),甚至可以指定调试时应处理的一些事件。有关详细信息,请参阅:
https://github.com/Viaceslavus/gdb-debug-until
mbjcgjjk6#
当前接受的答案包括大量文件io,并且只在断点处停止,但是忽略了观察点、信号,甚至可能忽略了程序结束。
使用python api可以很好地处理这个问题:
stop
事件处理程序,用于检查停止原因并在其中存储步骤类型下面的代码可以放在www.example.com中gdb-auto-step.py,您可以随时使用
source gdb-auto-step.py
激活它(或将其包含在.gdbinit文件中,使其始终可用):要使用参数指定默认值(也称为“gdb方式”),请添加另一个参数并使用该参数(还附带0 =无限制)