From 054323d809cb15d47ca72d0deeadb5cfc2737780 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 1 Apr 2022 11:12:22 -0400 Subject: [PATCH] debug/pe: rework reading of aux symbols to fix endianity problems This patch reworks CL 394534 to fix things so that reading auxiliary symbol info works properly in a cross-endian mode (running debug/pe-based tool on a big-endian system). The previous implementation read in all symbol records using the primary symbol format, then just used a pointer cast to convert to the auxiliary format, which doesn't play well if host and target have different endianness. Fixes #52079. Change-Id: I143d94d9313a265f11ca7befd254bdb150698834 Reviewed-on: https://go-review.googlesource.com/c/go/+/397485 Run-TryBot: Than McIntosh TryBot-Result: Gopher Robot Reviewed-by: Alex Brainman Reviewed-by: Cherry Mui --- src/debug/pe/symbol.go | 51 +++++++++++++++++++++++++++++++++--- src/debug/pe/symbols_test.go | 8 ------ 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/debug/pe/symbol.go b/src/debug/pe/symbol.go index 323fa8c3df..dfbeb11414 100644 --- a/src/debug/pe/symbol.go +++ b/src/debug/pe/symbol.go @@ -23,6 +23,29 @@ type COFFSymbol struct { NumberOfAuxSymbols uint8 } +// readCOFFSymbols reads in the symbol table for a PE file, returning +// a slice of COFFSymbol objects. The PE format includes both primary +// symbols (whose fields are described by COFFSymbol above) and +// auxiliary symbols; all symbols are 18 bytes in size. The auxiliary +// symbols for a given primary symbol are placed following it in the +// array, e.g. +// +// ... +// k+0: regular sym k +// k+1: 1st aux symbol for k +// k+2: 2nd aux symbol for k +// k+3: regular sym k+3 +// k+4: 1st aux symbol for k+3 +// k+5: regular sym k+5 +// k+6: regular sym k+6 +// +// The PE format allows for several possible aux symbol formats. For +// more info see: +// +// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-symbol-records +// +// At the moment this package only provides APIs for looking at +// aux symbols of format 5 (associated with section definition symbols). func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) { if fh.PointerToSymbolTable == 0 { return nil, nil @@ -35,9 +58,31 @@ func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) { return nil, fmt.Errorf("fail to seek to symbol table: %v", err) } syms := make([]COFFSymbol, fh.NumberOfSymbols) - err = binary.Read(r, binary.LittleEndian, syms) - if err != nil { - return nil, fmt.Errorf("fail to read symbol table: %v", err) + naux := 0 + for k := range syms { + if naux == 0 { + // Read a primary symbol. + err = binary.Read(r, binary.LittleEndian, &syms[k]) + if err != nil { + return nil, fmt.Errorf("fail to read symbol table: %v", err) + } + // Record how many auxiliary symbols it has. + naux = int(syms[k].NumberOfAuxSymbols) + } else { + // Read an aux symbol. At the moment we assume all + // aux symbols are format 5 (obviously this doesn't always + // hold; more cases will be needed below if more aux formats + // are supported in the future). + naux-- + aux := (*COFFSymbolAuxFormat5)(unsafe.Pointer(&syms[k])) + err = binary.Read(r, binary.LittleEndian, aux) + if err != nil { + return nil, fmt.Errorf("fail to read symbol table: %v", err) + } + } + } + if naux != 0 { + return nil, fmt.Errorf("fail to read symbol table: %d aux symbols unread", naux) } return syms, nil } diff --git a/src/debug/pe/symbols_test.go b/src/debug/pe/symbols_test.go index 5ccf635830..c4dcd95391 100644 --- a/src/debug/pe/symbols_test.go +++ b/src/debug/pe/symbols_test.go @@ -6,7 +6,6 @@ package pe import ( "fmt" - "runtime" "testing" ) @@ -18,13 +17,6 @@ type testpoint struct { } func TestReadCOFFSymbolAuxInfo(t *testing.T) { - - switch runtime.GOARCH { - case "mips", "mips64", "ppc64", "s390x": - t.Skipf("Skipping on %s (big endian) until issue #52079 fixed", - runtime.GOARCH) - } - testpoints := map[int]testpoint{ 39: testpoint{ name: ".rdata$.refptr.__native_startup_lock",