覆盖测试中高效代码插桩技术的研究
2.1 CodeTest 工具的插桩技术分析
Codetest 的插桩过程简单来说分为两步:
(1)对源代码进行预编译;被测程序首先会通过CodeTest 的编译驱动器调用程序的原编译器进行预编译,通常是进行宏替换。
(2)对预编译后的文件进行插桩,生成插桩后的.C 文件和.IDB 的插桩符号数据库文件;预编译完成后,CodeTest的插装器(即源代码分析程序)据不同的参数对预编译后的源代码进行相应方式的自动插桩,即在需要插桩的位置写入一条赋值语句(如:amc_ctrl=0x74100010),并把插入的标记送入数据库文件中生成一个符号数据库暂存起来,为以后的分析时调用。然后,CodeTest的编译驱动器会调用原编译器对插桩后的代码进行编译生成可执行目标代码送到目标板上运行。当程序在目标系统运行到插桩点的位置时,目标板的控制总线和地址总线上会出现相应的控制信号和地址信号。当 CodeTest的辅助硬件(信号捕获探头)从控制总线和地址总线上监视到符合以上条件的信号时,CodeTest会主动地从数据总线上把数据捕获回来送到CodeTest的内存中暂存并对这些数据进行预处理,然后将预处理后的数据通过局域网送到工作平台上。通过与前面生成的符号数据库中的数据进行比较,我们就此得知当前程序的运行状态,借此完成对嵌入式软件的性能分析,高级覆盖率分析,内存分析和大容量的代码跟踪。
CodeTest是一个硬件辅助软件的测试与分析工具,它吸取软件打点技术,并对这种技术进行了改善,纯软件工具插入的是一个函数,而 CodeTest插入的是一条赋值语句,它在汇编级也是一条语句,所以它执行的时间非常短,占用的空间也非常少,同时避免了被其它的中断所中断,所以它对目标系统的影响非常小(1%-15%)。
2.2 程序插桩的切入点
CodeTest 作为一种商品,很多技术不对外公开 ,但是我们仍可以明白其插桩的原理,进而以此为参考对插桩技术做进一步的研究;在国内,虽有很多工具使用了插桩技术,但是都不够高效, 为了方便研究我们选择GCC 作为插桩技术研究的平台。
GCC 是一个高度优化,高度可移植,且广泛使用的编译系统。它能处理多种语言,包括C/C++、Fortran、Java、Ada 等多种语言前端,而且后端几乎支持所有的处理器结构。同时GCC作为源码开放的软件,可以自由修改和使用。
![](http://m.amcfsurvey.com/editerupload/fetch/20131219/202489_2_0.jpg)
![](http://m.amcfsurvey.com/editerupload/fetch/20131219/202489_2_1.jpg)
图1 是GCC 增加插桩阶段后的编译流程。
GCC 编译器的工作流程大致可以分为前端、中端和后端。中端Gimple 层是高版本GCC 中新增加的,是用来对经过词法、语法分析后的程序进行优化和整理的阶段,我们这里可以暂时忽略这个阶段。前端包括预处理和词法、语法分析。
预处理通常是做宏替换处理。词法、语法分析的输入是预处理后的文件,输出是AST ,AST 经过优化后产生Gimple Tree,然后交给RTL 模块去处理。RTL(Register Transfer Language)是一种中间语言,作为编译器工作的后端,是GCC内部使用的一种能对实际体系结构作抽象的,与硬件无关的语言。在GCC 中将生成的中间代码表达式以一种双向链表的形式组织起来的,在链表中有一些特殊的节点,这些节点记录了程序的结构信息。
GCC 编译器前端的工作完成后,词法语法分析器已经识别完程序的所有特征,因此将词法、语法分析至Gimple 这个阶段作为代码插桩的切入点是完全可行的。然后,GCC 利用中间代码生成会汇编代码时,如果扫描到RTL 中的特殊节点就会根据用户的需要适当的插入一些完成信息采集功能的汇编代码行,从而就可以实现代码插桩。但是这种做法有两个缺点:一是代码的插桩和编译器的结合很紧密,并且在汇编代码的生成过程中需要针对不同的CPU 生成不同的汇编代码,与CPU 的关联性很强,不便于移植;而是,当程序很大时,探针的植入会造成代码的膨胀,及进行信息采集的代码的插入就需要很多时间。
评论