1.若想进行gdb调试,在编译时需选择添加调试信息
g++ -g main.cpp -o helloworld
g++ -c -g main.cpp -o main.o
2.启动gdb调试
gdb program ///最常用的用gdb启动程序,开始调试的方式
gdb program core ///用gdb查看core dump文件,跟踪程序core的原因
gdb program pid ///用gdb调试已经开始运行的程序,指定pid即可
gdb -q program ///加-q参数可以去除广告
3.gdb调试的常用参数
命令 | 命令缩写 | 命令说明 |
list | l | 显示多行源代码 |
break | b | 设置断点,程序运行到断点的位置会停下来 |
info | i | 描述程序的状态 |
run | r | 从头开始运行程序 |
display | disp | 跟踪查看某个变量,每次停下来都显示它的值 |
step | s | 执行下一条语句,如果该语句为函数调用,则进入函数执行其中的第一条语句 |
next | n | 执行下一条语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步地调试函数内部语句) |
| p | 打印内部变量值 |
continue | c | 继续程序的运行,直到遇到下一个断点,或程序运行结束 |
set var name=v |
| 设置变量的值 |
start | st | 开始执行程序,在main函数的第一条语句前面停下来 |
file |
| 装入需要调试的程序 |
kill | k | 终止正在调试的程序 |
watch |
| 监视变量值的变化 |
backtrace | bt | 产看函数调用信息(堆栈) |
frame | f | 查看栈帧 |
quit | q | 退出GDB环境 |
examine | x | 查看内存 |
4.常用指令详解
list详解
list命令 显示多行源代码,从上次的位置开始显示,默认情况下,一次显示10行,第一次使用时,从代码其实位置显示
(gdb) list
1 #include<stdio.h>
2
3 int main()
4 {
5 int a, b;
6 scanf("%d%d", &a, &b);
7 int c = a+b;
8 printf("%d\n", c);
9 printf("lalala\n");
10
(gdb)
list n命令 显示已第n-1行未中心的10行代码
(gdb) list 8
3 int main()
4 {
5 int a, b;
6 scanf("%d%d", &a, &b);
7 int c = a+b;
8 printf("%d\n", c);
9 printf("lalala\n");
10
11 char str[] = "123456789";
12 int arr[] = {1,2,3,4,5};
(gdb)
list functionname命令 显示以functionname的函数为中心的10行代码
(gdb) list main
4 {
5 printf("aaaa\n");
6 }
7
8 int main()
9 {
10 int a, b;
11 scanf("%d%d", &a, &b);
12 int c = a+b;
13 printf("%d\n", c);
(gdb)
list -命令 显示刚才打印过的源代码之前的代码
(gdb) list 10
5 printf("aaaa\n");
6 }
7
8 int main()
9 {
10 int a, b;
11 scanf("%d%d", &a, &b);
12 int c = a+b;
13 printf("%d\n", c);
14 printf("lalala\n");
(gdb) list -
1 #include<stdio.h>
2
3 void test()
4 {
(gdb)
break详解
break functionname命令 在functionname函数开始处添加添加断点(经本人测试,似乎会跳过定义变量的语句。希望有大佬给解释下原因。)
(gdb) l 11
6 }
7
8 int main()
9 {
10 int a, b;
11 scanf("%d%d", &a, &b);
12 int c = a+b;
13 printf("%d\n", c);
14 printf("lalala\n");
15
(gdb) break main
Breakpoint 1 at 0x80484f1: file gdb.cpp, line 11.
(gdb)
break filename:n命令 在filename文件的第n行添加断点
(gdb) break gdb.cpp:10
Breakpoint 3 at 0x80484f1: file gdb.cpp, line 10.
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x080484f1 in main() at gdb.cpp:10
(gdb)
brea n命令 在当前文件的第n行添加断点
(gdb) break 12
Breakpoint 4 at 0x804850d: file gdb.cpp, line 12.
(gdb) info break
Num Type Disp Enb Address What
4 breakpoint keep y 0x0804850d in main() at gdb.cpp:12
(gdb)
break classname::functionname命令 在classname类的functionname函数开始处添加断点。(与第一个类似)
info break命令 显示当前所有断点
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x080484f1 in main() at gdb.cpp:11
2 breakpoint keep y 0x0804851c in main() at gdb.cpp:13
3 breakpoint keep y 0x08048530 in main() at gdb.cpp:14
(gdb)
del break命令 删除全部断点
(gdb) del break
Delete all breakpoints? (y or n) y
(gdb) info break
No breakpoints or watchpoints.
(gdb)
del break n命令 删除指定编号的断点
(gdb) info break
Num Type Disp Enb Address What
4 breakpoint keep y 0x080484f1 in main() at gdb.cpp:11
5 breakpoint keep y 0x0804851c in main() at gdb.cpp:13
6 breakpoint keep y 0x08048530 in main() at gdb.cpp:14
(gdb) del break 5
(gdb) info break
Num Type Disp Enb Address What
4 breakpoint keep y 0x080484f1 in main() at gdb.cpp:11
6 breakpoint keep y 0x08048530 in main() at gdb.cpp:14
(gdb)
next详解
next命令 执行下面一步
next n命令 执行下面n步(第二个n表示数字)
print详解
print val命令 打印变量val
(gdb) print a
$5 = 12
(gdb)
print expression命令 打印表达式的值
(gdb) print a+b
$6 = 25
(gdb)
display详解
display(val)命令 程序每次中断时都打印val的值
help及examine详解
help command命令 可以查看某个子命令的帮助
(gdb) help x
Examine memory: x/FMT ADDRESS.
ADDRESS is an expression for the memory address to examine.
FMT is a repeat count followed by a format letter and a size letter.
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
t(binary), f(float), a(address), i(instruction), c(char) and s(string).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
The specified number of objects of the specified size are printed
according to the format.
Defaults for format and size letters are those previously used.
Default count is 1. Default address is following last thing printed
with this command or "print".
(gdb)
x/<n/f/u> <addr>
n、f、u是可选的参数。
n是一个正整数,表示需要显示的内存单元的个数,也就是说从当前地址向后显示几个内存单元的内容,一个内存单元的大小由后面的u定义。
f 表示显示的格式,参见下面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
s 按字符串格式显示变量。
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。
<addr>表示一个内存地址。
注意:严格区分n和u的关系,n表示单元个数,u表示每个单元的大小。
5.段错误的定位
1.在GDB中运行目标程序,当发生段错误时,GDB中运行的程序会自动停下来。(用bt命令查看调用堆栈)
2.直接运行目标程序,使其在发生段错误时产生内存转储(core dump)文件,GDB对该文件进行调试。(适用于不易复现的错误,如常年累月运行逐渐积累造成的错误。)
ulimit -c unlimited
在终端执行上述命令后运行程序产生内存转储文件,一般名为core.xxxx。(xxxx为数字)
(注:重新打开终端后需重复执行上述命令)
gdb abort core.6485
用gdb调试来查看发生错误的代码位置。(用bt命令查看调用堆栈)
6.gdb调试的应用场景
单元测试(较短的代码,功能单纯的函数)
段错误的定位
注:大型程序(尤其是使用了多线程的程序)、错误只在运行时出现的程序一般不适用gdb调试,而使用打印调试。
本博文参考借鉴了
https://www.cnblogs.com/HKUI/p/8955443.html
https://blog.csdn.net/angus_monroe/article/details/78515887
并进行了适当修正补充。