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