|  | // 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 | 
|  | } |