插桩
1、编译器背景
编译器主要三大块:前端(frontEnd),优化器(Optimizer)和后端(backEnd)。
源码翻译为中间表示,中间表示翻译为特定机器码
GCC(GNU Compiler Collection) 是一个工具集合,包含的预处理器为cpp,还会调用汇编器as、连接器ld。
GCC 也将三段式做的比较好,并且实现了很多前端,支持了很多语言。但是致命缺陷是,他们是一个完整的可执行文件,没有给其它语言的开发者提供代码重用的接口。即使 GCC 是开源的,但是源代码重用的难度也比较大。也就是说GCC太庞大了,耦合度太高!!
LLVM (Low Level Virtual Machine),顾名思义是一种中间表示,类似Java虚拟机,降低耦合度,解决重用问题。
clang + llvm ≈ GCC ,其实llvm+gcc/clang/其他,也是可以的。上述的GCC(RTL)与llvm(IR)的中间表达是不一样的。
2、SanitizerCoverage插桩
插桩编译
1 | clang -fsanitize=address -fsanitize-coverage=trace-pc-guard -o test test.c |
-fsanitize-coverage=trace-pc-guard:对边进行插桩。(默认:edge)
-fsanitize-coverage=func,trace-pc-guard:对每个函数插桩。
-fsanitize-coverage=bb,no-prune,trace-pc-guard:对基本块插桩。
或者直接在makefile文件里加:
1 | CC = clang |
或者make命令后加:
1 | make CC="clang -O2 -fno-omit-frame-pointer -g -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-gep,trace-div" |
执行程序获取覆盖率数据文件。
1 | ASAN_OPTIONS=coverage=1 ./test |
.sancov文件是 AddressSanitizer生成的覆盖率文件,这些文件包含了程序在运行时覆盖的代码部分的信息。将该文件转换为覆盖率信息。
1 | sancov -symbolize *.sancov ./test > test.symcov |
查看覆盖率信息。
1 | cat test.symcov |
打印覆盖的函数:
1 | sancov -covered-functions *.sancov ./test |
3、Code Coverage插桩
插桩编译
1 | clang -fprofile-instr-generate -fcoverage-mapping test.c -o test |
或者直接在makefile文件里加:
1 | CC = clang |
或者make命令后加:
1 | make CC="clang -O2 -fno-omit-frame-pointer -g -fprofile-instr-generate -fcoverage-mapping" |
执行程序获取覆盖率数据文件。
LLVM_PROFILE_FILE="test.profraw" ./test
合并生成的覆盖率数据文件。
llvm-profdata merge -sparse test.profraw test2.profraw ... -o test.profdata
查看覆盖率信息:
llvm-cov show ./test -instr-profile=test.profdata
查看覆盖率报告:
llvm-cov report ./test -instr-profile=test.profdata
4、gcov 插桩
插桩编译
1 | gcc test.c -c -fprofile-arcs -ftest-coverage -o test.o |
或者直接在makefile文件里加:
1 | CC=gcc |
或者make命令后加:
1 | make CC="gcc -g -fprofile-arcs -ftest-coverage" |
运行程序后,会生成一个 *.gcda 文件,里面包含代码执行次数等数据。
注意:遇到*.gcda不能生成的情况,大概率是因为程序没有正常结束,比如用ctrl+c
源码中添加信号处理
1 | #include <signal.h> |
再启动:
1 | timeout -k 0 -s SIGUSR1 3s ./test //3s控制运行时长 |
输出覆盖率报告
# 生成覆盖率文本报告
lcov -c -d . -o test.info --rc lcov_branch_coverage=1
# 生成覆盖率网页报告
genhtml --branch-coverage -o result test.info