2016-07-22 20:15:38 +02:00
|
|
|
// 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) {
|
2017-01-14 01:05:42 +01:00
|
|
|
if fh.PointerToSymbolTable == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2016-07-22 20:15:38 +02:00
|
|
|
if fh.NumberOfSymbols <= 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2017-01-14 01:05:42 +01:00
|
|
|
_, err := r.Seek(int64(fh.PointerToSymbolTable), seekStart)
|
2016-07-22 20:15:38 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-01-14 01:05:42 +01:00
|
|
|
// FullName finds real name of symbol sym. Normally name is stored
|
2016-07-22 20:15:38 +02:00
|
|
|
// in sym.Name, but if it is longer then 8 characters, it is stored
|
|
|
|
// in COFF string table st instead.
|
2017-01-14 01:05:42 +01:00
|
|
|
func (sym *COFFSymbol) FullName(st StringTable) (string, error) {
|
2016-07-22 20:15:38 +02:00
|
|
|
if ok, offset := isSymNameOffset(sym.Name); ok {
|
|
|
|
return st.String(offset)
|
|
|
|
}
|
|
|
|
return cstring(sym.Name[:]), nil
|
|
|
|
}
|
|
|
|
|
2017-01-14 01:05:42 +01:00
|
|
|
func removeAuxSymbols(allsyms []COFFSymbol, st StringTable) ([]*Symbol, error) {
|
2016-07-22 20:15:38 +02:00
|
|
|
if len(allsyms) == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
syms := make([]*Symbol, 0)
|
|
|
|
aux := uint8(0)
|
|
|
|
for _, sym := range allsyms {
|
|
|
|
if aux > 0 {
|
|
|
|
aux--
|
|
|
|
continue
|
|
|
|
}
|
2017-01-14 01:05:42 +01:00
|
|
|
name, err := sym.FullName(st)
|
2016-07-22 20:15:38 +02:00
|
|
|
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
|
|
|
|
}
|