aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/cover/html.go
diff options
context:
space:
mode:
authorZubin Mithra <zsm@google.com>2023-03-07 16:21:41 -0800
committerDmitry Vyukov <dvyukov@google.com>2023-03-10 07:45:18 +0100
commit5205ef306e8b4217fc49cb8d8bd18670b7d08c3c (patch)
treeb91b96f1402ae75c5c6a86cff16b40100ef3ce0b /pkg/cover/html.go
parentf08b59ac0d8759f409d594ddca4f08c920e23237 (diff)
tools/syz-cover: allow for exporting source line coverage info
Add a `json` CLI flag that allows for writing out a JSON file with the following coverage information. * Module * Filename * Covered source lines * Uncovered source lines * Both source lines This can be used to view syzkaller coverage information on other source browsing/viewing tools. Usage: $ ./syz-cover -kernel_obj <path/to/vmlinux> -json <output_json> rawcover
Diffstat (limited to 'pkg/cover/html.go')
-rw-r--r--pkg/cover/html.go61
1 files changed, 61 insertions, 0 deletions
diff --git a/pkg/cover/html.go b/pkg/cover/html.go
index c5c18c698..874160c8c 100644
--- a/pkg/cover/html.go
+++ b/pkg/cover/html.go
@@ -7,6 +7,7 @@ import (
"bufio"
"bytes"
"encoding/csv"
+ "encoding/json"
"fmt"
"html"
"html/template"
@@ -118,6 +119,66 @@ func (rg *ReportGenerator) DoHTML(w io.Writer, progs []Prog, coverFilter map[uin
return coverTemplate.Execute(w, d)
}
+type lineCoverExport struct {
+ Module string `json:",omitempty"`
+ Filename string
+ Covered []int `json:",omitempty"`
+ Uncovered []int `json:",omitempty"`
+ Both []int `json:",omitempty"`
+}
+
+func (rg *ReportGenerator) DoLineJSON(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error {
+ progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
+ files, err := rg.prepareFileMap(progs)
+ if err != nil {
+ return err
+ }
+ var entries []lineCoverExport
+ for _, file := range files {
+ lines, err := parseFile(file.filename)
+ if err != nil {
+ // Ignore and continue onto the next file.
+ continue
+ }
+ entries = append(entries, fileLineContents(file, lines))
+ }
+ encoder := json.NewEncoder(w)
+ encoder.SetIndent("", "\t")
+ if err := encoder.Encode(entries); err != nil {
+ return fmt.Errorf("encoding [%v] entries failed: %v", len(entries), err)
+ }
+ return nil
+}
+
+func fileLineContents(file *file, lines [][]byte) lineCoverExport {
+ lce := lineCoverExport{
+ Module: file.module,
+ Filename: file.filename,
+ }
+ lineCover := perLineCoverage(file.covered, file.uncovered)
+ for i, ln := range lines {
+ start := 0
+ cover := append(lineCover[i+1], lineCoverChunk{End: backend.LineEnd})
+ for _, cov := range cover {
+ end := cov.End - 1
+ if end > len(ln) {
+ end = len(ln)
+ }
+ if end == start {
+ continue
+ }
+ if cov.Covered && cov.Uncovered {
+ lce.Both = append(lce.Both, i+1)
+ } else if cov.Covered {
+ lce.Covered = append(lce.Covered, i+1)
+ } else if cov.Uncovered {
+ lce.Uncovered = append(lce.Uncovered, i+1)
+ }
+ }
+ }
+ return lce
+}
+
func (rg *ReportGenerator) DoRawCoverFiles(w http.ResponseWriter, progs []Prog, coverFilter map[uint32]uint32) error {
progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
if err := rg.lazySymbolize(progs); err != nil {