Source file
src/debug/pe/file_test.go
1
2
3
4
5 package pe
6
7 import (
8 "bytes"
9 "debug/dwarf"
10 "internal/testenv"
11 "os"
12 "os/exec"
13 "path/filepath"
14 "reflect"
15 "regexp"
16 "runtime"
17 "strconv"
18 "testing"
19 "text/template"
20 )
21
22 type fileTest struct {
23 file string
24 hdr FileHeader
25 opthdr any
26 sections []*SectionHeader
27 symbols []*Symbol
28 hasNoDwarfInfo bool
29 }
30
31 var fileTests = []fileTest{
32 {
33 file: "testdata/gcc-386-mingw-obj",
34 hdr: FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
35 sections: []*SectionHeader{
36 {".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
37 {".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
38 {".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
39 {".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
40 {".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
41 {".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
42 {".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
43 {".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
44 {".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
45 {".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
46 {".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
47 {".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
48 },
49 symbols: []*Symbol{
50 {".file", 0x0, -2, 0x0, 0x67},
51 {"_main", 0x0, 1, 0x20, 0x2},
52 {".text", 0x0, 1, 0x0, 0x3},
53 {".data", 0x0, 2, 0x0, 0x3},
54 {".bss", 0x0, 3, 0x0, 0x3},
55 {".debug_abbrev", 0x0, 4, 0x0, 0x3},
56 {".debug_info", 0x0, 5, 0x0, 0x3},
57 {".debug_line", 0x0, 6, 0x0, 0x3},
58 {".rdata", 0x0, 7, 0x0, 0x3},
59 {".debug_frame", 0x0, 8, 0x0, 0x3},
60 {".debug_loc", 0x0, 9, 0x0, 0x3},
61 {".debug_pubnames", 0x0, 10, 0x0, 0x3},
62 {".debug_pubtypes", 0x0, 11, 0x0, 0x3},
63 {".debug_aranges", 0x0, 12, 0x0, 0x3},
64 {"___main", 0x0, 0, 0x20, 0x2},
65 {"_puts", 0x0, 0, 0x20, 0x2},
66 },
67 },
68 {
69 file: "testdata/gcc-386-mingw-exec",
70 hdr: FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
71 opthdr: &OptionalHeader32{
72 0x10b, 0x2, 0x38, 0xe00, 0x1a00, 0x200, 0x1160, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x10000, 0x400, 0x14abb, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
73 [16]DataDirectory{
74 {0x0, 0x0},
75 {0x5000, 0x3c8},
76 {0x0, 0x0},
77 {0x0, 0x0},
78 {0x0, 0x0},
79 {0x0, 0x0},
80 {0x0, 0x0},
81 {0x0, 0x0},
82 {0x0, 0x0},
83 {0x7000, 0x18},
84 {0x0, 0x0},
85 {0x0, 0x0},
86 {0x0, 0x0},
87 {0x0, 0x0},
88 {0x0, 0x0},
89 {0x0, 0x0},
90 },
91 },
92 sections: []*SectionHeader{
93 {".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
94 {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
95 {".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
96 {".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080},
97 {".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
98 {".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
99 {".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
100 {".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
101 {".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000},
102 {".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000},
103 {".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
104 {".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
105 {".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000},
106 {".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000},
107 {".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
108 },
109 },
110 {
111 file: "testdata/gcc-386-mingw-no-symbols-exec",
112 hdr: FileHeader{0x14c, 0x8, 0x69676572, 0x0, 0x0, 0xe0, 0x30f},
113 opthdr: &OptionalHeader32{0x10b, 0x2, 0x18, 0xe00, 0x1e00, 0x200, 0x1280, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x9000, 0x400, 0x5306, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
114 [16]DataDirectory{
115 {0x0, 0x0},
116 {0x6000, 0x378},
117 {0x0, 0x0},
118 {0x0, 0x0},
119 {0x0, 0x0},
120 {0x0, 0x0},
121 {0x0, 0x0},
122 {0x0, 0x0},
123 {0x0, 0x0},
124 {0x8004, 0x18},
125 {0x0, 0x0},
126 {0x0, 0x0},
127 {0x60b8, 0x7c},
128 {0x0, 0x0},
129 {0x0, 0x0},
130 {0x0, 0x0},
131 },
132 },
133 sections: []*SectionHeader{
134 {".text", 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
135 {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
136 {".rdata", 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
137 {".eh_fram", 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040},
138 {".bss", 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080},
139 {".idata", 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
140 {".CRT", 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
141 {".tls", 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
142 },
143 hasNoDwarfInfo: true,
144 },
145 {
146 file: "testdata/gcc-amd64-mingw-obj",
147 hdr: FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
148 sections: []*SectionHeader{
149 {".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020},
150 {".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
151 {".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080},
152 {".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040},
153 {".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
154 {".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
155 },
156 symbols: []*Symbol{
157 {".file", 0x0, -2, 0x0, 0x67},
158 {"main", 0x0, 1, 0x20, 0x2},
159 {".text", 0x0, 1, 0x0, 0x3},
160 {".data", 0x0, 2, 0x0, 0x3},
161 {".bss", 0x0, 3, 0x0, 0x3},
162 {".rdata", 0x0, 4, 0x0, 0x3},
163 {".xdata", 0x0, 5, 0x0, 0x3},
164 {".pdata", 0x0, 6, 0x0, 0x3},
165 {"__main", 0x0, 0, 0x20, 0x2},
166 {"puts", 0x0, 0, 0x20, 0x2},
167 },
168 hasNoDwarfInfo: true,
169 },
170 {
171 file: "testdata/gcc-amd64-mingw-exec",
172 hdr: FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
173 opthdr: &OptionalHeader64{
174 0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x45000, 0x600, 0x46f19, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
175 [16]DataDirectory{
176 {0x0, 0x0},
177 {0xe000, 0x990},
178 {0x0, 0x0},
179 {0xa000, 0x498},
180 {0x0, 0x0},
181 {0x0, 0x0},
182 {0x0, 0x0},
183 {0x0, 0x0},
184 {0x0, 0x0},
185 {0x10000, 0x28},
186 {0x0, 0x0},
187 {0x0, 0x0},
188 {0xe254, 0x218},
189 {0x0, 0x0},
190 {0x0, 0x0},
191 {0x0, 0x0},
192 }},
193 sections: []*SectionHeader{
194 {".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020},
195 {".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
196 {".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040},
197 {".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
198 {".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040},
199 {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
200 {".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
201 {".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
202 {".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
203 {".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040},
204 {".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
205 {".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
206 {".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
207 {".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040},
208 {".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040},
209 {".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040},
210 {".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
211 },
212 },
213 {
214
215
216
217
218
219
220
221 file: "testdata/vmlinuz-4.15.0-47-generic",
222 hdr: FileHeader{0x8664, 0x4, 0x0, 0x0, 0x1, 0xa0, 0x206},
223 opthdr: &OptionalHeader64{
224 0x20b, 0x2, 0x14, 0x7c0590, 0x0, 0x168f870, 0x4680, 0x200, 0x0, 0x20, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e50000, 0x200, 0x7c3ab0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6,
225 [16]DataDirectory{
226 {0x0, 0x0},
227 {0x0, 0x0},
228 {0x0, 0x0},
229 {0x0, 0x0},
230 {0x7c07a0, 0x778},
231 {0x0, 0x0},
232 {0x0, 0x0},
233 {0x0, 0x0},
234 {0x0, 0x0},
235 {0x0, 0x0},
236 {0x0, 0x0},
237 {0x0, 0x0},
238 {0x0, 0x0},
239 {0x0, 0x0},
240 {0x0, 0x0},
241 {0x0, 0x0},
242 }},
243 sections: []*SectionHeader{
244 {".setup", 0x41e0, 0x200, 0x41e0, 0x200, 0x0, 0x0, 0x0, 0x0, 0x60500020},
245 {".reloc", 0x20, 0x43e0, 0x20, 0x43e0, 0x0, 0x0, 0x0, 0x0, 0x42100040},
246 {".text", 0x7bc390, 0x4400, 0x7bc390, 0x4400, 0x0, 0x0, 0x0, 0x0, 0x60500020},
247 {".bss", 0x168f870, 0x7c0790, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc8000080},
248 },
249 hasNoDwarfInfo: true,
250 },
251 }
252
253 func isOptHdrEq(a, b any) bool {
254 switch va := a.(type) {
255 case *OptionalHeader32:
256 vb, ok := b.(*OptionalHeader32)
257 if !ok {
258 return false
259 }
260 return *vb == *va
261 case *OptionalHeader64:
262 vb, ok := b.(*OptionalHeader64)
263 if !ok {
264 return false
265 }
266 return *vb == *va
267 case nil:
268 return b == nil
269 }
270 return false
271 }
272
273 func TestOpen(t *testing.T) {
274 for i := range fileTests {
275 tt := &fileTests[i]
276
277 f, err := Open(tt.file)
278 if err != nil {
279 t.Error(err)
280 continue
281 }
282 if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
283 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
284 continue
285 }
286 if !isOptHdrEq(tt.opthdr, f.OptionalHeader) {
287 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr)
288 continue
289 }
290
291 for i, sh := range f.Sections {
292 if i >= len(tt.sections) {
293 break
294 }
295 have := &sh.SectionHeader
296 want := tt.sections[i]
297 if !reflect.DeepEqual(have, want) {
298 t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
299 }
300 }
301 tn := len(tt.sections)
302 fn := len(f.Sections)
303 if tn != fn {
304 t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
305 }
306 for i, have := range f.Symbols {
307 if i >= len(tt.symbols) {
308 break
309 }
310 want := tt.symbols[i]
311 if !reflect.DeepEqual(have, want) {
312 t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
313 }
314 }
315 if !tt.hasNoDwarfInfo {
316 _, err = f.DWARF()
317 if err != nil {
318 t.Errorf("fetching %s dwarf details failed: %v", tt.file, err)
319 }
320 }
321 }
322 }
323
324 func TestOpenFailure(t *testing.T) {
325 filename := "file.go"
326 _, err := Open(filename)
327 if err == nil {
328 t.Errorf("open %s: succeeded unexpectedly", filename)
329 }
330 }
331
332 const (
333 linkNoCgo = iota
334 linkCgoDefault
335 linkCgoInternal
336 linkCgoExternal
337 )
338
339 func getImageBase(f *File) uintptr {
340 switch oh := f.OptionalHeader.(type) {
341 case *OptionalHeader32:
342 return uintptr(oh.ImageBase)
343 case *OptionalHeader64:
344 return uintptr(oh.ImageBase)
345 default:
346 panic("unexpected optionalheader type")
347 }
348 }
349
350 func testDWARF(t *testing.T, linktype int) {
351 if runtime.GOOS != "windows" {
352 t.Skip("skipping windows only test")
353 }
354 testenv.MustHaveGoRun(t)
355
356 tmpdir := t.TempDir()
357
358 src := filepath.Join(tmpdir, "a.go")
359 file, err := os.Create(src)
360 if err != nil {
361 t.Fatal(err)
362 }
363 err = template.Must(template.New("main").Parse(testprog)).Execute(file, linktype != linkNoCgo)
364 if err != nil {
365 if err := file.Close(); err != nil {
366 t.Error(err)
367 }
368 t.Fatal(err)
369 }
370 if err := file.Close(); err != nil {
371 t.Fatal(err)
372 }
373
374 exe := filepath.Join(tmpdir, "a.exe")
375 args := []string{"build", "-o", exe}
376 switch linktype {
377 case linkNoCgo:
378 case linkCgoDefault:
379 case linkCgoInternal:
380 args = append(args, "-ldflags", "-linkmode=internal")
381 case linkCgoExternal:
382 args = append(args, "-ldflags", "-linkmode=external")
383 default:
384 t.Fatalf("invalid linktype parameter of %v", linktype)
385 }
386 args = append(args, src)
387 out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
388 if err != nil {
389 t.Fatalf("building test executable for linktype %d failed: %s %s", linktype, err, out)
390 }
391 out, err = exec.Command(exe).CombinedOutput()
392 if err != nil {
393 t.Fatalf("running test executable failed: %s %s", err, out)
394 }
395 t.Logf("Testprog output:\n%s", string(out))
396
397 matches := regexp.MustCompile("offset=(.*)\n").FindStringSubmatch(string(out))
398 if len(matches) < 2 {
399 t.Fatalf("unexpected program output: %s", out)
400 }
401 wantoffset, err := strconv.ParseUint(matches[1], 0, 64)
402 if err != nil {
403 t.Fatalf("unexpected main offset %q: %s", matches[1], err)
404 }
405
406 f, err := Open(exe)
407 if err != nil {
408 t.Fatal(err)
409 }
410 defer f.Close()
411
412 imageBase := getImageBase(f)
413
414 var foundDebugGDBScriptsSection bool
415 for _, sect := range f.Sections {
416 if sect.Name == ".debug_gdb_scripts" {
417 foundDebugGDBScriptsSection = true
418 }
419 }
420 if !foundDebugGDBScriptsSection {
421 t.Error(".debug_gdb_scripts section is not found")
422 }
423
424 d, err := f.DWARF()
425 if err != nil {
426 t.Fatal(err)
427 }
428
429
430 r := d.Reader()
431 for {
432 e, err := r.Next()
433 if err != nil {
434 t.Fatal("r.Next:", err)
435 }
436 if e == nil {
437 break
438 }
439 if e.Tag == dwarf.TagSubprogram {
440 name, ok := e.Val(dwarf.AttrName).(string)
441 if ok && name == "main.main" {
442 t.Logf("Found main.main")
443 addr, ok := e.Val(dwarf.AttrLowpc).(uint64)
444 if !ok {
445 t.Fatal("Failed to get AttrLowpc")
446 }
447 offset := uintptr(addr) - imageBase
448 if offset != uintptr(wantoffset) {
449 t.Fatalf("Runtime offset (0x%x) did "+
450 "not match dwarf offset "+
451 "(0x%x)", wantoffset, offset)
452 }
453 return
454 }
455 }
456 }
457 t.Fatal("main.main not found")
458 }
459
460 func TestBSSHasZeros(t *testing.T) {
461 testenv.MustHaveExec(t)
462
463 if runtime.GOOS != "windows" {
464 t.Skip("skipping windows only test")
465 }
466 gccpath, err := exec.LookPath("gcc")
467 if err != nil {
468 t.Skip("skipping test: gcc is missing")
469 }
470
471 tmpdir := t.TempDir()
472
473 srcpath := filepath.Join(tmpdir, "a.c")
474 src := `
475 #include <stdio.h>
476
477 int zero = 0;
478
479 int
480 main(void)
481 {
482 printf("%d\n", zero);
483 return 0;
484 }
485 `
486 err = os.WriteFile(srcpath, []byte(src), 0644)
487 if err != nil {
488 t.Fatal(err)
489 }
490
491 objpath := filepath.Join(tmpdir, "a.obj")
492 cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath)
493 out, err := cmd.CombinedOutput()
494 if err != nil {
495 t.Fatalf("failed to build object file: %v - %v", err, string(out))
496 }
497
498 f, err := Open(objpath)
499 if err != nil {
500 t.Fatal(err)
501 }
502 defer f.Close()
503
504 var bss *Section
505 for _, sect := range f.Sections {
506 if sect.Name == ".bss" {
507 bss = sect
508 break
509 }
510 }
511 if bss == nil {
512 t.Fatal("could not find .bss section")
513 }
514
515 if _, err := bss.Data(); err == nil {
516 t.Error("bss.Data succeeded, expected error")
517 }
518 }
519
520 func TestDWARF(t *testing.T) {
521 testDWARF(t, linkNoCgo)
522 }
523
524 const testprog = `
525 package main
526
527 import "fmt"
528 import "syscall"
529 import "unsafe"
530 {{if .}}import "C"
531 {{end}}
532
533 // struct MODULEINFO from the Windows SDK
534 type moduleinfo struct {
535 BaseOfDll uintptr
536 SizeOfImage uint32
537 EntryPoint uintptr
538 }
539
540 func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
541 return unsafe.Pointer(uintptr(p) + x)
542 }
543
544 func funcPC(f interface{}) uintptr {
545 var a uintptr
546 return **(**uintptr)(add(unsafe.Pointer(&f), unsafe.Sizeof(a)))
547 }
548
549 func main() {
550 kernel32 := syscall.MustLoadDLL("kernel32.dll")
551 psapi := syscall.MustLoadDLL("psapi.dll")
552 getModuleHandle := kernel32.MustFindProc("GetModuleHandleW")
553 getCurrentProcess := kernel32.MustFindProc("GetCurrentProcess")
554 getModuleInformation := psapi.MustFindProc("GetModuleInformation")
555
556 procHandle, _, _ := getCurrentProcess.Call()
557 moduleHandle, _, err := getModuleHandle.Call(0)
558 if moduleHandle == 0 {
559 panic(fmt.Sprintf("GetModuleHandle() failed: %d", err))
560 }
561
562 var info moduleinfo
563 ret, _, err := getModuleInformation.Call(procHandle, moduleHandle,
564 uintptr(unsafe.Pointer(&info)), unsafe.Sizeof(info))
565
566 if ret == 0 {
567 panic(fmt.Sprintf("GetModuleInformation() failed: %d", err))
568 }
569
570 offset := funcPC(main) - info.BaseOfDll
571 fmt.Printf("base=0x%x\n", info.BaseOfDll)
572 fmt.Printf("main=%p\n", main)
573 fmt.Printf("offset=0x%x\n", offset)
574 }
575 `
576
577 func TestBuildingWindowsGUI(t *testing.T) {
578 testenv.MustHaveGoBuild(t)
579
580 if runtime.GOOS != "windows" {
581 t.Skip("skipping windows only test")
582 }
583 tmpdir := t.TempDir()
584
585 src := filepath.Join(tmpdir, "a.go")
586 if err := os.WriteFile(src, []byte(`package main; func main() {}`), 0644); err != nil {
587 t.Fatal(err)
588 }
589 exe := filepath.Join(tmpdir, "a.exe")
590 cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags", "-H=windowsgui", "-o", exe, src)
591 out, err := cmd.CombinedOutput()
592 if err != nil {
593 t.Fatalf("building test executable failed: %s %s", err, out)
594 }
595
596 f, err := Open(exe)
597 if err != nil {
598 t.Fatal(err)
599 }
600 defer f.Close()
601
602 switch oh := f.OptionalHeader.(type) {
603 case *OptionalHeader32:
604 if oh.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI {
605 t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI)
606 }
607 case *OptionalHeader64:
608 if oh.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI {
609 t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI)
610 }
611 default:
612 t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh)
613 }
614 }
615
616 func TestImportTableInUnknownSection(t *testing.T) {
617 if runtime.GOOS != "windows" {
618 t.Skip("skipping Windows-only test")
619 }
620
621
622
623 const filename = "ws2_32.dll"
624 path, err := exec.LookPath(filename)
625 if err != nil {
626 t.Fatalf("unable to locate required file %q in search path: %s", filename, err)
627 }
628
629 f, err := Open(path)
630 if err != nil {
631 t.Error(err)
632 }
633 defer f.Close()
634
635
636 symbols, err := f.ImportedSymbols()
637 if err != nil {
638 t.Error(err)
639 }
640
641 if len(symbols) == 0 {
642 t.Fatalf("unable to locate any imported symbols within file %q.", path)
643 }
644 }
645
646 func TestInvalidOptionalHeaderMagic(t *testing.T) {
647
648
649
650 data := []byte("\x00\x00\x00\x0000000\x00\x00\x00\x00\x00\x00\x000000" +
651 "00000000000000000000" +
652 "000000000\x00\x00\x0000000000" +
653 "00000000000000000000" +
654 "0000000000000000")
655
656 _, err := NewFile(bytes.NewReader(data))
657 if err == nil {
658 t.Fatal("NewFile succeeded unexpectedly")
659 }
660 }
661
662 func TestImportedSymbolsNoPanicMissingOptionalHeader(t *testing.T) {
663
664
665 data, err := os.ReadFile("testdata/gcc-amd64-mingw-obj")
666 if err != nil {
667 t.Fatal(err)
668 }
669
670 f, err := NewFile(bytes.NewReader(data))
671 if err != nil {
672 t.Fatal(err)
673 }
674
675 if f.OptionalHeader != nil {
676 t.Fatal("expected f.OptionalHeader to be nil, received non-nil optional header")
677 }
678
679 syms, err := f.ImportedSymbols()
680 if err != nil {
681 t.Fatal(err)
682 }
683
684 if len(syms) != 0 {
685 t.Fatalf("expected len(syms) == 0, received len(syms) = %d", len(syms))
686 }
687
688 }
689
690 func TestImportedSymbolsNoPanicWithSliceOutOfBound(t *testing.T) {
691
692
693
694 data := []byte("L\x01\b\x00regi\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x0f\x03" +
695 "\v\x01\x02\x18\x00\x0e\x00\x00\x00\x1e\x00\x00\x00\x02\x00\x00\x80\x12\x00\x00" +
696 "\x00\x10\x00\x00\x00 \x00\x00\x00\x00@\x00\x00\x10\x00\x00\x00\x02\x00\x00" +
697 "\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00" +
698 "\x00\x04\x00\x00\x06S\x00\x00\x03\x00\x00\x00\x00\x00 \x00\x00\x10\x00\x00" +
699 "\x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00" +
700 "\x00\x00\x00\x00\x00`\x00\x00x\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
701 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
702 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
703 "\x00\x00\x00\x00\x00\x00\x00\x00\x04\x80\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00" +
704 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8`\x00\x00|\x00\x00\x00" +
705 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
706 "\x00\x00\x00\x00.text\x00\x00\x00d\f\x00\x00\x00\x10\x00\x00" +
707 "\x00\x0e\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
708 "`\x00P`.data\x00\x00\x00\x10\x00\x00\x00\x00 \x00\x00" +
709 "\x00\x02\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
710 "@\x000\xc0.rdata\x00\x004\x01\x00\x00\x000\x00\x00" +
711 "\x00\x02\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
712 "@\x000@.eh_fram\xa0\x03\x00\x00\x00@\x00\x00" +
713 "\x00\x04\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
714 "@\x000@.bss\x00\x00\x00\x00`\x00\x00\x00\x00P\x00\x00" +
715 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
716 "\x80\x000\xc0.idata\x00\x00x\x03\x00\x00\x00`\x00\x00" +
717 "\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00" +
718 "0\xc0.CRT\x00\x00\x00\x00\x18\x00\x00\x00\x00p\x00\x00\x00\x02" +
719 "\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00" +
720 "0\xc0.tls\x00\x00\x00\x00 \x00\x00\x00\x00\x80\x00\x00\x00\x02" +
721 "\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\xc9" +
722 "H\x895\x1d")
723
724 f, err := NewFile(bytes.NewReader(data))
725 if err != nil {
726 t.Fatal(err)
727 }
728
729 syms, err := f.ImportedSymbols()
730 if err != nil {
731 t.Fatal(err)
732 }
733
734 if len(syms) != 0 {
735 t.Fatalf("expected len(syms) == 0, received len(syms) = %d", len(syms))
736 }
737 }
738
View as plain text