一.启动调试
在CmakeLists.txt中设置gdb指令:
SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
调试方式运行程序:
调试启动无参程序:
gdb helloworld
2.调试启动带参程序:
gdb helloworld
run 参数
或
gdb helloworld
set args 参数
run
调试已运行程序:
使用ps命令找到进程id:
ps -ef|grep 进程名
获取进程id后,使用attach方式调试进程:
gdb
(gdb)attach 进程id
二、断点设置
1.info breakpoints查看已设置的断点:
2.根据行号设置断点
b 9 #break 可简写为b
或
b test.c:9
则运行到第9行的时候会断住
3.根据函数名设置断点:将断点设置在函数处
b printNum
4.根据条件设置断点:
假设程序某处崩溃,怀疑崩溃的原因是某个地方出现了非期望的值,那么可以在这里使用条件设置断点
break test.c:23 if b==0
当在b等于0时,程序将会在第23行断住
它和condition有着类似的作用,假设上面的断点号为1,那么相当于:
condition 1 b==0
5.根据规则设置断点:
例如 rbreak printNum* 意思是对所有以printNum开头的函数都设置了断点
#用法:rbreak file:regex
rbreak .
rbreak test.c:. #对test.c中所有函数设置断点
rbreak test.c:^print #对以print开头的函数设置断点
6.设置临时断点
假设想要在某处的断点只生效一次,那么可以设置临时断点
tbreak test.c:10 #在第10行设置临时断点
7.跳过多次设置断点
ignore 1 30 #1为要忽略的断点号,30是需要跳过的次数
8.根据表达式值变化产生断点
有时需要观察某个值或表达式的变化,则可以借助watch命令:
watch a
此时,让程序继续运行,如果a的值发生变化,则会打印相关的内容
rwatch和watch均可以设置观察点,前者是当变量值被读时断住,后者是被读或者被改写时断住
9.禁用或启动断点
disable #禁用所有断点
disable bnum #禁用标号为bnum的断点
enable #启用所有断点
enable bnum #启用标号为bnum的断点
enable delete bnum #启动标号为bnum的断点,并且再次之后删除该断点
10.断点清除
clear #删除当前行所有breakpoints
clear function #删除函数名为function处的断点
clear filename:function #删除文件filename中函数function处的断点
clear lineNum #删除行号为lineNum处的断点
clear filename: lineNum #删除文件filename中行号为lineNum处的断点
delete #删除所有breakpoints,watchpoints和catchpoints
delete bnum #删除断点为bnum的断点
三、变量查看
1.普通变量查看
打印基本类型变量,数组,字符数组
使用print(可简写为p)打印变量内容
例如: (gdb) p a
当多个函数或者多个文件会有同一个变量名时,可以在前面加上函数名或者文件名来区分
(gdb) p 'test.c'::a
(gdb) p 'main'::b
2.打印指针指向内容
(gdb) p d #打印指针的地址
(gdb) p *d #打印指针指向的内容
仅使用*只能打印出第一个值,如果想打印多个值,后面跟上@并加上要打印的长度,或者@后跟上变量值
(gdb) p *d@10 或 (gdb) p *d@a
此外,$可表示上一个变量,假设此时有一个链表ListNode,它有next成员代表下一个节点,则使用下面方式可不断打印链表内容:
(gdb) p *ListNode
(gdb) p *$.next
如果想要查看前面数组的内容,可以将下标一个一个累加,还可以定义一个类似UNIX环境变量:
例如:
(gdb) set $index=0
(gdb) p b[$index++]
3.按照特定格式打印变量
常见的格式控制字符:
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
例如: (gdb) p/x c #按照16进制打印
4.查看内存内容
examine(简写为x)可以用来查看内存地址中的值
语法为:x/[n][f][u] addr
其中,n表示要显示的内存单元数,默认是1
f表示要打印的格式
u表示要打印的单元长度
addr 内存地址
单元长度类型常见的有:
b 字节
h 半字,即双字节
w 字,即四字节
g 八字节
例如:
(gdb) x/4tb &e
0x7fffffffdbd4: 00000000 00000000 00001000 01000001
5.自动显示变量内容
(gdb) display e #程序断住时自动显示该变量的值。每次程序断住时,就会打印e的值
要查看哪些变量被设置了display,可以使用:
(gdb) info display
如果想要清除自动显示可以使用: delete display num #num为前面变量前的编号,不带num清除所有
或者:disable display num #num为前面变量前的编号,不带num清除所有
6.查看寄存器内容
(gdb) info registers
四、单步调试
1.单步调试-next
next命令(可简写为n)用于在程序断住后,继续执行下一条语句,假设已经启动调试,并在第12行停住,如果要继续执行,则使用n执行下一条语句,如果后面跟上数字num,则表示执行该命令num次,就达到继续执行n行的效果了
next命令不会进入单个函数的内部
2.单步进入-step
如果想要跟踪函数内部,可以使用step命令(可简写为s),它可以单步跟踪到函数内部,但前提是该函数有调试信息并且有源码信息
如果通过step命令尝试进入函数,但是没有该函数源码,需要跳过该函数执行,可使用finish命令,继续后面的执行
step-mode:用来设置当遇到没有调试信息的函数,step命令是否跳过该函数而继续执行,默认情况下是跳过的,即为off
(gdb)show step-mode
(gdb)set step-mode on
(gdb)set step-mode off
stepi(可简写为si)命令为每次执行一条机器指令
3.继续执行到下一个断点-continue
我们可能打了多出断点或者断点打在循环内,想要跳过这个断点,甚至跳过多次断点继续执行,可以使用continue命令(可简写为c)或者fg,它会继续执行,直到再次遇到断点
(gdb)fg #继续运行,直到下一次断住
(gdb)c 3 #跳过三次断点
4.继续运行到指定位置-until
使用until命令(可简写为u)在指定的行停住
(gdb)u 29 #运行到29行停住,利用的是临时断点
5.跳过执行-skip
skip命令可以在step时跳过一些不想关注的函数或者某个文件的代码
(gdb)skip function ad #step时跳过add函数
五、源码查看
我们在调试过程中难免要对照源码进行查看,如果已经开始了调试,而查看源码或者编辑源码却要另外打开一个窗口,那未免显得太麻烦。下面介绍如何在GDB调试模式下查看源码或对源码进行编辑。
1.直接打印源码
list命令(可简写为l),用来打印源码
(gdb) l
直接输入l可从第一行开始显示源码,继续输入l,可列出后面的源码。后面也可以跟上+或者-,分别表示要列出上一次列出的源码的后面部分和前面部分
2.列出指定行附近源码
l 后可以跟行号,表示要列出附近的源码
3.列出指定函数附近的源码
l后面跟函数名
(gdb) l printNum
4.设置源码一次列出行数
通过listsize属性来设置一次性列出的源码行数
(gdb) set listsize 20 #设置每次列出20行
5.列出指定行之间的源码
list first,last (两者之一可以省略一个)
(gdb) l 3,15 #列出3到15行之间的源码
6.列出指定文件的源码
l location 其中国location可以是文件名加行号或函数名
(gdb) l test.c:1 #查看指定文件的指定行数
(gdb) l test.c:printNum #查看指定文件的指定函数
(gdb) l test.c:1,test.c:3 #查看test.c文件的1到3行
7.指定源码路径
若源码移动了目录,则使用list命令查看不了源码,可以使用dir命令指定源码路径
(gdb) dir ./temp
若编译好的程序文件放到另一台机器上进行调试,或者源码文件全都移动到了其它路径下,可以使用set substitute-path from to将原来的路径替换为新的路径
借助readelf命令得到原来的源码路径:
$ readelf main -p .debug_str #main为将要调试的程序名
(gdb) set substitute-path 原路径 新路径
8.编辑源码
直接在gdb模式下编辑源码,默认使用的编辑器是/bin/ex,
使用其它编辑器,通过下面的方式进行设置:
$EDITOR=/usr/bin/vim
$export EDITOR
借助whereis或者which命令查看编辑器的位置
使用命令edit location在gdb调试模式下进行编辑源码
(gdb)edit 3 #编辑第三行
(gdb)edit test.c:5 #编辑test.c第5行
编辑完保存后,需要重新编译程序
(gdb)shell 编译语句
注意:为了在gdb调试模式下执行shell命令,需要在命令之前加上shell,表明这是一条shell命令,这样就能在不用退出gdb调试模式的情况下编译程序了
9.另一种模式
启动时,带上tui(Text User Interface)参数,它会将调试在多个文本窗口呈现
gdb main -tui