【问题标题】:Using __gcov_flush within a library doesn't force the other modules to yield .gcda files在库中使用 __gcov_flush 不会强制其他模块生成 .gcda 文件
【发布时间】:2023-09-02 23:54:01
【问题描述】:

最近我一直在尝试使用 gcc/gcov 对 C++ 项目进行代码覆盖测试。该项目由它的主要模块和几个.so库组成,这些都应该被纳入衡量。

我已经用 gcc 编译了所有带有 --coverage 参数的模块,并将它们保存在它们生成的地方,以及相应的 .gcno 标记文件。在正常执行和正常退出后,可以正确生成 .gcda 文件。 问题是,程序应该是一个没有中断或终止的服务,并且不允许在主模块中插入任何自定义代码(如信号处理程序)。正如来自网络的解决方案所建议的那样,我在独立的 .so 库中编写了一个信号处理函数,它在接收到 SIGUSR1 信号时调用 __gcov_flush 以将运行时覆盖计数器刷新到文件.

然而,据观察,虽然 __gcov_flush 函数保证被正确调用,但在运行时仅生成 .so 库的 .gcda 文件。在我看来, __gcov_flush 负责刷新包装模块的数据,而不是其他模块。我想知道这是否应该是这样工作的,还是我需要注意一些技巧才能产生完整的结果?

【问题讨论】:

    标签: c++ c gcc code-coverage gcov


    【解决方案1】:

    我发现这里有两个问题。

    • 如果你的可执行文件加载了多个共享库,那就很难了 获得所需的功能。链接器从 libgcov.a 对于每个共享库,很难调用每个 图书馆的__gcov_flush() 来自一个中心位置,如信号处理程序 在另一个共享库中定义。

    • 声明了来自libgcov.a的函数__gcov_flush()函数 __attribute__ ((__visibility__ ("hidden")))

    如果您从存档中提取 _gcov.o 并运行

    objdump -t _gcov.o

    你会看到类似的东西

       _gcov.o:     file format elf32-littlearm
    
       SYMBOL TABLE:
       000014b4 g     F .text  00000016 .hidden __gcov_flush
    

    即使您要求链接器这样做,它也不会导出隐藏符号 正如它提到的herehere

    所以我看到了第二个问题的两种解决方案。

    1. 您可以尝试在libgcov.a 中编辑_gcov.o 的符号表和 将可见性设置为 "default" 而不是 "hidden"。我没拿 那样是因为我没有找到任何好的精灵编辑器。

      如果您成功了,请确保更新您的链接命令,以便 它链接了这个修补过的_gcov.o,而不是默认的 libgcov.a。基本上,您需要从中删除 --coverage 选项 你的链接器标志。

    2. 您可以为__gcov_flush() 创建一个包装器声明并导出它 正如上面链接中所建议的那样。从你的调用这个包装器 共享库中的信号处理程序。

      我建议您不要为小信号处理程序添加分析 图书馆——真的没必要。

    【讨论】: