diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2024-04-09 10:29:06 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2024-04-09 12:15:39 +0000 |
| commit | b3198cd94cc221153d34443bc657c799ec47a2ed (patch) | |
| tree | 32f1a630a8aaafadd345b5c368e6c7ed35f6daef | |
| parent | e38e134c4df9e4b637ba5140cff0904ebe5491b1 (diff) | |
pkg/symbolizer: use llvm-addr2line
Use llvm-addr2line instead of addr2line if it's available.
llvm-addr2line seems to be way faster than llvm-addr2line
and consumes less memory on syzbot's vmlinux.
Also move the detection logic to sys/targets since that's
where we generally do this type of logic. This also allows
to reuse addr2line binary in other packages if needed.
| -rw-r--r-- | pkg/symbolizer/symbolizer.go | 28 | ||||
| -rw-r--r-- | sys/targets/targets.go | 48 | ||||
| -rw-r--r-- | tools/docker/syzbot/Dockerfile | 1 |
3 files changed, 50 insertions, 27 deletions
diff --git a/pkg/symbolizer/symbolizer.go b/pkg/symbolizer/symbolizer.go index fb378d09f..ad57f005e 100644 --- a/pkg/symbolizer/symbolizer.go +++ b/pkg/symbolizer/symbolizer.go @@ -7,10 +7,8 @@ package symbolizer import ( "bufio" - "bytes" "fmt" "io" - "os" "os/exec" "strconv" "strings" @@ -65,35 +63,11 @@ func (s *Symbolizer) Close() { } } -func (s *Symbolizer) checkBinSupport(addr2line string) error { - if s.target.OS != targets.Darwin || s.target.Arch != targets.AMD64 { - return nil - } - - cmd := exec.Command(addr2line, "--help") - cmd.Env = append(os.Environ(), "LC_ALL=C") - out, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("addr2line execution failed: %w", err) - } - if !bytes.Contains(out, []byte("supported targets:")) { - return fmt.Errorf("addr2line output didn't contain supported targets") - } - if !bytes.Contains(out, []byte("mach-o-x86-64")) { - return fmt.Errorf("addr2line was built without mach-o-x86-64 support") - } - return nil -} - func (s *Symbolizer) getSubprocess(bin string) (*subprocess, error) { if sub := s.subprocs[bin]; sub != nil { return sub, nil } - addr2line := "addr2line" - if s.target.Triple != "" { - addr2line = s.target.Triple + "-" + addr2line - } - err := s.checkBinSupport(addr2line) + addr2line, err := s.target.Addr2Line() if err != nil { return nil, err } diff --git a/sys/targets/targets.go b/sys/targets/targets.go index 9a5c82948..d7488fcb5 100644 --- a/sys/targets/targets.go +++ b/sys/targets/targets.go @@ -4,6 +4,7 @@ package targets import ( + "bytes" "encoding/binary" "fmt" "os" @@ -38,6 +39,7 @@ type Target struct { NeedSyscallDefine func(nr uint64) bool HostEndian binary.ByteOrder SyscallTrampolines map[string]string + Addr2Line func() (string, error) init *sync.Once initOther *sync.Once @@ -775,6 +777,52 @@ func initTarget(target *Target, OS, arch string) { target.ExecutorUsesForkServer = false target.HostFuzzer = true } + target.initAddr2Line() +} + +func (target *Target) initAddr2Line() { + // Initialize addr2line lazily since lots of tests don't need it, + // but we invoke a number of external binaries during addr2line detection. + var ( + init sync.Once + bin string + err error + ) + target.Addr2Line = func() (string, error) { + init.Do(func() { bin, err = target.findAddr2Line() }) + return bin, err + } +} + +func (target *Target) findAddr2Line() (string, error) { + // Try llvm-addr2line first as it's significantly faster on large binaries. + // But it's unclear if it works for darwin binaries. + if target.OS != Darwin { + if path, err := exec.LookPath("llvm-addr2line"); err == nil { + return path, nil + } + } + bin := "addr2line" + if target.Triple != "" { + bin = target.Triple + "-" + bin + } + if target.OS != Darwin || target.Arch != AMD64 { + return bin, nil + } + // A special check for darwin kernel to produce a more useful error. + cmd := exec.Command(bin, "--help") + cmd.Env = append(os.Environ(), "LC_ALL=C") + out, err := cmd.CombinedOutput() + if err != nil { + return "", fmt.Errorf("addr2line execution failed: %w", err) + } + if !bytes.Contains(out, []byte("supported targets:")) { + return "", fmt.Errorf("addr2line output didn't contain supported targets") + } + if !bytes.Contains(out, []byte("mach-o-x86-64")) { + return "", fmt.Errorf("addr2line was built without mach-o-x86-64 support") + } + return bin, nil } func (target *Target) Timeouts(slowdown int) Timeouts { diff --git a/tools/docker/syzbot/Dockerfile b/tools/docker/syzbot/Dockerfile index e80a41e59..ececc2f2a 100644 --- a/tools/docker/syzbot/Dockerfile +++ b/tools/docker/syzbot/Dockerfile @@ -45,6 +45,7 @@ RUN sudo update-alternatives --install /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm RUN sudo update-alternatives --install /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-15 100 RUN sudo update-alternatives --install /usr/bin/llvm-objcopy llvm-objcopy /usr/bin/llvm-objcopy-15 100 RUN sudo update-alternatives --install /usr/bin/llvm-objdump llvm-objdump /usr/bin/llvm-objdump-15 100 +RUN sudo update-alternatives --install /usr/bin/llvm-addr2line llvm-addr2line /usr/bin/llvm-addr2line-15 100 # Not really GRTE, but it's enough to run some scripts that hardcode the path. RUN mkdir -p /usr/grte/v5/bin && ln -s /usr/bin/python3 /usr/grte/v5/bin/python2.7 |
