aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/report/bsd.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-06-06 09:15:20 +0200
committerDmitry Vyukov <dvyukov@google.com>2020-06-07 10:41:01 +0200
commitcdf1aa4dc338ddd37917942e7d6b992f4e079a00 (patch)
treeca0f1aec1472d7871b6b2995f70359cfbd8a07af /pkg/report/bsd.go
parent21b79583f15c7626926fc9f4fb528147a59ea3c5 (diff)
pkg/report: deduplicate code across netbsd and openbsd
Diffstat (limited to 'pkg/report/bsd.go')
-rw-r--r--pkg/report/bsd.go136
1 files changed, 136 insertions, 0 deletions
diff --git a/pkg/report/bsd.go b/pkg/report/bsd.go
new file mode 100644
index 000000000..369ffcab9
--- /dev/null
+++ b/pkg/report/bsd.go
@@ -0,0 +1,136 @@
+// 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 bsd struct {
+ *config
+ oopses []*oops
+ symbolizeRes []*regexp.Regexp
+ kernelObject string
+ symbols map[string][]symbolizer.Symbol
+}
+
+func ctorBSD(cfg *config, oopses []*oops, symbolizeRes []*regexp.Regexp) (Reporter, error) {
+ var symbols map[string][]symbolizer.Symbol
+ kernelObject := ""
+ if cfg.kernelObj != "" {
+ kernelObject = filepath.Join(cfg.kernelObj, cfg.target.KernelObject)
+ var err error
+ symbols, err = symbolizer.ReadTextSymbols(kernelObject)
+ if err != nil {
+ return nil, err
+ }
+ }
+ ctx := &bsd{
+ config: cfg,
+ oopses: oopses,
+ symbolizeRes: symbolizeRes,
+ kernelObject: kernelObject,
+ symbols: symbols,
+ }
+ return ctx, nil
+}
+
+func (ctx *bsd) ContainsCrash(output []byte) bool {
+ return containsCrash(output, ctx.oopses, ctx.ignores)
+}
+
+func (ctx *bsd) 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, ctx.oopses, nil, ctx.ignores)
+ if rep == nil {
+ return nil
+ }
+ rep.Output = output
+ return rep
+}
+
+func (ctx *bsd) 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 *bsd) 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 ctx.symbolizeRes {
+ 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
+}