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