Home | History | Annotate | Download | only in pe
      1 // Copyright 2016 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package pe
      6 
      7 import (
      8 	"encoding/binary"
      9 	"fmt"
     10 	"io"
     11 )
     12 
     13 const COFFSymbolSize = 18
     14 
     15 // COFFSymbol represents single COFF symbol table record.
     16 type COFFSymbol struct {
     17 	Name               [8]uint8
     18 	Value              uint32
     19 	SectionNumber      int16
     20 	Type               uint16
     21 	StorageClass       uint8
     22 	NumberOfAuxSymbols uint8
     23 }
     24 
     25 func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
     26 	if fh.PointerToSymbolTable == 0 {
     27 		return nil, nil
     28 	}
     29 	if fh.NumberOfSymbols <= 0 {
     30 		return nil, nil
     31 	}
     32 	_, err := r.Seek(int64(fh.PointerToSymbolTable), seekStart)
     33 	if err != nil {
     34 		return nil, fmt.Errorf("fail to seek to symbol table: %v", err)
     35 	}
     36 	syms := make([]COFFSymbol, fh.NumberOfSymbols)
     37 	err = binary.Read(r, binary.LittleEndian, syms)
     38 	if err != nil {
     39 		return nil, fmt.Errorf("fail to read symbol table: %v", err)
     40 	}
     41 	return syms, nil
     42 }
     43 
     44 // isSymNameOffset checks symbol name if it is encoded as offset into string table.
     45 func isSymNameOffset(name [8]byte) (bool, uint32) {
     46 	if name[0] == 0 && name[1] == 0 && name[2] == 0 && name[3] == 0 {
     47 		return true, binary.LittleEndian.Uint32(name[4:])
     48 	}
     49 	return false, 0
     50 }
     51 
     52 // FullName finds real name of symbol sym. Normally name is stored
     53 // in sym.Name, but if it is longer then 8 characters, it is stored
     54 // in COFF string table st instead.
     55 func (sym *COFFSymbol) FullName(st StringTable) (string, error) {
     56 	if ok, offset := isSymNameOffset(sym.Name); ok {
     57 		return st.String(offset)
     58 	}
     59 	return cstring(sym.Name[:]), nil
     60 }
     61 
     62 func removeAuxSymbols(allsyms []COFFSymbol, st StringTable) ([]*Symbol, error) {
     63 	if len(allsyms) == 0 {
     64 		return nil, nil
     65 	}
     66 	syms := make([]*Symbol, 0)
     67 	aux := uint8(0)
     68 	for _, sym := range allsyms {
     69 		if aux > 0 {
     70 			aux--
     71 			continue
     72 		}
     73 		name, err := sym.FullName(st)
     74 		if err != nil {
     75 			return nil, err
     76 		}
     77 		aux = sym.NumberOfAuxSymbols
     78 		s := &Symbol{
     79 			Name:          name,
     80 			Value:         sym.Value,
     81 			SectionNumber: sym.SectionNumber,
     82 			Type:          sym.Type,
     83 			StorageClass:  sym.StorageClass,
     84 		}
     85 		syms = append(syms, s)
     86 	}
     87 	return syms, nil
     88 }
     89 
     90 // Symbol is similar to COFFSymbol with Name field replaced
     91 // by Go string. Symbol also does not have NumberOfAuxSymbols.
     92 type Symbol struct {
     93 	Name          string
     94 	Value         uint32
     95 	SectionNumber int16
     96 	Type          uint16
     97 	StorageClass  uint8
     98 }
     99