aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2022-03-23 16:16:33 +0000
committerAleksandr Nogikh <wp32pw@gmail.com>2022-03-28 12:03:35 +0200
commitee339263ba6b1a08006ea3e8e1862e15181a640d (patch)
tree29862861fc231b07aded7c6bf45e5cde45711d16
parentcdcc8b96dd9215a47ce5ce1074567a1be93eda5f (diff)
syz-manager: display raw coverage
-rw-r--r--pkg/cover/html.go46
-rw-r--r--pkg/cover/report.go23
-rw-r--r--pkg/cover/report_test.go2
-rw-r--r--syz-manager/cover.go2
-rw-r--r--syz-manager/html.go115
-rw-r--r--tools/syz-cover/syz-cover.go2
6 files changed, 154 insertions, 36 deletions
diff --git a/pkg/cover/html.go b/pkg/cover/html.go
index 4e6e89cef..98572b7f8 100644
--- a/pkg/cover/html.go
+++ b/pkg/cover/html.go
@@ -63,7 +63,8 @@ func (rg *ReportGenerator) DoHTML(w io.Writer, progs []Prog, coverFilter map[uin
return err
}
d := &templateData{
- Root: new(templateDir),
+ Root: new(templateDir),
+ RawCover: rg.rawCoverEnabled,
}
haveProgs := len(progs) > 1 || progs[0].Data != ""
fileOpenErr := fmt.Errorf("failed to open/locate any source file")
@@ -133,7 +134,10 @@ func (rg *ReportGenerator) DoHTML(w io.Writer, progs []Prog, coverFilter map[uin
return fileOpenErr
}
for _, prog := range progs {
- d.Progs = append(d.Progs, template.HTML(html.EscapeString(prog.Data)))
+ d.Progs = append(d.Progs, templateProg{
+ Sig: prog.Sig,
+ Content: template.HTML(html.EscapeString(prog.Data)),
+ })
}
processDir(d.Root)
@@ -163,19 +167,23 @@ func (rg *ReportGenerator) DoRawCoverFiles(w http.ResponseWriter, progs []Prog,
func (rg *ReportGenerator) DoRawCover(w http.ResponseWriter, progs []Prog, coverFilter map[uint32]uint32) {
progs = fixUpPCs(rg.target.Arch, progs, coverFilter)
var pcs []uint64
- uniquePCs := make(map[uint64]bool)
- for _, prog := range progs {
- for _, pc := range prog.PCs {
- if uniquePCs[pc] {
- continue
+ if len(progs) == 1 && rg.rawCoverEnabled {
+ pcs = append([]uint64{}, progs[0].PCs...)
+ } else {
+ uniquePCs := make(map[uint64]bool)
+ for _, prog := range progs {
+ for _, pc := range prog.PCs {
+ if uniquePCs[pc] {
+ continue
+ }
+ uniquePCs[pc] = true
+ pcs = append(pcs, pc)
}
- uniquePCs[pc] = true
- pcs = append(pcs, pc)
}
+ sort.Slice(pcs, func(i, j int) bool {
+ return pcs[i] < pcs[j]
+ })
}
- sort.Slice(pcs, func(i, j int) bool {
- return pcs[i] < pcs[j]
- })
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
buf := bufio.NewWriter(w)
@@ -718,8 +726,14 @@ func parseFile(fn string) ([][]byte, error) {
type templateData struct {
Root *templateDir
Contents []template.HTML
- Progs []template.HTML
+ Progs []templateProg
Functions []template.HTML
+ RawCover bool
+}
+
+type templateProg struct {
+ Sig string
+ Content template.HTML
}
type templateBase struct {
@@ -852,8 +866,12 @@ var coverTemplate = template.Must(template.New("").Parse(`
{{range $i, $f := .Contents}}
<pre class="file" id="contents_{{$i}}">{{$f}}</pre>
{{end}}
+ {{$base := .}}
{{range $i, $p := .Progs}}
- <pre class="file" id="prog_{{$i}}">{{$p}}</pre>
+ <pre class="file" id="prog_{{$i}}">
+{{if $base.RawCover}}<a href="/debuginput?sig={{$p.Sig}}">[raw coverage]</a><br />{{end}}
+{{$p.Content}}
+</pre>
{{end}}
{{range $i, $p := .Functions}}
<div class="function list" id="function_{{$i}}">{{$p}}</div>
diff --git a/pkg/cover/report.go b/pkg/cover/report.go
index 788603119..3423d9b09 100644
--- a/pkg/cover/report.go
+++ b/pkg/cover/report.go
@@ -14,14 +14,16 @@ import (
)
type ReportGenerator struct {
- target *targets.Target
- srcDir string
- buildDir string
- subsystem []mgrconfig.Subsystem
+ target *targets.Target
+ srcDir string
+ buildDir string
+ subsystem []mgrconfig.Subsystem
+ rawCoverEnabled bool
*backend.Impl
}
type Prog struct {
+ Sig string
Data string
PCs []uint64
}
@@ -29,7 +31,7 @@ type Prog struct {
var RestorePC = backend.RestorePC
func MakeReportGenerator(target *targets.Target, vm, objDir, srcDir, buildDir string, subsystem []mgrconfig.Subsystem,
- moduleObj []string, modules []host.KernelModule) (*ReportGenerator, error) {
+ moduleObj []string, modules []host.KernelModule, rawCover bool) (*ReportGenerator, error) {
impl, err := backend.Make(target, vm, objDir, srcDir, buildDir, moduleObj, modules)
if err != nil {
return nil, err
@@ -39,11 +41,12 @@ func MakeReportGenerator(target *targets.Target, vm, objDir, srcDir, buildDir st
Paths: []string{""},
})
rg := &ReportGenerator{
- target: target,
- srcDir: srcDir,
- buildDir: buildDir,
- subsystem: subsystem,
- Impl: impl,
+ target: target,
+ srcDir: srcDir,
+ buildDir: buildDir,
+ subsystem: subsystem,
+ rawCoverEnabled: rawCover,
+ Impl: impl,
}
return rg, nil
}
diff --git a/pkg/cover/report_test.go b/pkg/cover/report_test.go
index a08fe9d1c..0f44c6e80 100644
--- a/pkg/cover/report_test.go
+++ b/pkg/cover/report_test.go
@@ -260,7 +260,7 @@ func generateReport(t *testing.T, target *targets.Target, test Test) ([]byte, []
},
}
- rg, err := MakeReportGenerator(target, "", dir, dir, dir, subsystem, nil, nil)
+ rg, err := MakeReportGenerator(target, "", dir, dir, dir, subsystem, nil, nil, false)
if err != nil {
return nil, nil, err
}
diff --git a/syz-manager/cover.go b/syz-manager/cover.go
index 8ddee085f..bc8d48e10 100644
--- a/syz-manager/cover.go
+++ b/syz-manager/cover.go
@@ -21,7 +21,7 @@ var getReportGenerator = func() func(cfg *mgrconfig.Config,
once.Do(func() {
log.Logf(0, "initializing coverage information...")
rg, err = cover.MakeReportGenerator(cfg.SysTarget, cfg.Type, cfg.KernelObj, cfg.KernelSrc,
- cfg.KernelBuildSrc, cfg.KernelSubsystem, cfg.ModuleObj, modules)
+ cfg.KernelBuildSrc, cfg.KernelSubsystem, cfg.ModuleObj, modules, cfg.RawCover)
})
return rg, err
}
diff --git a/syz-manager/html.go b/syz-manager/html.go
index dc3e54519..781ba3279 100644
--- a/syz-manager/html.go
+++ b/syz-manager/html.go
@@ -54,6 +54,7 @@ func (mgr *Manager) initHTTP() {
mux.HandleFunc("/funccover", mgr.httpFuncCover)
mux.HandleFunc("/filecover", mgr.httpFileCover)
mux.HandleFunc("/input", mgr.httpInput)
+ mux.HandleFunc("/debuginput", mgr.httpDebugInput)
// Browsers like to request this, without special handler this goes to / handler.
mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {})
@@ -197,7 +198,8 @@ func (mgr *Manager) httpCorpus(w http.ResponseWriter, r *http.Request) {
defer mgr.mu.Unlock()
data := UICorpus{
- Call: r.FormValue("call"),
+ Call: r.FormValue("call"),
+ RawCover: mgr.cfg.RawCover,
}
for sig, inp := range mgr.corpus {
if data.Call != "" && data.Call != inp.Call {
@@ -293,17 +295,31 @@ func (mgr *Manager) httpCoverCover(w http.ResponseWriter, r *http.Request, funcF
var progs []cover.Prog
if sig := r.FormValue("input"); sig != "" {
inp := mgr.corpus[sig]
- progs = append(progs, cover.Prog{
- Data: string(inp.Prog),
- PCs: coverToPCs(rg, inp.Cover),
- })
+ if r.FormValue("update_id") != "" {
+ updateID, err := strconv.Atoi(r.FormValue("update_id"))
+ if err != nil || updateID < 0 || updateID >= len(inp.Updates) {
+ http.Error(w, "bad call_id", http.StatusBadRequest)
+ }
+ progs = append(progs, cover.Prog{
+ Sig: sig,
+ Data: string(inp.Prog),
+ PCs: coverToPCs(rg, inp.Updates[updateID].RawCover),
+ })
+ } else {
+ progs = append(progs, cover.Prog{
+ Sig: sig,
+ Data: string(inp.Prog),
+ PCs: coverToPCs(rg, inp.Cover),
+ })
+ }
} else {
call := r.FormValue("call")
- for _, inp := range mgr.corpus {
+ for sig, inp := range mgr.corpus {
if call != "" && call != inp.Call {
continue
}
progs = append(progs, cover.Prog{
+ Sig: sig,
Data: string(inp.Prog),
PCs: coverToPCs(rg, inp.Cover),
})
@@ -451,6 +467,46 @@ func (mgr *Manager) httpInput(w http.ResponseWriter, r *http.Request) {
w.Write(inp.Prog)
}
+func (mgr *Manager) httpDebugInput(w http.ResponseWriter, r *http.Request) {
+ mgr.mu.Lock()
+ defer mgr.mu.Unlock()
+ inp, ok := mgr.corpus[r.FormValue("sig")]
+ if !ok {
+ http.Error(w, "can't find the input", http.StatusInternalServerError)
+ return
+ }
+ getIDs := func(callID int) []int {
+ ret := []int{}
+ for id, update := range inp.Updates {
+ if update.CallID == callID {
+ ret = append(ret, id)
+ }
+ }
+ return ret
+ }
+ data := []UIRawCallCover{}
+ for pos, line := range strings.Split(string(inp.Prog), "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" {
+ continue
+ }
+ data = append(data, UIRawCallCover{
+ Sig: r.FormValue("sig"),
+ Call: line,
+ UpdateIDs: getIDs(pos),
+ })
+ }
+ extraIDs := getIDs(-1)
+ if len(extraIDs) > 0 {
+ data = append(data, UIRawCallCover{
+ Sig: r.FormValue("sig"),
+ Call: ".extra",
+ UpdateIDs: extraIDs,
+ })
+ }
+ executeTemplate(w, rawCoverTemplate, data)
+}
+
func (mgr *Manager) httpReport(w http.ResponseWriter, r *http.Request) {
mgr.mu.Lock()
defer mgr.mu.Unlock()
@@ -683,8 +739,9 @@ type UICallType struct {
}
type UICorpus struct {
- Call string
- Inputs []*UIInput
+ Call string
+ RawCover bool
+ Inputs []*UIInput
}
type UIInput struct {
@@ -839,7 +896,12 @@ var corpusTemplate = html.CreatePage(`
</tr>
{{range $inp := $.Inputs}}
<tr>
- <td><a href='/cover?input={{$inp.Sig}}'>{{$inp.Cover}}</a></td>
+ <td>
+ <a href='/cover?input={{$inp.Sig}}'>{{$inp.Cover}}</a>
+ {{if $.RawCover}}
+ / <a href="/debuginput?sig={{$inp.Sig}}">[raw]</a>
+ {{end}}
+ </td>
<td><a href="/input?sig={{$inp.Sig}}">{{$inp.Short}}</a></td>
</tr>
{{end}}
@@ -915,3 +977,38 @@ var fallbackCoverTemplate = html.CreatePage(`
</table>
</body></html>
`)
+
+type UIRawCallCover struct {
+ Sig string
+ Call string
+ UpdateIDs []int
+}
+
+var rawCoverTemplate = html.CreatePage(`
+<!doctype html>
+<html>
+<head>
+ <title>syzkaller raw cover</title>
+ {{HEAD}}
+</head>
+<body>
+
+<table class="list_table">
+ <caption>Raw cover</caption>
+ <tr>
+ <th>Line</th>
+ <th>Links</th>
+ </tr>
+ {{range $line := .}}
+ <tr>
+ <td>{{$line.Call}}</td>
+ <td>
+ {{range $id := $line.UpdateIDs}}
+ <a href="/rawcover?input={{$line.Sig}}&update_id={{$id}}">[{{$id}}]</a>
+ {{end}}
+</td>
+ </tr>
+ {{end}}
+</table>
+</body></html>
+`)
diff --git a/tools/syz-cover/syz-cover.go b/tools/syz-cover/syz-cover.go
index 42e592bd9..5aa183ae1 100644
--- a/tools/syz-cover/syz-cover.go
+++ b/tools/syz-cover/syz-cover.go
@@ -68,7 +68,7 @@ func main() {
tool.Fail(err)
}
rg, err := cover.MakeReportGenerator(target, *flagVM, *flagKernelObj,
- *flagKernelSrc, *flagKernelBuildSrc, nil, nil, nil)
+ *flagKernelSrc, *flagKernelBuildSrc, nil, nil, nil, false)
if err != nil {
tool.Fail(err)
}