1
2
3
4
5
6
7 package objfile
8
9 import (
10 "debug/dwarf"
11 "debug/pe"
12 "fmt"
13 "io"
14 "slices"
15 "sort"
16 )
17
18 type peFile struct {
19 pe *pe.File
20 }
21
22 func openPE(r io.ReaderAt) (rawFile, error) {
23 f, err := pe.NewFile(r)
24 if err != nil {
25 return nil, err
26 }
27 return &peFile{f}, nil
28 }
29
30 func (f *peFile) symbols() ([]Sym, error) {
31
32
33 var addrs []uint64
34
35 imageBase, _ := f.imageBase()
36
37 var syms []Sym
38 for _, s := range f.pe.Symbols {
39 const (
40 N_UNDEF = 0
41 N_ABS = -1
42 N_DEBUG = -2
43 )
44 sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'}
45 switch s.SectionNumber {
46 case N_UNDEF:
47 sym.Code = 'U'
48 case N_ABS:
49 sym.Code = 'C'
50 case N_DEBUG:
51 sym.Code = '?'
52 default:
53 if s.SectionNumber < 0 || len(f.pe.Sections) < int(s.SectionNumber) {
54 return nil, fmt.Errorf("invalid section number in symbol table")
55 }
56 sect := f.pe.Sections[s.SectionNumber-1]
57 const (
58 text = 0x20
59 data = 0x40
60 bss = 0x80
61 permW = 0x80000000
62 )
63 ch := sect.Characteristics
64 switch {
65 case ch&text != 0:
66 sym.Code = 'T'
67 case ch&data != 0:
68 if ch&permW == 0 {
69 sym.Code = 'R'
70 } else {
71 sym.Code = 'D'
72 }
73 case ch&bss != 0:
74 sym.Code = 'B'
75 }
76 sym.Addr += imageBase + uint64(sect.VirtualAddress)
77 }
78 syms = append(syms, sym)
79 addrs = append(addrs, sym.Addr)
80 }
81
82 slices.Sort(addrs)
83 for i := range syms {
84 j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr })
85 if j < len(addrs) {
86 syms[i].Size = int64(addrs[j] - syms[i].Addr)
87 }
88 }
89
90 return syms, nil
91 }
92
93 func (f *peFile) pcln() (textStart uint64, pclntab []byte, err error) {
94 imageBase, err := f.imageBase()
95 if err != nil {
96 return 0, nil, err
97 }
98
99 if sect := f.pe.Section(".text"); sect != nil {
100 textStart = imageBase + uint64(sect.VirtualAddress)
101 }
102 if pclntab, err = loadPETable(f.pe, "runtime.pclntab", "runtime.epclntab"); err != nil {
103
104
105 var err2 error
106 if pclntab, err2 = loadPETable(f.pe, "pclntab", "epclntab"); err2 != nil {
107 return 0, nil, err
108 }
109 }
110 return textStart, pclntab, nil
111 }
112
113 func (f *peFile) text() (textStart uint64, text []byte, err error) {
114 imageBase, err := f.imageBase()
115 if err != nil {
116 return 0, nil, err
117 }
118
119 sect := f.pe.Section(".text")
120 if sect == nil {
121 return 0, nil, fmt.Errorf("text section not found")
122 }
123 textStart = imageBase + uint64(sect.VirtualAddress)
124 text, err = sect.Data()
125 return
126 }
127
128 func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) {
129 for _, s := range f.Symbols {
130 if s.Name != name {
131 continue
132 }
133 if s.SectionNumber <= 0 {
134 return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber)
135 }
136 if len(f.Sections) < int(s.SectionNumber) {
137 return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections))
138 }
139 return s, nil
140 }
141 return nil, fmt.Errorf("no %s symbol found", name)
142 }
143
144 func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
145 ssym, err := findPESymbol(f, sname)
146 if err != nil {
147 return nil, err
148 }
149 esym, err := findPESymbol(f, ename)
150 if err != nil {
151 return nil, err
152 }
153 if ssym.SectionNumber != esym.SectionNumber {
154 return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename)
155 }
156 sect := f.Sections[ssym.SectionNumber-1]
157 data, err := sect.Data()
158 if err != nil {
159 return nil, err
160 }
161 return data[ssym.Value:esym.Value], nil
162 }
163
164 func (f *peFile) goarch() string {
165 switch f.pe.Machine {
166 case pe.IMAGE_FILE_MACHINE_I386:
167 return "386"
168 case pe.IMAGE_FILE_MACHINE_AMD64:
169 return "amd64"
170 case pe.IMAGE_FILE_MACHINE_ARM64:
171 return "arm64"
172 default:
173 return ""
174 }
175 }
176
177 func (f *peFile) loadAddress() (uint64, error) {
178 return f.imageBase()
179 }
180
181 func (f *peFile) imageBase() (uint64, error) {
182 switch oh := f.pe.OptionalHeader.(type) {
183 case *pe.OptionalHeader32:
184 return uint64(oh.ImageBase), nil
185 case *pe.OptionalHeader64:
186 return oh.ImageBase, nil
187 default:
188 return 0, fmt.Errorf("pe file format not recognized")
189 }
190 }
191
192 func (f *peFile) dwarf() (*dwarf.Data, error) {
193 return f.pe.DWARF()
194 }
195
View as plain text