golang symbol 代码
文件路径:/src/debug/pe/symbol.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
}
/ readCOFFSymbols reads in the symbol table for a PE file, returning
/ a slice of COFFSymbol objects. The PE format includes both primary
/ symbols (whose fields are described by COFFSymbol above) and
/ auxiliary symbols; all symbols are 18 bytes in size. The auxiliary
/ symbols for a given primary symbol are placed following it in the
/ array, e.g.
/
/ ...
/ k+0: regular sym k
/ k+1: 1st aux symbol for k
/ k+2: 2nd aux symbol for k
/ k+3: regular sym k+3
/ k+4: 1st aux symbol for k+3
/ k+5: regular sym k+5
/ k+6: regular sym k+6
/
/ The PE format allows for several possible aux symbol formats. For
/ more info see:
/
/ https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-symbol-records
/
/ At the moment this package only provides APIs for looking at
/ aux symbols of format 5 (associated with section definition symbols).
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)
naux := 0
for k := range syms {
if naux == 0 {
/ Read a primary symbol.
err = binary.Read(r, binary.LittleEndian, &syms[k])
if err != nil {
return nil, fmt.Errorf("fail to read symbol table: %v", err)
}
/ Record how many auxiliary symbols it has.
naux = int(syms[k].NumberOfAuxSymbols)
} else {
/ Read an aux symbol. At the moment we assume all
/ aux symbols are format 5 (obviously this doesn't always
/ hold; more cases will be needed below if more aux formats
/ are supported in the future).
naux--
aux := (*COFFSymbolAuxFormat5)(unsafe.Pointer(&syms[k]))
err = binary.Read(r, binary.LittleEndian, aux)
if err != nil {
return nil, fmt.Errorf("fail to read symbol table: %v", err)
}
}
}
if naux != 0 {
return nil, fmt.Errorf("fail to read symbol table: %d aux symbols unread", naux)
}
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
}