pkg/coverage¶
LLVM source-based code coverage collection, HTML report generation, and per-file summary statistics.
Types¶
FileCoverage¶
type FileCoverage struct {
Filename string
Lines int
LineHits int
LinePct float64
Funcs int
FuncHits int
FuncPct float64
Branches int
BranchHit int
BranchPct float64
}
Coverage statistics for a single source file, parsed from llvm-cov export --summary-only JSON output.
ReportSummary¶
Aggregate coverage data across all source files. Files is sorted by LinePct ascending (worst-covered files first). The summary deliberately does not retain the temporary profile directory: the CLI removes that directory after reporting, so exposing it would publish a dead path.
Functions¶
CollectAndMerge¶
func CollectAndMerge(
harness, corpusDir, tmpDir string,
timeout time.Duration,
extraEnv []string,
) (string, error)
Recursively replays seed files in corpusDir through the harness binary, collecting raw .profraw files via LLVM_PROFILE_FILE. Hidden directories and non-seed extensions such as dictionaries, logs, scripts, and existing profile data are skipped. Each seed receives a unique profile name derived from its relative path.
timeout is the per-seed deadline (0 means no deadline). extraEnv entries are appended to the child environment, so callers can supply target-specific assets and runtime settings. The function merges all collected profiles into one .profdata with llvm-profdata merge -sparse.
Returns the path to the merged profdata file within tmpDir. The caller is responsible for cleaning up tmpDir.
The harness must be built with -fprofile-instr-generate -fcoverage-mapping and must execute one input then return; a libFuzzer main loop is not a coverage-replay harness.
Returns an error if no profile data is collected from any corpus entry.
GenerateHTML¶
Runs llvm-cov show to produce an HTML coverage report directory. The report includes annotated source files with line-by-line execution counts and region highlighting.
When sourceDir is non-empty, it is passed as -path-equivalence=/,<sourceDir> to remap source paths.
GenerateSummary¶
Runs llvm-cov export --summary-only and parses the JSON result into per-file coverage statistics. Returns a ReportSummary with files sorted by line coverage percentage (worst first).
FormatSummary¶
Returns a human-readable table of per-file coverage stats. Includes columns for file name, lines (total/hit/percent), and functions (total/hit/percent). Long file paths are shortened for display.
Usage¶
tmpDir, _ := os.MkdirTemp("", "crucible-cov-*")
defer os.RemoveAll(tmpDir)
// Collect coverage from corpus replay
profdata, err := coverage.CollectAndMerge(
"./crucible-cov", "./corpus", tmpDir,
30*time.Second, nil,
)
if err != nil {
log.Fatal(err)
}
// Generate HTML report
coverage.GenerateHTML("./crucible-cov", profdata, "/path/to/llama.cpp", "./coverage-report")
// Print per-file summary
summary, _ := coverage.GenerateSummary("./crucible-cov", profdata)
fmt.Println(coverage.FormatSummary(summary))
Prerequisites¶
The harness binary must be built with LLVM coverage instrumentation:
clang -g -O1 -fprofile-instr-generate -fcoverage-mapping \
-DGGML_USE_CPU \
ggml/src/ggml.c ggml/src/gguf.c \
harness/libfuzzer/harness.c \
-o crucible-cov \
-lstdc++ -lm
llvm-profdata and llvm-cov must be available in PATH.