// 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 peimport ()constCOFFSymbolSize = 18// COFFSymbol represents single COFF symbol table record.typeCOFFSymbolstruct { 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( *FileHeader, io.ReadSeeker) ([]COFFSymbol, error) {if .PointerToSymbolTable == 0 {returnnil, nil }if .NumberOfSymbols <= 0 {returnnil, nil } , := .Seek(int64(.PointerToSymbolTable), io.SeekStart)if != nil {returnnil, fmt.Errorf("fail to seek to symbol table: %v", ) } := saferio.SliceCap[COFFSymbol](uint64(.NumberOfSymbols))if < 0 {returnnil, errors.New("too many symbols; file may be corrupt") } := make([]COFFSymbol, 0, ) := 0for := uint32(0); < .NumberOfSymbols; ++ {varCOFFSymbolif == 0 {// Read a primary symbol. = binary.Read(, binary.LittleEndian, &)if != nil {returnnil, fmt.Errorf("fail to read symbol table: %v", ) }// Record how many auxiliary symbols it has. = int(.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). -- := (*COFFSymbolAuxFormat5)(unsafe.Pointer(&)) = binary.Read(, binary.LittleEndian, )if != nil {returnnil, fmt.Errorf("fail to read symbol table: %v", ) } } = append(, ) }if != 0 {returnnil, fmt.Errorf("fail to read symbol table: %d aux symbols unread", ) }return , nil}// isSymNameOffset checks symbol name if it is encoded as offset into string table.func isSymNameOffset( [8]byte) (bool, uint32) {if [0] == 0 && [1] == 0 && [2] == 0 && [3] == 0 {returntrue, binary.LittleEndian.Uint32([4:]) }returnfalse, 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 ( *COFFSymbol) ( StringTable) (string, error) {if , := isSymNameOffset(.Name); {return .String() }returncstring(.Name[:]), nil}func removeAuxSymbols( []COFFSymbol, StringTable) ([]*Symbol, error) {iflen() == 0 {returnnil, nil } := make([]*Symbol, 0) := uint8(0)for , := range {if > 0 { --continue } , := .FullName()if != nil {returnnil, } = .NumberOfAuxSymbols := &Symbol{Name: ,Value: .Value,SectionNumber: .SectionNumber,Type: .Type,StorageClass: .StorageClass, } = append(, ) }return , nil}// Symbol is similar to [COFFSymbol] with Name field replaced// by Go string. Symbol also does not have NumberOfAuxSymbols.typeSymbolstruct { 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.typeCOFFSymbolAuxFormat5struct { 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 = 1IMAGE_COMDAT_SELECT_ANY = 2IMAGE_COMDAT_SELECT_SAME_SIZE = 3IMAGE_COMDAT_SELECT_EXACT_MATCH = 4IMAGE_COMDAT_SELECT_ASSOCIATIVE = 5IMAGE_COMDAT_SELECT_LARGEST = 6)// COFFSymbolReadSectionDefAux returns a blob of auxiliary 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-definitionsfunc ( *File) ( int) (*COFFSymbolAuxFormat5, error) {var *COFFSymbolAuxFormat5if < 0 || >= len(.COFFSymbols) {return , fmt.Errorf("invalid symbol index") } := &.COFFSymbols[]const = 3if .StorageClass != uint8() {return , fmt.Errorf("incorrect symbol storage class") }if .NumberOfAuxSymbols == 0 || +1 >= len(.COFFSymbols) {return , fmt.Errorf("aux symbol unavailable") }// Locate and return a pointer to the successor aux symbol. := &.COFFSymbols[+1] = (*COFFSymbolAuxFormat5)(unsafe.Pointer())return , nil}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.