一个简单快速的GDB使用入门,直接上手使用进行调试。
GCC/G++ 编译文件
在使用gdb进行调试之前,需要使用GCC的编译器编译可执行文件,我们以C++代码为例,使用g++进行编译,此时应该带上编译选项-g确保生成调试信息,点击此处查看具体信息GNU/GCC Debugging-Options。
$ g++ main.cc -g -o main#include <iostream>
int main() { std::cout << "Hello\n"; return 0;}GDB Text User Interface (TUI)
其实gdb也是有UI的,一种终端接口,直接在终端中显示源文件、程序输出、程序寄存器等。点击此处查阅文档GDB Text User Interface。在使用时gdb,添加上选项-tui即可。如果直接使用gdb execution_file,那么也可以输入tui enable切换进入tui模式。
$ gdb main -tui开始调试
如果你正确使用了g++的-g选项,那么你应该可以在gdb打开后看见源代码在上方,命令窗口在下方。如下图,颜色不同仅仅是终端配置区别。这里我没有指定输出的可执行文件名,所以是a.out。

打上断点
我们可以看见各代码的行数,在gdb中,使用break,或简单地使用b打断点,例如我们在main函数处打断点则会在该函数的下面一行添加一个断点。我们也可以用delete或者clear清除断点,前者用于指定某个断点,后者则全部清空。
$ b main# or you can also specific lines$ b 4运行
使用run或者r,将直接运行至当前的第一个断点处,此时可以继续使用step或者s步过,也可以使用stepi或者si步入。可以看见直接输入s后代码框左边的箭头>指向了return 0,并且在命令行看见了运行结果。
此时当我们输入si的话,则需要layout asm查看汇编,因为这时候步入到主函数返回。我们看见当前的汇编恰好对应ret。

监视变量
现在我们修改一下源代码,如下并重新编译调试。
int foo(int& x){ x = 10; return x * x;}
int main(){ int val = 90; foo(val); return 0;}我们使用b main,b foo在两个函数的位置打上断点,通过watch监视变量。此时则需要先run程序,让程序走到需要监视的变量被初始化的作用域,才能成功监视。我们先r。然后再watch val。可以看见我们成功停在了main函数,同时也成功watch了val这个变量。

打印变量值
我们再不断s,直到程序断在foo函数——由于我们在foo打了断点,所以s不会直接步过foo,当我们经过了x = 10的赋值语句,此时命令行会提醒我们val的值变化。

我们也可以使用print或者p打印x,即p x,此时的作用域下只能打印x。也可以通过p/x指定打印的格式,例如p/x就是按照十六进制打印。p/x x或p/t x。如果要打印变量地址的话,则p &x即可,当然,由于我们的程序中x是左值引用,所以p x的时候,就会显示出其指向的地址,我们的程序是0x7fffffffd4b4。也可以用p *0x7fffffffd4b4打印出该地址的值。
- x 按十六进制格式显示变量。
- d 按十进制格式显示变量。
- u 按十六进制格式显示无符号整型。
- o 按八进制格式显示变量。
- t 按二进制格式显示变量。
- a 按十六进制格式显示变量。
- c 按字符格式显示变量。
- f 按浮点数格式显示变量。

大家应该察觉到了,当我们目前在foo函数内时,p val是无法打印出main函数内的值的,此时应该使用p 'main'::val进行打印。如果你有多个文件,也可以通过p 'file2.cc::value'打印file2.cc当中的某个值。这个也适用于各种打印方法,比如watch。

对于数组类型,我们需要通过p *array@len进行打印,其中len是指定的个数。例如我们将arr的前5个元素打印出来p *arr@5。

自动显示变量
我们每次都使用p来显示变量太麻烦了,使用watch的话也只能在变量改变的时候显示,在各种ide里调试的时候可以实时显示当前的每一个变量,太酷了😎,其实我们也可以用display来监视,在该变量存在的作用域内,每次操作都会打印一次被display的变量。

退出调试
使用q然后y退出
Python自动化的GDB脚本
我们可以直接使用python编写gdb脚本,让我们每次直接运行该脚本,免去调试时重复输入的痛苦😻。例如我们使用gdb -x debug.py -tui进行调试,会自动帮我们执行这些指令。点击这里查看GDB Python API
import gdb
gdb.execute("file ./a.out")gdb.execute("b main" )gdb.execute("r")gdb.execute("display 'main'::val")一点启示
如果我们可以自动根据当前作用域display所有变量并绘制一份UI······