mirror of https://github.com/golang/go.git
157 lines
4.8 KiB
Go
157 lines
4.8 KiB
Go
// 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"
|
|
"unsafe"
|
|
)
|
|
|
|
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
|
|
}
|
|
|
|
// COFFSymbolAuxFormat5 describes the expected form of an aux symbol
|
|
// attached to a section definition symbol. The PE format defines a
|
|
// number of different aux symbol formats: format 1 for function
|
|
// definitions, format 2 for .be and .ef symbols, and so on. Format 5
|
|
// holds extra info associated with a section definition, including
|
|
// number of relocations + line numbers, as well as COMDAT info. See
|
|
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
|
|
// for more on what's going on here.
|
|
type COFFSymbolAuxFormat5 struct {
|
|
Size uint32
|
|
NumRelocs uint16
|
|
NumLineNumbers uint16
|
|
Checksum uint32
|
|
SecNum uint16
|
|
Selection uint8
|
|
_ [3]uint8 // padding
|
|
}
|
|
|
|
// These constants make up the possible values for the 'Selection'
|
|
// field in an AuxFormat5.
|
|
const (
|
|
IMAGE_COMDAT_SELECT_NODUPLICATES = 1
|
|
IMAGE_COMDAT_SELECT_ANY = 2
|
|
IMAGE_COMDAT_SELECT_SAME_SIZE = 3
|
|
IMAGE_COMDAT_SELECT_EXACT_MATCH = 4
|
|
IMAGE_COMDAT_SELECT_ASSOCIATIVE = 5
|
|
IMAGE_COMDAT_SELECT_LARGEST = 6
|
|
)
|
|
|
|
// COFFSymbolReadSectionDefAux returns a blob of axiliary information
|
|
// (including COMDAT info) for a section definition symbol. Here 'idx'
|
|
// is the index of a section symbol in the main COFFSymbol array for
|
|
// the File. Return value is a pointer to the appropriate aux symbol
|
|
// struct. For more info, see:
|
|
//
|
|
// auxiliary symbols: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-symbol-records
|
|
// COMDAT sections: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#comdat-sections-object-only
|
|
// auxiliary info for section definitions: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
|
|
func (f *File) COFFSymbolReadSectionDefAux(idx int) (*COFFSymbolAuxFormat5, error) {
|
|
var rv *COFFSymbolAuxFormat5
|
|
if idx < 0 || idx >= len(f.COFFSymbols) {
|
|
return rv, fmt.Errorf("invalid symbol index")
|
|
}
|
|
pesym := &f.COFFSymbols[idx]
|
|
const IMAGE_SYM_CLASS_STATIC = 3
|
|
if pesym.StorageClass != uint8(IMAGE_SYM_CLASS_STATIC) {
|
|
return rv, fmt.Errorf("incorrect symbol storage class")
|
|
}
|
|
if pesym.NumberOfAuxSymbols == 0 || idx+1 >= len(f.COFFSymbols) {
|
|
return rv, fmt.Errorf("aux symbol unavailable")
|
|
}
|
|
// Locate and return a pointer to the successor aux symbol.
|
|
pesymn := &f.COFFSymbols[idx+1]
|
|
rv = (*COFFSymbolAuxFormat5)(unsafe.Pointer(pesymn))
|
|
return rv, nil
|
|
}
|