xref: /openbmc/libpldm/tests/fuzz/fuzz-coverage.py (revision abe9b37f49a1ccda64a728e79858d9eae2d2edd3)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
3
4# usage: fuzz-coverage.py [-h] corpus program srcdir builddir outdir
5
6# Runs corpus (directory of testcases) against a program
7# built with coverage, and produces a html report.
8
9# The program should be built with --coverage -fprofile-abs-path
10# -O0 may make the html report more legible?
11
12# Requires lcov and https://github.com/mozilla/grcov
13
14import argparse
15import subprocess
16import sys
17from pathlib import Path
18
19
20def run(args):
21    corpus = Path(args.corpus)
22    outdir = Path(args.outdir)
23
24    for c in Path(args.builddir).glob("**/*.gcda"):
25        print(f"Removed old coverage {c}", file=sys.stderr)
26        c.unlink()
27
28    print("Running corpus", file=sys.stderr)
29    for c in corpus.glob("*"):
30        c = c.open("rb").read()
31        subprocess.run([args.program], input=c)
32
33    print("Running grcov", file=sys.stderr)
34    outdir.mkdir(parents=True, exist_ok=True)
35    coverage_paths = [args.builddir]
36    lcov_file = outdir / "lcov.info"
37
38    subprocess.run(
39        [
40            "grcov",
41            "-b",
42            args.program,
43            "-o",
44            lcov_file,
45            "-t",
46            "lcov",
47            "-s",
48            args.srcdir,
49        ]
50        + coverage_paths,
51        check=True,
52    )
53
54    print("Running genhtml", file=sys.stderr)
55    subprocess.run(
56        [
57            "genhtml",
58            "-o",
59            outdir,
60            "--show-details",
61            "--highlight",
62            "--ignore-errors",
63            "source",
64            "--legend",
65            lcov_file,
66        ],
67        check=True,
68    )
69
70    html = outdir / "index.html"
71    print(f"\n\nOutput is file://{html.absolute()}", file=sys.stderr)
72
73
74def main():
75    parser = argparse.ArgumentParser()
76    parser.add_argument("corpus", type=str, help="Corpus directory")
77    parser.add_argument("program", type=str, help="Target Program")
78    parser.add_argument("srcdir", type=str, help="Source directory")
79    parser.add_argument("builddir", type=str)
80    parser.add_argument("outdir", type=str)
81    args = parser.parse_args()
82
83    run(args)
84
85
86if __name__ == "__main__":
87    main()
88