| #!/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() |