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