| // Copyright 2016 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| 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 | |
| SectionNumber int16 | |
| Type uint16 | |
| StorageClass uint8 | |
| NumberOfAuxSymbols uint8 | |
| } | |
| func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) { | |
| if fh.PointerToSymbolTable == 0 { | |
| return nil, nil | |
| } | |
| if fh.NumberOfSymbols <= 0 { | |
| return nil, nil | |
| } | |
| _, err := r.Seek(int64(fh.PointerToSymbolTable), 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 | |
| SectionNumber int16 | |
| Type uint16 | |
| StorageClass uint8 | |
| } |