github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/debug/pe/file_test.go (about) 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 "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 215 func isOptHdrEq(a, b interface{}) bool { 216 switch va := a.(type) { 217 case *OptionalHeader32: 218 vb, ok := b.(*OptionalHeader32) 219 if !ok { 220 return false 221 } 222 return *vb == *va 223 case *OptionalHeader64: 224 vb, ok := b.(*OptionalHeader64) 225 if !ok { 226 return false 227 } 228 return *vb == *va 229 case nil: 230 return b == nil 231 } 232 return false 233 } 234 235 func TestOpen(t *testing.T) { 236 for i := range fileTests { 237 tt := &fileTests[i] 238 239 f, err := Open(tt.file) 240 if err != nil { 241 t.Error(err) 242 continue 243 } 244 if !reflect.DeepEqual(f.FileHeader, tt.hdr) { 245 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr) 246 continue 247 } 248 if !isOptHdrEq(tt.opthdr, f.OptionalHeader) { 249 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr) 250 continue 251 } 252 253 for i, sh := range f.Sections { 254 if i >= len(tt.sections) { 255 break 256 } 257 have := &sh.SectionHeader 258 want := tt.sections[i] 259 if !reflect.DeepEqual(have, want) { 260 t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 261 } 262 } 263 tn := len(tt.sections) 264 fn := len(f.Sections) 265 if tn != fn { 266 t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn) 267 } 268 for i, have := range f.Symbols { 269 if i >= len(tt.symbols) { 270 break 271 } 272 want := tt.symbols[i] 273 if !reflect.DeepEqual(have, want) { 274 t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 275 } 276 } 277 if !tt.hasNoDwarfInfo { 278 _, err = f.DWARF() 279 if err != nil { 280 t.Errorf("fetching %s dwarf details failed: %v", tt.file, err) 281 } 282 } 283 } 284 } 285 286 func TestOpenFailure(t *testing.T) { 287 filename := "file.go" // not a PE file 288 _, err := Open(filename) // don't crash 289 if err == nil { 290 t.Errorf("open %s: succeeded unexpectedly", filename) 291 } 292 } 293 294 const ( 295 linkNoCgo = iota 296 linkCgoDefault 297 linkCgoInternal 298 linkCgoExternal 299 ) 300 301 func testDWARF(t *testing.T, linktype int) { 302 if runtime.GOOS != "windows" { 303 t.Skip("skipping windows only test") 304 } 305 testenv.MustHaveGoRun(t) 306 307 tmpdir, err := ioutil.TempDir("", "TestDWARF") 308 if err != nil { 309 t.Fatal(err) 310 } 311 defer os.RemoveAll(tmpdir) 312 313 src := filepath.Join(tmpdir, "a.go") 314 file, err := os.Create(src) 315 if err != nil { 316 t.Fatal(err) 317 } 318 err = template.Must(template.New("main").Parse(testprog)).Execute(file, linktype != linkNoCgo) 319 if err != nil { 320 if err := file.Close(); err != nil { 321 t.Error(err) 322 } 323 t.Fatal(err) 324 } 325 if err := file.Close(); err != nil { 326 t.Fatal(err) 327 } 328 329 exe := filepath.Join(tmpdir, "a.exe") 330 args := []string{"build", "-o", exe} 331 switch linktype { 332 case linkNoCgo: 333 case linkCgoDefault: 334 case linkCgoInternal: 335 args = append(args, "-ldflags", "-linkmode=internal") 336 case linkCgoExternal: 337 args = append(args, "-ldflags", "-linkmode=external") 338 default: 339 t.Fatalf("invalid linktype parameter of %v", linktype) 340 } 341 args = append(args, src) 342 out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput() 343 if err != nil { 344 t.Fatalf("building test executable failed: %s %s", err, out) 345 } 346 out, err = exec.Command(exe).CombinedOutput() 347 if err != nil { 348 t.Fatalf("running test executable failed: %s %s", err, out) 349 } 350 351 matches := regexp.MustCompile("main=(.*)\n").FindStringSubmatch(string(out)) 352 if len(matches) < 2 { 353 t.Fatalf("unexpected program output: %s", out) 354 } 355 wantaddr, err := strconv.ParseUint(matches[1], 0, 64) 356 if err != nil { 357 t.Fatalf("unexpected main address %q: %s", matches[1], err) 358 } 359 360 f, err := Open(exe) 361 if err != nil { 362 t.Fatal(err) 363 } 364 defer f.Close() 365 366 d, err := f.DWARF() 367 if err != nil { 368 t.Fatal(err) 369 } 370 371 // look for main.main 372 r := d.Reader() 373 for { 374 e, err := r.Next() 375 if err != nil { 376 t.Fatal("r.Next:", err) 377 } 378 if e == nil { 379 break 380 } 381 if e.Tag == dwarf.TagSubprogram { 382 if name, ok := e.Val(dwarf.AttrName).(string); ok && name == "main.main" { 383 if addr, ok := e.Val(dwarf.AttrLowpc).(uint64); ok && addr == wantaddr { 384 return 385 } 386 } 387 } 388 } 389 t.Fatal("main.main not found") 390 } 391 392 func TestBSSHasZeros(t *testing.T) { 393 testenv.MustHaveExec(t) 394 395 if runtime.GOOS != "windows" { 396 t.Skip("skipping windows only test") 397 } 398 gccpath, err := exec.LookPath("gcc") 399 if err != nil { 400 t.Skip("skipping test: gcc is missing") 401 } 402 403 tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros") 404 if err != nil { 405 t.Fatal(err) 406 } 407 defer os.RemoveAll(tmpdir) 408 409 srcpath := filepath.Join(tmpdir, "a.c") 410 src := ` 411 #include <stdio.h> 412 413 int zero = 0; 414 415 int 416 main(void) 417 { 418 printf("%d\n", zero); 419 return 0; 420 } 421 ` 422 err = ioutil.WriteFile(srcpath, []byte(src), 0644) 423 if err != nil { 424 t.Fatal(err) 425 } 426 427 objpath := filepath.Join(tmpdir, "a.obj") 428 cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath) 429 out, err := cmd.CombinedOutput() 430 if err != nil { 431 t.Fatalf("failed to build object file: %v - %v", err, string(out)) 432 } 433 434 f, err := Open(objpath) 435 if err != nil { 436 t.Fatal(err) 437 } 438 defer f.Close() 439 440 var bss *Section 441 for _, sect := range f.Sections { 442 if sect.Name == ".bss" { 443 bss = sect 444 break 445 } 446 } 447 if bss == nil { 448 t.Fatal("could not find .bss section") 449 } 450 data, err := bss.Data() 451 if err != nil { 452 t.Fatal(err) 453 } 454 if len(data) == 0 { 455 t.Fatalf("%s file .bss section cannot be empty", objpath) 456 } 457 for _, b := range data { 458 if b != 0 { 459 t.Fatalf(".bss section has non zero bytes: %v", data) 460 } 461 } 462 } 463 464 func TestDWARF(t *testing.T) { 465 testDWARF(t, linkNoCgo) 466 } 467 468 const testprog = ` 469 package main 470 471 import "fmt" 472 {{if .}}import "C" 473 {{end}} 474 475 func main() { 476 fmt.Printf("main=%p\n", main) 477 } 478 `