Home | History | Annotate | Download | only in pe
      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 
      5 package pe
      6 
      7 import (
      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 
     22 type fileTest struct {
     23 	file           string
     24 	hdr            FileHeader
     25 	opthdr         interface{}
     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 func 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 
    235 func 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 
    286 func 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 
    294 const (
    295 	linkNoCgo = iota
    296 	linkCgoDefault
    297 	linkCgoInternal
    298 	linkCgoExternal
    299 )
    300 
    301 func testDWARF(t *testing.T, linktype int) {
    302 	if runtime.GOOS != "windows" {
    303 		t.Skip("skipping windows only test")
    304 	}
    305 	testenv.MustHaveGoRun(t)
    306 
    307 	tmpdir, err := ioutil.TempDir("", "TestDWARF")
    308 	if err != nil {
    309 		t.Fatal(err)
    310 	}
    311 	defer os.RemoveAll(tmpdir)
    312 
    313 	src := filepath.Join(tmpdir, "a.go")
    314 	file, err := os.Create(src)
    315 	if err != nil {
    316 		t.Fatal(err)
    317 	}
    318 	err = template.Must(template.New("main").Parse(testprog)).Execute(file, linktype != linkNoCgo)
    319 	if err != nil {
    320 		if err := file.Close(); err != nil {
    321 			t.Error(err)
    322 		}
    323 		t.Fatal(err)
    324 	}
    325 	if err := file.Close(); err != nil {
    326 		t.Fatal(err)
    327 	}
    328 
    329 	exe := filepath.Join(tmpdir, "a.exe")
    330 	args := []string{"build", "-o", exe}
    331 	switch linktype {
    332 	case linkNoCgo:
    333 	case linkCgoDefault:
    334 	case linkCgoInternal:
    335 		args = append(args, "-ldflags", "-linkmode=internal")
    336 	case linkCgoExternal:
    337 		args = append(args, "-ldflags", "-linkmode=external")
    338 	default:
    339 		t.Fatalf("invalid linktype parameter of %v", linktype)
    340 	}
    341 	args = append(args, src)
    342 	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
    343 	if err != nil {
    344 		t.Fatalf("building test executable for linktype %d failed: %s %s", linktype, err, out)
    345 	}
    346 	out, err = exec.Command(exe).CombinedOutput()
    347 	if err != nil {
    348 		t.Fatalf("running test executable failed: %s %s", err, out)
    349 	}
    350 
    351 	matches := regexp.MustCompile("main=(.*)\n").FindStringSubmatch(string(out))
    352 	if len(matches) < 2 {
    353 		t.Fatalf("unexpected program output: %s", out)
    354 	}
    355 	wantaddr, err := strconv.ParseUint(matches[1], 0, 64)
    356 	if err != nil {
    357 		t.Fatalf("unexpected main address %q: %s", matches[1], err)
    358 	}
    359 
    360 	f, err := Open(exe)
    361 	if err != nil {
    362 		t.Fatal(err)
    363 	}
    364 	defer f.Close()
    365 
    366 	var foundDebugGDBScriptsSection bool
    367 	for _, sect := range f.Sections {
    368 		if sect.Name == ".debug_gdb_scripts" {
    369 			foundDebugGDBScriptsSection = true
    370 		}
    371 	}
    372 	if !foundDebugGDBScriptsSection {
    373 		t.Error(".debug_gdb_scripts section is not found")
    374 	}
    375 
    376 	d, err := f.DWARF()
    377 	if err != nil {
    378 		t.Fatal(err)
    379 	}
    380 
    381 	// look for main.main
    382 	r := d.Reader()
    383 	for {
    384 		e, err := r.Next()
    385 		if err != nil {
    386 			t.Fatal("r.Next:", err)
    387 		}
    388 		if e == nil {
    389 			break
    390 		}
    391 		if e.Tag == dwarf.TagSubprogram {
    392 			if name, ok := e.Val(dwarf.AttrName).(string); ok && name == "main.main" {
    393 				if addr, ok := e.Val(dwarf.AttrLowpc).(uint64); ok && addr == wantaddr {
    394 					return
    395 				}
    396 			}
    397 		}
    398 	}
    399 	t.Fatal("main.main not found")
    400 }
    401 
    402 func TestBSSHasZeros(t *testing.T) {
    403 	testenv.MustHaveExec(t)
    404 
    405 	if runtime.GOOS != "windows" {
    406 		t.Skip("skipping windows only test")
    407 	}
    408 	gccpath, err := exec.LookPath("gcc")
    409 	if err != nil {
    410 		t.Skip("skipping test: gcc is missing")
    411 	}
    412 
    413 	tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros")
    414 	if err != nil {
    415 		t.Fatal(err)
    416 	}
    417 	defer os.RemoveAll(tmpdir)
    418 
    419 	srcpath := filepath.Join(tmpdir, "a.c")
    420 	src := `
    421 #include <stdio.h>
    422 
    423 int zero = 0;
    424 
    425 int
    426 main(void)
    427 {
    428 	printf("%d\n", zero);
    429 	return 0;
    430 }
    431 `
    432 	err = ioutil.WriteFile(srcpath, []byte(src), 0644)
    433 	if err != nil {
    434 		t.Fatal(err)
    435 	}
    436 
    437 	objpath := filepath.Join(tmpdir, "a.obj")
    438 	cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath)
    439 	out, err := cmd.CombinedOutput()
    440 	if err != nil {
    441 		t.Fatalf("failed to build object file: %v - %v", err, string(out))
    442 	}
    443 
    444 	f, err := Open(objpath)
    445 	if err != nil {
    446 		t.Fatal(err)
    447 	}
    448 	defer f.Close()
    449 
    450 	var bss *Section
    451 	for _, sect := range f.Sections {
    452 		if sect.Name == ".bss" {
    453 			bss = sect
    454 			break
    455 		}
    456 	}
    457 	if bss == nil {
    458 		t.Fatal("could not find .bss section")
    459 	}
    460 	data, err := bss.Data()
    461 	if err != nil {
    462 		t.Fatal(err)
    463 	}
    464 	if len(data) == 0 {
    465 		t.Fatalf("%s file .bss section cannot be empty", objpath)
    466 	}
    467 	for _, b := range data {
    468 		if b != 0 {
    469 			t.Fatalf(".bss section has non zero bytes: %v", data)
    470 		}
    471 	}
    472 }
    473 
    474 func TestDWARF(t *testing.T) {
    475 	testDWARF(t, linkNoCgo)
    476 }
    477 
    478 const testprog = `
    479 package main
    480 
    481 import "fmt"
    482 {{if .}}import "C"
    483 {{end}}
    484 
    485 func main() {
    486 	fmt.Printf("main=%p\n", main)
    487 }
    488 `
    489 
    490 func TestBuildingWindowsGUI(t *testing.T) {
    491 	testenv.MustHaveGoBuild(t)
    492 
    493 	if runtime.GOOS != "windows" {
    494 		t.Skip("skipping windows only test")
    495 	}
    496 	tmpdir, err := ioutil.TempDir("", "TestBuildingWindowsGUI")
    497 	if err != nil {
    498 		t.Fatal(err)
    499 	}
    500 	defer os.RemoveAll(tmpdir)
    501 
    502 	src := filepath.Join(tmpdir, "a.go")
    503 	err = ioutil.WriteFile(src, []byte(`package main; func main() {}`), 0644)
    504 	if err != nil {
    505 		t.Fatal(err)
    506 	}
    507 	exe := filepath.Join(tmpdir, "a.exe")
    508 	cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags", "-H=windowsgui", "-o", exe, src)
    509 	out, err := cmd.CombinedOutput()
    510 	if err != nil {
    511 		t.Fatalf("building test executable failed: %s %s", err, out)
    512 	}
    513 
    514 	f, err := Open(exe)
    515 	if err != nil {
    516 		t.Fatal(err)
    517 	}
    518 	defer f.Close()
    519 
    520 	const _IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
    521 
    522 	switch oh := f.OptionalHeader.(type) {
    523 	case *OptionalHeader32:
    524 		if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
    525 			t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
    526 		}
    527 	case *OptionalHeader64:
    528 		if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
    529 			t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
    530 		}
    531 	default:
    532 		t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh)
    533 	}
    534 }
    535