aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/symbolizer/symbolizer.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/symbolizer/symbolizer.go')
-rw-r--r--pkg/symbolizer/symbolizer.go191
1 files changed, 7 insertions, 184 deletions
diff --git a/pkg/symbolizer/symbolizer.go b/pkg/symbolizer/symbolizer.go
index 02e6b7693..e3625d313 100644
--- a/pkg/symbolizer/symbolizer.go
+++ b/pkg/symbolizer/symbolizer.go
@@ -1,27 +1,9 @@
-// Copyright 2016 syzkaller project authors. All rights reserved.
+// Copyright 2025 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.
-// TODO: strip " (discriminator N)", "constprop", "isra" from function names.
-
package symbolizer
-import (
- "bufio"
- "fmt"
- "io"
- "os/exec"
- "strconv"
- "strings"
-
- "github.com/google/syzkaller/pkg/osutil"
- "github.com/google/syzkaller/sys/targets"
-)
-
-type Symbolizer struct {
- target *targets.Target
- subprocs map[string]*subprocess
- interner Interner
-}
+import "github.com/google/syzkaller/sys/targets"
type Frame struct {
PC uint64
@@ -31,170 +13,11 @@ type Frame struct {
Inline bool
}
-type subprocess struct {
- cmd *exec.Cmd
- stdin io.Closer
- stdout io.Closer
- input *bufio.Writer
- scanner *bufio.Scanner
-}
-
-func NewSymbolizer(target *targets.Target) *Symbolizer {
- return &Symbolizer{target: target}
-}
-
-func (s *Symbolizer) Symbolize(bin string, pc uint64) ([]Frame, error) {
- return s.SymbolizeArray(bin, []uint64{pc})
-}
-
-func (s *Symbolizer) SymbolizeArray(bin string, pcs []uint64) ([]Frame, error) {
- sub, err := s.getSubprocess(bin)
- if err != nil {
- return nil, err
- }
- return symbolize(&s.interner, sub.input, sub.scanner, pcs)
-}
-
-func (s *Symbolizer) Close() {
- for _, sub := range s.subprocs {
- sub.stdin.Close()
- sub.stdout.Close()
- sub.cmd.Process.Kill()
- sub.cmd.Wait()
- }
-}
-
-func (s *Symbolizer) getSubprocess(bin string) (*subprocess, error) {
- if sub := s.subprocs[bin]; sub != nil {
- return sub, nil
- }
- addr2line, err := s.target.Addr2Line()
- if err != nil {
- return nil, err
- }
- cmd := osutil.Command(addr2line, "-afi", "-e", bin)
- stdin, err := cmd.StdinPipe()
- if err != nil {
- return nil, err
- }
- stdout, err := cmd.StdoutPipe()
- if err != nil {
- stdin.Close()
- return nil, err
- }
- if err := cmd.Start(); err != nil {
- stdin.Close()
- stdout.Close()
- return nil, err
- }
- sub := &subprocess{
- cmd: cmd,
- stdin: stdin,
- stdout: stdout,
- input: bufio.NewWriter(stdin),
- scanner: bufio.NewScanner(stdout),
- }
- if s.subprocs == nil {
- s.subprocs = make(map[string]*subprocess)
- }
- s.subprocs[bin] = sub
- return sub, nil
-}
-
-func symbolize(interner *Interner, input *bufio.Writer, scanner *bufio.Scanner, pcs []uint64) ([]Frame, error) {
- var frames []Frame
- done := make(chan error, 1)
- go func() {
- var err error
- defer func() {
- done <- err
- }()
- if !scanner.Scan() {
- if err = scanner.Err(); err == nil {
- err = io.EOF
- }
- return
- }
- for range pcs {
- var frames1 []Frame
- frames1, err = parse(interner, scanner)
- if err != nil {
- return
- }
- frames = append(frames, frames1...)
- }
- for i := 0; i < 2; i++ {
- scanner.Scan()
- }
- }()
-
- for _, pc := range pcs {
- if _, err := fmt.Fprintf(input, "0x%x\n", pc); err != nil {
- return nil, err
- }
- }
- // Write an invalid PC so that parse doesn't block reading input.
- // We read out result for this PC at the end of the function.
- if _, err := fmt.Fprintf(input, "0xffffffffffffffff\n"); err != nil {
- return nil, err
- }
- input.Flush()
-
- if err := <-done; err != nil {
- return nil, err
- }
- return frames, nil
+type Symbolizer interface {
+ Symbolize(bin string, pcs ...uint64) ([]Frame, error)
+ Close()
}
-func parse(interner *Interner, s *bufio.Scanner) ([]Frame, error) {
- pc, err := strconv.ParseUint(s.Text(), 0, 64)
- if err != nil {
- return nil, fmt.Errorf("failed to parse pc '%v' in addr2line output: %w", s.Text(), err)
- }
- var frames []Frame
- for {
- if !s.Scan() {
- break
- }
- ln := s.Text()
- if len(ln) > 3 && ln[0] == '0' && ln[1] == 'x' {
- break
- }
- fn := ln
- if !s.Scan() {
- err := s.Err()
- if err == nil {
- err = io.EOF
- }
- return nil, fmt.Errorf("failed to read file:line from addr2line: %w", err)
- }
- ln = s.Text()
- colon := strings.LastIndexByte(ln, ':')
- if colon == -1 {
- return nil, fmt.Errorf("failed to parse file:line in addr2line output: %v", ln)
- }
- lineEnd := colon + 1
- for lineEnd < len(ln) && ln[lineEnd] >= '0' && ln[lineEnd] <= '9' {
- lineEnd++
- }
- file := ln[:colon]
- line, err := strconv.Atoi(ln[colon+1 : lineEnd])
- if err != nil || fn == "" || fn == "??" || file == "" || file == "??" || line <= 0 {
- continue
- }
- frames = append(frames, Frame{
- PC: pc,
- Func: interner.Do(fn),
- File: interner.Do(file),
- Line: line,
- Inline: true,
- })
- }
- if err := s.Err(); err != nil {
- return nil, err
- }
- if len(frames) != 0 {
- frames[len(frames)-1].Inline = false
- }
- return frames, nil
+func Make(target *targets.Target) Symbolizer {
+ return &addr2Line{target: target}
}