github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/debug/pe/file_test.go (about)

     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 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  
   312  func 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  
   426  func 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  
   447  int zero = 0;
   448  
   449  int
   450  main(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  
   498  func TestDWARF(t *testing.T) {
   499  	testDWARF(t, linkNoCgo)
   500  }
   501  
   502  const testprog = `
   503  package main
   504  
   505  import "fmt"
   506  import "syscall"
   507  import "unsafe"
   508  {{if .}}import "C"
   509  {{end}}
   510  
   511  // struct MODULEINFO from the Windows SDK
   512  type moduleinfo struct {
   513  	BaseOfDll uintptr
   514  	SizeOfImage uint32
   515  	EntryPoint uintptr
   516  }
   517  
   518  func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
   519  	return unsafe.Pointer(uintptr(p) + x)
   520  }
   521  
   522  func funcPC(f interface{}) uintptr {
   523  	var a uintptr
   524  	return **(**uintptr)(add(unsafe.Pointer(&f), unsafe.Sizeof(a)))
   525  }
   526  
   527  func 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  
   555  func 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  
   601  func 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  }