blob: 07756b0cc7f98b748b97a0c6e6a248994f2f25f0 [file] [log] [blame]
Matt Johnstonabe9b372024-11-11 17:17:44 +08001#!/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()