diff options
Diffstat (limited to 'src/cmd/go/note.go')
-rw-r--r-- | src/cmd/go/note.go | 40 |
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) +} |