GDB
GDB 调试器的使用
前提需求
如果是使用 GCC 编译程序的时候,需要使用 -ggdb3 -Wall 参数
如果是使用 CMake,则 CMAKE_BUILD_TYPE 需要设置为Debug/RelWithDebInfo
另外,调试时如果用到了动态库,gdb 会自动下载动态库的 debuginfo。对于 Fedora 而言,还可以使用 dnf debuginfo-install 手动安装。包名与提供动态库的包名相同
设置断点
gdb 通过 breakpoint 进行打断点,此指令的简写形式为 break、b。命令格式为
break location
break location if cond
其中 location 的值为:
location |
含义 |
|---|---|
行号 |
入口函数所在文件的行号 |
文件名:行号 |
指定文件的行号 |
函数名 |
在函数内部的第一行代码暂停 |
文件名:函数名 |
在执行指定文件的指定函数时暂停 |
此外,上述所有 location 都可以接 location offset 的形式进行偏移。offset 可为正负,单位为行
命令 |
做用 |
|---|---|
d [n] |
删除所有断点或者删除 n 号断点 |
clear [行号] |
删除指定行断点 |
disable |
禁用断点 |
enable |
启用断点 |
info breakpoints |
查看断点 |
运行代码
执行有两种方式:
命令 |
作用 |
|---|---|
run |
直接运行到断点 |
start |
在 main() 处中断 |
next |
Step Over |
step |
Step Into |
cont |
执行到下一个断点 |
查看运行时信息
bt |
显示栈帧 |
bt full |
显示局部变量 |
print/p |
计算并打印表达式的结果 |
display |
跟踪表达式的结果 |
info reg |
查看寄存器内容 |
watch |
表达式变化时暂停 |
awatch |
表达式 rw 时暂停 |
rwatch |
表达式 r 时暂停 |
step |
修改变量的值 |
多线程如何调试?
线程里直接加个 while(true) 等线程开始后 attach 进去,然后手动退出循环
GDB 脚本
将 gdb 调试过程写入一个文件中,就成为了一个 gdb 脚本。此脚本可在启动时通过参数 -x 引入,以自动完成某些工作。例如:
b threadpool.cpp:8
run
b if terminate_ == true
c
然后通过命令 gdb ./build/Debug/threadpool_test -x ./debug.gdb 启动命令即可
调试 Core 文件
首先拷贝并解压 Core 文件
cp cp /var/lib/systemd/coredump/core.test_threadpool.zst .
extract core.test_threadpool.zst
然后使用 gdb ./build/Debug/threadpool_test core.test_threadpool 开始调试。之后可以通过 bt 查看栈帧
跟踪过程调用
有三个相关工具:strace, ltrace 和 ftrace 分别用于跟踪系统调用、用户态程序调用和所有函数调用
多线程调试
多线程情况下崩溃有以下几种原因:
对失效的锁(对象失效)调用了 lock
加锁解锁顺序不对
加锁解锁不在同一线程中
对无锁的锁尝试解锁
动态库调试
动态库的调试与普通二进制文件的调试差不多,在加载可执行文件后,直接通过 breakpoint function_name 打断点,之后出现的提示选 y,正常执行即可