GDB是什么
GDB调试器可以运行你在程序运行的时候检查里面发生了什么
GDB的主要功能
设置断点
使程序在指定的代码行上暂停执行,便于观察
单步执行程序,便于调试
查看程序中变量值的变化
动态改变程序的执行环境
分析崩溃程序产生的core文件
GDB安装
安装命令
sudo apt-get install gdb
检查gdb是否成功安装
gdb --version
使用gdb进行调试前需要先编译目标文件
gcc -g test.c -o test
在编译时必须添加-g选项
gdb常用命令
## 以下命令后括号内为命令的简化使用,比如run(r),直接输入命令 r 就代表命令run
$(gdb)help(h) # 查看命令帮助,具体命令查询在gdb中输入help + 命令
$(gdb)run(r) # 重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件)
$(gdb)start # 单步执行,运行程序,停在第一行执行语句
$(gdb)list(l) # 查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函数)
$(gdb)set # 设置变量的值
$(gdb)next(n) # 单步调试(逐过程,函数直接执行)
$(gdb)step(s) # 单步调试(逐语句:跳入自定义函数内部执行)
$(gdb)backtrace(bt) # 查看函数的调用的栈帧和层级关系
$(gdb)frame(f) # 切换函数的栈帧
$(gdb)info(i) # 查看函数内部局部变量的数值
$(gdb)finish # 结束当前函数,返回到函数调用点
$(gdb)continue(c) # 继续运行
$(gdb)print(p) # 打印值及地址
$(gdb)quit(q) # 退出gdb
$(gdb)break+num(b) # 在第num行设置断点
$(gdb)info breakpoints # 查看当前设置的所有断点
$(gdb)delete breakpoints num(d) # 删除第num个断点
$(gdb)display # 追踪查看具体变量值
$(gdb)undisplay # 取消追踪观察变量
$(gdb)watch # 被设置观察点的变量发生修改时,打印显示
$(gdb)i watch # 显示观察点
$(gdb)enable breakpoints # 启用断点
$(gdb)disable breakpoints # 禁用断点
$(gdb)x # 查看内存x/20xw 显示20个单元,16进制,4字节每单元
$(gdb)run argv[1] argv[2] # 调试时命令行传参
$(gdb)set follow-fork-mode child # Makefile项目管理:选择跟踪父子进程(fork())
Tips:
-
编译程序时需要加上-g,之后才能用gdb进行调试:gcc -g main.c -o main
-
回车键:重复上一命令
部分gdb命令使用实例
set arg 设置命令行参数
list 查看我们的源代码
list 14 //从源代码的第14行开始打印10行
list //默认从头开始打印10行
list //再次调用从上次打印的末尾开始打印10行
break b 打断点
b 10 //在源代码的第十行打断点
info b 查看断点的信息(可以查看断点数量及位置)
print p 打印变量
p var//显示变量var的值
p data[10] //显示数组中元素的值
p &data //打印元素的地址
step s 进入一个具体函数调试(真正的单步调试)
next
单步调试
continue
运行到下个断点
watchpoint 观察一个变量的变化
相当于监视窗
print &i
1 = (int *) 0x7fffffffe52c
watch *0x7fffffffe52c
每当watchpoints监视的变量发生变化,就会打印
使用info watchpoints可以查看详情观察点详情
在调试父子进程时
set follow-fork-mode child
优先追踪子进程
GDB之多进/线程切换
GDB调试之多线程切换
进程切换
选择调试进程
在GDB中有两个选项来确定调试的进程:
-
follow-fork-mode
,设置调试哪个进程 -
detach-on-fork
,GDB在fork之后是否断开(detach)某个进程的调试
这两个选项的参数组合起来的效果如下表
follow-fork-mode | detach-on-fork | 效果 |
---|---|---|
parent | on | 只调试父进程 |
child | on | 只调试子进程 |
parent | off | 同时调试两个进程,子进程暂停 |
child | off | 同时调试两个进程,子进程暂停 |
进程切换
-
info inferiors
,查看当前所有进程 -
inferiors <num>
,切换当前GDB调试进程,其中num
为上一条指令中列出的进程Num
多线程切换
当你的程序是多线程时,你可以定义你的断点是否在所有的线程上,或是在某个特定的线程。
break line thread threadNo
其中line
为你的源码行数,threadNo
为info threads
命令中GDB给出的线程ID,若不指定threadNo
,则为所有线程打断点
多线程调试时,可以设置其余线程的阻塞状态
show scheduler-locking
,查看设置
set scheduler-locking <on><off><step>
on
,表示调试线程执行时,其余线程锁定,阻塞等待,
off
,表示不锁定其他线程
step
,表示在step(单步)调试时,只有当前线程运行
这样就可以避免next调试时总是跳转到其他线程啦
线程和进程一样,同样支持切换
info thread
, 列出当前所有线程
thread <num>
,切换线程,num为上一条指令给出的
GDB小技巧
shell 后可接shell命令
shell ls
日志功能
set logging on //打开gdb的日志功能
carchpoint
watchpoint
调试运行中出现错误的程序
打开core文件的限制(core文件不会默认生成)
ulimit -a //显示目前资源限制的设定
ulimit -c unlimited //解除core文件限制
打开core文件限制后,当程序运行出错时会自动创建core文件
ulimit文档
Linux ulimit命令 | 菜鸟教程 (runoob.com)
同时调用执行文件和core文件
gdb ./a.out core
执行这个命令行会显示使程序运行出错的那行代码
调试一个运行中的进程
在后台运行一个进程
./a.out &
调用以下命令行
gdb -p [pid]
如果调用该命令出错,可以切换到root用户来运行