...

Source file src/debug/pe/file_test.go

Documentation: debug/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  	"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				 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  		// testdata/vmlinuz-4.15.0-47-generic is a trimmed down version of Linux Kernel image.
	 215  		// The original Linux Kernel image is about 8M and it is not recommended to add such a big binary file to the repo.
	 216  		// Moreover only a very small portion of the original Kernel image was being parsed by debug/pe package.
	 217  		// In order to identify this portion, the original image was first parsed by modified debug/pe package.
	 218  		// Modification essentially communicated reader's positions before and after parsing.
	 219  		// Finally, bytes between those positions where written to a separate file,
	 220  		// generating trimmed down version Linux Kernel image used in this test case.
	 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 interface{}) 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"		// not a PE file
	 326  	_, err := Open(filename) // don't crash
	 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  	// look for main.main
	 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  	// ws2_32.dll import table is located in ".rdata" section,
	 630  	// so it is good enough to test issue #16103.
	 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  	// now we can extract its imports
	 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  	// Files with invalid optional header magic should return error from NewFile()
	 656  	// (see https://golang.org/issue/30250 and https://golang.org/issue/32126 for details).
	 657  	// Input generated by gofuzz
	 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  	// https://golang.org/issue/30250
	 672  	// ImportedSymbols shouldn't panic if optional headers is missing
	 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  	// https://golang.org/issue/30253
	 700  	// ImportedSymbols shouldn't panic with slice out of bounds
	 701  	// Input generated by gofuzz
	 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  		"@\[email protected]_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  		"@\[email protected]\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