mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-24 11:59:58 +00:00
syz-dash: add search over reports
- add claimed status for bugs - add search over all reports - some other minor improvements
This commit is contained in:
parent
895e034a4d
commit
a091396fc1
@ -68,6 +68,7 @@ const (
|
||||
BugStatusReported
|
||||
BugStatusFixed
|
||||
BugStatusUnclear
|
||||
BugStatusClaimed
|
||||
BugStatusClosed = 1000 + iota
|
||||
BugStatusDeleted
|
||||
)
|
||||
@ -82,6 +83,8 @@ func statusToString(status int) string {
|
||||
return "fixed"
|
||||
case BugStatusUnclear:
|
||||
return "unclear"
|
||||
case BugStatusClaimed:
|
||||
return "claimed"
|
||||
case BugStatusClosed:
|
||||
return "closed"
|
||||
case BugStatusDeleted:
|
||||
@ -101,6 +104,8 @@ func stringToStatus(status string) (int, error) {
|
||||
return BugStatusFixed, nil
|
||||
case "unclear":
|
||||
return BugStatusUnclear, nil
|
||||
case "claimed":
|
||||
return BugStatusClaimed, nil
|
||||
case "closed":
|
||||
return BugStatusClosed, nil
|
||||
case "deleted":
|
||||
|
@ -7,7 +7,7 @@ handlers:
|
||||
- url: /static
|
||||
static_dir: static
|
||||
secure: always
|
||||
- url: /(|bug|text)
|
||||
- url: /(|bug|search|text)
|
||||
script: _go_app
|
||||
login: required
|
||||
secure: always
|
||||
|
@ -20,6 +20,7 @@
|
||||
{{else}}
|
||||
<td><select name="status">
|
||||
<option value="new" {{if eq .Status "new"}}selected{{end}}>New</option>
|
||||
<option value="claimed" {{if eq .Status "claimed"}}selected{{end}}>Claimed</option>
|
||||
<option value="reported" {{if eq .Status "reported"}}selected{{end}}>Reported</option>
|
||||
<option value="fixed" {{if eq .Status "fixed"}}selected{{end}}>Fixed</option>
|
||||
<option value="unclear" {{if eq .Status "unclear"}}selected{{end}}>Unclear</option>
|
||||
@ -149,27 +150,7 @@ new crashes will produce a new bug"/>
|
||||
<br>
|
||||
{{end}}
|
||||
|
||||
<table class="list_table">
|
||||
<caption>Crashes:</caption>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Manager</th>
|
||||
<th>Time</th>
|
||||
<th>Tag</th>
|
||||
<th>Log</th>
|
||||
<th>Report</th>
|
||||
</tr>
|
||||
{{range $c := $.Crashes}}
|
||||
<tr>
|
||||
<td class="title">{{$c.Title}}</td>
|
||||
<td class="manager">{{$c.Manager}}</td>
|
||||
<td class="time">{{formatTime $c.Time}}</td>
|
||||
<td class="tag">{{$c.Tag}}</td>
|
||||
<td class="log">{{if $c.Log}}<a href="/text?id={{$c.Log}}">log</a>{{end}}</td>
|
||||
<td class="report">{{if $c.Report}}<a href="/text?id={{$c.Report}}">report</a>{{end}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
{{template "crash_list" $.Crashes}}
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,8 +1,42 @@
|
||||
{{define "header"}}
|
||||
<header id="topbar">
|
||||
<h1><a href="/">syzkaller</a></h1>
|
||||
{{.Found}} bugs found, {{.Fixed}} bugs fixed, {{.Crashed}} kernels crashed
|
||||
<table class="position_table">
|
||||
<tr>
|
||||
<td>
|
||||
<h1><a href="/">syzkaller</a></h1>
|
||||
{{.Found}} bugs found, {{.Fixed}} bugs fixed, {{.Crashed}} kernels crashed
|
||||
</td>
|
||||
<td class="search">
|
||||
<form action="/search">
|
||||
<input name="query" type="text" size="30" maxlength="1000" value="{{.Query}}" required/>
|
||||
<input type="submit" value="Search reports" class="button"/>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</header>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{define "crash_list"}}
|
||||
<table class="list_table">
|
||||
<caption>{{if .Title}}<a href="{{.Link}}">{{.Title}}</a>{{else}}Crashes:{{end}}</caption>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Manager</th>
|
||||
<th>Time</th>
|
||||
<th>Tag</th>
|
||||
<th>Log</th>
|
||||
<th>Report</th>
|
||||
</tr>
|
||||
{{range $c := .List}}
|
||||
<tr>
|
||||
<td class="title">{{$c.Title}}</td>
|
||||
<td class="managers" title="{{$c.Manager}}">{{$c.Manager}}</td>
|
||||
<td class="time">{{formatTime $c.Time}}</td>
|
||||
<td class="tag">{{$c.Tag}}</td>
|
||||
<td class="log">{{if $c.Log}}<a href="/text?id={{$c.Log}}">log</a>{{end}}</td>
|
||||
<td class="report">{{if $c.Report}}<a href="/text?id={{$c.Report}}">report</a>{{end}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
{{end}}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{{define "bug_table"}}
|
||||
<table class="list_table">
|
||||
<caption>{{.Name}}:</caption>
|
||||
<caption>{{.Name}} ({{len $.Bugs}}):</caption>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Count</th>
|
||||
@ -10,7 +10,7 @@
|
||||
</tr>
|
||||
{{range $b := $.Bugs}}
|
||||
<tr>
|
||||
<td class="title"><a href="/bug?id={{$b.ID}}">{{$b.Title}}</a></td>
|
||||
<td class="title"><a href="/bug?id={{$b.ID}}" title="{{$b.Comment}}">{{$b.Title}}</a></td>
|
||||
<td class="count">{{$b.NumCrashes}}</td>
|
||||
<td class="repro">{{$b.Repro}}</td>
|
||||
<td class="time">{{formatTime $b.LastTime}}</td>
|
||||
|
@ -6,6 +6,7 @@
|
||||
package dash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
@ -24,6 +25,7 @@ func init() {
|
||||
http.Handle("/", handlerWrapper(handleAuth(handleDash)))
|
||||
http.Handle("/bug", handlerWrapper(handleAuth(handleBug)))
|
||||
http.Handle("/text", handlerWrapper(handleAuth(handleText)))
|
||||
http.Handle("/search", handlerWrapper(handleAuth(handleSearch)))
|
||||
http.Handle("/client", handlerWrapper(handleAuth(handleClient)))
|
||||
}
|
||||
|
||||
@ -88,11 +90,18 @@ func handleDash(c appengine.Context, w http.ResponseWriter, r *http.Request) err
|
||||
data := &dataDash{}
|
||||
bugGroups := map[int]*uiBugGroup{
|
||||
BugStatusNew: &uiBugGroup{Name: "New bugs"},
|
||||
BugStatusClaimed: &uiBugGroup{Name: "Claimed bugs"},
|
||||
BugStatusReported: &uiBugGroup{Name: "Reported bugs"},
|
||||
BugStatusUnclear: &uiBugGroup{Name: "Unclear bugs"},
|
||||
BugStatusFixed: &uiBugGroup{Name: "Fixed bugs"},
|
||||
}
|
||||
data.BugGroups = append(data.BugGroups, bugGroups[BugStatusNew], bugGroups[BugStatusReported], bugGroups[BugStatusUnclear], bugGroups[BugStatusFixed])
|
||||
data.BugGroups = append(data.BugGroups,
|
||||
bugGroups[BugStatusNew],
|
||||
bugGroups[BugStatusClaimed],
|
||||
bugGroups[BugStatusReported],
|
||||
bugGroups[BugStatusUnclear],
|
||||
bugGroups[BugStatusFixed],
|
||||
)
|
||||
|
||||
all := r.FormValue("all") != ""
|
||||
if all {
|
||||
@ -104,7 +113,7 @@ func handleDash(c appengine.Context, w http.ResponseWriter, r *http.Request) err
|
||||
var bugs []*Bug
|
||||
var keys []*ds.Key
|
||||
var err error
|
||||
query := ds.NewQuery("Bug").Project("Title", "Status")
|
||||
query := ds.NewQuery("Bug").Project("Title", "Status", "Comment")
|
||||
if !all {
|
||||
query = query.Filter("Status <", BugStatusClosed)
|
||||
}
|
||||
@ -116,9 +125,10 @@ func handleDash(c appengine.Context, w http.ResponseWriter, r *http.Request) err
|
||||
for i, bug := range bugs {
|
||||
id := keys[i].IntID()
|
||||
ui := &uiBug{
|
||||
ID: id,
|
||||
Title: bug.Title,
|
||||
Status: statusToString(bug.Status),
|
||||
ID: id,
|
||||
Title: bug.Title,
|
||||
Status: statusToString(bug.Status),
|
||||
Comment: bug.Comment,
|
||||
}
|
||||
bugMap[id] = ui
|
||||
managers[id] = make(map[string]bool)
|
||||
@ -211,9 +221,9 @@ func handleBug(c appengine.Context, w http.ResponseWriter, r *http.Request) erro
|
||||
if reportLink == "" {
|
||||
return fmt.Errorf("enter report link")
|
||||
}
|
||||
case BugStatusUnclear:
|
||||
case BugStatusClaimed, BugStatusUnclear:
|
||||
if comment == "" {
|
||||
return fmt.Errorf("enter comment as to why it's unclear")
|
||||
return fmt.Errorf("enter comment as to why it's unclear/who claimed it")
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +238,7 @@ func handleBug(c appengine.Context, w http.ResponseWriter, r *http.Request) erro
|
||||
if status == BugStatusFixed && len(bug.Patches) == 0 {
|
||||
return fmt.Errorf("add a patch for fixed bugs")
|
||||
}
|
||||
flushCached = bug.Status != status
|
||||
flushCached = bug.Status != status || bug.Title != title
|
||||
bug.Title = title
|
||||
bug.Status = status
|
||||
bug.ReportLink = reportLink
|
||||
@ -314,7 +324,7 @@ func handleBug(c appengine.Context, w http.ResponseWriter, r *http.Request) erro
|
||||
dstBug.Version++
|
||||
dstBug.ReportLink = mergeStrings(dstBug.ReportLink, srcBug.ReportLink)
|
||||
dstBug.Comment = mergeStrings(dstBug.Comment, srcBug.Comment)
|
||||
dstBug.CVE = mergeStrings(dstBug.ReportLink, srcBug.CVE)
|
||||
dstBug.CVE = mergeStrings(dstBug.CVE, srcBug.CVE)
|
||||
var groupKeys []*ds.Key
|
||||
var groups []*Group
|
||||
for _, hash := range srcBug.Groups {
|
||||
@ -517,7 +527,7 @@ func handleBug(c appengine.Context, w http.ResponseWriter, r *http.Request) erro
|
||||
return fmt.Errorf("failed to fetch crashes: %v", err)
|
||||
}
|
||||
for _, crash := range crashes {
|
||||
data.Crashes = append(data.Crashes, &uiCrash{
|
||||
data.Crashes.List = append(data.Crashes.List, &uiCrash{
|
||||
Title: group.DisplayTitle(),
|
||||
Manager: crash.Manager,
|
||||
Tag: crash.Tag,
|
||||
@ -545,7 +555,7 @@ func handleBug(c appengine.Context, w http.ResponseWriter, r *http.Request) erro
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(uiCrashArray(data.Crashes))
|
||||
sort.Sort(uiCrashArray(data.Crashes.List))
|
||||
sort.Sort(uiReproArray(data.Repros))
|
||||
|
||||
if len(data.Groups) == 1 {
|
||||
@ -576,10 +586,75 @@ func handleText(c appengine.Context, w http.ResponseWriter, r *http.Request) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleSearch(c appengine.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
cached, err := getCached(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data := &dataSearch{
|
||||
Header: headerFromCached(cached),
|
||||
}
|
||||
data.Header.Query = r.FormValue("query")
|
||||
query := []byte(data.Header.Query)
|
||||
|
||||
bugTitles := make(map[int64]string)
|
||||
for _, b := range cached.Bugs {
|
||||
bugTitles[b.ID] = b.Title
|
||||
}
|
||||
resMap := make(map[int64]*uiCrashGroup)
|
||||
|
||||
var groups []*Group
|
||||
if _, err := ds.NewQuery("Group").GetAll(c, &groups); err != nil {
|
||||
return fmt.Errorf("failed to fetch crash groups: %v", err)
|
||||
}
|
||||
for _, group := range groups {
|
||||
var crashes []*Crash
|
||||
if _, err := ds.NewQuery("Crash").Ancestor(group.Key(c)).GetAll(c, &crashes); err != nil {
|
||||
return fmt.Errorf("failed to fetch crashes: %v", err)
|
||||
}
|
||||
for _, crash := range crashes {
|
||||
if crash.Report == 0 {
|
||||
continue
|
||||
}
|
||||
report, err := getText(c, crash.Report)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Contains(report, query) {
|
||||
continue
|
||||
}
|
||||
cg := resMap[group.Bug]
|
||||
if cg == nil {
|
||||
cg = &uiCrashGroup{
|
||||
Title: bugTitles[group.Bug],
|
||||
Link: fmt.Sprintf("/bug?id=%v", group.Bug),
|
||||
}
|
||||
resMap[group.Bug] = cg
|
||||
}
|
||||
cg.List = append(cg.List, &uiCrash{
|
||||
Title: group.DisplayTitle(),
|
||||
Manager: crash.Manager,
|
||||
Tag: crash.Tag,
|
||||
Time: crash.Time,
|
||||
Log: crash.Log,
|
||||
Report: crash.Report,
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, res := range resMap {
|
||||
sort.Sort(uiCrashArray(res.List))
|
||||
data.Results = append(data.Results, res)
|
||||
}
|
||||
sort.Sort(uiCrashGroupArray(data.Results))
|
||||
|
||||
return templates.ExecuteTemplate(w, "search.html", data)
|
||||
}
|
||||
|
||||
type dataHeader struct {
|
||||
Found int64
|
||||
Fixed int64
|
||||
Crashed int64
|
||||
Query string
|
||||
}
|
||||
|
||||
func headerFromCached(cached *Cached) *dataHeader {
|
||||
@ -590,6 +665,11 @@ func headerFromCached(cached *Cached) *dataHeader {
|
||||
}
|
||||
}
|
||||
|
||||
type dataSearch struct {
|
||||
Header *dataHeader
|
||||
Results []*uiCrashGroup
|
||||
}
|
||||
|
||||
type dataDash struct {
|
||||
Header *dataHeader
|
||||
BugGroups []*uiBugGroup
|
||||
@ -598,12 +678,18 @@ type dataDash struct {
|
||||
type dataBug struct {
|
||||
Header *dataHeader
|
||||
uiBug
|
||||
Crashes []*uiCrash
|
||||
Crashes uiCrashGroup
|
||||
Repros []*uiRepro
|
||||
Message string
|
||||
AllBugs []*uiBug
|
||||
}
|
||||
|
||||
type uiCrashGroup struct {
|
||||
Title string
|
||||
Link string
|
||||
List []*uiCrash
|
||||
}
|
||||
|
||||
type uiBugGroup struct {
|
||||
Name string
|
||||
Bugs []*uiBug
|
||||
@ -694,6 +780,20 @@ func (a uiCrashArray) Swap(i, j int) {
|
||||
a[i], a[j] = a[j], a[i]
|
||||
}
|
||||
|
||||
type uiCrashGroupArray []*uiCrashGroup
|
||||
|
||||
func (a uiCrashGroupArray) Len() int {
|
||||
return len(a)
|
||||
}
|
||||
|
||||
func (a uiCrashGroupArray) Less(i, j int) bool {
|
||||
return a[i].Title < a[j].Title
|
||||
}
|
||||
|
||||
func (a uiCrashGroupArray) Swap(i, j int) {
|
||||
a[i], a[j] = a[j], a[i]
|
||||
}
|
||||
|
||||
type uiReproArray []*uiRepro
|
||||
|
||||
func (a uiReproArray) Len() int {
|
||||
|
@ -14,6 +14,7 @@ indexes:
|
||||
properties:
|
||||
- name: Status
|
||||
- name: Title
|
||||
- name: Comment
|
||||
|
||||
- kind: Crash
|
||||
ancestor: yes
|
||||
|
@ -75,7 +75,7 @@ func buildCached(c appengine.Context) (*Cached, error) {
|
||||
})
|
||||
}
|
||||
switch bug.Status {
|
||||
case BugStatusNew, BugStatusReported, BugStatusUnclear:
|
||||
case BugStatusNew, BugStatusReported, BugStatusUnclear, BugStatusClaimed:
|
||||
cached.Found++
|
||||
case BugStatusFixed, BugStatusClosed:
|
||||
cached.Found++
|
||||
@ -95,7 +95,7 @@ func buildCached(c appengine.Context) (*Cached, error) {
|
||||
return nil, fmt.Errorf("failed to find bug for crash %v (%v)", group.Title, group.Seq)
|
||||
}
|
||||
switch status {
|
||||
case BugStatusNew, BugStatusReported, BugStatusFixed, BugStatusUnclear, BugStatusClosed:
|
||||
case BugStatusNew, BugStatusReported, BugStatusFixed, BugStatusUnclear, BugStatusClaimed, BugStatusClosed:
|
||||
cached.Crashed += group.NumCrashes
|
||||
case BugStatusDeleted:
|
||||
default:
|
||||
|
@ -34,16 +34,7 @@ func parsePatch(text string) (title string, diff string, err error) {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(ln, "Subject: ") {
|
||||
ln = ln[len("Subject: "):]
|
||||
if strings.Contains(strings.ToLower(ln), "[patch") {
|
||||
pos := strings.IndexByte(ln, ']')
|
||||
if pos == -1 {
|
||||
err = fmt.Errorf("subject line does not contain ']'")
|
||||
return
|
||||
}
|
||||
ln = ln[pos+1:]
|
||||
}
|
||||
title = ln
|
||||
title = ln[len("Subject: "):]
|
||||
continue
|
||||
}
|
||||
if ln == "" || title != "" || diffStarted {
|
||||
@ -57,6 +48,14 @@ func parsePatch(text string) (title string, diff string, err error) {
|
||||
if err = s.Err(); err != nil {
|
||||
return
|
||||
}
|
||||
if strings.Contains(strings.ToLower(title), "[patch") {
|
||||
pos := strings.IndexByte(title, ']')
|
||||
if pos == -1 {
|
||||
err = fmt.Errorf("title contains '[patch' but not ']'")
|
||||
return
|
||||
}
|
||||
title = title[pos+1:]
|
||||
}
|
||||
title = strings.TrimSpace(title)
|
||||
if title == "" {
|
||||
err = fmt.Errorf("failed to extract title")
|
||||
|
18
syz-dash/search.html
Normal file
18
syz-dash/search.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Syzkaller Dashboard</title>
|
||||
<link rel="stylesheet" href="/static/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
{{template "header" .Header}}
|
||||
|
||||
{{if .Results}}
|
||||
{{range $r := .Results}}
|
||||
{{template "crash_list" $r}}
|
||||
{{end}}
|
||||
{{else}}
|
||||
<b>No matches found</b>
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
@ -35,6 +35,22 @@ table td, table th {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.position_table {
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.position_table td, .position_table tr {
|
||||
vertical-align: center;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.position_table .search {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.list_table td, .list_table th {
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
@ -62,7 +78,9 @@ table td, table th {
|
||||
|
||||
.list_table .tag {
|
||||
font-family: monospace;
|
||||
font-size: 9pt;
|
||||
font-size: 8pt;
|
||||
width: 200pt;
|
||||
max-width: 200pt;
|
||||
}
|
||||
|
||||
.list_table .opts {
|
||||
|
Loading…
Reference in New Issue
Block a user