aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-04-09 10:29:06 +0200
committerDmitry Vyukov <dvyukov@google.com>2024-04-09 12:15:39 +0000
commitb3198cd94cc221153d34443bc657c799ec47a2ed (patch)
tree32f1a630a8aaafadd345b5c368e6c7ed35f6daef
parente38e134c4df9e4b637ba5140cff0904ebe5491b1 (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.go28
-rw-r--r--sys/targets/targets.go48
-rw-r--r--tools/docker/syzbot/Dockerfile1
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