| // Copyright 2017 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 netbsd struct { |
| *config |
| kernelObject string |
| symbols map[string][]symbolizer.Symbol |
| } |
| |
| var ( |
| netbsdSymbolizeRe = []*regexp.Regexp{ |
| // stack |
| regexp.MustCompile(` at netbsd:([A-Za-z0-9_]+)\+0x([0-9a-f]+)`), |
| // witness |
| regexp.MustCompile(`#[0-9]+ +([A-Za-z0-9_]+)\+0x([0-9a-f]+)`), |
| } |
| ) |
| |
| func ctorNetbsd(cfg *config) (Reporter, []string, error) { |
| var symbols map[string][]symbolizer.Symbol |
| cfg.ignores = append(cfg.ignores, regexp.MustCompile("event_init: unable to initialize")) // postfix output |
| kernelObject := "" |
| if cfg.kernelObj != "" { |
| kernelObject = filepath.Join(cfg.kernelObj, cfg.target.KernelObject) |
| var err error |
| symbols, err = symbolizer.ReadSymbols(kernelObject) |
| if err != nil { |
| return nil, nil, err |
| } |
| } |
| ctx := &netbsd{ |
| config: cfg, |
| kernelObject: kernelObject, |
| symbols: symbols, |
| } |
| return ctx, nil, nil |
| } |
| |
| func (ctx *netbsd) ContainsCrash(output []byte) bool { |
| return containsCrash(output, netbsdOopses, ctx.ignores) |
| } |
| |
| func (ctx *netbsd) Parse(output []byte) *Report { |
| stripped := bytes.Replace(output, []byte{'\r', '\n'}, []byte{'\n'}, -1) |
| stripped = bytes.Replace(stripped, []byte{'\n', '\r'}, []byte{'\n'}, -1) |
| for len(stripped) != 0 && stripped[0] == '\r' { |
| stripped = stripped[1:] |
| } |
| rep := simpleLineParser(stripped, netbsdOopses, nil, ctx.ignores) |
| if rep == nil { |
| return nil |
| } |
| rep.Output = output |
| return rep |
| } |
| |
| func (ctx *netbsd) Symbolize(rep *Report) error { |
| symb := symbolizer.NewSymbolizer() |
| defer symb.Close() |
| var symbolized []byte |
| s := bufio.NewScanner(bytes.NewReader(rep.Report)) |
| prefix := rep.reportPrefixLen |
| for s.Scan() { |
| line := append([]byte{}, s.Bytes()...) |
| line = append(line, '\n') |
| newLine := ctx.symbolizeLine(symb.Symbolize, line) |
| if prefix > len(symbolized) { |
| prefix += len(newLine) - len(line) |
| } |
| symbolized = append(symbolized, newLine...) |
| } |
| rep.Report = symbolized |
| rep.reportPrefixLen = prefix |
| return nil |
| } |
| |
| func (ctx *netbsd) symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error), |
| line []byte) []byte { |
| var match []int |
| // Check whether the line corresponds to the any of the parts that |
| // require symbolization. |
| for _, re := range netbsdSymbolizeRe { |
| match = re.FindSubmatchIndex(line) |
| if match != nil { |
| break |
| } |
| } |
| if match == nil { |
| return line |
| } |
| // First part of the matched regex contains the function name |
| // Second part contains the offset |
| fn := line[match[2]:match[3]] |
| off, err := strconv.ParseUint(string(line[match[4]:match[5]]), 16, 64) |
| if err != nil { |
| return line |
| } |
| |
| // Get the symbol from the list of symbols generated using |
| // the kernel object and addr2line |
| symb := ctx.symbols[string(fn)] |
| if len(symb) == 0 { |
| return line |
| } |
| fnStart := (0xffffffff << 32) | symb[0].Addr |
| |
| // Retrieve the frames for the corresponding offset of the function |
| frames, err := symbFunc(ctx.kernelObject, fnStart+off) |
| if err != nil || len(frames) == 0 { |
| return line |
| } |
| var symbolized []byte |
| // Go through each of the frames and add the corresponding file names |
| // and line numbers. |
| for _, frame := range frames { |
| file := frame.File |
| file = strings.TrimPrefix(file, ctx.kernelBuildSrc) |
| file = strings.TrimPrefix(file, "/") |
| info := fmt.Sprintf(" %v:%v", file, frame.Line) |
| modified := append([]byte{}, line...) |
| modified = replace(modified, match[5], match[5], []byte(info)) |
| if frame.Inline { |
| // If frames are marked inline then show that in the report also |
| end := match[5] + len(info) |
| modified = replace(modified, end, end, []byte(" [inline]")) |
| modified = replace(modified, match[5], match[5], []byte(" "+frame.Func)) |
| } |
| symbolized = append(symbolized, modified...) |
| } |
| return symbolized |
| } |
| |
| // nolint: lll |
| var netbsdOopses = append([]*oops{ |
| { |
| []byte("fault in supervisor mode"), |
| []oopsFormat{ |
| { |
| title: compile("fatal (page|protection|integer divide) fault in supervisor mode"), |
| report: compile(`fatal (page|protection|integer divide) fault in supervisor mode(?:.*\n)+?.*Stopped in.*netbsd:([^\\+]+)`), |
| fmt: "%[1]v fault in %[2]v", |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("panic: "), |
| []oopsFormat{ |
| { |
| title: compile("panic: kernel diagnostic assertion"), |
| report: compile(`panic: kernel diagnostic assertion "(.*?)"`), |
| fmt: "assert failed: %[1]v", |
| }, |
| { |
| title: compile("panic: lock error"), |
| report: compile(`panic: lock error:(?:.*\n)+?.*?Begin traceback.*?\n(?:.*(?:panic|printf|lockdebug|abort|mutex).*\n)*.*?\](.*?)\(`), |
| fmt: "lock error in %[1]v", |
| }, |
| { |
| title: compile("ASan: Unauthorized Access"), |
| report: compile(`ASan: Unauthorized Access (?:.*\n)+kasan.*\n(.*)\(`), |
| fmt: "ASan: Unauthorized Access in %[1]v", |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| { |
| []byte("UBSan:"), |
| []oopsFormat{ |
| { |
| title: compile("UBSan:"), |
| fmt: "UBSan: Undefined behavior", |
| }, |
| }, |
| []*regexp.Regexp{}, |
| }, |
| }, commonOopses...) |