Skip to content

Commit 41b6ca9

Browse files
committed
pkg/symbolizer: introduce Symbolizer interface
To simplify interface Read*Symbols were moved out from it.
1 parent 831e362 commit 41b6ca9

File tree

15 files changed

+249
-241
lines changed

15 files changed

+249
-241
lines changed

pkg/cover/backend/dwarf.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ func symbolizeModule(target *targets.Target, interner *symbolizer.Interner, objD
419419
pcchan := make(chan []uint64, procs)
420420
for p := 0; p < procs; p++ {
421421
go func() {
422-
symb := symbolizer.NewSymbolizer(target)
422+
symb := symbolizer.Make(target)
423423
defer symb.Close()
424424
var res symbolizerResult
425425
for pcs := range pcchan {
@@ -430,7 +430,7 @@ func symbolizeModule(target *targets.Target, interner *symbolizer.Interner, objD
430430
pcs[i] = pc - mod.Addr
431431
}
432432
}
433-
frames, err := symb.SymbolizeArray(mod.Path, pcs)
433+
frames, err := symb.Symbolize(mod.Path, pcs...)
434434
if err != nil {
435435
res.err = fmt.Errorf("failed to symbolize: %w", err)
436436
}

pkg/cover/report_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,7 @@ func generateReport(t *testing.T, target *targets.Target, test *Test) (*reports,
357357
} else if target.OS == runtime.GOOS && (target.Arch == runtime.GOARCH || target.VMArch == runtime.GOARCH) {
358358
t.Fatal(err)
359359
} else {
360-
symb := symbolizer.NewSymbolizer(target)
361-
text, err := symb.ReadTextSymbols(bin)
360+
text, err := symbolizer.ReadTextSymbols(bin)
362361
if err != nil {
363362
t.Fatal(err)
364363
}

pkg/ifaceprobe/ifaceprobe.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ type fileDesc struct {
6868
}
6969

7070
func (pr *prober) run() (*Info, error) {
71-
symb := symbolizer.NewSymbolizer(pr.cfg.SysTarget)
71+
symb := symbolizer.Make(pr.cfg.SysTarget)
7272
defer symb.Close()
7373

7474
for _, glob := range globList() {

pkg/report/bsd.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ func ctorBSD(cfg *config, oopses []*oops, symbolizeRes []*regexp.Regexp) (report
2828
if cfg.kernelObj != "" {
2929
kernelObject = filepath.Join(cfg.kernelObj, cfg.target.KernelObject)
3030
var err error
31-
symb := symbolizer.NewSymbolizer(cfg.target)
32-
symbols, err = symb.ReadTextSymbols(kernelObject)
31+
symbols, err = symbolizer.ReadTextSymbols(kernelObject)
3332
if err != nil {
3433
return nil, err
3534
}
@@ -53,7 +52,7 @@ func (ctx *bsd) Parse(output []byte) *Report {
5352
}
5453

5554
func (ctx *bsd) Symbolize(rep *Report) error {
56-
symb := symbolizer.NewSymbolizer(ctx.config.target)
55+
symb := symbolizer.Make(ctx.config.target)
5756
defer symb.Close()
5857
var symbolized []byte
5958
prefix := rep.reportPrefixLen
@@ -70,7 +69,7 @@ func (ctx *bsd) Symbolize(rep *Report) error {
7069
return nil
7170
}
7271

73-
func (ctx *bsd) symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error),
72+
func (ctx *bsd) symbolizeLine(symbFunc func(string, ...uint64) ([]symbolizer.Frame, error),
7473
line []byte) []byte {
7574
var match []int
7675
// Check whether the line corresponds to the any of the parts that require symbolization.

pkg/report/bsd_test.go

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,39 @@ func testSymbolizeLine(t *testing.T, ctor fn, tests []symbolizeLineTest) {
2424
{Addr: 0x81237520, Size: 0x173},
2525
},
2626
}
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-
}
27+
symb := func(bin string, pcs ...uint64) ([]symbolizer.Frame, error) {
28+
var res []symbolizer.Frame
29+
for _, pc := range pcs {
30+
if bin != "bsd.gdb" {
31+
return nil, fmt.Errorf("unknown pc 0x%x", pc)
32+
}
3133

32-
switch pc & 0xffffffff {
33-
case 0x8150894f:
34-
return []symbolizer.Frame{
35-
{
34+
switch pc & 0xffffffff {
35+
case 0x8150894f:
36+
res = append(res, symbolizer.Frame{
3637
Func: "closef",
3738
File: "/bsd/src/kern_descrip.c",
3839
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)
40+
})
41+
case 0x81237542:
42+
res = append(res,
43+
symbolizer.Frame{
44+
Func: "sleep_finish_timeout",
45+
File: "/bsd/src/kern_synch.c",
46+
Line: 336,
47+
Inline: true,
48+
},
49+
symbolizer.Frame{
50+
Func: "sleep_finish_all",
51+
File: "/bsd/src/kern_synch.c",
52+
Line: 157,
53+
},
54+
)
55+
default:
56+
return nil, fmt.Errorf("unknown pc 0x%x", pc)
57+
}
5758
}
59+
return res, nil
5860
}
5961
reporter, _, err := ctor(&config{
6062
kernelSrc: "/bsd/src2",

pkg/report/fuchsia.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func (ctx *fuchsia) shortenReport(report []byte) []byte {
134134
}
135135

136136
func (ctx *fuchsia) symbolize(output []byte) []byte {
137-
symb := symbolizer.NewSymbolizer(ctx.config.target)
137+
symb := symbolizer.Make(ctx.config.target)
138138
defer symb.Close()
139139
out := new(bytes.Buffer)
140140

@@ -167,7 +167,7 @@ func (ctx *fuchsia) symbolize(output []byte) []byte {
167167
return out.Bytes()
168168
}
169169

170-
func (ctx *fuchsia) processPC(out *bytes.Buffer, symb *symbolizer.Symbolizer,
170+
func (ctx *fuchsia) processPC(out *bytes.Buffer, symb symbolizer.Symbolizer,
171171
line []byte, match []int, call bool) bool {
172172
prefix := line[match[0]:match[1]]
173173
pcStart := match[2] - match[0]

pkg/report/linux.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,15 @@ func ctorLinux(cfg *config) (reporterImpl, []string, error) {
4242
if cfg.kernelObj != "" {
4343
vmlinux = filepath.Join(cfg.kernelObj, cfg.target.KernelObject)
4444
var err error
45-
symb := symbolizer.NewSymbolizer(cfg.target)
46-
symbols[""], err = symb.ReadTextSymbols(vmlinux)
45+
symbols[""], err = symbolizer.ReadTextSymbols(vmlinux)
4746
if err != nil {
4847
return nil, nil, err
4948
}
5049
for _, mod := range cfg.kernelModules {
5150
if mod.Name == "" {
5251
continue
5352
}
54-
ss, err := symb.ReadTextSymbols(mod.Path)
53+
ss, err := symbolizer.ReadTextSymbols(mod.Path)
5554
if err != nil {
5655
continue
5756
}
@@ -408,7 +407,7 @@ func (ctx *linux) Symbolize(rep *Report) error {
408407
}
409408

410409
func (ctx *linux) symbolize(rep *Report) error {
411-
symb := symbolizer.NewSymbolizer(ctx.config.target)
410+
symb := symbolizer.Make(ctx.config.target)
412411
defer symb.Close()
413412
symbFunc := func(bin string, pc uint64) ([]symbolizer.Frame, error) {
414413
return ctx.symbolizerCache.Symbolize(symb.Symbolize, bin, pc)

pkg/symbolizer/addr2liner.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// Copyright 2016 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+
// TODO: strip " (discriminator N)", "constprop", "isra" from function names.
5+
6+
package symbolizer
7+
8+
import (
9+
"bufio"
10+
"fmt"
11+
"io"
12+
"os/exec"
13+
"strconv"
14+
"strings"
15+
16+
"github.com/google/syzkaller/pkg/osutil"
17+
"github.com/google/syzkaller/sys/targets"
18+
)
19+
20+
type addr2Liner struct {
21+
target *targets.Target
22+
subprocs map[string]*subprocess
23+
interner Interner
24+
}
25+
26+
type subprocess struct {
27+
cmd *exec.Cmd
28+
stdin io.Closer
29+
stdout io.Closer
30+
input *bufio.Writer
31+
scanner *bufio.Scanner
32+
}
33+
34+
func (s *addr2Liner) Symbolize(bin string, pcs ...uint64) ([]Frame, error) {
35+
sub, err := s.getSubprocess(bin)
36+
if err != nil {
37+
return nil, err
38+
}
39+
return symbolize(&s.interner, sub.input, sub.scanner, pcs)
40+
}
41+
42+
func (s *addr2Liner) Close() {
43+
for _, sub := range s.subprocs {
44+
sub.stdin.Close()
45+
sub.stdout.Close()
46+
sub.cmd.Process.Kill()
47+
sub.cmd.Wait()
48+
}
49+
}
50+
51+
func (s *addr2Liner) getSubprocess(bin string) (*subprocess, error) {
52+
if sub := s.subprocs[bin]; sub != nil {
53+
return sub, nil
54+
}
55+
addr2line, err := s.target.Addr2Line()
56+
if err != nil {
57+
return nil, err
58+
}
59+
cmd := osutil.Command(addr2line, "-afi", "-e", bin)
60+
stdin, err := cmd.StdinPipe()
61+
if err != nil {
62+
return nil, err
63+
}
64+
stdout, err := cmd.StdoutPipe()
65+
if err != nil {
66+
stdin.Close()
67+
return nil, err
68+
}
69+
if err := cmd.Start(); err != nil {
70+
stdin.Close()
71+
stdout.Close()
72+
return nil, err
73+
}
74+
sub := &subprocess{
75+
cmd: cmd,
76+
stdin: stdin,
77+
stdout: stdout,
78+
input: bufio.NewWriter(stdin),
79+
scanner: bufio.NewScanner(stdout),
80+
}
81+
if s.subprocs == nil {
82+
s.subprocs = make(map[string]*subprocess)
83+
}
84+
s.subprocs[bin] = sub
85+
return sub, nil
86+
}
87+
88+
func symbolize(interner *Interner, input *bufio.Writer, scanner *bufio.Scanner, pcs []uint64) ([]Frame, error) {
89+
var frames []Frame
90+
done := make(chan error, 1)
91+
go func() {
92+
var err error
93+
defer func() {
94+
done <- err
95+
}()
96+
if !scanner.Scan() {
97+
if err = scanner.Err(); err == nil {
98+
err = io.EOF
99+
}
100+
return
101+
}
102+
for range pcs {
103+
var frames1 []Frame
104+
frames1, err = parse(interner, scanner)
105+
if err != nil {
106+
return
107+
}
108+
frames = append(frames, frames1...)
109+
}
110+
for i := 0; i < 2; i++ {
111+
scanner.Scan()
112+
}
113+
}()
114+
115+
for _, pc := range pcs {
116+
if _, err := fmt.Fprintf(input, "0x%x\n", pc); err != nil {
117+
return nil, err
118+
}
119+
}
120+
// Write an invalid PC so that parse doesn't block reading input.
121+
// We read out result for this PC at the end of the function.
122+
if _, err := fmt.Fprintf(input, "0xffffffffffffffff\n"); err != nil {
123+
return nil, err
124+
}
125+
input.Flush()
126+
127+
if err := <-done; err != nil {
128+
return nil, err
129+
}
130+
return frames, nil
131+
}
132+
133+
func parse(interner *Interner, s *bufio.Scanner) ([]Frame, error) {
134+
pc, err := strconv.ParseUint(s.Text(), 0, 64)
135+
if err != nil {
136+
return nil, fmt.Errorf("failed to parse pc '%v' in addr2line output: %w", s.Text(), err)
137+
}
138+
var frames []Frame
139+
for {
140+
if !s.Scan() {
141+
break
142+
}
143+
ln := s.Text()
144+
if len(ln) > 3 && ln[0] == '0' && ln[1] == 'x' {
145+
break
146+
}
147+
fn := ln
148+
if !s.Scan() {
149+
err := s.Err()
150+
if err == nil {
151+
err = io.EOF
152+
}
153+
return nil, fmt.Errorf("failed to read file:line from addr2line: %w", err)
154+
}
155+
ln = s.Text()
156+
colon := strings.LastIndexByte(ln, ':')
157+
if colon == -1 {
158+
return nil, fmt.Errorf("failed to parse file:line in addr2line output: %v", ln)
159+
}
160+
lineEnd := colon + 1
161+
for lineEnd < len(ln) && ln[lineEnd] >= '0' && ln[lineEnd] <= '9' {
162+
lineEnd++
163+
}
164+
file := ln[:colon]
165+
line, err := strconv.Atoi(ln[colon+1 : lineEnd])
166+
if err != nil || fn == "" || fn == "??" || file == "" || file == "??" || line <= 0 {
167+
continue
168+
}
169+
frames = append(frames, Frame{
170+
PC: pc,
171+
Func: interner.Do(fn),
172+
File: interner.Do(file),
173+
Line: line,
174+
Inline: true,
175+
})
176+
}
177+
if err := s.Err(); err != nil {
178+
return nil, err
179+
}
180+
if len(frames) != 0 {
181+
frames[len(frames)-1].Inline = false
182+
}
183+
return frames, nil
184+
}

pkg/symbolizer/cache.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type cacheVal struct {
2424
err error
2525
}
2626

27-
func (c *Cache) Symbolize(inner func(string, uint64) ([]Frame, error), bin string, pc uint64) ([]Frame, error) {
27+
func (c *Cache) Symbolize(inner func(string, ...uint64) ([]Frame, error), bin string, pc uint64) ([]Frame, error) {
2828
key := cacheKey{bin, pc}
2929
c.mu.RLock()
3030
val, ok := c.cache[key]

0 commit comments

Comments
 (0)