Skip to content

Commit cdf1aa4

Browse files
committed
pkg/report: deduplicate code across netbsd and openbsd
1 parent 21b7958 commit cdf1aa4

File tree

7 files changed

+226
-379
lines changed

7 files changed

+226
-379
lines changed

.golangci.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ linters-settings:
7474
# TODO: consider reducing this value.
7575
min-complexity: 24
7676
dupl:
77-
# TODO: consider reducing this value.
7877
threshold: 60
7978
goconst:
8079
min-len: 7
@@ -107,10 +106,6 @@ issues:
107106
text: "don't use ALL_CAPS in Go names|should not use ALL_CAPS in Go names"
108107
- path: (prog/.*)
109108
text: "methods on the same type should have the same receiver name"
110-
# TODO: this is bad, need to fix and remove the suppression.
111-
- path: (pkg/report/(net|open)bsd.*)
112-
linters:
113-
- dupl
114109
- path: (dashboard/app/.*_test\.go)
115110
linters:
116111
- dupl

pkg/report/bsd.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Copyright 2017 syzkaller project authors. All rights reserved.
2+
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3+
4+
package report
5+
6+
import (
7+
"bufio"
8+
"bytes"
9+
"fmt"
10+
"path/filepath"
11+
"regexp"
12+
"strconv"
13+
"strings"
14+
15+
"github.com/google/syzkaller/pkg/symbolizer"
16+
)
17+
18+
type bsd struct {
19+
*config
20+
oopses []*oops
21+
symbolizeRes []*regexp.Regexp
22+
kernelObject string
23+
symbols map[string][]symbolizer.Symbol
24+
}
25+
26+
func ctorBSD(cfg *config, oopses []*oops, symbolizeRes []*regexp.Regexp) (Reporter, error) {
27+
var symbols map[string][]symbolizer.Symbol
28+
kernelObject := ""
29+
if cfg.kernelObj != "" {
30+
kernelObject = filepath.Join(cfg.kernelObj, cfg.target.KernelObject)
31+
var err error
32+
symbols, err = symbolizer.ReadTextSymbols(kernelObject)
33+
if err != nil {
34+
return nil, err
35+
}
36+
}
37+
ctx := &bsd{
38+
config: cfg,
39+
oopses: oopses,
40+
symbolizeRes: symbolizeRes,
41+
kernelObject: kernelObject,
42+
symbols: symbols,
43+
}
44+
return ctx, nil
45+
}
46+
47+
func (ctx *bsd) ContainsCrash(output []byte) bool {
48+
return containsCrash(output, ctx.oopses, ctx.ignores)
49+
}
50+
51+
func (ctx *bsd) Parse(output []byte) *Report {
52+
stripped := bytes.Replace(output, []byte{'\r', '\n'}, []byte{'\n'}, -1)
53+
stripped = bytes.Replace(stripped, []byte{'\n', '\r'}, []byte{'\n'}, -1)
54+
for len(stripped) != 0 && stripped[0] == '\r' {
55+
stripped = stripped[1:]
56+
}
57+
rep := simpleLineParser(stripped, ctx.oopses, nil, ctx.ignores)
58+
if rep == nil {
59+
return nil
60+
}
61+
rep.Output = output
62+
return rep
63+
}
64+
65+
func (ctx *bsd) Symbolize(rep *Report) error {
66+
symb := symbolizer.NewSymbolizer()
67+
defer symb.Close()
68+
var symbolized []byte
69+
s := bufio.NewScanner(bytes.NewReader(rep.Report))
70+
prefix := rep.reportPrefixLen
71+
for s.Scan() {
72+
line := append([]byte{}, s.Bytes()...)
73+
line = append(line, '\n')
74+
newLine := ctx.symbolizeLine(symb.Symbolize, line)
75+
if prefix > len(symbolized) {
76+
prefix += len(newLine) - len(line)
77+
}
78+
symbolized = append(symbolized, newLine...)
79+
}
80+
rep.Report = symbolized
81+
rep.reportPrefixLen = prefix
82+
return nil
83+
}
84+
85+
func (ctx *bsd) symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error),
86+
line []byte) []byte {
87+
var match []int
88+
// Check whether the line corresponds to the any of the parts that require symbolization.
89+
for _, re := range ctx.symbolizeRes {
90+
match = re.FindSubmatchIndex(line)
91+
if match != nil {
92+
break
93+
}
94+
}
95+
if match == nil {
96+
return line
97+
}
98+
// First part of the matched regex contains the function name.
99+
// Second part contains the offset.
100+
fn := line[match[2]:match[3]]
101+
off, err := strconv.ParseUint(string(line[match[4]:match[5]]), 16, 64)
102+
if err != nil {
103+
return line
104+
}
105+
106+
// Get the symbol from the list of symbols generated using the kernel object and addr2line.
107+
symb := ctx.symbols[string(fn)]
108+
if len(symb) == 0 {
109+
return line
110+
}
111+
fnStart := (0xffffffff << 32) | symb[0].Addr
112+
113+
// Retrieve the frames for the corresponding offset of the function.
114+
frames, err := symbFunc(ctx.kernelObject, fnStart+off)
115+
if err != nil || len(frames) == 0 {
116+
return line
117+
}
118+
var symbolized []byte
119+
// Go through each of the frames and add the corresponding file names and line numbers.
120+
for _, frame := range frames {
121+
file := frame.File
122+
file = strings.TrimPrefix(file, ctx.kernelBuildSrc)
123+
file = strings.TrimPrefix(file, "/")
124+
info := fmt.Sprintf(" %v:%v", file, frame.Line)
125+
modified := append([]byte{}, line...)
126+
modified = replace(modified, match[5], match[5], []byte(info))
127+
if frame.Inline {
128+
// If frames are marked inline then show that in the report also.
129+
end := match[5] + len(info)
130+
modified = replace(modified, end, end, []byte(" [inline]"))
131+
modified = replace(modified, match[5], match[5], []byte(" "+frame.Func))
132+
}
133+
symbolized = append(symbolized, modified...)
134+
}
135+
return symbolized
136+
}

pkg/report/bsd_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2018 syzkaller project authors. All rights reserved.
2+
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3+
4+
package report
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
10+
"github.com/google/syzkaller/pkg/symbolizer"
11+
)
12+
13+
type symbolizeLineTest struct {
14+
line string
15+
result string
16+
}
17+
18+
func testSymbolizeLine(t *testing.T, ctor fn, tests []symbolizeLineTest) {
19+
symbols := map[string][]symbolizer.Symbol{
20+
"closef": {
21+
{Addr: 0x815088a0, Size: 0x12f},
22+
},
23+
"sleep_finish_all": {
24+
{Addr: 0x81237520, Size: 0x173},
25+
},
26+
}
27+
symb := func(bin string, pc uint64) ([]symbolizer.Frame, error) {
28+
if bin != "bsd.gdb" {
29+
return nil, fmt.Errorf("unknown pc 0x%x", pc)
30+
}
31+
32+
switch pc & 0xffffffff {
33+
case 0x8150894f:
34+
return []symbolizer.Frame{
35+
{
36+
Func: "closef",
37+
File: "/bsd/src/kern_descrip.c",
38+
Line: 1241,
39+
},
40+
}, nil
41+
case 0x81237542:
42+
return []symbolizer.Frame{
43+
{
44+
Func: "sleep_finish_timeout",
45+
File: "/bsd/src/kern_synch.c",
46+
Line: 336,
47+
Inline: true,
48+
},
49+
{
50+
Func: "sleep_finish_all",
51+
File: "/bsd/src/kern_synch.c",
52+
Line: 157,
53+
},
54+
}, nil
55+
default:
56+
return nil, fmt.Errorf("unknown pc 0x%x", pc)
57+
}
58+
}
59+
reporter, _, err := ctor(&config{
60+
kernelSrc: "/bsd/src2",
61+
kernelBuildSrc: "/bsd/src",
62+
})
63+
if err != nil {
64+
t.Fatal(err)
65+
}
66+
bsd := reporter.(*bsd)
67+
bsd.symbols = symbols
68+
bsd.kernelObject = "bsd.gdb"
69+
for i, test := range tests {
70+
t.Run(fmt.Sprint(i), func(t *testing.T) {
71+
result := bsd.symbolizeLine(symb, []byte(test.line))
72+
if test.result != string(result) {
73+
t.Errorf("want %q\n\t get %q", test.result, string(result))
74+
}
75+
})
76+
}
77+
}

pkg/report/netbsd.go

Lines changed: 4 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -4,144 +4,19 @@
44
package report
55

66
import (
7-
"bufio"
8-
"bytes"
9-
"fmt"
10-
"path/filepath"
117
"regexp"
12-
"strconv"
13-
"strings"
14-
15-
"github.com/google/syzkaller/pkg/symbolizer"
168
)
179

18-
type netbsd struct {
19-
*config
20-
kernelObject string
21-
symbols map[string][]symbolizer.Symbol
22-
}
23-
24-
var (
25-
netbsdSymbolizeRe = []*regexp.Regexp{
10+
func ctorNetbsd(cfg *config) (Reporter, []string, error) {
11+
symbolizeRes := []*regexp.Regexp{
2612
// stack
2713
regexp.MustCompile(` at netbsd:([A-Za-z0-9_]+)\+0x([0-9a-f]+)`),
2814
// witness
2915
regexp.MustCompile(`#[0-9]+ +([A-Za-z0-9_]+)\+0x([0-9a-f]+)`),
3016
}
31-
)
32-
33-
func ctorNetbsd(cfg *config) (Reporter, []string, error) {
34-
var symbols map[string][]symbolizer.Symbol
3517
cfg.ignores = append(cfg.ignores, regexp.MustCompile("event_init: unable to initialize")) // postfix output
36-
kernelObject := ""
37-
if cfg.kernelObj != "" {
38-
kernelObject = filepath.Join(cfg.kernelObj, cfg.target.KernelObject)
39-
var err error
40-
symbols, err = symbolizer.ReadTextSymbols(kernelObject)
41-
if err != nil {
42-
return nil, nil, err
43-
}
44-
}
45-
ctx := &netbsd{
46-
config: cfg,
47-
kernelObject: kernelObject,
48-
symbols: symbols,
49-
}
50-
return ctx, nil, nil
51-
}
52-
53-
func (ctx *netbsd) ContainsCrash(output []byte) bool {
54-
return containsCrash(output, netbsdOopses, ctx.ignores)
55-
}
56-
57-
func (ctx *netbsd) Parse(output []byte) *Report {
58-
stripped := bytes.Replace(output, []byte{'\r', '\n'}, []byte{'\n'}, -1)
59-
stripped = bytes.Replace(stripped, []byte{'\n', '\r'}, []byte{'\n'}, -1)
60-
for len(stripped) != 0 && stripped[0] == '\r' {
61-
stripped = stripped[1:]
62-
}
63-
rep := simpleLineParser(stripped, netbsdOopses, nil, ctx.ignores)
64-
if rep == nil {
65-
return nil
66-
}
67-
rep.Output = output
68-
return rep
69-
}
70-
71-
func (ctx *netbsd) Symbolize(rep *Report) error {
72-
symb := symbolizer.NewSymbolizer()
73-
defer symb.Close()
74-
var symbolized []byte
75-
s := bufio.NewScanner(bytes.NewReader(rep.Report))
76-
prefix := rep.reportPrefixLen
77-
for s.Scan() {
78-
line := append([]byte{}, s.Bytes()...)
79-
line = append(line, '\n')
80-
newLine := ctx.symbolizeLine(symb.Symbolize, line)
81-
if prefix > len(symbolized) {
82-
prefix += len(newLine) - len(line)
83-
}
84-
symbolized = append(symbolized, newLine...)
85-
}
86-
rep.Report = symbolized
87-
rep.reportPrefixLen = prefix
88-
return nil
89-
}
90-
91-
func (ctx *netbsd) symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error),
92-
line []byte) []byte {
93-
var match []int
94-
// Check whether the line corresponds to the any of the parts that
95-
// require symbolization.
96-
for _, re := range netbsdSymbolizeRe {
97-
match = re.FindSubmatchIndex(line)
98-
if match != nil {
99-
break
100-
}
101-
}
102-
if match == nil {
103-
return line
104-
}
105-
// First part of the matched regex contains the function name
106-
// Second part contains the offset
107-
fn := line[match[2]:match[3]]
108-
off, err := strconv.ParseUint(string(line[match[4]:match[5]]), 16, 64)
109-
if err != nil {
110-
return line
111-
}
112-
113-
// Get the symbol from the list of symbols generated using
114-
// the kernel object and addr2line
115-
symb := ctx.symbols[string(fn)]
116-
if len(symb) == 0 {
117-
return line
118-
}
119-
fnStart := (0xffffffff << 32) | symb[0].Addr
120-
121-
// Retrieve the frames for the corresponding offset of the function
122-
frames, err := symbFunc(ctx.kernelObject, fnStart+off)
123-
if err != nil || len(frames) == 0 {
124-
return line
125-
}
126-
var symbolized []byte
127-
// Go through each of the frames and add the corresponding file names
128-
// and line numbers.
129-
for _, frame := range frames {
130-
file := frame.File
131-
file = strings.TrimPrefix(file, ctx.kernelBuildSrc)
132-
file = strings.TrimPrefix(file, "/")
133-
info := fmt.Sprintf(" %v:%v", file, frame.Line)
134-
modified := append([]byte{}, line...)
135-
modified = replace(modified, match[5], match[5], []byte(info))
136-
if frame.Inline {
137-
// If frames are marked inline then show that in the report also
138-
end := match[5] + len(info)
139-
modified = replace(modified, end, end, []byte(" [inline]"))
140-
modified = replace(modified, match[5], match[5], []byte(" "+frame.Func))
141-
}
142-
symbolized = append(symbolized, modified...)
143-
}
144-
return symbolized
18+
ctx, err := ctorBSD(cfg, netbsdOopses, symbolizeRes)
19+
return ctx, nil, err
14520
}
14621

14722
// nolint: lll

0 commit comments

Comments
 (0)