GDB用过一段时间了,确实很强大,总结一下平时经常用到的命令。
针对 Linux 下 C/C++ 程序。编译的时候请加上 -g 选项(默认-g2, -g3可以调试宏),关掉优化或者改成 -O0, 保证行号一致和局部变量不被优化掉。
断点、观察点
b func # b : break
b file:line
b +offset #在当前断点行号,后 offset 偏移行再加个断点
b -offset #与上面相反,前 offset 偏移行加个断点
b *addr #在地址 addr 上打断点, 返汇编函数可以看代码段,指令的地址,无源码或者行对不上时有用
b file:line thread all
b [where] if [condition] # 条件断点,满足condition时停住
i b # info breakpoints
del n # delete 断点n
dis n # disable 断点n
en n # enable 断点n
watch expr # 观察点,expr 变化时断住, expr当前上下文可见
#eg: watch *(unsigned int *)0xbffff400==2
rwatch expr # 观察点,expr 被读时断住
awatch expr # 观察点,expr 被读或写时断住
info watchpoints # 查看观察点
运行
c # continue 恢复程序运行
r # run 重新运行
fin # finish 执行完毕此函数,退出函数
ret val # 强制函数return val值,不执行完毕
l # list source code
until # 走出当前循环
until loc # 往下走,直到loc位置
s # step 单步,遇到函数进入
n # next 单步,遇到函数不进入
set disassemble-next-line auto ## 汇编级单步时显示行号
si # step instruction, 汇编级单步,遇函数进入
ni # next instruction, 汇编级单步,遇函数不进
p my_var=5 # 改变变量的值
set var my_var=5 #
ret val # return ,强制结束函数 ,并且返回 val
jump <line> # 不要跨栈帧,一个函数内可以用用
call func # 强制调用函数
set $epc = 0x10 #修改寄存器
set *(unsigned int*)0x8048a54=6a #修改内存的值
调用栈
bt # backtrace
t a a bt # thread apply all backtrace, 查看所有线程调用栈
f n # frame 切换栈帧, 栈 高地址 -> 低地址
up n # 上移n个栈帧函数,缺省1
down n # 下移n个栈帧函数,缺省1
i r # info registers, 可以看函数入参
# %rdi 1
# %rsi 2
# %rdx 3
# %rcx 4
# %r8 5
# %r9 6
#eg: p $rdi 就可以看第一个参数了
i r a # 查看所有寄存器
i args # 当前栈帧函数入参
i loc # locals 查看栈帧内所有局部变量
pt var # ptype 显示变量的类型
whatis var # 查看类型
disass # 当前栈帧函数的反汇编
disass func #看func反汇编
disass /m func #反汇编与源代码行号对应
p $pc #看当前汇编指令地址
多线程
i threads # 查看线程
thread n # 切换到线程n
set scheduler-locking [off|on|step] # 设置多线程
# off 不锁定任何线程,也就是所有线程都执行,这是默认值
# on 只有当前被调试程序会执行
# step 在单步的时候,除了next过一个函数的情况(是一个设置断点然后continue的行为)以外,只有当前线程会执行
attach 进程
gdb - pid # 先用 ps 命令查 pid
gdb -p pid
gdb att pid
gdb attach pid
i prog # program 查看程序是否在运行,进程号,被暂停的原因
打印
set pr pr on # set print pretty on, 打开printf pretty这个选项,那么当GDB显示结构体时会比较漂亮!
p/[format] var # 打印变量值 /x 16进制, /d 10进制
x/[n][format][size] address # 显示内存
# [n] n为要打印的对象数目
# [format] 格式字符,o(octal), x(hex), d(decimal), u(unsigned decimal),
#t(binary), f(float), a(address), i(instruction), c(char) and s(string)
# [size] size指示符,b(byte), h(halfword), w(word), g(giant, 8 bytes)
p *array@len # 查看动态数组,malloc的数组,array里包含了数组的类型了,len是数组元素个数
display/<fmt> <expr> # 自动显示,程序被断住或停住是,自动显示这个值,非常有用!!!
display/<fmt> <addr>
display/i $pc # $pc是GDB的环境变量,表示着指令的地址,/i则表示输出汇编
自动化脚本
command n # n表示断点号
命令
命令
...
end
GDB 环境变量
set $my_var = exp
e.g.
set $i = 0
print bar[$i++]->contents # 回车,下次会自动递增
调试宏
macro expand 带参宏(自己随便定一个入参) # 测试宏展开, 也可以 gcc -E 看预编译的源码
信号Signals
信号是一种软中断,是一种处理异步事件的方法。比如:SIGINT
表示中断字符信号,也就是Ctrl+C
的信号。
handle
info signals
info handle # 查看有哪些信号在被GDB检测中
pass noignore # 当被调试的程序收到信号时,GDB不处理信号。这表示,GDB会把这个信号交给被调试程序会处理
# 有些信号处理是必要的,如果给忽略了,程序可能由于自身或其他保护机制退出