aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSiddharth M <siddharth.muralee@gmail.com>2019-06-13 22:09:32 +0530
committerDmitry Vyukov <dvyukov@google.com>2019-06-13 18:39:32 +0200
commita139f92feffd8dddce2b307b80cc9a1ac9525fc6 (patch)
treea46455c106bb8cbc4f20165aebab37927e20fb83
parentd25bb7ad41f9d44dc58107b2d5e264cae1169611 (diff)
pkg/report: Add initial support for report symbolisation
* pkg/report: initial netbsd commit * pkg/report: fix netbsd errors and add comments to help * fix spelling error
-rw-r--r--pkg/report/netbsd.go126
-rw-r--r--pkg/report/netbsd_test.go98
2 files changed, 217 insertions, 7 deletions
diff --git a/pkg/report/netbsd.go b/pkg/report/netbsd.go
index b284e1a59..7177a0146 100644
--- a/pkg/report/netbsd.go
+++ b/pkg/report/netbsd.go
@@ -4,24 +4,54 @@
package report
import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "path/filepath"
"regexp"
+ "strconv"
+ "strings"
+ "github.com/google/syzkaller/pkg/symbolizer"
"github.com/google/syzkaller/sys/targets"
)
type netbsd struct {
- kernelSrc string
- kernelObj string
- ignores []*regexp.Regexp
+ kernelSrc string
+ kernelObj string
+ kernelObject string
+ symbols map[string][]symbolizer.Symbol
+ ignores []*regexp.Regexp
}
+var (
+ netbsdSymbolizeRe = []*regexp.Regexp{
+ // stack
+ regexp.MustCompile(` at ([A-Za-z0-9_]+)\+0x([0-9a-f]+)`),
+ // witness
+ regexp.MustCompile(`#[0-9]+ +([A-Za-z0-9_]+)\+0x([0-9a-f]+)`),
+ }
+)
+
func ctorNetbsd(target *targets.Target, kernelSrc, kernelObj string,
ignores []*regexp.Regexp) (Reporter, []string, error) {
+ var symbols map[string][]symbolizer.Symbol
ignores = append(ignores, regexp.MustCompile("event_init: unable to initialize")) // postfix output
+ kernelObject := ""
+ if kernelObj != "" {
+ kernelObject = filepath.Join(kernelObj, target.KernelObject)
+ var err error
+ symbols, err = symbolizer.ReadSymbols(kernelObject)
+ if err != nil {
+ return nil, nil, err
+ }
+ }
ctx := &netbsd{
- kernelSrc: kernelSrc,
- kernelObj: kernelObj,
- ignores: ignores,
+ kernelSrc: kernelSrc,
+ kernelObj: kernelObj,
+ kernelObject: kernelObject,
+ symbols: symbols,
+ ignores: ignores,
}
return ctx, nil, nil
}
@@ -31,13 +61,95 @@ func (ctx *netbsd) ContainsCrash(output []byte) bool {
}
func (ctx *netbsd) Parse(output []byte) *Report {
- return simpleLineParser(output, netbsdOopses, nil, ctx.ignores)
+ 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.kernelSrc)
+ 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 = []*oops{
{
diff --git a/pkg/report/netbsd_test.go b/pkg/report/netbsd_test.go
new file mode 100644
index 000000000..1934e6453
--- /dev/null
+++ b/pkg/report/netbsd_test.go
@@ -0,0 +1,98 @@
+// 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 (
+ "fmt"
+ "testing"
+
+ "github.com/google/syzkaller/pkg/symbolizer"
+)
+
+func TestNetbsdSymbolizeLine(t *testing.T) {
+ tests := []struct {
+ line string
+ result string
+ }{
+ // Normal symbolization.
+ {
+ "closef(ffffffff,ffffffff) at closef+0xaf\n",
+ "closef(ffffffff,ffffffff) at closef+0xaf kern_descrip.c:1241\n",
+ },
+ // Inlined frames.
+ {
+ "sleep_finish_all(ffffffff,32) at sleep_finish_all+0x22\n",
+ "sleep_finish_all(ffffffff,32) at sleep_finish_all+0x22 sleep_finish_timeout kern_synch.c:336 [inline]\n" +
+ "sleep_finish_all(ffffffff,32) at sleep_finish_all+0x22 kern_synch.c:157\n",
+ },
+ // Missing symbol.
+ {
+ "foo(ffffffff,ffffffff) at foo+0x1e",
+ "foo(ffffffff,ffffffff) at foo+0x1e",
+ },
+ // Witness symbolization.
+ {
+ "#4 closef+0xaf\n",
+ "#4 closef+0xaf kern_descrip.c:1241\n",
+ },
+ {
+ "#10 closef+0xaf\n",
+ "#10 closef+0xaf kern_descrip.c:1241\n",
+ },
+ }
+ symbols := map[string][]symbolizer.Symbol{
+ "closef": {
+ {Addr: 0x815088a0, Size: 0x12f},
+ },
+ "sleep_finish_all": {
+ {Addr: 0x81237520, Size: 0x173},
+ },
+ }
+ symb := func(bin string, pc uint64) ([]symbolizer.Frame, error) {
+ if bin != "netbsd.gdb" {
+ return nil, fmt.Errorf("unknown pc 0x%x", pc)
+ }
+
+ switch pc & 0xffffffff {
+ case 0x8150894f:
+ return []symbolizer.Frame{
+ {
+ Func: "closef",
+ File: "netbsd/src/kern_descrip.c",
+ Line: 1241,
+ },
+ }, nil
+ case 0x81237542:
+ return []symbolizer.Frame{
+ {
+ Func: "sleep_finish_timeout",
+ File: "netbsd/src/kern_synch.c",
+ Line: 336,
+ Inline: true,
+ },
+ {
+ Func: "sleep_finish_all",
+ File: "netbsd/src/kern_synch.c",
+ Line: 157,
+ },
+ }, nil
+ default:
+ return nil, fmt.Errorf("unknown pc 0x%x", pc)
+ }
+ }
+ nbsd := netbsd{
+ kernelSrc: "netbsd/src",
+ kernelObj: "/netbsd/src/obj/sys/arch/amd64/compile/GENERIC",
+ kernelObject: "netbsd.gdb",
+ symbols: symbols,
+ }
+ for i, test := range tests {
+ t.Run(fmt.Sprint(i), func(t *testing.T) {
+ result := nbsd.symbolizeLine(symb, []byte(test.line))
+ if test.result != string(result) {
+ t.Errorf("want %q\n\t get %q", test.result, string(result))
+ }
+ })
+ }
+}