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 	"strconv"
     12 )
     13 
     14 // SectionHeader32 represents real PE COFF section header.
     15 type SectionHeader32 struct {
     16 	Name                 [8]uint8
     17 	VirtualSize          uint32
     18 	VirtualAddress       uint32
     19 	SizeOfRawData        uint32
     20 	PointerToRawData     uint32
     21 	PointerToRelocations uint32
     22 	PointerToLineNumbers uint32
     23 	NumberOfRelocations  uint16
     24 	NumberOfLineNumbers  uint16
     25 	Characteristics      uint32
     26 }
     27 
     28 // fullName finds real name of section sh. Normally name is stored
     29 // in sh.Name, but if it is longer then 8 characters, it is stored
     30 // in COFF string table st instead.
     31 func (sh *SectionHeader32) fullName(st StringTable) (string, error) {
     32 	if sh.Name[0] != '/' {
     33 		return cstring(sh.Name[:]), nil
     34 	}
     35 	i, err := strconv.Atoi(cstring(sh.Name[1:]))
     36 	if err != nil {
     37 		return "", err
     38 	}
     39 	return st.String(uint32(i))
     40 }
     41 
     42 // TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here
     43 
     44 // Reloc represents a PE COFF relocation.
     45 // Each section contains its own relocation list.
     46 type Reloc struct {
     47 	VirtualAddress   uint32
     48 	SymbolTableIndex uint32
     49 	Type             uint16
     50 }
     51 
     52 func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) {
     53 	if sh.NumberOfRelocations <= 0 {
     54 		return nil, nil
     55 	}
     56 	_, err := r.Seek(int64(sh.PointerToRelocations), seekStart)
     57 	if err != nil {
     58 		return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err)
     59 	}
     60 	relocs := make([]Reloc, sh.NumberOfRelocations)
     61 	err = binary.Read(r, binary.LittleEndian, relocs)
     62 	if err != nil {
     63 		return nil, fmt.Errorf("fail to read section relocations: %v", err)
     64 	}
     65 	return relocs, nil
     66 }
     67 
     68 // SectionHeader is similar to SectionHeader32 with Name
     69 // field replaced by Go string.
     70 type SectionHeader struct {
     71 	Name                 string
     72 	VirtualSize          uint32
     73 	VirtualAddress       uint32
     74 	Size                 uint32
     75 	Offset               uint32
     76 	PointerToRelocations uint32
     77 	PointerToLineNumbers uint32
     78 	NumberOfRelocations  uint16
     79 	NumberOfLineNumbers  uint16
     80 	Characteristics      uint32
     81 }
     82 
     83 // Section provides access to PE COFF section.
     84 type Section struct {
     85 	SectionHeader
     86 	Relocs []Reloc
     87 
     88 	// Embed ReaderAt for ReadAt method.
     89 	// Do not embed SectionReader directly
     90 	// to avoid having Read and Seek.
     91 	// If a client wants Read and Seek it must use
     92 	// Open() to avoid fighting over the seek offset
     93 	// with other clients.
     94 	io.ReaderAt
     95 	sr *io.SectionReader
     96 }
     97 
     98 // Data reads and returns the contents of the PE section s.
     99 func (s *Section) Data() ([]byte, error) {
    100 	dat := make([]byte, s.sr.Size())
    101 	n, err := s.sr.ReadAt(dat, 0)
    102 	if n == len(dat) {
    103 		err = nil
    104 	}
    105 	return dat[0:n], err
    106 }
    107 
    108 // Open returns a new ReadSeeker reading the PE section s.
    109 func (s *Section) Open() io.ReadSeeker {
    110 	return io.NewSectionReader(s.sr, 0, 1<<63-1)
    111 }
    112