aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/note.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/go/note.go')
-rw-r--r--src/cmd/go/note.go40
1 files changed, 40 insertions, 0 deletions
diff --git a/src/cmd/go/note.go b/src/cmd/go/note.go
index 97e18651e4..f8d6588b73 100644
--- a/src/cmd/go/note.go
+++ b/src/cmd/go/note.go
@@ -7,6 +7,7 @@ package main
import (
"bytes"
"debug/elf"
+ "debug/macho"
"encoding/binary"
"fmt"
"io"
@@ -114,3 +115,42 @@ func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string,
// No note. Treat as successful but build ID empty.
return "", nil
}
+
+// The Go build ID is stored at the beginning of the Mach-O __text segment.
+// The caller has already opened filename, to get f, and read a few kB out, in data.
+// Sadly, that's not guaranteed to hold the note, because there is an arbitrary amount
+// of other junk placed in the file ahead of the main text.
+func readMachoGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) {
+ // If the data we want has already been read, don't worry about Mach-O parsing.
+ // This is both an optimization and a hedge against the Mach-O parsing failing
+ // in the future due to, for example, the name of the __text section changing.
+ if b, err := readRawGoBuildID(filename, data); b != "" && err == nil {
+ return b, err
+ }
+
+ mf, err := macho.NewFile(f)
+ if err != nil {
+ return "", &os.PathError{Path: filename, Op: "parse", Err: err}
+ }
+
+ sect := mf.Section("__text")
+ if sect == nil {
+ // Every binary has a __text section. Something is wrong.
+ return "", &os.PathError{Path: filename, Op: "parse", Err: fmt.Errorf("cannot find __text section")}
+ }
+
+ // It should be in the first few bytes, but read a lot just in case,
+ // especially given our past problems on OS X with the build ID moving.
+ // There shouldn't be much difference between reading 4kB and 32kB:
+ // the hard part is getting to the data, not transferring it.
+ n := sect.Size
+ if n > uint64(BuildIDReadSize) {
+ n = uint64(BuildIDReadSize)
+ }
+ buf := make([]byte, n)
+ if _, err := f.ReadAt(buf, int64(sect.Offset)); err != nil {
+ return "", err
+ }
+
+ return readRawGoBuildID(filename, buf)
+}