diff options
Diffstat (limited to 'pkg/symbolizer/symbolizer.go')
| -rw-r--r-- | pkg/symbolizer/symbolizer.go | 191 |
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} } |
