| // 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" | |
| "strconv" | |
| ) | |
| // SectionHeader32 represents real PE COFF section header. | |
| type SectionHeader32 struct { | |
| Name [8]uint8 | |
| VirtualSize uint32 | |
| VirtualAddress uint32 | |
| SizeOfRawData uint32 | |
| PointerToRawData uint32 | |
| PointerToRelocations uint32 | |
| PointerToLineNumbers uint32 | |
| NumberOfRelocations uint16 | |
| NumberOfLineNumbers uint16 | |
| Characteristics uint32 | |
| } | |
| // fullName finds real name of section sh. Normally name is stored | |
| // in sh.Name, but if it is longer then 8 characters, it is stored | |
| // in COFF string table st instead. | |
| func (sh *SectionHeader32) fullName(st StringTable) (string, error) { | |
| if sh.Name[0] != '/' { | |
| return cstring(sh.Name[:]), nil | |
| } | |
| i, err := strconv.Atoi(cstring(sh.Name[1:])) | |
| if err != nil { | |
| return "", err | |
| } | |
| return st.String(uint32(i)) | |
| } | |
| // TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here | |
| // Reloc represents a PE COFF relocation. | |
| // Each section contains its own relocation list. | |
| type Reloc struct { | |
| VirtualAddress uint32 | |
| SymbolTableIndex uint32 | |
| Type uint16 | |
| } | |
| func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) { | |
| if sh.NumberOfRelocations <= 0 { | |
| return nil, nil | |
| } | |
| _, err := r.Seek(int64(sh.PointerToRelocations), seekStart) | |
| if err != nil { | |
| return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err) | |
| } | |
| relocs := make([]Reloc, sh.NumberOfRelocations) | |
| err = binary.Read(r, binary.LittleEndian, relocs) | |
| if err != nil { | |
| return nil, fmt.Errorf("fail to read section relocations: %v", err) | |
| } | |
| return relocs, nil | |
| } | |
| // SectionHeader is similar to SectionHeader32 with Name | |
| // field replaced by Go string. | |
| type SectionHeader struct { | |
| Name string | |
| VirtualSize uint32 | |
| VirtualAddress uint32 | |
| Size uint32 | |
| Offset uint32 | |
| PointerToRelocations uint32 | |
| PointerToLineNumbers uint32 | |
| NumberOfRelocations uint16 | |
| NumberOfLineNumbers uint16 | |
| Characteristics uint32 | |
| } | |
| // Section provides access to PE COFF section. | |
| type Section struct { | |
| SectionHeader | |
| Relocs []Reloc | |
| // Embed ReaderAt for ReadAt method. | |
| // Do not embed SectionReader directly | |
| // to avoid having Read and Seek. | |
| // If a client wants Read and Seek it must use | |
| // Open() to avoid fighting over the seek offset | |
| // with other clients. | |
| io.ReaderAt | |
| sr *io.SectionReader | |
| } | |
| // Data reads and returns the contents of the PE section s. | |
| func (s *Section) Data() ([]byte, error) { | |
| dat := make([]byte, s.sr.Size()) | |
| n, err := s.sr.ReadAt(dat, 0) | |
| if n == len(dat) { | |
| err = nil | |
| } | |
| return dat[0:n], err | |
| } | |
| // Open returns a new ReadSeeker reading the PE section s. | |
| func (s *Section) Open() io.ReadSeeker { | |
| return io.NewSectionReader(s.sr, 0, 1<<63-1) | |
| } |