Debugging 如何使用gdb调试代码?

Debugging 如何使用gdb调试代码?,debugging,gdb,Debugging,Gdb,作为一名开发人员,您如何使用gdb跟踪代码中的错误?你用什么技巧让你的生活变得更轻松?一般来说,你会发现一些不应该是这样的东西,然后反向工作,直到你明白为什么 最明显的是最有用的:在函数或行号上设置断点,并逐行遍历代码 另一个方便的技巧是为所有结构/对象提供显示函数,即使它们从未在程序中使用过,因为您可以在gdb中运行这些函数: gdb> p show_my_struct(struct) My custom display of Foo: ... 监视点也非常方便,但可能会大大降

作为一名开发人员,您如何使用gdb跟踪代码中的错误?你用什么技巧让你的生活变得更轻松?

一般来说,你会发现一些不应该是这样的东西,然后反向工作,直到你明白为什么

最明显的是最有用的:在函数或行号上设置断点,并逐行遍历代码

另一个方便的技巧是为所有结构/对象提供显示函数,即使它们从未在程序中使用过,因为您可以在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看起来也很不错,但仍在开发中)
  • 确保所有重要部分都有调试符号和源代码(您自己的代码和一些系统库)
    • 在RedHat上,您可以安装-debuginfo包,使符号和源代码神奇地出现在调试器中-非常酷,因为您可以查看libc函数调用等
    • 在Debian/Ubuntu上,您可以安装-dbg包来获取符号;不过,为系统包安装适当的源文件似乎很困难
  • 我倾向于在不应该到达的地方或我想研究的地方(某种重量级断点)添加assert()和abort()调用
  • 理想情况下,assert()或abort()调用应该封装在某个方法或宏中,该方法或宏只在调试版本中启用它们,或者更好的方法是仅在设置了某个环境变量时启用它们
  • 为SIGSEGV和SIGABRT安装信号处理器;我个人在安装处理程序之前检查是否设置了某个环境变量;在处理程序中,我执行一个硬编码的外部命令,该命令通常位于~/.local/bin/中的某个位置;该命令可能会启动kdbg并将其连接到崩溃的应用程序。瞧,当你的应用程序出现问题时,调试器就会弹出
  • 如果您使用单元测试,您可以在测试用例失败时附加调试器,然后检查应用程序

使用ddd,gdb的可视前端。它让您只需点击几下鼠标即可轻松完成任务,并可视化代码的工作方式,此外,在调试器控制台中,您还可以使用Interactive gdb。

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),您可以查看程序的完整回溯:

(gdb) backtrace
#0  0x08048364 in foo () at foo.c:4
#1  0x0804837f in main () at foo.c:9

此时,您知道调用
foo()
foo()
main()
在尝试为
*x
赋值时在第4行崩溃。很多时候,这提供了足够的信息来修复bug。

我做了很多并行程序开发,因此我发现在python/ruby中使用一个简单的包装器,允许我将gdb连接到所有节点上的所有进程并与我通信,这非常有帮助(如果有人知道的话,我还没有找到更好的方法,不过不要劫持线程…)

我不确定OP的经验如何,因此:

GDB文档非常好,包罗万象。第一章很好地介绍了所有的基础知识

虽然不是gdb,但它们是相关的: 我个人发现,将复杂的行分解以帮助确定哪些语句是错误的有帮助


另外,Valgrind()在处理缓冲区溢出等问题上非常好/有用(我在gdb上没有这样做的运气。

基本但非常有用-与选项-tui一起使用。

我使用集成gdb的IDE使我的生活更轻松!;)这是一个不错的选择。我被告知我的工作将在一两年后进入21世纪。不过,知道如何手动执行某些操作以从所有功能中获益总是很有用的,例如使用代码中当前点的变量运行自己的函数。实际上,在构建时,如果不进行调试,断言通常会被删除g(-g).来自ASSERT(3):“如果宏NDEBUG是在最后一次包含时定义的,那么宏ASSERT()不会生成任何代码,因此不会执行任何操作。”我不确定我是否会称之为“正常”。我通常会保留我的断言,而且我还认为必须使用NDEBUG宏这一事实(与不定义宏“DEBUG”相反))暗示assert的设计者同意assert通常应该保留。为什么不简单地说“p my_struct”,而不是“p show_my_struct(my_struct)”?因为您可以解码flags字段、运行验证代码等。它不仅仅是结构值的转储,而是可以转储含义,包括指向的相关对象。例如,如果obj1有一个obj2s列表,那么您可以在其中嵌套所有obj2s的显示。您可以使用C激活gdb tui模式TRL-X CTRL-A