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