前言
GDB 全称“GNU symbolic debugger”,使用GDB调试将会更加灵活。GDB占用资源少,通用性强,且可以看到一些IDE调试无法展现的东西(比如说要看一个指针引用数组的所有元素)。本人在使用vscode调试过程中发现一些需要查看一些指针数据的时候vscode就显得力不从心了,所以转向gdb调试,虽然操作麻烦一些,但是效果可观。
一、编译
-
直接编译
一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,我们必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数可以做到这一点。如:
gcc -g hello.c -o hello g++ -g hello.cpp -o hello
要用gdb调试程序,必须在编译时加上-g和-ggdb选项,-g选项的作用是在可执行文件中加入源文件信息,但并不是将源文件嵌入可执行文件,所以在调试时必须保证gdb必须能找到源文件。-g 和 -ggdb 都是令 gcc 生成调试信息,但是二者有一些区别。
-
使用CMake编译
添加<-g3> <-gdwarf-2>
到CMakelists.txt
,确保项目在debug模式下运行(-DCMAKE_BUILD_TYPE=Debug
)。
二、GDB启动
-
直接启动
gdb program
program 也就是你的执行文件,一般在当前目录下。
-
启动unit_tests(在build目录下)
$ gdb unit_tests (gdb) run --gtest_filter=[XXXXXX]
三、TUI模式
在TUI模式中,GDB窗口划分为两个子窗口——一个用于输入GDB命令,而另一个用于查看源代码。
(gdb) layout src # display source code
(gdb) winheight src +5 # heighten source code window by 5 line
(gdb) layout split # display assembly code
(gdb) focus cmd # change focus on cmd to allow arrow key use
(gdb) focus src # change focus on src window
退出tui模式,使用CTRL + X + A
快捷键
四、设置断点
-
设置断点
(gdb) b test_hello:hello //在源文件filename的function函数的入口处停住 (gdb) b test_hello:102 //在源文件filename的linenum行处停住 (gdb) break 2 if i == count - 1 //当条件成立的时候停住,应对循环的情况
-
查看断点
(gdb)info break [n] //n表示断点号
-
删除断点
(gdb) delete 2 // delete breakpoint numbered 2 (gdb) delete // delete all breakpoints
五、调试代码
run 运行程序,可简写为r
next 单步跟踪,函数调用当作一条简单语句执行,可简写为n
step 单步跟踪,函数调进入被调用函数体内,可简写为s
finish 退出进入的函数
until 在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体,可简写为u。
continue 继续运行程序,可简写为c
六、查看运行过程中的数据
(gdb) print i
$1 = 503
// char str[] = "hello world"
(gdb) p/s str
$1 = "hello world"
(gdb) p str[0]='V'
$2 = 86 'V'
(gdb) p/s str
$3 = "vello world"
//p ELEM@COUNT
// int main(char *argv[], int argc)
(gdb) p argv[0]@argc
/* int *arr = (int *) malloc( 2 * sizeof(int));
arr[0] = 1;
arr[1] = 2;*/
(gdb) p *(int *)arr@2
$1 = {1, 2}
七、查看内存地址
x / [Length] [Format] [Modifier] [Address]
Length:确定检查的个数(e.g. 14 or 9)
Format:打印的格式(e.g. b, h, w or g),bytes(1 byte), half words(2 bytes), words(4 bytes), giant words(8 bytes)
Modifier:输出的位数(e.g c or x or f)(c :char, x :hexadecimal, f :floating point)
# char str[14] = "hello, world!"
(gdb) x/14bc str
0x7fffffffd7b0: 104 'h' 101 'e' 108 'l' 108 'l' 111 'o' 44 ',' 32 ' ' 119 'w'
0x7fffffffd7b8: 111 'o' 114 'r' 108 'l' 100 'd' 33 '!' 0 '\000'
(gdb) x/14bx str
0x7fffffffd7b0: 0x68 0x65 0x6c 0x6c 0x6f 0x2c 0x20 0x77
0x7fffffffd7b8: 0x6f 0x72 0x6c 0x64 0x21 0x00
# double data[3 * 3] = { 1.5, 2.0, 1.5,
# 2.3, 4.0, 5.5,
# 6.6, 0.0, 7.2 };
(gdb) x/9gf data
0x7fffffffdb50: 1.5 2
0x7fffffffdb60: 1.5 2.2999999999999998
0x7fffffffdb70: 4 5.5
0x7fffffffdb80: 6.5999999999999996 0
0x7fffffffdb90: 7.2000000000000002