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 data, err := bss.Data()
515 if err != nil {
516 t.Fatal(err)
517 }
518 if len(data) == 0 {
519 t.Fatalf("%s file .bss section cannot be empty", objpath)
520 }
521 for _, b := range data {
522 if b != 0 {
523 t.Fatalf(".bss section has non zero bytes: %v", data)
524 }
525 }
526 }
527
528 func TestDWARF(t *testing.T) {
529 testDWARF(t, linkNoCgo)
530 }
531
532 const testprog = `
533 package main
534
535 import "fmt"
536 import "syscall"
537 import "unsafe"
538 {{if .}}import "C"
539 {{end}}
540
541 // struct MODULEINFO from the Windows SDK
542 type moduleinfo struct {
543 BaseOfDll uintptr
544 SizeOfImage uint32
545 EntryPoint uintptr
546 }
547
548 func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
549 return unsafe.Pointer(uintptr(p) + x)
550 }
551
552 func funcPC(f interface{}) uintptr {
553 var a uintptr
554 return **(**uintptr)(add(unsafe.Pointer(&f), unsafe.Sizeof(a)))
555 }
556
557 func main() {
558 kernel32 := syscall.MustLoadDLL("kernel32.dll")
559 psapi := syscall.MustLoadDLL("psapi.dll")
560 getModuleHandle := kernel32.MustFindProc("GetModuleHandleW")
561 getCurrentProcess := kernel32.MustFindProc("GetCurrentProcess")
562 getModuleInformation := psapi.MustFindProc("GetModuleInformation")
563
564 procHandle, _, _ := getCurrentProcess.Call()
565 moduleHandle, _, err := getModuleHandle.Call(0)
566 if moduleHandle == 0 {
567 panic(fmt.Sprintf("GetModuleHandle() failed: %d", err))
568 }
569
570 var info moduleinfo
571 ret, _, err := getModuleInformation.Call(procHandle, moduleHandle,
572 uintptr(unsafe.Pointer(&info)), unsafe.Sizeof(info))
573
574 if ret == 0 {
575 panic(fmt.Sprintf("GetModuleInformation() failed: %d", err))
576 }
577
578 offset := funcPC(main) - info.BaseOfDll
579 fmt.Printf("base=0x%x\n", info.BaseOfDll)
580 fmt.Printf("main=%p\n", main)
581 fmt.Printf("offset=0x%x\n", offset)
582 }
583 `
584
585 func TestBuildingWindowsGUI(t *testing.T) {
586 testenv.MustHaveGoBuild(t)
587
588 if runtime.GOOS != "windows" {
589 t.Skip("skipping windows only test")
590 }
591 tmpdir := t.TempDir()
592
593 src := filepath.Join(tmpdir, "a.go")
594 if err := os.WriteFile(src, []byte(`package main; func main() {}`), 0644); err != nil {
595 t.Fatal(err)
596 }
597 exe := filepath.Join(tmpdir, "a.exe")
598 cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags", "-H=windowsgui", "-o", exe, src)
599 out, err := cmd.CombinedOutput()
600 if err != nil {
601 t.Fatalf("building test executable failed: %s %s", err, out)
602 }
603
604 f, err := Open(exe)
605 if err != nil {
606 t.Fatal(err)
607 }
608 defer f.Close()
609
610 switch oh := f.OptionalHeader.(type) {
611 case *OptionalHeader32:
612 if oh.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI {
613 t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI)
614 }
615 case *OptionalHeader64:
616 if oh.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI {
617 t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI)
618 }
619 default:
620 t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh)
621 }
622 }
623
624 func TestImportTableInUnknownSection(t *testing.T) {
625 if runtime.GOOS != "windows" {
626 t.Skip("skipping Windows-only test")
627 }
628
629
630
631 const filename = "ws2_32.dll"
632 path, err := exec.LookPath(filename)
633 if err != nil {
634 t.Fatalf("unable to locate required file %q in search path: %s", filename, err)
635 }
636
637 f, err := Open(path)
638 if err != nil {
639 t.Error(err)
640 }
641 defer f.Close()
642
643
644 symbols, err := f.ImportedSymbols()
645 if err != nil {
646 t.Error(err)
647 }
648
649 if len(symbols) == 0 {
650 t.Fatalf("unable to locate any imported symbols within file %q.", path)
651 }
652 }
653
654 func TestInvalidOptionalHeaderMagic(t *testing.T) {
655
656
657
658 data := []byte("\x00\x00\x00\x0000000\x00\x00\x00\x00\x00\x00\x000000" +
659 "00000000000000000000" +
660 "000000000\x00\x00\x0000000000" +
661 "00000000000000000000" +
662 "0000000000000000")
663
664 _, err := NewFile(bytes.NewReader(data))
665 if err == nil {
666 t.Fatal("NewFile succeeded unexpectedly")
667 }
668 }
669
670 func TestImportedSymbolsNoPanicMissingOptionalHeader(t *testing.T) {
671
672
673 data, err := os.ReadFile("testdata/gcc-amd64-mingw-obj")
674 if err != nil {
675 t.Fatal(err)
676 }
677
678 f, err := NewFile(bytes.NewReader(data))
679 if err != nil {
680 t.Fatal(err)
681 }
682
683 if f.OptionalHeader != nil {
684 t.Fatal("expected f.OptionalHeader to be nil, received non-nil optional header")
685 }
686
687 syms, err := f.ImportedSymbols()
688 if err != nil {
689 t.Fatal(err)
690 }
691
692 if len(syms) != 0 {
693 t.Fatalf("expected len(syms) == 0, received len(syms) = %d", len(syms))
694 }
695
696 }
697
698 func TestImportedSymbolsNoPanicWithSliceOutOfBound(t *testing.T) {
699
700
701
702 data := []byte("L\x01\b\x00regi\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x0f\x03" +
703 "\v\x01\x02\x18\x00\x0e\x00\x00\x00\x1e\x00\x00\x00\x02\x00\x00\x80\x12\x00\x00" +
704 "\x00\x10\x00\x00\x00 \x00\x00\x00\x00@\x00\x00\x10\x00\x00\x00\x02\x00\x00" +
705 "\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00" +
706 "\x00\x04\x00\x00\x06S\x00\x00\x03\x00\x00\x00\x00\x00 \x00\x00\x10\x00\x00" +
707 "\x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00" +
708 "\x00\x00\x00\x00\x00`\x00\x00x\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
709 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
710 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
711 "\x00\x00\x00\x00\x00\x00\x00\x00\x04\x80\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00" +
712 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8`\x00\x00|\x00\x00\x00" +
713 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
714 "\x00\x00\x00\x00.text\x00\x00\x00d\f\x00\x00\x00\x10\x00\x00" +
715 "\x00\x0e\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
716 "`\x00P`.data\x00\x00\x00\x10\x00\x00\x00\x00 \x00\x00" +
717 "\x00\x02\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
718 "@\x000\xc0.rdata\x00\x004\x01\x00\x00\x000\x00\x00" +
719 "\x00\x02\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
720 "@\x000@.eh_fram\xa0\x03\x00\x00\x00@\x00\x00" +
721 "\x00\x04\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
722 "@\x000@.bss\x00\x00\x00\x00`\x00\x00\x00\x00P\x00\x00" +
723 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
724 "\x80\x000\xc0.idata\x00\x00x\x03\x00\x00\x00`\x00\x00" +
725 "\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00" +
726 "0\xc0.CRT\x00\x00\x00\x00\x18\x00\x00\x00\x00p\x00\x00\x00\x02" +
727 "\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00" +
728 "0\xc0.tls\x00\x00\x00\x00 \x00\x00\x00\x00\x80\x00\x00\x00\x02" +
729 "\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\xc9" +
730 "H\x895\x1d")
731
732 f, err := NewFile(bytes.NewReader(data))
733 if err != nil {
734 t.Fatal(err)
735 }
736
737 syms, err := f.ImportedSymbols()
738 if err != nil {
739 t.Fatal(err)
740 }
741
742 if len(syms) != 0 {
743 t.Fatalf("expected len(syms) == 0, received len(syms) = %d", len(syms))
744 }
745 }
746
View as plain text