#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later # usage: fuzz-coverage.py [-h] corpus program srcdir builddir outdir # Runs corpus (directory of testcases) against a program # built with coverage, and produces a html report. # The program should be built with --coverage -fprofile-abs-path # -O0 may make the html report more legible? # Requires lcov and https://github.com/mozilla/grcov import argparse import subprocess import sys from pathlib import Path def run(args): corpus = Path(args.corpus) outdir = Path(args.outdir) for c in Path(args.builddir).glob("**/*.gcda"): print(f"Removed old coverage {c}", file=sys.stderr) c.unlink() print("Running corpus", file=sys.stderr) for c in corpus.glob("*"): c = c.open("rb").read() subprocess.run([args.program], input=c) print("Running grcov", file=sys.stderr) outdir.mkdir(parents=True, exist_ok=True) coverage_paths = [args.builddir] lcov_file = outdir / "lcov.info" subprocess.run( [ "grcov", "-b", args.program, "-o", lcov_file, "-t", "lcov", "-s", args.srcdir, ] + coverage_paths, check=True, ) print("Running genhtml", file=sys.stderr) subprocess.run( [ "genhtml", "-o", outdir, "--show-details", "--highlight", "--ignore-errors", "source", "--legend", lcov_file, ], check=True, ) html = outdir / "index.html" print(f"\n\nOutput is file://{html.absolute()}", file=sys.stderr) def main(): parser = argparse.ArgumentParser() parser.add_argument("corpus", type=str, help="Corpus directory") parser.add_argument("program", type=str, help="Target Program") parser.add_argument("srcdir", type=str, help="Source directory") parser.add_argument("builddir", type=str) parser.add_argument("outdir", type=str) args = parser.parse_args() run(args) if __name__ == "__main__": main()