3.10.2 应用:使用 GDB 调试器

3.10.2 应用:使用 GDB 调试器

GNU 的调试器 GDB 提供了许多有用的特性,支持机器级程序的运行时评估和分析。对于本书中的示例和练习,我们试图通过阅读代码,来推断出程序的行为。有了 GDB,可以观察正在运行的程序,同时又对程序的执行有相当的控制,这使得研究程序的行为变为可能。

图 3-39 给出了一些 GDB 命令的例子,帮助研究机器级 x86-64 程序。先运行 OBJDUMP 来获得程序的反汇编版本,是很有好处的。我们的示例都基于对文件 prog 运行 GDB,程序的描述和反汇编见 3.2.3 节。我们用下面的命令行来启动 GDB:

linux> gdb prog

通常的方法是在程序中感兴趣的地方附近设置断点。断点可以设置在函数入口后面,或是一个程序的地址处。程序在执行过程中遇到一个断点时,程序会停下来,并将控制返回给用户。在断点处,我们能够以各种方式查看各个寄存器和内存位置。我们也可以单步跟踪程序,一次只执行几条指令,或是前进到下一个断点。

类别 命令 效果
开始和停止 quit 退出 GDB
开始和停止 run 运行程序(在此给出命令行参数)
开始和停止 kill 停止程序
断点 break multstore 在函数 multstore 入口处设置断点
断点 break * 0x400540 在地址 0x400540 处设置断点
断点 delete 1 删除断点 1
断点 delete 删除所有断点
执行 stepi 执行 1 条指令
执行 stepi 4 执行 4 条指令
执行 nexti 类似于 stepi,但以函数调用为单位
执行 continue 继续执行
执行 finish 运行到当前函数返回
检查代码 disas 反汇编当前函数
检查代码 disas multstore 反汇编函数 multstore
检查代码 disas 0x400544 反汇编位于地址 0x400544 附近的函数
检查代码 disas 0x400540,0x40054d 反汇编指定地址范围内的代码
检查代码 print /x $rip 以十六进制输出程序计数器的值
检查数据 print $rax 以十进制输出 %rax 的内容
检查数据 print /x $rax 以十六进制输出 %rax 的内容
检查数据 print /t $rax 以二进制输出 %rax 的内容
检查数据 print 0x100 输出 0x100 的十进制表示
检查数据 print /x 555 输出 555 的十六进制表示
检查数据 print /x ($rsp+8) 以十六进制输出 %rsp 的内容加上 8
检查数据 print *(long *) 0x7fffffffe818 输出位于地址 0x7fffffffe818 的长整数
检查数据 print *(long *) ($rsp+8) 输出位于地址 %rsp+8 处的长整数
检查数据 x/2g 0x7fffffffe818 检查从地址 0x7fffffffe818 开始的双(8 字节)字
检查数据 x/20b multstore 检查函数 multstore 的前 20 个字节
有用的信息 info frame 有关当前栈帧的信息
有用的信息 info registers 所有寄存器的值
有用的信息 help 获取有关 GDB 的信息

图 3-39 GDB 命令示例。说明了一些 GDB 支持机器级程序调试的方式

正如我们的示例表明的那样,GDB 的命令语法有点晦涩,但是在线帮助信息(用 GDB 的 help 命令调用)能克服这些毛病。相对于使用命令行接口来访问 GDB,许多程序员更愿意使用 DDD,它是 GDB 的一个扩展,提供了图形用户界面。