Code Coverage for WebAssembly
This is a general overview of the WasmCov WebAssembly coverage generation method used by Wasmcov. In 2023, generating WASM coverage reports using LLVM-COV wasn’t possible for projects using the WebAssembly VM. This document aims to guide projects using the WebAssembly VM in implementing code coverage functionality.
Step 1: Add Coverage Instrumentation To Your WasmCov Binary
Rust
Minicov provides an easy way to add LLVM instrumentation coverage to Rust projects. This will allow you to get the coverage information.
Set the RUSTFLAGS to:
RUSTFLAGS="-Cinstrument-coverage -Zno-profiler-runtime --emit=llvm-ir"
And then compile your project in debug/develop mode (or as release with LTO disabled).
Note: minicov
doesn’t mention --emit=llvm-ir
, but it’s needed later.
Step 2: Parsing Raw Coverage Data
Executing your code will result in one or more .profraw
files. Merge these into a single .profdata
file using LLVM tooling:
llvm-profdata merge -sparse *.profraw -o coverage.profdata
Note: Your llvm-profdata
install must match your Rust version (rustc --version --verbose
). If they differ, install the correct LLVM version and adjust the command accordingly (e.g. llvm-profdata-17
).
Step 3: Generate An Object File
Coverage generation doesn’t work by default because a .wasm
binary doesn’t have a __llvm_covmap
section, required by llvm-cov
to generate the report.
$ llvm-cov-17 show --instr-profile=coverage.profdata our_binary.wasm
error: Failed to load coverage: 'our_binary.wasm': No coverage data found
Rust
To fix this, the IR file our_binary.ll
generated by the --emit=llvm-ir
flag and located in target/wasm32-unknown-unknown/debug/deps
is used.
clang-17 our_binary.ll -Wno-override-module -c
Step 4: Stub WASM Specific Instructions
The above approach won’t work if the project is using instructions only available in WebAssembly, like memory.size
or memory.grow
.
Fortunately, instructions in our_binary.ll
are not needed to generate a coverage report, so you can just remove all of them using a regex.
perl -i -p0e 's/(^define[^\n]*\n).*?^}\s*$/$1start:\n unreachable\n}\n/gms' our_binary.ll
Step 5: Generate The Coverage Report
The report can now be generated using the object file for function mapping instead of the wasm compile.
llvm-cov-17 show --instr-profile=coverage.profdata our_binary.o --format=html -output-dir=coverage/
While this method utilizes some workarounds, it’s functional. A more streamlined approach would involve integrating WASM file support into llvm-cov
. However, this would be more challenging and time-consuming. Thus, this solution is recommended for now.