aboutsummaryrefslogtreecommitdiff
path: root/src/debug
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2021-12-06 13:38:04 -0500
committerRuss Cox <rsc@golang.org>2021-12-07 20:14:56 +0000
commitb37a5391f9e452aa779205add12bd89f44e3fcf0 (patch)
tree38489628da587462da8fc40a7e39173e9aaca7e1 /src/debug
parent4300f105147dc0da9d1034704ad1cd24bedde5da (diff)
downloadgo-b37a5391f9e452aa779205add12bd89f44e3fcf0.tar.gz
go-b37a5391f9e452aa779205add12bd89f44e3fcf0.zip
cmd/link, cmd/go: make version info easier to extract
Reading the version information to date has required evaluating two pointers to strings (which themselves contain pointers to data), which means applying relocations, which can be very system-dependent. To simplify the lookup, inline the string data into the build info blob. This makes go version work on binaries built with external linking on darwin/arm64. Also test that at least the very basics work on a trivial binary, even in short mode. Change-Id: I463088c19e837ae0ce57e1278c7b72e74a80b2c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/369977 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/buildinfo/buildinfo.go54
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))