GDB的使用
编译选项
要调试C/C++的程序,在编译时,要把调试信息加到可执行文件中。编译器(cc/gcc/g++)添加-g参数。
比如:g++ -g hello.cpp -o hello
启动gdb
1) gdb -p 进程ID
调试正在运行的程序, 找到进程ID之后, gdb -p过去就可以
2) gdb 二进制文件名
直接用gdb启动程序, 如果程序做过fork之类的, 需要设置gdb参数`set follow-fork-mode child`
3) gdb 二进制文件名 coredump
调试dump文件
常用的调试命令
设置断点:
1) b 文件名:行号
(gdb) b main.cpp:10
2) b 函数名
```gdb
(gdb) b ProcessMessage
(gdb) b Server::Loop
```
条件断点:
cond(ition) bnum expression
例如想要在a变量等于1的时候, 进入断点10, 那么就是:
(gdb)cond 10 a == 1
数据断点
watch 变量
例如有一个变量a, 我想知道他在那里被改变了
(gdb)watch a
也有可能是程序写越界导致了a变量被改变(a的类型为int)
(gdb)watch *(int*)&a
启用关闭断点
info b可以看到所有的断点信息(状态)
enable 断点编号, 启用断点
disable 断点编号, 关闭断点
delete 断点编号, 删除断点
(gdb) info b
(gdb) enable 1
(gdb) disable 2
(gdb) delete 3
恢复程序运行和单步调试:
step/s : 单步跟踪,如果有函数调用,会进入该函数
next/n : 单步跟踪,如果有函数调用,不会进入该函数
finish : 运行程序,知道当前函数完成返回
continue/c : 继续运行
run/r : 运行程序
其他常用命令:
p i : 打印变量i的值,p是print命令的缩写
x : 用来查看一段内存的指令, x/nfu, n是个数, f是format, u是单位(b,h,w,g), 具体需要看gdb手册
bt : 查看函数堆栈
f: 切换函数栈, 比如f 1, f 10
frame 栈帧号 : 打印栈帧
list : 显示程序中的代码, 可以通过+-来控制向上翻还是向下翻
quit :退出gdb
设置变量的值
有时候需要在运行的时候修改变量的值, 可以通过set来做
(gdb) set a = 10
(gdb) set *(int*)0x8048a51 = 100
coredump等问题的定位及解决
gdb coredump应用程序 coredump文件
通过以下命令调试
info threads 显示所有线程
bt 显示线程堆栈信息
thread thread_num 切换线程
frame num 切换栈
gdb常见问题
1) C++11的auto变量打印
auto变量可能不能正常打印期数据和类型
2) 捕获信号
发送给程序的信号, 可能会被gdb捕获, 而不是被程序处理, 这是正常现象 3) 变量值错误
gdb有时候会打印错误的变量值, 跟log的值不一样, 推荐尽量打log, log里面的值一定是正确的, gdb里面不一定 4) 复杂类型变量
gdb支持pretty printer, 可以让复杂类型看起来更舒服一些
(gdb) set print pretty on
(gdb) p *this
$2 = {
<gsdk::Singleton<gsdk::message::MainLoop>> = {
<gsdk::Noncopyable> = {<No data fields>},
members of gsdk::Singleton<gsdk::message::MainLoop>:
static once_ = {
_M_once = 2
},
static ptr_ = 0x612000000ac0
},
members of gsdk::message::MainLoop:
run_ = true,
gdb可以通过python插件扩展来支持个复杂类型的打印, 例如STL等, Ubuntu等发行版自带了STL的pretty printer.
(gdb) p this->queue_.queue_
$4 = std::vector of length 0, capacity 1
5)
