diff options
Diffstat (limited to 'src/debug')
| -rw-r--r-- | src/debug/buildinfo/buildinfo.go | 54 |
1 files changed, 38 insertions, 16 deletions
diff --git a/src/debug/buildinfo/buildinfo.go b/src/debug/buildinfo/buildinfo.go index f84429a342..2c0200e8dc 100644 --- a/src/debug/buildinfo/buildinfo.go +++ b/src/debug/buildinfo/buildinfo.go @@ -146,12 +146,18 @@ func readRawBuildInfo(r io.ReaderAt) (vers, mod string, err error) { } const ( buildInfoAlign = 16 - buildinfoSize = 32 + buildInfoSize = 32 ) - for ; !bytes.HasPrefix(data, buildInfoMagic); data = data[buildInfoAlign:] { - if len(data) < 32 { + for { + i := bytes.Index(data, buildInfoMagic) + if i < 0 || len(data)-i < buildInfoSize { return "", "", errNotGoExe } + if i%buildInfoAlign == 0 && len(data)-i >= buildInfoSize { + data = data[i:] + break + } + data = data[(i+buildInfoAlign-1)&^buildInfoAlign:] } // Decode the blob. @@ -161,25 +167,33 @@ func readRawBuildInfo(r io.ReaderAt) (vers, mod string, err error) { // Two virtual addresses to Go strings follow that: runtime.buildVersion, // and runtime.modinfo. // On 32-bit platforms, the last 8 bytes are unused. + // If the endianness has the 2 bit set, then the pointers are zero + // and the 32-byte header is followed by varint-prefixed string data + // for the two string values we care about. ptrSize := int(data[14]) - bigEndian := data[15] != 0 - var bo binary.ByteOrder - if bigEndian { - bo = binary.BigEndian - } else { - bo = binary.LittleEndian - } - var readPtr func([]byte) uint64 - if ptrSize == 4 { - readPtr = func(b []byte) uint64 { return uint64(bo.Uint32(b)) } + if data[15]&2 != 0 { + vers, data = decodeString(data[32:]) + mod, data = decodeString(data) } else { - readPtr = bo.Uint64 + bigEndian := data[15] != 0 + var bo binary.ByteOrder + if bigEndian { + bo = binary.BigEndian + } else { + bo = binary.LittleEndian + } + var readPtr func([]byte) uint64 + if ptrSize == 4 { + readPtr = func(b []byte) uint64 { return uint64(bo.Uint32(b)) } + } else { + readPtr = bo.Uint64 + } + vers = readString(x, ptrSize, readPtr, readPtr(data[16:])) + mod = readString(x, ptrSize, readPtr, readPtr(data[16+ptrSize:])) } - vers = readString(x, ptrSize, readPtr, readPtr(data[16:])) if vers == "" { return "", "", errNotGoExe } - mod = readString(x, ptrSize, readPtr, readPtr(data[16+ptrSize:])) if len(mod) >= 33 && mod[len(mod)-17] == '\n' { // Strip module framing: sentinel strings delimiting the module info. // These are cmd/go/internal/modload.infoStart and infoEnd. @@ -191,6 +205,14 @@ func readRawBuildInfo(r io.ReaderAt) (vers, mod string, err error) { return vers, mod, nil } +func decodeString(data []byte) (s string, rest []byte) { + u, n := binary.Uvarint(data) + if n <= 0 || u >= uint64(len(data)-n) { + return "", nil + } + return string(data[n : uint64(n)+u]), data[uint64(n)+u:] +} + // readString returns the string at address addr in the executable x. func readString(x exe, ptrSize int, readPtr func([]byte) uint64, addr uint64) string { hdr, err := x.ReadData(addr, uint64(2*ptrSize)) |
