Linux下gdb调试常用知识总结

版权声明:若您发现我的博文中有纰漏或有其他想法,诚挚希望您能与我讨论。QQ1171297065 https://blog.csdn.net/qq_40758751/article/details/83305288

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

执行下一条语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步地调试函数内部语句)

print

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

并进行了适当修正补充。

猜你喜欢

转载自blog.csdn.net/qq_40758751/article/details/83305288