aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pkg/cover/file.go73
-rw-r--r--pkg/covermerger/provider_web.go11
-rw-r--r--tools/syz-cover/syz-cover.go49
3 files changed, 126 insertions, 7 deletions
diff --git a/pkg/cover/file.go b/pkg/cover/file.go
new file mode 100644
index 000000000..3e04e3d2d
--- /dev/null
+++ b/pkg/cover/file.go
@@ -0,0 +1,73 @@
+// Copyright 2024 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package cover
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "cloud.google.com/go/civil"
+ "github.com/google/syzkaller/pkg/covermerger"
+)
+
+type lineRender func(string, bool, int, int) string
+
+func RendFileCoverage(c context.Context, ns, repo, commit, filePath string,
+ fromDate, toDate civil.Date, render lineRender) (string, error) {
+ fileContent, err := covermerger.GetFileVersion(filePath, repo, commit)
+ if err != nil {
+ return "", fmt.Errorf("failed to GetFileVersion for file %s, commit %s from repo %s: %w",
+ filePath, commit, repo, err)
+ }
+ config := &covermerger.Config{
+ Jobs: 1,
+ Base: covermerger.RepoBranchCommit{
+ Repo: repo,
+ Commit: commit,
+ },
+ FileVersProvider: covermerger.MakeWebGit(),
+ }
+
+ dbReader := covermerger.MakeBQCSVReader()
+ if err := dbReader.InitNsRecords(c,
+ ns,
+ filePath,
+ fromDate,
+ toDate,
+ ); err != nil {
+ return "", fmt.Errorf("failed to dbReader.InitNsRecords: %w", err)
+ }
+ defer dbReader.Close()
+ csvReader, err := dbReader.Reader()
+ if err != nil {
+ return "", fmt.Errorf("failed to dbReader.Reader: %w", err)
+ }
+
+ mergeResult, err := covermerger.MergeCSVData(config, csvReader)
+ if err != nil {
+ return "", fmt.Errorf("error merging coverage: %w", err)
+ }
+
+ return rendResult(fileContent, mergeResult[filePath], render), nil
+}
+
+func rendResult(content string, coverage *covermerger.MergeResult, render lineRender) string {
+ srclines := strings.Split(content, "\n")
+ var htmlLines []string
+ for i, srcLine := range srclines {
+ lineNum := i + 1
+ covered, instrumented := coverage.HitCounts[lineNum]
+ htmlLines = append(htmlLines, render(srcLine, instrumented, covered, lineNum))
+ }
+ return strings.Join(htmlLines, "\n")
+}
+
+func RendTextLine(code string, instrumented bool, covered, num int) string {
+ covStr := fmt.Sprintf("%6d", covered)
+ if !instrumented {
+ covStr = strings.Repeat(" ", 6)
+ }
+ return fmt.Sprintf("%s %6d %s", covStr, num, code)
+}
diff --git a/pkg/covermerger/provider_web.go b/pkg/covermerger/provider_web.go
index 72933f280..3347f7931 100644
--- a/pkg/covermerger/provider_web.go
+++ b/pkg/covermerger/provider_web.go
@@ -63,3 +63,14 @@ func loadFile(filePath, repo, commit string) ([]byte, error) {
func MakeWebGit() FileVersProvider {
return &webGit{}
}
+
+func GetFileVersion(filePath, repo, commit string) (string, error) {
+ rbc := RepoBranchCommit{repo, "", commit}
+ files, err := MakeWebGit().GetFileVersions(nil,
+ filePath,
+ []RepoBranchCommit{rbc})
+ if err != nil {
+ return "", fmt.Errorf("failed to GetFileVersions: %w", err)
+ }
+ return files[rbc], nil
+}
diff --git a/tools/syz-cover/syz-cover.go b/tools/syz-cover/syz-cover.go
index 9446dffd8..6832596e5 100644
--- a/tools/syz-cover/syz-cover.go
+++ b/tools/syz-cover/syz-cover.go
@@ -23,8 +23,10 @@ package main
import (
"bufio"
"bytes"
+ "context"
"encoding/json"
"flag"
+ "fmt"
"os"
"os/exec"
"strconv"
@@ -54,18 +56,29 @@ var (
flagDateTo = flag.String("to",
civil.DateOf(time.Now()).String(), "heatmap date to(optional)")
flagProjectID = flag.String("project", "syzkaller", "spanner db project name")
+ flagForFile = flag.String("for-file", "", "[optional]show file coverage")
+ flagRepo = flag.String("repo", "git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git",
+ "[optional] repo to be used by -for-file")
+ flagCommit = flag.String("commit", "", "commit to be used by -for-file")
+ flagNamespace = flag.String("namespace", "upstream", "[optional] used by -for-file")
)
+func parseDates() (civil.Date, civil.Date) {
+ dateFrom, errDateFrom := civil.ParseDate(*flagDateFrom)
+ if errDateFrom != nil {
+ tool.Failf("failed to parse date from: %v", errDateFrom.Error())
+ }
+ dateTo, errDateTo := civil.ParseDate(*flagDateTo)
+ if errDateTo != nil {
+ tool.Failf("failed to parse date to: %v", errDateTo.Error())
+ }
+ return dateFrom, dateTo
+}
+
func toolBuildNsHeatmap() {
buf := new(bytes.Buffer)
- var dateFrom, dateTo civil.Date
+ dateFrom, dateTo := parseDates()
var err error
- if dateFrom, err = civil.ParseDate(*flagDateFrom); err != nil {
- tool.Failf("failed to parse date from: %v", err.Error())
- }
- if dateTo, err = civil.ParseDate(*flagDateTo); err != nil {
- tool.Failf("failed to parse date to: %v", err.Error())
- }
switch *flagNsHeatmapGroupBy {
case "dir":
if err = cover.DoDirHeatMap(buf, *flagProjectID, *flagNsHeatmap, dateFrom, dateTo); err != nil {
@@ -83,8 +96,30 @@ func toolBuildNsHeatmap() {
}
}
+func toolFileCover() {
+ dateFrom, dateTo := parseDates()
+ details, err := cover.RendFileCoverage(
+ context.Background(),
+ *flagNamespace,
+ *flagRepo,
+ *flagCommit,
+ *flagForFile,
+ dateFrom,
+ dateTo,
+ cover.RendTextLine,
+ )
+ if err != nil {
+ tool.Fail(err)
+ }
+ fmt.Println(details)
+}
+
func main() {
defer tool.Init()()
+ if *flagForFile != "" {
+ toolFileCover()
+ return
+ }
if *flagNsHeatmap != "" {
toolBuildNsHeatmap()
return