Content
0. 序
1. 编译 gcov/gcov-dump
2. 额外的话
3. gcov-dump 程序的一个 bug
3.1 bug 描述
3.2 bug 分析与修复
3.3 正确的输出
3.4 gcov-dump 的打印开关
3.5 一个问题:上面红色的 0 是什么?谁打印出来的?
4. 总结
0. 序
某些版本的 Gcc 在默认情况下编译,可能不会产生 gcov-dump 程序,或者不会安装到 /usr/bin 。但 gcov-dump 程序在做覆盖率测试时 dump 相关文件 (.gcda/.gcno) 内容时非常必要和好用。
Gcc 的编译耗时又繁琐,如果某些配置不正确,会导致编译过程中各种莫名其妙的错误。因此,本文主要讲述在不重新编译整个 Gcc 项目的情况下,如何获得 gcov-dump 程序。
本文在 Linux 平台上实验,以 gcc-4.1.2 为例,且 gcc 源代码在 /usr/src/gcc-4.1.2 目录。以下若不做特别说明, . 表示 gcc 源代码目录,即 /usr/src/gcc-4.1.2 。
1. 编译 gcov/gcov-dump
Gcov-dump.c 位于 ./gcc 目录下,因此,可以通过 ./gcc 的 makefile 文件编译生成 gcov-dump 。 gcc 目录下 configure 程序即可生成该 makefile 。
makefile 文件中的 gcov-dump 如下,由 ./gcc/build 下的 Makefile 文件中抽取出来。
至于其他的定义,非本文重点,不予解释。
程序提示在 ../build-i686-pc-linux-gnu/libiberty 目录下没有找到 genmodes 所需的静态库 libiberty.a 。
从 makefile 文件中也了解到, gcov/gcov-dump 实际所需的静态库是 libcpp.a 和 libiberty.a 。实际上,只需在 gcc 目录下的 makefile 文件中指定好这两个静态库的路径 ( 绝对路径和相对路径均可 ) 即可解决问题。例如: /usr/bin/libiberty.a 。
2. 额外的话
不得不指出的一点:事实上,对 libcpp.a 的依赖几乎为 0 ,且对 libiberty.a 的依赖也仅限于以下函数。
这两个函数的声明在 ./include/libiberty.h 中。
因此,了解这些之后,就可以将 gcov/gcov-dump 相关的文件抽取出来,单独成为一个独立的项目,来编译出 gcov/gcov-dump ,以方便对 gcov/gcov-dump 源代码和原理的学习、调试。
——将另文讨论。
3. gcov-dump 程序的一个 bug
3.1 bug 描述
用上述生成的 gcov-dump 程序 dump 出某个 .gcda 文件的内容,如下。
很显然,该文件里并没有这些庞大的数据,也就证实了我们的猜测。基本可以确定, gcov-dump 有 bug 。
3.2 bug 分析与修复
如何分析,自然想到了 gdb 。有问题的数据貌似在 dump Object Summary 和 Program Summary 时出现的。那么在 tag_summary () 函数中设置断点是很自然的事。经一番调试后,发现问题就在 tag_summary() 函数里。如下。
其中, GCOV_COUNTERS 的定义如下,其值为 5 ,故每次打印均打印出 5 个 summary 的内容。但实际应该是按照 summary(Object 或者 program) 的个数来打印信息。
输出的信息,如,
counts=5, runs=1, sum_all=12, run_max=10, sum_max=10
即为 gcov_ctr_summary 结构,其定义如下。在 ./gcc/gcov_io.h 文件中。
GCOV_COUNTERS_SUMMABLE =1 ,因此, gcov_summary 结构中的 ctrs 数组,实际上是一个指针而已,当 summary 有多个时 ( 不超过 5 个 ) ,应该为其分配空间。