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