一、基本知识
概念
GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。
在实际应用中,有两种调试方法:在线调试和离线调试。
- 离线调试适用于开发测试环境,可以自由启停进程,设置断点;
- 在线调试一般用于现场问题分析,不能随便启停进程,对于技术要求较高。
前提条件
1、编译
若想执行gdb调试,在Makefile文件中需要增加编译调试选项-g,例如:
gcc -g hello.c -o hello
说明:
-g选项的作用是在可执行文件(ELF)中加入源代码的相关信息,比如ELF中第几条机器指令对应源代码的行数。但不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能找到源文件。
-g完整格式是-glevel,其中,level中指定了调试信息中包含了调试信息的多少,默认的是2,level=1最少,level=3最多。
2、readelf查看段信息
例如:
readelf -S helloWorld|grep debug
注:helloWorld为文件名,如果没有任何debug信息,则不能被调试。
二、使用方法
启动调试
在开发中可以将源码和可执行文件拷贝到某一目录下,使用gdb启动进程进行调试,也可以不拷贝源码和可执行文件,使用NFS挂载到编译环境执行调试;在现场环境中使用ps获取进程的pid,然后gdb –p pid执行在线调试。
$gdb <program>
$gdb <program> <core dump file>
$gdb <program> <PID>
显示源码
1. list
2. list "文件名.后缀名":行号(显示别的文件)
3. show listsize
4. set listsize count
5. search text:该命令可显示在当前文件中包含text串的下一行。
6. Reverse-search text:该命令可以显示包含text 的前一行。
设置断点
打断点还是比较有技巧的,虽然有很多打断点的方法,但是实际调试中一般就使用以下几种:
- 函数打断点:b 函数名
- 某一行打断点:b 源文件:行号
1、简单断点
break 设置断点,可以简写为b
b 10 设置断点,在源程序第10行
b func 设置断点,在func函数入口处
2、条件断点
设置一个条件断点
b test.c:8 if intValue == 5 //在test.c文件第8行设置断点
b main //在main函数入口处设置断点
condition 与break if类似,只是condition只能用在已存在的断点上
修改断点号为bnum的停止条件为expression
condition bnum expression
清楚断点号为bnum的停止条件
condition bnum
ignore 忽略停止条件几次。表示忽略断点号为bnum的停止条件count次
Ignore bnum count
4、查询断点
info b
5、维护断点
delete 断点号n:删除第n个断点
disable 断点号n:暂停第n个断点
enable 断点号n:开启第n个断点
clear 行号n:清除第n行的断点
delete breakpoints:清除所有断点
运行程序
run 运行程序,可简写为r
next 单步跟踪,函数调用当作一条简单语句执行,可简写为n
step 单步跟踪,函数调进入被调用函数体内,可简写为s
finish 退出函数
until 在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体,可简写为u。
continue 继续运行程序,可简写为c
info program 来查看程序的是否在运行,进程号,被暂停的原因。
quit:简记为 q ,退出gdb
return:忽略当前未执行的部分,强制返回
打印表达式
print 打印变量、字符串、表达式等的值,可简写为p
打印变量:p 变量
打印字符/表达式:p “%s”,字符/表达式
格式化输出:p/格式控制符 打印内容
说明:
gdb可支持的变量显示格式有:
x:按16进制格式显示变量
d:按10进制格式显示变量
u:按16进制格式显示无符号整型
o:按8进制格式显示变量
t:按2进制格式显示变量
c:按字符格式显示变量
f:按浮点数格式显示变量
也可以使用x(Examination)来打印需要显示的字符信息,格式如下:
x/格式 地址
格式(可选)一般是NFU:
1、N表示重复次数(表示显示内存的长度,也就是说从当前向后显示几个地址的内容)
2、F表示显示格式
3、U表示单位(b:字节,h:半字[2字节],w:字[4字节,默认],g:双字[8字节])。表示多少个字节作为一个值取出来,如果不指定的话,GDB默认是1个byte,当我们指定了字节长度后,GDB会从指定内存的地址开始,读取指定字节,并把其作为一个值取出来。
其中U可使用下面字符代替:
b:表示单字节
h:表示双字节
w:表示四字节
g:表示八字节
查看运行信息
whatis 命令可以显示某个变量的类型
where/bt :当前运行的堆栈列表;
frame
info program: 来查看程序的是否在运行,进程号,被暂停的原因。
调试函数
可以使用反汇编的指令disassemble去探究究竟在函数中发生了哪些操作,具体如下:
1、disassemble
2、disassemble 程序计数器
3、disassemble 开始地址 结束地址
格式1表示反汇编当前整个函数,
格式2表示反汇编计数器所在函数的整个函数,
格式3表示反汇编从开始地址到结束地址的部分。
另外可能会用到call,用法如下:
强制调用函数:call 表达式