// 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 ( "bufio" "bytes" "fmt" "path/filepath" "regexp" "strconv" "strings" "github.com/google/syzkaller/pkg/symbolizer" ) type akaros struct { ignores []*regexp.Regexp objfile string } func ctorAkaros(kernelSrc, kernelObj string, ignores []*regexp.Regexp) (Reporter, []string, error) { ctx := &akaros{ ignores: ignores, objfile: filepath.Join(kernelObj, "akaros-kernel-64b"), } return ctx, nil, nil } func (ctx *akaros) ContainsCrash(output []byte) bool { return containsCrash(output, akarosOopses, ctx.ignores) } func (ctx *akaros) Parse(output []byte) *Report { rep := simpleLineParser(output, akarosOopses, akarosStackParams, ctx.ignores) if rep == nil { return nil } rep.Report = ctx.minimizeReport(rep.Report) return rep } func (ctx *akaros) Symbolize(rep *Report) error { symb := symbolizer.NewSymbolizer() defer symb.Close() var symbolized []byte s := bufio.NewScanner(bytes.NewReader(rep.Report)) for s.Scan() { line := bytes.Trim(s.Bytes(), "\r") line = ctx.symbolizeLine(symb.Symbolize, ctx.objfile, line) symbolized = append(symbolized, line...) symbolized = append(symbolized, '\n') } rep.Report = symbolized return nil } func (ctx *akaros) symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error), objfile string, line []byte) []byte { match := akarosSymbolizeRe.FindSubmatchIndex(line) if match == nil { return line } addr, err := strconv.ParseUint(string(line[match[2]:match[3]]), 0, 64) if err != nil { return line } frames, err := symbFunc(objfile, addr-1) if err != nil || len(frames) == 0 { return line } var symbolized []byte for i, frame := range frames { if i != 0 { symbolized = append(symbolized, '\n') } file := frame.File if pos := strings.LastIndex(file, "/kern/"); pos != -1 { file = file[pos+6:] } modified := append([]byte{}, line...) modified = append(modified, fmt.Sprintf(" at %v:%v", file, frame.Line)...) if frame.Inline { modified = replace(modified, match[4], match[5], []byte(frame.Func)) modified = replace(modified, match[2], match[3], []byte(" [inline] ")) } symbolized = append(symbolized, modified...) } return symbolized } func (ctx *akaros) minimizeReport(report []byte) []byte { out := new(bytes.Buffer) for s := bufio.NewScanner(bytes.NewReader(report)); s.Scan(); { line := bytes.Trim(s.Bytes(), "\r") if len(line) == 0 || bytes.Contains(line, []byte("Entering Nanwan's Dungeon")) || bytes.Contains(line, []byte("Type 'help' for a list of commands")) { continue } out.Write(line) out.WriteByte('\n') } return out.Bytes() } var ( akarosSymbolizeRe = compile(`^#[0-9]+ \[\<(0x[0-9a-f]+)\>\] in ([a-zA-Z0-9_]+)`) akarosBacktraceRe = compile(`(?:Stack Backtrace|Backtrace of kernel context) on Core [0-9]+:`) ) var akarosStackParams = &stackParams{ stackStartRes: []*regexp.Regexp{ akarosBacktraceRe, }, frameRes: []*regexp.Regexp{ compile(`^#[0-9]+ {{PC}} in ([a-zA-Z0-9_]+)`), }, skipPatterns: []string{ "backtrace", "mon_backtrace", "monitor", "_panic", "_warn", }, } var akarosOopses = []*oops{ { []byte("kernel panic"), []oopsFormat{ { title: compile("kernel panic at {{SRC}}, from core [0-9]+: assertion failed: (.*)"), fmt: "assertion failed: %[2]v", stack: &stackFmt{ parts: []*regexp.Regexp{ akarosBacktraceRe, parseStackTrace, }, }, }, { title: compile("kernel panic at {{SRC}}, from core [0-9]+: (.*)"), fmt: "kernel panic: %[2]v", stack: &stackFmt{ parts: []*regexp.Regexp{ akarosBacktraceRe, parseStackTrace, }, }, }, { title: compile("kernel panic"), fmt: "kernel panic", noStackTrace: true, corrupted: true, }, }, []*regexp.Regexp{}, }, { []byte("kernel warning"), []oopsFormat{ { title: compile("kernel warning at {{SRC}}, from core [0-9]+"), fmt: "kernel warning in %[2]v", stack: &stackFmt{ parts: []*regexp.Regexp{ akarosBacktraceRe, parseStackTrace, }, }, }, { title: compile("kernel warning"), fmt: "kernel warning", noStackTrace: true, corrupted: true, }, }, []*regexp.Regexp{}, }, }