1// Copyright 2009 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	"debug/dwarf"
9	"internal/testenv"
10	"io/ioutil"
11	"os"
12	"os/exec"
13	"path/filepath"
14	"reflect"
15	"regexp"
16	"runtime"
17	"strconv"
18	"testing"
19	"text/template"
20)
21
22type fileTest struct {
23	file           string
24	hdr            FileHeader
25	opthdr         interface{}
26	sections       []*SectionHeader
27	symbols        []*Symbol
28	hasNoDwarfInfo bool
29}
30
31var 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
215func isOptHdrEq(a, b interface{}) bool {
216	switch va := a.(type) {
217	case *OptionalHeader32:
218		vb, ok := b.(*OptionalHeader32)
219		if !ok {
220			return false
221		}
222		return *vb == *va
223	case *OptionalHeader64:
224		vb, ok := b.(*OptionalHeader64)
225		if !ok {
226			return false
227		}
228		return *vb == *va
229	case nil:
230		return b == nil
231	}
232	return false
233}
234
235func TestOpen(t *testing.T) {
236	for i := range fileTests {
237		tt := &fileTests[i]
238
239		f, err := Open(tt.file)
240		if err != nil {
241			t.Error(err)
242			continue
243		}
244		if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
245			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
246			continue
247		}
248		if !isOptHdrEq(tt.opthdr, f.OptionalHeader) {
249			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr)
250			continue
251		}
252
253		for i, sh := range f.Sections {
254			if i >= len(tt.sections) {
255				break
256			}
257			have := &sh.SectionHeader
258			want := tt.sections[i]
259			if !reflect.DeepEqual(have, want) {
260				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
261			}
262		}
263		tn := len(tt.sections)
264		fn := len(f.Sections)
265		if tn != fn {
266			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
267		}
268		for i, have := range f.Symbols {
269			if i >= len(tt.symbols) {
270				break
271			}
272			want := tt.symbols[i]
273			if !reflect.DeepEqual(have, want) {
274				t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
275			}
276		}
277		if !tt.hasNoDwarfInfo {
278			_, err = f.DWARF()
279			if err != nil {
280				t.Errorf("fetching %s dwarf details failed: %v", tt.file, err)
281			}
282		}
283	}
284}
285
286func TestOpenFailure(t *testing.T) {
287	filename := "file.go"    // not a PE file
288	_, err := Open(filename) // don't crash
289	if err == nil {
290		t.Errorf("open %s: succeeded unexpectedly", filename)
291	}
292}
293
294const (
295	linkNoCgo = iota
296	linkCgoDefault
297	linkCgoInternal
298	linkCgoExternal
299)
300
301func getImageBase(f *File) uintptr {
302	switch oh := f.OptionalHeader.(type) {
303	case *OptionalHeader32:
304		return uintptr(oh.ImageBase)
305	case *OptionalHeader64:
306		return uintptr(oh.ImageBase)
307	default:
308		panic("unexpected optionalheader type")
309	}
310}
311
312func testDWARF(t *testing.T, linktype int) {
313	if runtime.GOOS != "windows" {
314		t.Skip("skipping windows only test")
315	}
316	testenv.MustHaveGoRun(t)
317
318	tmpdir, err := ioutil.TempDir("", "TestDWARF")
319	if err != nil {
320		t.Fatal(err)
321	}
322	defer os.RemoveAll(tmpdir)
323
324	src := filepath.Join(tmpdir, "a.go")
325	file, err := os.Create(src)
326	if err != nil {
327		t.Fatal(err)
328	}
329	err = template.Must(template.New("main").Parse(testprog)).Execute(file, linktype != linkNoCgo)
330	if err != nil {
331		if err := file.Close(); err != nil {
332			t.Error(err)
333		}
334		t.Fatal(err)
335	}
336	if err := file.Close(); err != nil {
337		t.Fatal(err)
338	}
339
340	exe := filepath.Join(tmpdir, "a.exe")
341	args := []string{"build", "-o", exe}
342	switch linktype {
343	case linkNoCgo:
344	case linkCgoDefault:
345	case linkCgoInternal:
346		args = append(args, "-ldflags", "-linkmode=internal")
347	case linkCgoExternal:
348		args = append(args, "-ldflags", "-linkmode=external")
349	default:
350		t.Fatalf("invalid linktype parameter of %v", linktype)
351	}
352	args = append(args, src)
353	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
354	if err != nil {
355		t.Fatalf("building test executable for linktype %d failed: %s %s", linktype, err, out)
356	}
357	out, err = exec.Command(exe).CombinedOutput()
358	if err != nil {
359		t.Fatalf("running test executable failed: %s %s", err, out)
360	}
361	t.Logf("Testprog output:\n%s", string(out))
362
363	matches := regexp.MustCompile("offset=(.*)\n").FindStringSubmatch(string(out))
364	if len(matches) < 2 {
365		t.Fatalf("unexpected program output: %s", out)
366	}
367	wantoffset, err := strconv.ParseUint(matches[1], 0, 64)
368	if err != nil {
369		t.Fatalf("unexpected main offset %q: %s", matches[1], err)
370	}
371
372	f, err := Open(exe)
373	if err != nil {
374		t.Fatal(err)
375	}
376	defer f.Close()
377
378	imageBase := getImageBase(f)
379
380	var foundDebugGDBScriptsSection bool
381	for _, sect := range f.Sections {
382		if sect.Name == ".debug_gdb_scripts" {
383			foundDebugGDBScriptsSection = true
384		}
385	}
386	if !foundDebugGDBScriptsSection {
387		t.Error(".debug_gdb_scripts section is not found")
388	}
389
390	d, err := f.DWARF()
391	if err != nil {
392		t.Fatal(err)
393	}
394
395	// look for main.main
396	r := d.Reader()
397	for {
398		e, err := r.Next()
399		if err != nil {
400			t.Fatal("r.Next:", err)
401		}
402		if e == nil {
403			break
404		}
405		if e.Tag == dwarf.TagSubprogram {
406			name, ok := e.Val(dwarf.AttrName).(string)
407			if ok && name == "main.main" {
408				t.Logf("Found main.main")
409				addr, ok := e.Val(dwarf.AttrLowpc).(uint64)
410				if !ok {
411					t.Fatal("Failed to get AttrLowpc")
412				}
413				offset := uintptr(addr) - imageBase
414				if offset != uintptr(wantoffset) {
415					t.Fatal("Runtime offset (0x%x) did "+
416						"not match dwarf offset "+
417						"(0x%x)", wantoffset, offset)
418				}
419				return
420			}
421		}
422	}
423	t.Fatal("main.main not found")
424}
425
426func TestBSSHasZeros(t *testing.T) {
427	testenv.MustHaveExec(t)
428
429	if runtime.GOOS != "windows" {
430		t.Skip("skipping windows only test")
431	}
432	gccpath, err := exec.LookPath("gcc")
433	if err != nil {
434		t.Skip("skipping test: gcc is missing")
435	}
436
437	tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros")
438	if err != nil {
439		t.Fatal(err)
440	}
441	defer os.RemoveAll(tmpdir)
442
443	srcpath := filepath.Join(tmpdir, "a.c")
444	src := `
445#include <stdio.h>
446
447int zero = 0;
448
449int
450main(void)
451{
452	printf("%d\n", zero);
453	return 0;
454}
455`
456	err = ioutil.WriteFile(srcpath, []byte(src), 0644)
457	if err != nil {
458		t.Fatal(err)
459	}
460
461	objpath := filepath.Join(tmpdir, "a.obj")
462	cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath)
463	out, err := cmd.CombinedOutput()
464	if err != nil {
465		t.Fatalf("failed to build object file: %v - %v", err, string(out))
466	}
467
468	f, err := Open(objpath)
469	if err != nil {
470		t.Fatal(err)
471	}
472	defer f.Close()
473
474	var bss *Section
475	for _, sect := range f.Sections {
476		if sect.Name == ".bss" {
477			bss = sect
478			break
479		}
480	}
481	if bss == nil {
482		t.Fatal("could not find .bss section")
483	}
484	data, err := bss.Data()
485	if err != nil {
486		t.Fatal(err)
487	}
488	if len(data) == 0 {
489		t.Fatalf("%s file .bss section cannot be empty", objpath)
490	}
491	for _, b := range data {
492		if b != 0 {
493			t.Fatalf(".bss section has non zero bytes: %v", data)
494		}
495	}
496}
497
498func TestDWARF(t *testing.T) {
499	testDWARF(t, linkNoCgo)
500}
501
502const testprog = `
503package main
504
505import "fmt"
506import "syscall"
507import "unsafe"
508{{if .}}import "C"
509{{end}}
510
511// struct MODULEINFO from the Windows SDK
512type moduleinfo struct {
513	BaseOfDll uintptr
514	SizeOfImage uint32
515	EntryPoint uintptr
516}
517
518func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
519	return unsafe.Pointer(uintptr(p) + x)
520}
521
522func funcPC(f interface{}) uintptr {
523	var a uintptr
524	return **(**uintptr)(add(unsafe.Pointer(&f), unsafe.Sizeof(a)))
525}
526
527func main() {
528	kernel32 := syscall.MustLoadDLL("kernel32.dll")
529	psapi := syscall.MustLoadDLL("psapi.dll")
530	getModuleHandle := kernel32.MustFindProc("GetModuleHandleW")
531	getCurrentProcess := kernel32.MustFindProc("GetCurrentProcess")
532	getModuleInformation := psapi.MustFindProc("GetModuleInformation")
533
534	procHandle, _, _ := getCurrentProcess.Call()
535	moduleHandle, _, err := getModuleHandle.Call(0)
536	if moduleHandle == 0 {
537		panic(fmt.Sprintf("GetModuleHandle() failed: %d", err))
538	}
539
540	var info moduleinfo
541	ret, _, err := getModuleInformation.Call(procHandle, moduleHandle,
542		uintptr(unsafe.Pointer(&info)), unsafe.Sizeof(info))
543
544	if ret == 0 {
545		panic(fmt.Sprintf("GetModuleInformation() failed: %d", err))
546	}
547
548	offset := funcPC(main) - info.BaseOfDll
549	fmt.Printf("base=0x%x\n", info.BaseOfDll)
550	fmt.Printf("main=%p\n", main)
551	fmt.Printf("offset=0x%x\n", offset)
552}
553`
554
555func TestBuildingWindowsGUI(t *testing.T) {
556	testenv.MustHaveGoBuild(t)
557
558	if runtime.GOOS != "windows" {
559		t.Skip("skipping windows only test")
560	}
561	tmpdir, err := ioutil.TempDir("", "TestBuildingWindowsGUI")
562	if err != nil {
563		t.Fatal(err)
564	}
565	defer os.RemoveAll(tmpdir)
566
567	src := filepath.Join(tmpdir, "a.go")
568	err = ioutil.WriteFile(src, []byte(`package main; func main() {}`), 0644)
569	if err != nil {
570		t.Fatal(err)
571	}
572	exe := filepath.Join(tmpdir, "a.exe")
573	cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags", "-H=windowsgui", "-o", exe, src)
574	out, err := cmd.CombinedOutput()
575	if err != nil {
576		t.Fatalf("building test executable failed: %s %s", err, out)
577	}
578
579	f, err := Open(exe)
580	if err != nil {
581		t.Fatal(err)
582	}
583	defer f.Close()
584
585	const _IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
586
587	switch oh := f.OptionalHeader.(type) {
588	case *OptionalHeader32:
589		if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
590			t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
591		}
592	case *OptionalHeader64:
593		if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
594			t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
595		}
596	default:
597		t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh)
598	}
599}
600
601func TestImportTableInUnknownSection(t *testing.T) {
602	if runtime.GOOS != "windows" {
603		t.Skip("skipping Windows-only test")
604	}
605
606	// ws2_32.dll import table is located in ".rdata" section,
607	// so it is good enough to test issue #16103.
608	const filename = "ws2_32.dll"
609	path, err := exec.LookPath(filename)
610	if err != nil {
611		t.Fatalf("unable to locate required file %q in search path: %s", filename, err)
612	}
613
614	f, err := Open(path)
615	if err != nil {
616		t.Error(err)
617	}
618	defer f.Close()
619
620	// now we can extract its imports
621	symbols, err := f.ImportedSymbols()
622	if err != nil {
623		t.Error(err)
624	}
625
626	if len(symbols) == 0 {
627		t.Fatalf("unable to locate any imported symbols within file %q.", path)
628	}
629}
630