gdb工具可用来跟踪调试代码,也可用来结合GCC源码追踪GCC的运行过程。
1. 基本调试使用
常用参数说明:
b : 等价于 break。表示设置断点
r : 等价于 run。表示执行
l : 等价于 list。表示显示代码,默认仅显示10行
i : 等价于 info。表示显示信息
p : 等价于 print。表示打印信息
c : 等价于 continue。表示单步执行
q : 等价于 quit。表示退出gdb
s : 等价于 step。表示进入函数
tb:等价于 tbreak。表示让断点只生效一次
常用选项还包括layout、disassemble、set等等。
对于一个简单的单文件代码调试,可使用-g选项编译,生成可调试的可执行文件,进行调试,如下:
1. gcc -g test.c -o testt //生成可调式的执行文件
2. gdb testt //gdb可执行
3. b main //先设置一个断点,可以就从main函数开始
4. r input.in //这一步非必须的,只有你的执行有输入参数才需要这一步
5. l //此时可使用l,查看当前所处断点的代码(l n,m:指定范围查看)
6. bt //查看当前函数调用信息
7. info functions //列出函数名称
8. b function2 //在function2上设置断点
9. c //运行到该断点处
10. p x //打印x的值
11. set main::p1="abc" //改变字符串值
12. s //step 进入函数
13. n //next 不进入函数
14. finish //单步调试一个函数时,若不想继续跟踪,这样可继续执行完,并打印返回值
15. frame n //选择函数堆栈帧
16. up n (down n) //向上或者向下选择函数堆栈帧
17. save breakpoints points-file //将设置的断点保存下来
18. source points-file //批量设置保存的断点
19. tcatch //设置catchpoint只触发一次
20. attach 1002 //开始调试进程1002(默认追踪父进程)
21. detach 1002 //退出调试进程1002
22. info threads //查看所有线程信息
23. maint info program-spaces //打印当前所有被调试的进程信息
对于benchmark源码的调试,同样也需要使用-g
,由于编译和链接分为两个步骤进行,可在Makefile选项中增加-g
之后再重新编译。之后进行设置断点,单步执行,查看堆栈信息,汇编信息等。
其中对于函数的调试采用 b function
命令,但断点不能设置到函数的汇编指令开头上,此时可使用b *function
,然后使用disassemble查看汇编就能看到断点在函数开头,这也是对应源码和汇编的有效信息。除此之外也可以使用命令:disassemble /m function
将代码和汇编码对应起来。部分操作如下:
如上图所示,在intel处理器上,gdb显示汇编码默认采用AT&T格式。可使用命令:set disassembly-flavor intel
将格式改为Intel格式。
2. GCC源码运行追踪
先使用gcc -O3 -flto test.c --verbose &>gdbfile
对test.c文件生成过程信息,其中包含cc1、collect2、lto1、as等信息。需要修改的地方如下:
修改gdbfile文件,只保留cc1信息,在cc1头部加上file,并设置断点为main和输入信息。其中“file”表示读取可执行文件(常与“file”连用的命令还有“core”,即core-file,用来动态加载可执行程序)。如下所示:
使用gdb -x gdbfile
开始断点调试。
结合GCC源码,根据断点走的函数从前端开始查看对应源码,提高源码阅读效率。若想调试GCC运行时的段错误可以使用b exit
,然后打印bt
信息进行分析。
同时为了更好地分析GCC的运行过程,可使用-fdump-tree-all、-fdump-tree-all-graph、-fdump-ipa-all
等选项得到跟多详细信息,例如-fdump-tree-all-graph
选项配合dot工具生成cfg图(dot -Tpng -o xx.png xx.dot
)。