准备工作¶
为了能让程序更直观的被调试,在编译时应该添加一些选项
-g
: 添加调试选项-ggdb3
: 调试宏定义
启动方式¶
不带参数¶
gdb ./a.out
带参数¶
gdb ./a.out
set args -a -b -c any_argument_you_need
b main
run
调试core文件¶
gdb bin_name core_name
调试正在运行的程序¶
大致按如下步骤
ps axu | grep bin_name
, 获取进程idgdb attach pid
,启动gdbb somewhere
,设置断点c
,继续运行程序
基本命令¶
括号里是命令缩写,详细命令介绍见http://www.yolinux.com/TUTORIALS/GDB-Commands.html,这里只列出常用的
命令 | 描述 |
---|---|
查看信息 | |
info break(b) | 查看断点 |
info threads | 查看线程 |
info watchpoints | 查看观察点 |
thread thread-number | 进入某个线程 |
删除信息 | |
delete(d) | 删除所有断点,观察点 |
delete(d) breakpoint-number |
case说明¶
-
手动加载源代码
当我们服务器上调试程序时,由于没有加载源码路径而无法查看代码,此时可以将源码目录拷贝到服务器上,然后在gdb调试时通过
dir directory-name
命令加载源码,注意,这里的directory-name一般是程序的makefile所在的路径 -
打印调试信息到日志文件
有时候需要对打印的信息进行查找分析,这种操作在gdb界面不太方便,可以将内容打印到日志,然后通过shell脚本处理。先打开日志调试开关
set logging on
,然后打印你需要的信息,再关闭开关set logging off
,这期间打印的信息就会被写入gdb.txt文件,如果不想写入这个文件,可以在打开日志开关前先设置日志文件名set logging file log-file
可视化调试¶
gdb自带TUI(Text User Interface)模式,详细介绍见https://sourceware.org/gdb/onlinedocs/gdb/TUI.html
基本使用方式如下
Ctrl-x a
:启动/结束TUI ,启动TUI还可以使用win命令Ctrl-x o
:切换激活窗口info win
:查看窗口focus next / prev / src / asm / regs / split
:激活指定窗口PgUp
:在激活窗口上翻PgDown
:在激活窗口下翻Up/Down/Left/Right
:在激活窗口上移一行/下移一行/左移一列/右移一列layout next / prev
:上一个/下一个窗口布局layout src
:只展示源码窗口layout asm
:只展示汇编窗口layout split
:展示源码和汇编窗口layout regs
:展示寄存器窗口winheight name +count/-count
:调整窗口高度(慎用,可能会让屏幕凌乱)
需要注意的是,在cmd窗口上,原本Up/Down是在历史命令中选择上一条/下一条命令,若想使用该功能,必须先将焦点转移到cmd窗口,即执行focus cmd
TUI的窗口一共有4种,src, cmd, asm, regs, 默认是打开src和cmd窗口,可以通过layout选择不同的窗口布局。最终的效果图是这样的
可以看到上面是代码区(src),可以查看当前执行的代码和断点信息,当前执行的代码被高亮显示,并且在代码最左边有一个符号>
,设置了断点的行最左边的符号是B
,下面是命令区(cmd),可以键入gdb调试命令
这样调试的时候执行到哪一行代码就一清二楚了,当然,用gdb调试最关键的还是掌握基本命令,TUI只是一中辅助手段
打印STL和boost数据结构¶
当我们要查看某种数据结构的变量,如果gdb不认识该数据结构,它会按照p/r variable-name
的方式打印数据的原始内容,对于比较复杂的数据结构,比如map类型,我们更关心的是它存储的元素内容,而不是它的数据结构原始内容,还好gdb7.0提供Python接口可以通过实现Python脚本打印特殊的数据结构,已经有一些开源代码提供对boost以及STL数据结构的解析
打印STL数据结构¶
首先查看系统下是否有/usr/share/gdb/python/libstdcxx目录,如果有,说明gdb已经自带对STL数据类型的解析,如果没有可以自己安装,详细介绍见https://sourceware.org/gdb/wiki/STLSupport,这里简单说明一下
- svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python
-
新建~/.gdbinit,键入如下内容
python import sys sys.path.insert(0, '/home/maude/gdb_printers/python') from libstdcxx.v6.printers import register_libstdcxx_printers register_libstdcxx_printers (None) end
其中/home/maude/gdb_printers/python是你实际下载svn代码的路径
打印boost数据结构¶
souceforge上有现成的boost-gdb-printers,但根据我的试验发现在打印unordered_map等数据结构时会报错,因此我做了一些修改并放在github上https://github.com/handy1989/boost-gdb-printers,经测试在boost的1.55和1.58版本下均可用
下载boost-gdb-printers,找到里面的boost-gdb-printers.py,修改boost.vx_y
为实际的版本,并获取文件绝对路径,假设为your_dir/boost-gdb-printers.py,在~/.gdbinit里添加
source your_dir/boost-gdb-printers.py
这时即可打印boost数据结构,我们用以下代码做一个简单的测试
// filename: gdb_test.cpp
#include <stdio.h>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
using std::map;
using std::string;
struct TestData
{
int x;
string y;
};
void break_here()
{
}
int main()
{
boost::shared_ptr<TestData> shared_x(new TestData());
shared_x->x = 100;
shared_x->y = "hello world";
TestData data1;
data1.x = 100;
data1.y = "first";
TestData data2;
data2.x = 200;
data2.y = "second";
boost::unordered_map<int, TestData> unordered_map_x;
unordered_map_x[1] = data1;
unordered_map_x[2] = data2;
break_here();
return 0;
}
编译如下
g++ -g gdb_test.cpp -I/your-boost-include-dir
your-boost-include-dir替换为实际的boost头文件所在路径,编写gdb脚本gdb_test.gdb如下
b break_here
r
fin
p/r shared_x
p shared_x
p/r unordered_map_x
p unordered_map_x
q
y
执行gdb ./a.out -x gdb_test.gdb,查看变量的输出如下
\\(1和\\)3分别是shared_ptr和unordered_map数据类型的原始打印格式,\(2和\)4是加载boost-gdb-printers之后的打印格式