我们如何使用gdb调试代码?
作为开发人员,我们如何使用gdb跟踪代码中的错误?我们使用什么技巧来使生活更轻松?
解决方案
通常,我们会发现不应该的东西,然后反向工作,直到我们了解原因为止。
最明显的是最有用的:在函数或者行号上设置断点,并逐行遍历代码。
另一个方便的技巧是即使程序中从未使用过所有结构/对象的show函数,因为我们可以在gdb中运行这些函数:
gdb> p show_my_struct(struct) My custom display of Foo: ...
监视点也可以非常方便,但是可能会大大降低程序速度。当变量或者地址的值更改时,这些中断了流程:
gdb> watch foo Watchpoint4: foo gdb>
一些提示:
- 使用图形化的前端(kdbg相当不错,ddd至少比命令行gdb更好,kdevelop的gdb前端很好,但是有一些bgs,nemiver看起来也不错,但仍在开发中)
- 在Debian / Ubuntu上,我们可以安装-dbg软件包来获取符号;尽管为系统软件包安装适当的源文件似乎很困难
- 我倾向于在不应该到达的地方或者我要研究的地方(某种重量级的断点)添加assert()和abort()调用。
- 理想情况下,assert()或者abort()调用应该包装在仅在调试版本中启用它们的某些方法或者宏中,或者甚至最好是在设置了特定环境变量的情况下才启用它们
- 为SIGSEGV和SIGABRT安装信号处理程序;我个人在安装处理程序之前检查是否设置了某个环境变量;然后在处理程序中执行一个硬编码的外部命令,该命令通常位于〜/ .local / bin /中;然后,该命令可能会启动kdbg并将其添加到崩溃的应用程序。瞧,调试器会在应用程序执行不良操作时弹出。
- 如果使用单元测试,则只要测试用例失败,我们都可以类似地添加调试器,然后检查应用程序。
使用ddd,它是gdb的可视前端。它使我们只需单击几下鼠标即可轻松完成操作,并可视化代码的工作方式,此外,在调试器控制台中还具有交互性gdb。
我们也可以使用Geany。
gdb的一个特别有用的功能是它能够检查崩溃的程序的最终状态。
要检查故障转储(或者核心文件,通常称为核心文件),请按以下方式启动gdb:
gdb <程序名称> <核心文件>
例如:
gdb a.out核心
在核心文件上运行此命令后,gdb会告诉我们程序如何终止并显示程序中发生错误的位置:
Program terminated with signal 11, Segmentation fault. #0 0x08048364 in foo () at foo.c:4 4 *x = 100;
在上面的示例中,我们可以看到程序在尝试为指针分配值时因分段错误而终止。通过在gdb的提示符下键入backtrace(或者bt或者where),我们可以查看程序的完整backtrace:
(gdb) backtrace #0 0x08048364 in foo () at foo.c:4 #1 0x0804837f in main () at foo.c:9
至此,我们知道在试图向* x赋值时,名为main()和foo()的main()
在第4行崩溃了。很多时候,这提供了足够的信息,使我们可以修复该错误。
我做了很多并行程序开发人员,因此我发现在python / ruby中使用一个简单的包装器可以使gdb添加到所有节点上的所有进程并与我通信非常有用(我没有找到了一种更好的方法,如果有人知道的话,不要劫持线程,但是...)
我不确定OP的经验如何,所以:
GDB文档非常不错,而且包含所有内容。第一章很好地介绍了所有基础知识。
http://www.gnu.org/software/gdb/documentation/
尽管不是gdb,但它们是相关的:
我个人发现,分解复杂的行以帮助确定哪些语句出错是有帮助的。
另外,Valgrind(http://valgrind.org/)对于解决缓冲区溢出之类的问题确实非常好/ usefull(我这样做对gdb并不走运。
基本但非常有用将文本gui与-tui选项一起使用。