文章目录
1. gdb通用命令
1.1 常用命令
命令 | 功能 | |
---|---|---|
break 文件名:行号 break symbol | 断点命令 | |
delete [断点对应许序号] | 删除断点 | |
backtrace (缩写t) | 查看调用站 | |
info local | 查看所有的局部变量 | |
thread apply all bt | 查看所有线程堆栈命令 | |
p <变量名> | 查看局部变量 | |
p <变量名> = xx | 修改变量 | |
thread <thread_number> | 转到线程 | |
frame <frame_number> | 转到帧 | |
next | 执行下一条,不会进入子函数 | |
step | 进入子函数 | |
continue | 继续执行直到下一个断点命令 | |
finish | 结束子函数返回到调用函数命令 | |
until | 结束循环命令 |
1.2 查看内存
格式:x/nfu 0xxxxxxx
- x是examine的缩写,意思是检查
- n表示要显示的内存单元的个数
- f表示显示方式
- u表示一个地址单元的长度
# f的取值
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
i 指令地址格式
c 按字符格式显示变量。
f 按浮点数格式显示变量。
# u的取值
b表示单字节,
h表示双字节,
w表示四字节,
g表示八字节
watch内存: 触发一次之后需要重新watch才可以继续监视
命令 | 功能 |
---|---|
watch expr | gdb在expr被程序及其值改变时停止 |
rwatch expr | gdb在expr被程序读取时停止 |
awatch expr | gdb在expr被程序读和写的时候停止 |
查看寄存器:info reg
1.3 屏蔽信号
- signals: 进程会产生某些信号打断gdb,需要屏蔽他们的影响
一般应用软件会自行一些信号,需要使用gdb屏蔽掉
# 查看gdb信号种类以及相应处理
info signals
# 改变GDB对signal信号的处理
handle signal <options>
## 操作方式如下
stop/nostop
print/noprint
pass/nopass
2. gdb跟踪调试
2.1 debug版本
-
使用带有-g编译选项
-
release版本中往往没有调试信息,需要汇编基础
-
使用
objdump -dr xxx.o
方式,查看重定位项,你可以看到函数调用关系 -
查看寻址偏移,可以帮助我们查看操作是否为结构体成员变量
- 比如常量、地址偏移一般就是给结构体成员变量赋值
-
注意:编码的时候尽量简洁,可以提升定位效率
-
2.2 gdb多线程调试
gdb多线程命令:
gdb命令 | 功能 |
---|---|
info thread | 显示所有thread线程 |
thread thread_num | gdb现场切换到对应的线程 |
thread apply id1 id2 command | 让一个或者多个线程执行gdb命令command |
thread apply all command | 让所有被调用线程执行gdb命令的command |
b symbol thread thread_num | 只给thread_num这个现成的xxx函数打断点 |
set scheduler-locking off|on|step | off: 不锁定任何线程,也就是所有线程都执行,这是默认值 on: 只有当前被调试程序汇之星 step: 当用 step 命令调试线程时,其他线程不会执行,但是用其他命令,比如next调试线程时,其他线程也许会执行 |
thread apply all bt | 查看所有线程调用栈 |
gdb调试小技巧:
-
场景一:只想获取指定任务的调用栈
# 1. 获取任务对应的tid find /proc/pic/task/ -name "sched" | xargs grep threads # 2. 使用gdb -batch -ex "bt" -p pid 获取对应线程调用栈
-
场景二:打印所有任务调用栈(
thread apply all bt
不好用的情况下)define allbt set $begin=1 set $end=xxx while $begin <= $end thread $begin bt set $begin=$begin + 1 end end
3. gdb内存监控
只能监控已经指导某块内存会出问题,然后复现监控
3.1 watch
-
优点:gdb原生功能,直接能使用
-
使用方法:见1.2
3.2 mprotect内存保护
-
系统库
-
使用场景:申请一块大内存(大于4k), 该内存数据不修改或者很少修改
3.3 perf_event数据断点API进行内存保护
-
是内核对用户态提供软硬件性能数据的一个统一接口,用户通过perf_event的句柄操作能获取到各式各样的性能数据
-
用户态接口:
int perf_event_open(struct perf_event_attr attr, pid_t pid, int group_fd, unsigned long flags)
4. 调试技巧
4.1 gdb不阻塞进程运行
一般的业务进程都会有心跳机制,两种处理办法:
- 方案一:关闭心跳机制
- 方案二:提前写好脚本,gdb执行之后快速退出
# 直接命令行快速退出
gdb -batch -ex "call test_show()" -p pid
# 使用脚本方式
gdb att pid
handle SIGXXX nostop noprint ---屏蔽信号
set height 0 ---打印全部信息
def oops ---自定义操作,断点之后的操作
bt ---打印调用栈
...
4.2 查看传参、返回值
ARM64:一般使用X0~X7 8个寄存器用来传参;X0一般作为返回值
# 查看传参
b sym
c
# hit断点之后,查看寄存器,一般X0~X7对应传参
info reg
# 查看返回值
## 命中断点之后
finish
## 查看寄存器,关注X0
info reg