| // Copyright 2018 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 report |
| |
| import ( |
| "bytes" |
| "regexp" |
| ) |
| |
| type gvisor struct { |
| ignores []*regexp.Regexp |
| } |
| |
| func ctorGvisor(kernelSrc, kernelObj string, ignores []*regexp.Regexp) (Reporter, []string, error) { |
| ctx := &gvisor{ |
| ignores: ignores, |
| } |
| suppressions := []string{ |
| "fatal error: runtime: out of memory", |
| "fatal error: runtime: cannot allocate memory", |
| "panic: ptrace sysemu failed: no such process", // OOM kill |
| "panic: ptrace set fpregs failed: no such process", // OOM kill |
| "panic: ptrace set regs failed: no such process", // OOM kill |
| "panic: failed to start executor binary", |
| "panic: executor failed: pthread_create failed", |
| "ERROR: ThreadSanitizer", // Go race failing due to OOM. |
| "FATAL: ThreadSanitizer", |
| } |
| return ctx, suppressions, nil |
| } |
| |
| func (ctx *gvisor) ContainsCrash(output []byte) bool { |
| return containsCrash(output, gvisorOopses, ctx.ignores) |
| } |
| |
| func (ctx *gvisor) Parse(output []byte) *Report { |
| rep := simpleLineParser(output, gvisorOopses, nil, ctx.ignores) |
| if rep == nil { |
| return nil |
| } |
| rep.Title = replaceTable(gvisorTitleReplacement, rep.Title) |
| rep.Report = ctx.shortenReport(rep.Report) |
| return rep |
| } |
| |
| func (ctx *gvisor) shortenReport(report []byte) []byte { |
| // gvisor panics include stacks of all goroutines. |
| // This output is too lengthy for report and not very useful. |
| // So we always take 5 lines from report and then cut it at the next empty line. |
| // The intention is to capture panic header and traceback of the first goroutine. |
| pos := 0 |
| for i := 0; i < 5; i++ { |
| pos1 := bytes.IndexByte(report[pos:], '\n') |
| if pos1 == -1 { |
| return report |
| } |
| pos += pos1 + 1 |
| } |
| end := bytes.Index(report[pos:], []byte{'\n', '\n'}) |
| if end == -1 { |
| return report |
| } |
| if bytes.Contains(report, []byte("WARNING: DATA RACE")) { |
| // For data races extract both stacks. |
| end2 := bytes.Index(report[pos+end+2:], []byte{'\n', '\n'}) |
| if end2 != -1 { |
| end += end2 + 2 |
| } |
| } |
| return report[:pos+end+1] |
| } |
| |
| func (ctx *gvisor) Symbolize(rep *Report) error { |
| return nil |
| } |
| |
| var gvisorTitleReplacement = []replacement{ |
| { |
| regexp.MustCompile(`container ".*"`), |
| "container NAME", |
| }, |
| } |
| |
| var gvisorOopses = []*oops{ |
| { |
| []byte("panic:"), |
| []oopsFormat{ |
| { |
| title: compile("panic:(.*)"), |
| fmt: "panic:%[1]v", |
| noStackTrace: true, |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("Panic:"), |
| []oopsFormat{ |
| { |
| title: compile("Panic:(.*)"), |
| fmt: "Panic:%[1]v", |
| noStackTrace: true, |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("fatal error:"), |
| []oopsFormat{ |
| { |
| title: compile("fatal error:(.*)"), |
| fmt: "fatal error:%[1]v", |
| noStackTrace: true, |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("runtime error:"), |
| []oopsFormat{ |
| { |
| title: compile("runtime error:(.*)"), |
| fmt: "runtime error:%[1]v", |
| noStackTrace: true, |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("SIGSEGV:"), |
| []oopsFormat{ |
| { |
| title: compile("SIGSEGV:(.*)"), |
| fmt: "SIGSEGV:%[1]v", |
| noStackTrace: true, |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("SIGBUS:"), |
| []oopsFormat{ |
| { |
| title: compile("SIGBUS:(.*)"), |
| fmt: "SIGBUS:%[1]v", |
| noStackTrace: true, |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("FATAL ERROR:"), |
| []oopsFormat{ |
| { |
| title: compile("FATAL ERROR:(.*)"), |
| fmt: "FATAL ERROR:%[1]v", |
| noStackTrace: true, |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("WARNING: DATA RACE"), |
| []oopsFormat{ |
| { |
| title: compile("WARNING: DATA RACE"), |
| report: compile("WARNING: DATA RACE\n(?:.*\n)*? (?:[a-zA-Z0-9./-_]+/)([a-zA-Z0-9.()*_]+)\\(\\)\n"), |
| fmt: "DATA RACE in %[1]v", |
| noStackTrace: true, |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("Invalid request partialResult"), |
| []oopsFormat{ |
| { |
| title: compile("Invalid request partialResult"), |
| report: compile("Invalid request partialResult .* for (.*) operation"), |
| fmt: "Invalid request partialResult in %[1]v", |
| noStackTrace: true, |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| } |