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