@@ -89,10 +89,10 @@ type exe interface {
89
89
// ReadData reads and returns up to size bytes starting at virtual address addr.
90
90
ReadData (addr , size uint64 ) ([]byte , error )
91
91
92
- // DataStart returns the virtual address of the segment or section that
92
+ // DataStart returns the virtual address and size of the segment or section that
93
93
// should contain build information. This is either a specially named section
94
94
// or the first writable non-zero data segment.
95
- DataStart () uint64
95
+ DataStart () ( uint64 , uint64 )
96
96
}
97
97
98
98
// readRawBuildInfo extracts the Go toolchain version and module information
@@ -148,13 +148,16 @@ func readRawBuildInfo(r io.ReaderAt) (vers, mod string, err error) {
148
148
return "" , "" , errUnrecognizedFormat
149
149
}
150
150
151
- // Read the first 64kB of dataAddr to find the build info blob.
151
+ // Read segment or section to find the build info blob.
152
152
// On some platforms, the blob will be in its own section, and DataStart
153
153
// returns the address of that section. On others, it's somewhere in the
154
154
// data segment; the linker puts it near the beginning.
155
155
// See cmd/link/internal/ld.Link.buildinfo.
156
- dataAddr := x .DataStart ()
157
- data , err := x .ReadData (dataAddr , 64 * 1024 )
156
+ dataAddr , dataSize := x .DataStart ()
157
+ if dataSize == 0 {
158
+ return "" , "" , errNotGoExe
159
+ }
160
+ data , err := x .ReadData (dataAddr , dataSize )
158
161
if err != nil {
159
162
return "" , "" , err
160
163
}
@@ -234,7 +237,7 @@ func hasPlan9Magic(magic []byte) bool {
234
237
235
238
func decodeString (data []byte ) (s string , rest []byte ) {
236
239
u , n := binary .Uvarint (data )
237
- if n <= 0 || u >= uint64 (len (data )- n ) {
240
+ if n <= 0 || u > uint64 (len (data )- n ) {
238
241
return "" , nil
239
242
}
240
243
return string (data [n : uint64 (n )+ u ]), data [uint64 (n )+ u :]
@@ -273,18 +276,18 @@ func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) {
273
276
return nil , errUnrecognizedFormat
274
277
}
275
278
276
- func (x * elfExe ) DataStart () uint64 {
279
+ func (x * elfExe ) DataStart () ( uint64 , uint64 ) {
277
280
for _ , s := range x .f .Sections {
278
281
if s .Name == ".go.buildinfo" {
279
- return s .Addr
282
+ return s .Addr , s . Size
280
283
}
281
284
}
282
285
for _ , p := range x .f .Progs {
283
286
if p .Type == elf .PT_LOAD && p .Flags & (elf .PF_X | elf .PF_W ) == elf .PF_W {
284
- return p .Vaddr
287
+ return p .Vaddr , p . Memsz
285
288
}
286
289
}
287
- return 0
290
+ return 0 , 0
288
291
}
289
292
290
293
// peExe is the PE (Windows Portable Executable) implementation of the exe interface.
@@ -316,7 +319,7 @@ func (x *peExe) ReadData(addr, size uint64) ([]byte, error) {
316
319
return nil , errUnrecognizedFormat
317
320
}
318
321
319
- func (x * peExe ) DataStart () uint64 {
322
+ func (x * peExe ) DataStart () ( uint64 , uint64 ) {
320
323
// Assume data is first writable section.
321
324
const (
322
325
IMAGE_SCN_CNT_CODE = 0x00000020
@@ -332,10 +335,10 @@ func (x *peExe) DataStart() uint64 {
332
335
for _ , sect := range x .f .Sections {
333
336
if sect .VirtualAddress != 0 && sect .Size != 0 &&
334
337
sect .Characteristics &^IMAGE_SCN_ALIGN_32BYTES == IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE {
335
- return uint64 (sect .VirtualAddress ) + x .imageBase ()
338
+ return uint64 (sect .VirtualAddress ) + x .imageBase (), uint64 ( sect . VirtualSize )
336
339
}
337
340
}
338
- return 0
341
+ return 0 , 0
339
342
}
340
343
341
344
// machoExe is the Mach-O (Apple macOS/iOS) implementation of the exe interface.
@@ -363,22 +366,22 @@ func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) {
363
366
return nil , errUnrecognizedFormat
364
367
}
365
368
366
- func (x * machoExe ) DataStart () uint64 {
369
+ func (x * machoExe ) DataStart () ( uint64 , uint64 ) {
367
370
// Look for section named "__go_buildinfo".
368
371
for _ , sec := range x .f .Sections {
369
372
if sec .Name == "__go_buildinfo" {
370
- return sec .Addr
373
+ return sec .Addr , sec . Size
371
374
}
372
375
}
373
376
// Try the first non-empty writable segment.
374
377
const RW = 3
375
378
for _ , load := range x .f .Loads {
376
379
seg , ok := load .(* macho.Segment )
377
380
if ok && seg .Addr != 0 && seg .Filesz != 0 && seg .Prot == RW && seg .Maxprot == RW {
378
- return seg .Addr
381
+ return seg .Addr , seg . Memsz
379
382
}
380
383
}
381
- return 0
384
+ return 0 , 0
382
385
}
383
386
384
387
// xcoffExe is the XCOFF (AIX eXtended COFF) implementation of the exe interface.
@@ -399,23 +402,23 @@ func (x *xcoffExe) ReadData(addr, size uint64) ([]byte, error) {
399
402
return nil , errors .New ("address not mapped" )
400
403
}
401
404
402
- func (x * xcoffExe ) DataStart () uint64 {
405
+ func (x * xcoffExe ) DataStart () ( uint64 , uint64 ) {
403
406
if s := x .f .SectionByType (xcoff .STYP_DATA ); s != nil {
404
- return s .VirtualAddress
407
+ return s .VirtualAddress , s . Size
405
408
}
406
- return 0
409
+ return 0 , 0
407
410
}
408
411
409
412
// plan9objExe is the Plan 9 a.out implementation of the exe interface.
410
413
type plan9objExe struct {
411
414
f * plan9obj.File
412
415
}
413
416
414
- func (x * plan9objExe ) DataStart () uint64 {
417
+ func (x * plan9objExe ) DataStart () ( uint64 , uint64 ) {
415
418
if s := x .f .Section ("data" ); s != nil {
416
- return uint64 (s .Offset )
419
+ return uint64 (s .Offset ), uint64 ( s . Size )
417
420
}
418
- return 0
421
+ return 0 , 0
419
422
}
420
423
421
424
func (x * plan9objExe ) ReadData (addr , size uint64 ) ([]byte , error ) {
0 commit comments