]> Cypherpunks repositories - gostls13.git/commitdiff
debug/pe: introduce File.COFFSymbols and (*COFFSymbol).FullName
authorAlex Brainman <alex.brainman@gmail.com>
Thu, 21 Apr 2016 06:51:36 +0000 (16:51 +1000)
committerAlex Brainman <alex.brainman@gmail.com>
Sun, 24 Apr 2016 01:37:03 +0000 (01:37 +0000)
Reloc.SymbolTableIndex is an index into symbol table. But
Reloc.SymbolTableIndex cannot be used as index into File.Symbols,
because File.Symbols slice has Aux lines removed as it is built.

We cannot change the way File.Symbols works, so I propose we
introduce new File.COFFSymbols that does not have that limitation.

Also unlike File.Symbols, File.COFFSymbols will consist of
COFFSymbol. COFFSymbol matches PE COFF specification exactly,
and it is simpler to use.

Updates #15345

Change-Id: Icbc265853a472529cd6d64a76427b27e5459e373
Reviewed-on: https://go-review.googlesource.com/22336
Reviewed-by: David Crawshaw <crawshaw@golang.org>
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/debug/pe/file.go
src/debug/pe/section.go
src/debug/pe/symbol.go

index cfd8e08a6384a276cf0de95f0a5f95f1905c5bf1..abc33dfea89a73ce9dae69de0f3a52a4b41007e3 100644 (file)
@@ -19,7 +19,8 @@ type File struct {
        FileHeader
        OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
        Sections       []*Section
-       Symbols        []*Symbol
+       Symbols        []*Symbol    // COFF symbols with auxiliary symbol records removed
+       COFFSymbols    []COFFSymbol // all COFF symbols (including auxiliary symbol records)
        StringTable    StringTable
 
        closer io.Closer
@@ -94,48 +95,14 @@ func NewFile(r io.ReaderAt) (*File, error) {
                return nil, err
        }
 
-       var ss []byte
-       if f.FileHeader.NumberOfSymbols > 0 {
-               // Get COFF string table, which is located at the end of the COFF symbol table.
-               sr.Seek(int64(f.FileHeader.PointerToSymbolTable+COFFSymbolSize*f.FileHeader.NumberOfSymbols), io.SeekStart)
-               var l uint32
-               if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
-                       return nil, err
-               }
-               ss = make([]byte, l)
-               if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+COFFSymbolSize*f.FileHeader.NumberOfSymbols)); err != nil {
-                       return nil, err
-               }
-
-               // Process COFF symbol table.
-               sr.Seek(int64(f.FileHeader.PointerToSymbolTable), io.SeekStart)
-               aux := uint8(0)
-               for i := 0; i < int(f.FileHeader.NumberOfSymbols); i++ {
-                       cs := new(COFFSymbol)
-                       if err := binary.Read(sr, binary.LittleEndian, cs); err != nil {
-                               return nil, err
-                       }
-                       if aux > 0 {
-                               aux--
-                               continue
-                       }
-                       var name string
-                       if cs.Name[0] == 0 && cs.Name[1] == 0 && cs.Name[2] == 0 && cs.Name[3] == 0 {
-                               si := int(binary.LittleEndian.Uint32(cs.Name[4:]))
-                               name, _ = getString(ss, si)
-                       } else {
-                               name = cstring(cs.Name[:])
-                       }
-                       aux = cs.NumberOfAuxSymbols
-                       s := &Symbol{
-                               Name:          name,
-                               Value:         cs.Value,
-                               SectionNumber: cs.SectionNumber,
-                               Type:          cs.Type,
-                               StorageClass:  cs.StorageClass,
-                       }
-                       f.Symbols = append(f.Symbols, s)
-               }
+       // Read symbol table.
+       f.COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr)
+       if err != nil {
+               return nil, err
+       }
+       f.Symbols, err = removeAuxSymbols(f.COFFSymbols, f.StringTable)
+       if err != nil {
+               return nil, err
        }
 
        // Read optional header.
index 69fe41fd7a4d85d01f0ee92194e4df66f5913c58..5d881577d3985d408d00da23d417a4a484789bb8 100644 (file)
@@ -39,6 +39,8 @@ func (sh *SectionHeader32) fullName(st StringTable) (string, error) {
        return st.String(uint32(i))
 }
 
+// TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here
+
 // Reloc represents a PE COFF relocation.
 // Each section contains its own relocation list.
 type Reloc struct {
index 559174838cfbff262b49debdbb677acf3963db1b..3cf5a101e74676253499e3a71ef9c5a2b8721e25 100644 (file)
@@ -4,8 +4,15 @@
 
 package pe
 
+import (
+       "encoding/binary"
+       "fmt"
+       "io"
+)
+
 const COFFSymbolSize = 18
 
+// COFFSymbol represents single COFF symbol table record.
 type COFFSymbol struct {
        Name               [8]uint8
        Value              uint32
@@ -15,6 +22,70 @@ type COFFSymbol struct {
        NumberOfAuxSymbols uint8
 }
 
+func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
+       if fh.NumberOfSymbols <= 0 {
+               return nil, nil
+       }
+       _, err := r.Seek(int64(fh.PointerToSymbolTable), io.SeekStart)
+       if err != nil {
+               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)
+       }
+       return syms, nil
+}
+
+// isSymNameOffset checks symbol name if it is encoded as offset into string table.
+func isSymNameOffset(name [8]byte) (bool, uint32) {
+       if name[0] == 0 && name[1] == 0 && name[2] == 0 && name[3] == 0 {
+               return true, binary.LittleEndian.Uint32(name[4:])
+       }
+       return false, 0
+}
+
+// FullName finds real name of symbol sym. Normally name is stored
+// in sym.Name, but if it is longer then 8 characters, it is stored
+// in COFF string table st instead.
+func (sym *COFFSymbol) FullName(st StringTable) (string, error) {
+       if ok, offset := isSymNameOffset(sym.Name); ok {
+               return st.String(offset)
+       }
+       return cstring(sym.Name[:]), nil
+}
+
+func removeAuxSymbols(allsyms []COFFSymbol, st StringTable) ([]*Symbol, error) {
+       if len(allsyms) == 0 {
+               return nil, nil
+       }
+       syms := make([]*Symbol, 0)
+       aux := uint8(0)
+       for _, sym := range allsyms {
+               if aux > 0 {
+                       aux--
+                       continue
+               }
+               name, err := sym.FullName(st)
+               if err != nil {
+                       return nil, err
+               }
+               aux = sym.NumberOfAuxSymbols
+               s := &Symbol{
+                       Name:          name,
+                       Value:         sym.Value,
+                       SectionNumber: sym.SectionNumber,
+                       Type:          sym.Type,
+                       StorageClass:  sym.StorageClass,
+               }
+               syms = append(syms, s)
+       }
+       return syms, nil
+}
+
+// Symbol is similar to COFFSymbol with Name field replaced
+// by Go string. Symbol also does not have NumberOfAuxSymbols.
 type Symbol struct {
        Name          string
        Value         uint32