aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/cover/cover.go5
-rw-r--r--pkg/cover/html.go219
-rw-r--r--pkg/cover/report.go27
-rw-r--r--pkg/cover/report_test.go22
-rw-r--r--pkg/kconfig/cause.config3
-rw-r--r--pkg/mgrconfig/config.go11
6 files changed, 275 insertions, 12 deletions
diff --git a/pkg/cover/cover.go b/pkg/cover/cover.go
index 814ae4fb6..572d5e5da 100644
--- a/pkg/cover/cover.go
+++ b/pkg/cover/cover.go
@@ -6,6 +6,11 @@ package cover
type Cover map[uint32]struct{}
+type Subsystem struct {
+ Name string `json:"name"`
+ Paths []string `json:"path"`
+}
+
func (cov *Cover) Merge(raw []uint32) {
c := *cov
if c == nil {
diff --git a/pkg/cover/html.go b/pkg/cover/html.go
index b353029a3..1757964b5 100644
--- a/pkg/cover/html.go
+++ b/pkg/cover/html.go
@@ -103,6 +103,165 @@ func (rg *ReportGenerator) DoHTML(w io.Writer, progs []Prog) error {
return coverTemplate.Execute(w, d)
}
+type fileStats struct {
+ Name string
+ CoveredLines int
+ TotalLines int
+ CoveredPCs int
+ TotalPCs int
+ TotalFunctions int
+ CoveredPCsInFunctions int
+ TotalPCsInFunctions int
+}
+
+var csvFilesHeader = []string{
+ "Filename",
+ "CoveredLines",
+ "TotalLines",
+ "CoveredPCs",
+ "TotalPCs",
+ "TotalFunctions",
+ "CoveredPCsInFunctions",
+ "TotalPCsInFunctions",
+}
+
+func (rg *ReportGenerator) convertToStats(progs []Prog) ([]fileStats, error) {
+ files, err := rg.prepareFileMap(progs)
+ if err != nil {
+ return nil, err
+ }
+
+ var data []fileStats
+ for fname, file := range files {
+ lines, err := parseFile(file.filename)
+ if err != nil {
+ fmt.Printf("failed to open/locate %s\n", file.filename)
+ continue
+ }
+ totalFuncs := len(file.functions)
+ var coveredInFunc int
+ var pcsInFunc int
+ for _, function := range file.functions {
+ coveredInFunc += function.covered
+ pcsInFunc += function.pcs
+ }
+ totalLines := len(lines)
+ var coveredLines int
+ for _, line := range file.lines {
+ if len(line.progCount) != 0 {
+ coveredLines++
+ }
+ }
+ data = append(data, fileStats{
+ Name: fname,
+ CoveredLines: coveredLines,
+ TotalLines: totalLines,
+ CoveredPCs: file.coveredPCs,
+ TotalPCs: file.totalPCs,
+ TotalFunctions: totalFuncs,
+ CoveredPCsInFunctions: coveredInFunc,
+ TotalPCsInFunctions: pcsInFunc,
+ })
+ }
+
+ return data, nil
+}
+
+func (rg *ReportGenerator) DoCSVFiles(w io.Writer, progs []Prog) error {
+ data, err := rg.convertToStats(progs)
+ if err != nil {
+ return err
+ }
+
+ sort.SliceStable(data, func(i, j int) bool {
+ return data[i].Name < data[j].Name
+ })
+
+ writer := csv.NewWriter(w)
+ defer writer.Flush()
+ if err := writer.Write(csvFilesHeader); err != nil {
+ return err
+ }
+
+ var d [][]string
+ for _, dt := range data {
+ d = append(d, []string{
+ dt.Name,
+ strconv.Itoa(dt.CoveredLines),
+ strconv.Itoa(dt.TotalLines),
+ strconv.Itoa(dt.CoveredPCs),
+ strconv.Itoa(dt.TotalPCs),
+ strconv.Itoa(dt.TotalFunctions),
+ strconv.Itoa(dt.CoveredPCsInFunctions),
+ strconv.Itoa(dt.TotalPCsInFunctions),
+ })
+ }
+ return writer.WriteAll(d)
+}
+
+func groupCoverByFilePrefixes(datas []fileStats, subsystems []Subsystem) map[string]map[string]string {
+ d := make(map[string]map[string]string)
+
+ for _, subsystem := range subsystems {
+ var coveredLines int
+ var totalLines int
+ var coveredPCsInFile int
+ var totalPCsInFile int
+ var totalFuncs int
+ var coveredPCsInFuncs int
+ var pcsInFuncs int
+ var percentLines float64
+ var percentPCsInFile float64
+ var percentPCsInFunc float64
+
+ for _, path := range subsystem.Paths {
+ for _, data := range datas {
+ if !strings.HasPrefix(data.Name, path) {
+ continue
+ }
+ coveredLines += data.CoveredLines
+ totalLines += data.TotalLines
+ coveredPCsInFile += data.CoveredPCs
+ totalPCsInFile += data.TotalPCs
+ totalFuncs += data.TotalFunctions
+ coveredPCsInFuncs += data.CoveredPCsInFunctions
+ pcsInFuncs += data.TotalPCsInFunctions
+ }
+ }
+
+ if totalLines != 0 {
+ percentLines = 100.0 * float64(coveredLines) / float64(totalLines)
+ }
+ if totalPCsInFile != 0 {
+ percentPCsInFile = 100.0 * float64(coveredPCsInFile) / float64(totalPCsInFile)
+ }
+ if pcsInFuncs != 0 {
+ percentPCsInFunc = 100.0 * float64(coveredPCsInFuncs) / float64(pcsInFuncs)
+ }
+
+ d[subsystem.Name] = map[string]string{
+ "subsystem": subsystem.Name,
+ "lines": fmt.Sprintf("%v / %v / %.2f%%", coveredLines, totalLines, percentLines),
+ "PCsInFiles": fmt.Sprintf("%v / %v / %.2f%%", coveredPCsInFile, totalPCsInFile, percentPCsInFile),
+ "totalFuncs": strconv.Itoa(totalFuncs),
+ "PCsInFuncs": fmt.Sprintf("%v / %v / %.2f%%", coveredPCsInFuncs, pcsInFuncs, percentPCsInFunc),
+ }
+ }
+
+ return d
+}
+
+func (rg *ReportGenerator) DoHTMLTable(w io.Writer, progs []Prog) error {
+ data, err := rg.convertToStats(progs)
+ if err != nil {
+ return err
+ }
+
+ d := groupCoverByFilePrefixes(data, rg.subsystem)
+
+ return coverTableTemplate.Execute(w, d)
+}
+
var csvHeader = []string{
"Filename",
"Function",
@@ -557,3 +716,63 @@ var coverTemplate = template.Must(template.New("").Parse(`
{{end}}
{{end}}
`))
+
+var coverTableTemplate = template.Must(template.New("coverTable").Parse(`
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <style>
+ body {
+ background: white;
+ }
+ #content {
+ color: rgb(70, 70, 70);
+ margin-top: 50px;
+ }
+ th, td {
+ text-align: left;
+ border: 1px solid black;
+ }
+ th {
+ background: gray;
+ }
+ tr:nth-child(2n+1) {
+ background: #CCC
+ }
+ table {
+ border-collapse: collapse;
+ border: 1px solid black;
+ margin-bottom: 20px;
+ }
+ </style>
+ </head>
+ <body>
+ <div>
+ <table>
+ <thead>
+ <tr>
+ <th>Subsystem</th>
+ <th>Covered / Total Lines / %</th>
+ <th>Covered / Total PCs in File / %</th>
+ <th>Covered / Total PCs in Function / %</th>
+ <th>Covered Functions</th>
+ </tr>
+ </thead>
+ <tbody id="content">
+ {{range $i, $p := .}}
+ <tr>
+ <td>{{$p.subsystem}}</td>
+ <td>{{$p.lines}}</td>
+ <td>{{$p.PCsInFiles}}</td>
+ <td>{{$p.PCsInFuncs}}</td>
+ <td>{{$p.totalFuncs}}</td>
+ </tr>
+ {{end}}
+ </tbody>
+ </table>
+ </div>
+ </body>
+</html>
+
+`))
diff --git a/pkg/cover/report.go b/pkg/cover/report.go
index f4e88954e..d8f2115e3 100644
--- a/pkg/cover/report.go
+++ b/pkg/cover/report.go
@@ -12,10 +12,11 @@ import (
)
type ReportGenerator struct {
- target *targets.Target
- srcDir string
- objDir string
- buildDir string
+ target *targets.Target
+ srcDir string
+ objDir string
+ buildDir string
+ subsystem []Subsystem
*backend.Impl
}
@@ -26,17 +27,23 @@ type Prog struct {
var RestorePC = backend.RestorePC
-func MakeReportGenerator(target *targets.Target, vm, objDir, srcDir, buildDir string) (*ReportGenerator, error) {
+func MakeReportGenerator(target *targets.Target, vm, objDir, srcDir, buildDir string,
+ subsystem []Subsystem) (*ReportGenerator, error) {
impl, err := backend.Make(target, vm, objDir, srcDir, buildDir)
if err != nil {
return nil, err
}
+ subsystem = append(subsystem, Subsystem{
+ Name: "all",
+ Paths: []string{""},
+ })
rg := &ReportGenerator{
- target: target,
- srcDir: srcDir,
- objDir: objDir,
- buildDir: buildDir,
- Impl: impl,
+ target: target,
+ srcDir: srcDir,
+ objDir: objDir,
+ buildDir: buildDir,
+ subsystem: subsystem,
+ Impl: impl,
}
return rg, nil
}
diff --git a/pkg/cover/report_test.go b/pkg/cover/report_test.go
index 63f1ff50a..0707eab64 100644
--- a/pkg/cover/report_test.go
+++ b/pkg/cover/report_test.go
@@ -180,7 +180,17 @@ func generateReport(t *testing.T, target *targets.Target, test Test) ([]byte, []
}
defer os.RemoveAll(dir)
bin := buildTestBinary(t, target, test, dir)
- rg, err := MakeReportGenerator(target, "", dir, dir, dir)
+ subsystem := []Subsystem{
+ {
+ Name: "sound",
+ Paths: []string{
+ "sound",
+ "techpack/audio",
+ },
+ },
+ }
+
+ rg, err := MakeReportGenerator(target, "", dir, dir, dir, subsystem)
if err != nil {
return nil, nil, err
}
@@ -216,10 +226,20 @@ func generateReport(t *testing.T, target *targets.Target, test Test) ([]byte, []
if err := rg.DoHTML(html, test.Progs); err != nil {
return nil, nil, err
}
+ htmlTable := new(bytes.Buffer)
+ if err := rg.DoHTMLTable(htmlTable, test.Progs); err != nil {
+ return nil, nil, err
+ }
+ _ = htmlTable
csv := new(bytes.Buffer)
if err := rg.DoCSV(csv, test.Progs); err != nil {
return nil, nil, err
}
+ csvFiles := new(bytes.Buffer)
+ if err := rg.DoCSVFiles(csvFiles, test.Progs); err != nil {
+ return nil, nil, err
+ }
+ _ = csvFiles
return html.Bytes(), csv.Bytes(), nil
}
diff --git a/pkg/kconfig/cause.config b/pkg/kconfig/cause.config
new file mode 100644
index 000000000..977642377
--- /dev/null
+++ b/pkg/kconfig/cause.config
@@ -0,0 +1,3 @@
+CONFIG_AX25=y
+CONFIG_HAMRADIO=y
+CONFIG_ROSE=y
diff --git a/pkg/mgrconfig/config.go b/pkg/mgrconfig/config.go
index a7476ac8e..e18607e7f 100644
--- a/pkg/mgrconfig/config.go
+++ b/pkg/mgrconfig/config.go
@@ -3,7 +3,10 @@
package mgrconfig
-import "encoding/json"
+import (
+ "encoding/json"
+ "github.com/google/syzkaller/pkg/cover"
+)
type Config struct {
// Instance name (used for identification and as GCE instance prefix).
@@ -41,6 +44,12 @@ type Config struct {
KernelSrc string `json:"kernel_src,omitempty"`
// Location of the driectory where the kernel was built (if not set defaults to KernelSrc)
KernelBuildSrc string `json:"kernel_build_src"`
+ // Kernel subsystem with paths to each subsystem
+ // "kernel_subsystem": [
+ // { "name": "sound", "path": ["sound", "techpack/audio"]},
+ // { "name": "mydriver": "path": ["mydriver_path"]}
+ // ]
+ KernelSubsystem []cover.Subsystem `json:"kernel_subsystem,omitempty"`
// Arbitrary optional tag that is saved along with crash reports (e.g. branch/commit).
Tag string `json:"tag,omitempty"`
// Location of the disk image file.