OpenCppCoverage是个很酷的工具,可以不用重新编译,就可以得到line coverage。不像bulleyes,需要用专门的编译,而且价格不菲。
先前简单的研究了一下它,对其有大致的了解。但是当公司真正使用的时候,发现原来正常运行的UT,在OpenCoverage中运行会发生各种奇怪的crash。
于是,就赶紧拉了代码,研究起来。
OpenCppCoverage的工作原理:
- 他以一个调试器在(debugger)的身份,把目标进程运行起来。
- 程序运行起来之后,去加载目标程序中模块的pdb文件。
- 根据PDB文件,枚举得到文件的行号信息。
- 在没一行都加上一个断点 ( 0xcc 指令 )
- 运行目标程序,openCppCoverage进入 debug-loop ( 也就是
WaitForDebugEvent (& debugEvent , INFINITE )
- 当该行代码被执行的时候,就会以
EXCEPTION_DEBUG_EVENT的通知到OpenCppCoverage。收到通知后,将该行代码标记为 "已执行"
一些调试的背景知道:
- 断点
通常,我们比较习惯在某一行代码上设置断点。但是调试器内部实现时,首先是先寻找目标的地址。找到地址后,将该处的指令读取出来并保存到调试器。然后将该处用 0xcc ( int 3 ) 指令填写。
中断指令被执行后,调试器会收到
EXCEPTION_DEBUG_EVENT (
ExceptionCode 为的
EXCEPTION_BREAKPOINT )通知。
在这个通知中,可以用相应的事情。
OpenCppCoverage中存在的问题
- 会在数据设置断点,从而破坏了数据,导致程序异常。这也是我们项目中碰到的问题。
通过在所有的代码行上,设置断点从而得到行覆盖的信息,这样的工作方式在绝大多的情况下工作的挺好,而且对效率影响较少。
但是,如果有些代码被编译后,是以数据的形式存在的话,会出问题。比如switch指令。
临时解决这个问题的方法是修改
OnNewLine,在设置断点之前,先判断一下,是否需要设置断点:
void
CodeCoverageRunner
::
OnNewLine
(
const
std
::
wstring
&
filename
,