diff options
| author | Siddharth M <siddharth.muralee@gmail.com> | 2019-06-13 22:09:32 +0530 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2019-06-13 18:39:32 +0200 |
| commit | a139f92feffd8dddce2b307b80cc9a1ac9525fc6 (patch) | |
| tree | a46455c106bb8cbc4f20165aebab37927e20fb83 | |
| parent | d25bb7ad41f9d44dc58107b2d5e264cae1169611 (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.go | 126 | ||||
| -rw-r--r-- | pkg/report/netbsd_test.go | 98 |
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)) + } + }) + } +} |
