本节书摘来自华章出版社《深入分析gcc 》一书中的第2章,第2.2节,作者 王亚刚 ,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
调试工具是代码分析中至关重要的工具之一。在使用vim+ctags查看代码时,经常会遇到难以理解的部分,此时,可以借助调试工具,对代码的运行过程进行跟踪,通过跟踪运行过程以及关键数据的变化,可以从程序执行的过程中理解源代码的功能。
调试工具有很多种,最常用的是gnu gdb工具。下面通过一个例子,介绍如何使用gdb,这些调试命令几乎就是笔者调试程序的所有命令,简单且实用。关于完整的gdb的使用,请参与gnu gdb文档,或者使用man gdb进行在线查询。
本例主要使用gdb来跟踪gcc的运行过程,因此,需要事先编译gcc源代码(编译时需要使用-g选项),生成可执行的编译程序cc1,下面利用gdb对cc1程序的运行进行跟踪。
首先,可以在程序入口处设置断点(break point):
单步跟踪程序的执行,step命令和next命令均可以进行单步跟踪,二者的主要区别在于step在单步执行函数代码时,会进入被调用的函数,而next则会将函数调用看作“单步”,一次执行完一个函数的调用。对于其他代码,step和next命令的功能基本相同。
此时可以看到,使用run命令执行程序后,程序执行到前面定义的断点处暂停执行。
如果此时需要查看toplev_main函数的执行细节,应该使用step命令进入该函数。
<code>(gdb) step ? 单步跟踪</code>
<code>toplev_main (argc=1, argv=0xbffff434) at ../.././gcc/toplev.c:2212</code>
对于程序执行过程中,需要查看某些变量的值,可以使用print命令。
查看变量的值可以使用print命令,如果在每一条指令后都需要查看某些变量的值,使用print显得有些烦琐,可以使用display命令,设置显示的变量。
可以看出,每执行一步,变量argc的值都会输出显示。
当需要连续执行程序时,可以使用continue命令,程序则恢复运行,直到下一个断点处再次暂停运行。
通常,在执行到某个断点处时,当需要了解当前函数的调用情况时,可以使用bt命令(backtrace)。
(gdb) bt ? 显示函数调用的堆栈
可以看出当前执行的函数为toplev_main函数,其调用者为函数main,并且这两个函数所在的文件及位置信息也在bt的输出中给出。bt命令的输出可以很详细地展示当前函数的调用关系,对于理解程序的执行流程非常有帮助。
另外,gdb在输入命令时,如果输入命令的开始部分可以完全确定一个命令时,则可以简写该命令,例如,一般用户经常将命令run简写为r,step命令简写为s,next命令简写为n,continue命令简写为c等,如果用户没有输入命令,直接按回车键,则gdb默认会执行上一次输入的命令。例如在单步跟踪时,如果输入了命令next,后续单步跟踪则可以只需要按[enter]键就可以了。这些规律,读者可以在使用过程中不断总结,提高调试效率。
界面如图2-3所示,可以看到cgdb中能够很方便地查看源代码。关于cgdb的使用请查阅相关文档,不再赘述。