lsekfe 发表于 2023-4-18 13:11:01

打桩、断言、代码覆盖之间关系之单元测试

Gcc在编译阶段指定 –ftest-coverage 等覆盖率测试选项后,GCC会:
  1、 在输出目标文件中留出一段存储区保存统计数据;
  2、 在源代码中每行可执行语句生成的代码之后附加一段更新覆盖率统计结果的代码,也就是插桩(后面详细介绍);
  3、 Gcc编译,会生成*.gcno文件,它包含重建基本块图和相应块的源码的行号信息;
  4、 在最终可执行文件中,进入main函数之前调用gcov_init内部函数初始化统计数据区,并将gcov_init内部函数注册为exit_handers,用户代码调用exit正常结束时,gcov_exit函数得到调用,并继续调用__gcov_flush输出统计数据到*.gcda文件。
  插桩
  在保证被测程序原有逻辑完整性的基础上在程序中插入一些探针,以获得程序控制流和数据流。
  gcov是使用基本块BB和跳转ARC计数。
http://www.51testing.com/attachments/2023/04/15326880_202304131543001XPNm.jpg
  基本块(basic block)是一段线性的代码,只能从这段代码开始处进入这段代码,没有其他代码会跳跃进入这段代码,只能从这段代码最后一行离开这段代码,中间没有其他代码会跳跃离开这段代码。
  跳转ARC:从一个BB跳转到另一个BB。
  如果把BB看作是一个节点,那么整个程序构成了有向图。要想知道程序中每个语句和分支的执行次数,就必须知道每个BB和ARC的执行次数。
  插桩过程
  1.GCC在插桩的过程中会向源文件末尾插入一个静态数组BX2.数组的大小就是这个源文件中桩点的个数。BX2+n表示第n个桩点的位置,数组元素的值就是桩点的执行次数。
  2.每个桩点插入汇编语句:inc$(BX2+n)
  3.BX2数组链表:为了方便统计,gcc还将各个源文件中的BX2数组连成一个链表,它在main函数之前就有一个类似于构造函数的__attribute__((constructor)) void before();会构建链表。这个函数在推出时调用exit函数计算执行次数生成.gcda文件。
  生成文件
  gcov 使用两个文件进行分析。这些文件的名称是通过将文件后缀替换为 .gcno 或 .gcda 来从原始目标文件派生的。这些文件包含以独立于平台的格式存储的覆盖率和剖面数据。 .gcno 文件与目标文件放置在同一目录中。默认情况下,.gcda 文件也存储在与目标文件相同的目录中,但可以使用 GCC -fprofile-dir 选项将 .gcda 文件存储在单独的目录中。
  使用 GCC -ftest-coverage 选项编译源文件时会生成 .gcno 注释文件。它包含重建基本块图和为块分配源行号的信息。
  执行包含使用 GCC -fprofile-arcs 选项构建的目标文件的程序时,会生成 .gcda 计数数据文件。为使用此选项编译的每个目标文件创建一个单独的 .gcda 文件。它包含弧过渡计数、值配置文件计数和一些摘要信息。

页: [1]
查看完整版本: 打桩、断言、代码覆盖之间关系之单元测试