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 	"runtime"
     16 	"testing"
     17 )
     18 
     19 type fileTest struct {
     20 	file           string
     21 	hdr            FileHeader
     22 	opthdr         interface{}
     23 	sections       []*SectionHeader
     24 	symbols        []*Symbol
     25 	hasNoDwarfInfo bool
     26 }
     27 
     28 var fileTests = []fileTest{
     29 	{
     30 		file: "testdata/gcc-386-mingw-obj",
     31 		hdr:  FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
     32 		sections: []*SectionHeader{
     33 			{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
     34 			{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
     35 			{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
     36 			{".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
     37 			{".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
     38 			{".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
     39 			{".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
     40 			{".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
     41 			{".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
     42 			{".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
     43 			{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
     44 			{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
     45 		},
     46 		symbols: []*Symbol{
     47 			{".file", 0x0, -2, 0x0, 0x67},
     48 			{"_main", 0x0, 1, 0x20, 0x2},
     49 			{".text", 0x0, 1, 0x0, 0x3},
     50 			{".data", 0x0, 2, 0x0, 0x3},
     51 			{".bss", 0x0, 3, 0x0, 0x3},
     52 			{".debug_abbrev", 0x0, 4, 0x0, 0x3},
     53 			{".debug_info", 0x0, 5, 0x0, 0x3},
     54 			{".debug_line", 0x0, 6, 0x0, 0x3},
     55 			{".rdata", 0x0, 7, 0x0, 0x3},
     56 			{".debug_frame", 0x0, 8, 0x0, 0x3},
     57 			{".debug_loc", 0x0, 9, 0x0, 0x3},
     58 			{".debug_pubnames", 0x0, 10, 0x0, 0x3},
     59 			{".debug_pubtypes", 0x0, 11, 0x0, 0x3},
     60 			{".debug_aranges", 0x0, 12, 0x0, 0x3},
     61 			{"___main", 0x0, 0, 0x20, 0x2},
     62 			{"_puts", 0x0, 0, 0x20, 0x2},
     63 		},
     64 	},
     65 	{
     66 		file: "testdata/gcc-386-mingw-exec",
     67 		hdr:  FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
     68 		opthdr: &OptionalHeader32{
     69 			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,
     70 			[16]DataDirectory{
     71 				{0x0, 0x0},
     72 				{0x5000, 0x3c8},
     73 				{0x0, 0x0},
     74 				{0x0, 0x0},
     75 				{0x0, 0x0},
     76 				{0x0, 0x0},
     77 				{0x0, 0x0},
     78 				{0x0, 0x0},
     79 				{0x0, 0x0},
     80 				{0x7000, 0x18},
     81 				{0x0, 0x0},
     82 				{0x0, 0x0},
     83 				{0x0, 0x0},
     84 				{0x0, 0x0},
     85 				{0x0, 0x0},
     86 				{0x0, 0x0},
     87 			},
     88 		},
     89 		sections: []*SectionHeader{
     90 			{".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
     91 			{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
     92 			{".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
     93 			{".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080},
     94 			{".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
     95 			{".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
     96 			{".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
     97 			{".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
     98 			{".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000},
     99 			{".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000},
    100 			{".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
    101 			{".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
    102 			{".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000},
    103 			{".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000},
    104 			{".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
    105 		},
    106 	},
    107 	{
    108 		file: "testdata/gcc-386-mingw-no-symbols-exec",
    109 		hdr:  FileHeader{0x14c, 0x8, 0x69676572, 0x0, 0x0, 0xe0, 0x30f},
    110 		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,
    111 			[16]DataDirectory{
    112 				{0x0, 0x0},
    113 				{0x6000, 0x378},
    114 				{0x0, 0x0},
    115 				{0x0, 0x0},
    116 				{0x0, 0x0},
    117 				{0x0, 0x0},
    118 				{0x0, 0x0},
    119 				{0x0, 0x0},
    120 				{0x0, 0x0},
    121 				{0x8004, 0x18},
    122 				{0x0, 0x0},
    123 				{0x0, 0x0},
    124 				{0x60b8, 0x7c},
    125 				{0x0, 0x0},
    126 				{0x0, 0x0},
    127 				{0x0, 0x0},
    128 			},
    129 		},
    130 		sections: []*SectionHeader{
    131 			{".text", 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
    132 			{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
    133 			{".rdata", 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
    134 			{".eh_fram", 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040},
    135 			{".bss", 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080},
    136 			{".idata", 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
    137 			{".CRT", 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
    138 			{".tls", 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
    139 		},
    140 		hasNoDwarfInfo: true,
    141 	},
    142 	{
    143 		file: "testdata/gcc-amd64-mingw-obj",
    144 		hdr:  FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
    145 		sections: []*SectionHeader{
    146 			{".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020},
    147 			{".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
    148 			{".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080},
    149 			{".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040},
    150 			{".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
    151 			{".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
    152 		},
    153 		symbols: []*Symbol{
    154 			{".file", 0x0, -2, 0x0, 0x67},
    155 			{"main", 0x0, 1, 0x20, 0x2},
    156 			{".text", 0x0, 1, 0x0, 0x3},
    157 			{".data", 0x0, 2, 0x0, 0x3},
    158 			{".bss", 0x0, 3, 0x0, 0x3},
    159 			{".rdata", 0x0, 4, 0x0, 0x3},
    160 			{".xdata", 0x0, 5, 0x0, 0x3},
    161 			{".pdata", 0x0, 6, 0x0, 0x3},
    162 			{"__main", 0x0, 0, 0x20, 0x2},
    163 			{"puts", 0x0, 0, 0x20, 0x2},
    164 		},
    165 		hasNoDwarfInfo: true,
    166 	},
    167 	{
    168 		file: "testdata/gcc-amd64-mingw-exec",
    169 		hdr:  FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
    170 		opthdr: &OptionalHeader64{
    171 			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,
    172 			[16]DataDirectory{
    173 				{0x0, 0x0},
    174 				{0xe000, 0x990},
    175 				{0x0, 0x0},
    176 				{0xa000, 0x498},
    177 				{0x0, 0x0},
    178 				{0x0, 0x0},
    179 				{0x0, 0x0},
    180 				{0x0, 0x0},
    181 				{0x0, 0x0},
    182 				{0x10000, 0x28},
    183 				{0x0, 0x0},
    184 				{0x0, 0x0},
    185 				{0xe254, 0x218},
    186 				{0x0, 0x0},
    187 				{0x0, 0x0},
    188 				{0x0, 0x0},
    189 			}},
    190 		sections: []*SectionHeader{
    191 			{".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020},
    192 			{".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
    193 			{".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040},
    194 			{".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
    195 			{".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040},
    196 			{".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
    197 			{".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
    198 			{".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
    199 			{".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
    200 			{".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040},
    201 			{".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
    202 			{".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
    203 			{".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
    204 			{".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040},
    205 			{".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040},
    206 			{".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040},
    207 			{".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
    208 		},
    209 	},
    210 }
    211 
    212 func isOptHdrEq(a, b interface{}) bool {
    213 	switch va := a.(type) {
    214 	case *OptionalHeader32:
    215 		vb, ok := b.(*OptionalHeader32)
    216 		if !ok {
    217 			return false
    218 		}
    219 		return *vb == *va
    220 	case *OptionalHeader64:
    221 		vb, ok := b.(*OptionalHeader64)
    222 		if !ok {
    223 			return false
    224 		}
    225 		return *vb == *va
    226 	case nil:
    227 		return b == nil
    228 	}
    229 	return false
    230 }
    231 
    232 func TestOpen(t *testing.T) {
    233 	for i := range fileTests {
    234 		tt := &fileTests[i]
    235 
    236 		f, err := Open(tt.file)
    237 		if err != nil {
    238 			t.Error(err)
    239 			continue
    240 		}
    241 		if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
    242 			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
    243 			continue
    244 		}
    245 		if !isOptHdrEq(tt.opthdr, f.OptionalHeader) {
    246 			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr)
    247 			continue
    248 		}
    249 
    250 		for i, sh := range f.Sections {
    251 			if i >= len(tt.sections) {
    252 				break
    253 			}
    254 			have := &sh.SectionHeader
    255 			want := tt.sections[i]
    256 			if !reflect.DeepEqual(have, want) {
    257 				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
    258 			}
    259 		}
    260 		tn := len(tt.sections)
    261 		fn := len(f.Sections)
    262 		if tn != fn {
    263 			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
    264 		}
    265 		for i, have := range f.Symbols {
    266 			if i >= len(tt.symbols) {
    267 				break
    268 			}
    269 			want := tt.symbols[i]
    270 			if !reflect.DeepEqual(have, want) {
    271 				t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
    272 			}
    273 		}
    274 		if !tt.hasNoDwarfInfo {
    275 			_, err = f.DWARF()
    276 			if err != nil {
    277 				t.Errorf("fetching %s dwarf details failed: %v", tt.file, err)
    278 			}
    279 		}
    280 	}
    281 }
    282 
    283 func TestOpenFailure(t *testing.T) {
    284 	filename := "file.go"    // not a PE file
    285 	_, err := Open(filename) // don't crash
    286 	if err == nil {
    287 		t.Errorf("open %s: succeeded unexpectedly", filename)
    288 	}
    289 }
    290 
    291 func TestDWARF(t *testing.T) {
    292 	if runtime.GOOS != "windows" {
    293 		t.Skip("skipping windows only test")
    294 	}
    295 
    296 	tmpdir, err := ioutil.TempDir("", "TestDWARF")
    297 	if err != nil {
    298 		t.Fatal("TempDir failed: ", err)
    299 	}
    300 	defer os.RemoveAll(tmpdir)
    301 
    302 	prog := `
    303 package main
    304 func main() {
    305 }
    306 `
    307 	src := filepath.Join(tmpdir, "a.go")
    308 	exe := filepath.Join(tmpdir, "a.exe")
    309 	err = ioutil.WriteFile(src, []byte(prog), 0644)
    310 	output, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
    311 	if err != nil {
    312 		t.Fatalf("building test executable failed: %s %s", err, output)
    313 	}
    314 
    315 	f, err := Open(exe)
    316 	if err != nil {
    317 		t.Fatal(err)
    318 	}
    319 	defer f.Close()
    320 
    321 	d, err := f.DWARF()
    322 	if err != nil {
    323 		t.Fatal(err)
    324 	}
    325 
    326 	// look for main.main
    327 	r := d.Reader()
    328 	for {
    329 		e, err := r.Next()
    330 		if err != nil {
    331 			t.Fatal("r.Next:", err)
    332 		}
    333 		if e == nil {
    334 			break
    335 		}
    336 		if e.Tag == dwarf.TagSubprogram {
    337 			for _, f := range e.Field {
    338 				if f.Attr == dwarf.AttrName && e.Val(dwarf.AttrName) == "main.main" {
    339 					return
    340 				}
    341 			}
    342 		}
    343 	}
    344 	t.Fatal("main.main not found")
    345 }
    346 
    347 func TestBSSHasZeros(t *testing.T) {
    348 	testenv.MustHaveExec(t)
    349 
    350 	if runtime.GOOS != "windows" {
    351 		t.Skip("skipping windows only test")
    352 	}
    353 	gccpath, err := exec.LookPath("gcc")
    354 	if err != nil {
    355 		t.Skip("skipping test: gcc is missing")
    356 	}
    357 
    358 	tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros")
    359 	if err != nil {
    360 		t.Fatal(err)
    361 	}
    362 	defer os.RemoveAll(tmpdir)
    363 
    364 	srcpath := filepath.Join(tmpdir, "a.c")
    365 	src := `
    366 #include <stdio.h>
    367 
    368 int zero = 0;
    369 
    370 int
    371 main(void)
    372 {
    373 	printf("%d\n", zero);
    374 	return 0;
    375 }
    376 `
    377 	err = ioutil.WriteFile(srcpath, []byte(src), 0644)
    378 	if err != nil {
    379 		t.Fatal(err)
    380 	}
    381 
    382 	objpath := filepath.Join(tmpdir, "a.obj")
    383 	cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath)
    384 	out, err := cmd.CombinedOutput()
    385 	if err != nil {
    386 		t.Fatalf("failed to build object file: %v - %v", err, string(out))
    387 	}
    388 
    389 	f, err := Open(objpath)
    390 	if err != nil {
    391 		t.Fatal(err)
    392 	}
    393 	defer f.Close()
    394 
    395 	var bss *Section
    396 	for _, sect := range f.Sections {
    397 		if sect.Name == ".bss" {
    398 			bss = sect
    399 			break
    400 		}
    401 	}
    402 	if bss == nil {
    403 		t.Fatal("could not find .bss section")
    404 	}
    405 	data, err := bss.Data()
    406 	if err != nil {
    407 		t.Fatal(err)
    408 	}
    409 	if len(data) == 0 {
    410 		t.Fatalf("%s file .bss section cannot be empty", objpath)
    411 	}
    412 	for _, b := range data {
    413 		if b != 0 {
    414 			t.Fatalf(".bss section has non zero bytes: %v", data)
    415 		}
    416 	}
    417 }
    418