GDB 调试工具使用指南

GDB 概述

  GDB 是 GNU 开源组织发布的一个强大的 UNIX 下的程序调试工具。也许大多数开发人员比较喜欢那种图形界面方式的,像 VC 、 BCB 等 IDE 的调试,但如果你是在 UNIX 平台下做软件开发,你会发现 GDB 这个调试工具有比 VC 、 BCB 的图形化调试器更强大的功能。所谓 “ 寸有所长,尺有所短 ” 就是这个道理。
  一般来说, GDB 可以帮助你完成以下几个方面的功能:

  • 启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
  • 可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
  • 当程序被停住时,可以检查此时你的程序中所发生的事。
  • 动态的改变你程序的执行环境。

  从上面看来, GDB 和一般的调试工具没有什么两样,基本上也是完成这些功能,不过在细节上,你会发现 GDB 这个调试工具的强大,大家可能比较习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。下面我们一一来看。

基础操作

  要使用 GDB 调试,需要在编译程序的时候加上 -g 参数,例如:

$ gcc -g test.c -o test

  启动 GDB 调试 test 程序:

$ gdb test

  执行 run(简写 r)运行程序,但是通常,你的命令行程序需要带上参数,那么就需要指定参数运行,例如:

(gdb) run -d /dev/mtd2

  另一种方法是使用 set args,例如:

(gdb) set args -d /dev/mtd2

  几乎每一次调试,我们都会设置断点,单步运行。GDB 设置断点的方式很灵活,使用 break(简写 b)。
  例如,在源程序第 232 行处设置断点:

(gdb) break 232

  在 function() 函数入口处设置断点:

(gdb) break function

  如果程序包含多个文件,我们还需要指定源文件,例如在 main.c 文件的第8行设置断点:

(gdb) break main.c:8

  查看断点信息:

(gdb) info break

  删除断点使用 delete(简写 d),其后的数字可以通过 info break 查看,例如删除第1个断点:

(gdb) delete 1

  执行单条语句,也就是单步运行使用 next(简写 n)命令。
  继续运行程序,使用 continue(简写 c)命令。
  使用 finish 命令退出函数。
  当程序在断点处停下来后,我们可能需要打印变量的值, 使用 print(简写 p)命令,可以打印基本类型,也可以打印复合类型,例如:

(gdb) print count

  很不幸,如果程序出错甚至崩溃,我们应该勇敢地面对它,使用 backtrace(简写 bt)命令查看函数堆栈。例如,我刚遇到了一个“Program received signal SIGSEGV, Segmentation fault.”错误:

(gdb) backtrace
#0  0x4007fc13 in _IO_getline_info () from /lib/libc.so.6
#1  0x4007fb6c in _IO_getline () from /lib/libc.so.6
#2  0x4007ef51 in fgets () from /lib/libc.so.6
#3  0x80484b2 in main (argc=1, argv=0xbffffaf4) at segfault.c:10
#4  0x40037f5c in __libc_start_main () from /lib/libc.so.6

  通常,我们只关心自己的代码,因此使用 frame 命令切换到3号堆栈帧(stack frame3),看看程序到底是在哪里崩溃的:

(gdb) frame 3
#3  0x80484b2 in main (argc=1, argv=0xbffffaf4) at segfault.c:10
10        fgets(buf, 1024, stdin)

  这样我们就可以定位到程序在 fgets() 函数处遇到了麻烦,对于这个例子,显然我们需要关注 fgets() 的参数,特别是指针类型的变量,因为这很可能是由于访问非法内存导致的。
  程序调试完,可以使用 kill(简写 k)杀死当前程序,或者使用 quit(简写 q)退出 gdb 调试。

远程调试

  前面例子是使用 gdb 调试本机程序,但是对于嵌入式开发,通常我们使用的是交叉编译环境,这样就会给调试带来一定的麻烦。
  有时候我们需要在成品机上进行调试,然而成品机把调试串口裁剪掉了。
  另外,嵌入式设备的存储容量有限,但是 gdb 调试过程需要配合源代码进行,因为 gdb 会加载对应的源代码来辅助调试,比如对于要查看一个结构体变量的内部数据时,就会去寻找该结构体在源代码中的具体定义,从而更好地解析每个数据域的内容。
  当然我们可以把源代码拷贝到嵌入式设备上,然后调试、修改、调试…… 很快我们就会发现这实在太抓狂了!
  因此,我们需要远程调试,通过 gdbserver 工具直接在嵌入式设备中调试程序。为了能够实现远程调试,需要将设备与 PC 连接到同一个网络。
  然后在设备端使用 gdbserver 启动一个远程调试会话,还是以我们的 test 程序为例,指定端口为 1234:

# gdbserver :1234 test

  在 PC 机上则直接输入 gdb 命令启动 GDB 调试工具,然后指定 ip 和端口,连接到设备端进行远程调试:

(gdb) target remote 192.168.3.100:1234

  接下来就会出现与之前的本地调试一样的提示画面了,后续的操作和本地调试也是一样的,Bingo!


【参考】

https://blog.csdn.net/zzymusic/article/details/4815142

猜你喜欢

转载自blog.csdn.net/luckydarcy/article/details/80516114