aboutsummaryrefslogtreecommitdiffstats
path: root/sys
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 /sys
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.
Diffstat (limited to 'sys')
-rw-r--r--sys/targets/targets.go48
1 files changed, 48 insertions, 0 deletions
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 {