github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/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 "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-amd64-mingw-obj", 109 hdr: FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4}, 110 sections: []*SectionHeader{ 111 {".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020}, 112 {".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, 113 {".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080}, 114 {".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040}, 115 {".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040}, 116 {".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040}, 117 }, 118 symbols: []*Symbol{ 119 {".file", 0x0, -2, 0x0, 0x67}, 120 {"main", 0x0, 1, 0x20, 0x2}, 121 {".text", 0x0, 1, 0x0, 0x3}, 122 {".data", 0x0, 2, 0x0, 0x3}, 123 {".bss", 0x0, 3, 0x0, 0x3}, 124 {".rdata", 0x0, 4, 0x0, 0x3}, 125 {".xdata", 0x0, 5, 0x0, 0x3}, 126 {".pdata", 0x0, 6, 0x0, 0x3}, 127 {"__main", 0x0, 0, 0x20, 0x2}, 128 {"puts", 0x0, 0, 0x20, 0x2}, 129 }, 130 hasNoDwarfInfo: true, 131 }, 132 { 133 file: "testdata/gcc-amd64-mingw-exec", 134 hdr: FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27}, 135 opthdr: &OptionalHeader64{ 136 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, 137 [16]DataDirectory{ 138 {0x0, 0x0}, 139 {0xe000, 0x990}, 140 {0x0, 0x0}, 141 {0xa000, 0x498}, 142 {0x0, 0x0}, 143 {0x0, 0x0}, 144 {0x0, 0x0}, 145 {0x0, 0x0}, 146 {0x0, 0x0}, 147 {0x10000, 0x28}, 148 {0x0, 0x0}, 149 {0x0, 0x0}, 150 {0xe254, 0x218}, 151 {0x0, 0x0}, 152 {0x0, 0x0}, 153 {0x0, 0x0}, 154 }}, 155 sections: []*SectionHeader{ 156 {".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020}, 157 {".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, 158 {".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040}, 159 {".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040}, 160 {".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040}, 161 {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080}, 162 {".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 163 {".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040}, 164 {".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040}, 165 {".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040}, 166 {".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 167 {".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 168 {".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 169 {".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040}, 170 {".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 171 {".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 172 {".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 173 }, 174 }, 175 } 176 177 func isOptHdrEq(a, b interface{}) bool { 178 switch va := a.(type) { 179 case *OptionalHeader32: 180 vb, ok := b.(*OptionalHeader32) 181 if !ok { 182 return false 183 } 184 return *vb == *va 185 case *OptionalHeader64: 186 vb, ok := b.(*OptionalHeader64) 187 if !ok { 188 return false 189 } 190 return *vb == *va 191 case nil: 192 return b == nil 193 } 194 return false 195 } 196 197 func TestOpen(t *testing.T) { 198 for i := range fileTests { 199 tt := &fileTests[i] 200 201 f, err := Open(tt.file) 202 if err != nil { 203 t.Error(err) 204 continue 205 } 206 if !reflect.DeepEqual(f.FileHeader, tt.hdr) { 207 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr) 208 continue 209 } 210 if !isOptHdrEq(tt.opthdr, f.OptionalHeader) { 211 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr) 212 continue 213 } 214 215 for i, sh := range f.Sections { 216 if i >= len(tt.sections) { 217 break 218 } 219 have := &sh.SectionHeader 220 want := tt.sections[i] 221 if !reflect.DeepEqual(have, want) { 222 t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 223 } 224 } 225 tn := len(tt.sections) 226 fn := len(f.Sections) 227 if tn != fn { 228 t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn) 229 } 230 for i, have := range f.Symbols { 231 if i >= len(tt.symbols) { 232 break 233 } 234 want := tt.symbols[i] 235 if !reflect.DeepEqual(have, want) { 236 t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 237 } 238 } 239 if !tt.hasNoDwarfInfo { 240 _, err = f.DWARF() 241 if err != nil { 242 t.Errorf("fetching %s dwarf details failed: %v", tt.file, err) 243 } 244 } 245 } 246 } 247 248 func TestOpenFailure(t *testing.T) { 249 filename := "file.go" // not a PE file 250 _, err := Open(filename) // don't crash 251 if err == nil { 252 t.Errorf("open %s: succeeded unexpectedly", filename) 253 } 254 } 255 256 func TestDWARF(t *testing.T) { 257 if runtime.GOOS != "windows" { 258 t.Skip("skipping windows only test") 259 } 260 261 tmpdir, err := ioutil.TempDir("", "TestDWARF") 262 if err != nil { 263 t.Fatal("TempDir failed: ", err) 264 } 265 defer os.RemoveAll(tmpdir) 266 267 prog := ` 268 package main 269 func main() { 270 } 271 ` 272 src := filepath.Join(tmpdir, "a.go") 273 exe := filepath.Join(tmpdir, "a.exe") 274 err = ioutil.WriteFile(src, []byte(prog), 0644) 275 output, err := exec.Command("go", "build", "-o", exe, src).CombinedOutput() 276 if err != nil { 277 t.Fatalf("building test executable failed: %s %s", err, output) 278 } 279 280 f, err := Open(exe) 281 if err != nil { 282 t.Fatal(err) 283 } 284 defer f.Close() 285 286 d, err := f.DWARF() 287 if err != nil { 288 t.Fatal(err) 289 } 290 291 // look for main.main 292 r := d.Reader() 293 for { 294 e, err := r.Next() 295 if err != nil { 296 t.Fatal("r.Next:", err) 297 } 298 if e == nil { 299 break 300 } 301 if e.Tag == dwarf.TagSubprogram { 302 for _, f := range e.Field { 303 if f.Attr == dwarf.AttrName && e.Val(dwarf.AttrName) == "main.main" { 304 return 305 } 306 } 307 } 308 } 309 t.Fatal("main.main not found") 310 } 311 312 func TestBSSHasZeros(t *testing.T) { 313 testenv.MustHaveExec(t) 314 315 if runtime.GOOS != "windows" { 316 t.Skip("skipping windows only test") 317 } 318 gccpath, err := exec.LookPath("gcc") 319 if err != nil { 320 t.Skip("skipping test: gcc is missing") 321 } 322 323 tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros") 324 if err != nil { 325 t.Fatal(err) 326 } 327 defer os.RemoveAll(tmpdir) 328 329 srcpath := filepath.Join(tmpdir, "a.c") 330 src := ` 331 #include <stdio.h> 332 333 int zero = 0; 334 335 int 336 main(void) 337 { 338 printf("%d\n", zero); 339 return 0; 340 } 341 ` 342 err = ioutil.WriteFile(srcpath, []byte(src), 0644) 343 if err != nil { 344 t.Fatal(err) 345 } 346 347 objpath := filepath.Join(tmpdir, "a.obj") 348 cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath) 349 out, err := cmd.CombinedOutput() 350 if err != nil { 351 t.Fatalf("failed to build object file: %v - %v", err, string(out)) 352 } 353 354 f, err := Open(objpath) 355 if err != nil { 356 t.Fatal(err) 357 } 358 defer f.Close() 359 360 var bss *Section 361 for _, sect := range f.Sections { 362 if sect.Name == ".bss" { 363 bss = sect 364 break 365 } 366 } 367 if bss == nil { 368 t.Fatal("could not find .bss section") 369 } 370 data, err := bss.Data() 371 if err != nil { 372 t.Fatal(err) 373 } 374 if len(data) == 0 { 375 t.Fatalf("%s file .bss section cannot be empty", objpath) 376 } 377 for _, b := range data { 378 if b != 0 { 379 t.Fatalf(".bss section has non zero bytes: %v", data) 380 } 381 } 382 }