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