github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/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 "bytes" 9 "debug/dwarf" 10 "internal/testenv" 11 "io/ioutil" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "reflect" 16 "regexp" 17 "runtime" 18 "strconv" 19 "testing" 20 "text/template" 21 ) 22 23 type fileTest struct { 24 file string 25 hdr FileHeader 26 opthdr interface{} 27 sections []*SectionHeader 28 symbols []*Symbol 29 hasNoDwarfInfo bool 30 } 31 32 var fileTests = []fileTest{ 33 { 34 file: "testdata/gcc-386-mingw-obj", 35 hdr: FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104}, 36 sections: []*SectionHeader{ 37 {".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020}, 38 {".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264}, 39 {".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328}, 40 {".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000}, 41 {".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832}, 42 {".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832}, 43 {".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616}, 44 {".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984}, 45 {".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832}, 46 {".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832}, 47 {".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832}, 48 {".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832}, 49 }, 50 symbols: []*Symbol{ 51 {".file", 0x0, -2, 0x0, 0x67}, 52 {"_main", 0x0, 1, 0x20, 0x2}, 53 {".text", 0x0, 1, 0x0, 0x3}, 54 {".data", 0x0, 2, 0x0, 0x3}, 55 {".bss", 0x0, 3, 0x0, 0x3}, 56 {".debug_abbrev", 0x0, 4, 0x0, 0x3}, 57 {".debug_info", 0x0, 5, 0x0, 0x3}, 58 {".debug_line", 0x0, 6, 0x0, 0x3}, 59 {".rdata", 0x0, 7, 0x0, 0x3}, 60 {".debug_frame", 0x0, 8, 0x0, 0x3}, 61 {".debug_loc", 0x0, 9, 0x0, 0x3}, 62 {".debug_pubnames", 0x0, 10, 0x0, 0x3}, 63 {".debug_pubtypes", 0x0, 11, 0x0, 0x3}, 64 {".debug_aranges", 0x0, 12, 0x0, 0x3}, 65 {"___main", 0x0, 0, 0x20, 0x2}, 66 {"_puts", 0x0, 0, 0x20, 0x2}, 67 }, 68 }, 69 { 70 file: "testdata/gcc-386-mingw-exec", 71 hdr: FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107}, 72 opthdr: &OptionalHeader32{ 73 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, 74 [16]DataDirectory{ 75 {0x0, 0x0}, 76 {0x5000, 0x3c8}, 77 {0x0, 0x0}, 78 {0x0, 0x0}, 79 {0x0, 0x0}, 80 {0x0, 0x0}, 81 {0x0, 0x0}, 82 {0x0, 0x0}, 83 {0x0, 0x0}, 84 {0x7000, 0x18}, 85 {0x0, 0x0}, 86 {0x0, 0x0}, 87 {0x0, 0x0}, 88 {0x0, 0x0}, 89 {0x0, 0x0}, 90 {0x0, 0x0}, 91 }, 92 }, 93 sections: []*SectionHeader{ 94 {".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060}, 95 {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 96 {".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040}, 97 {".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080}, 98 {".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 99 {".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 100 {".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 101 {".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000}, 102 {".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000}, 103 {".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000}, 104 {".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000}, 105 {".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000}, 106 {".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000}, 107 {".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000}, 108 {".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000}, 109 }, 110 }, 111 { 112 file: "testdata/gcc-386-mingw-no-symbols-exec", 113 hdr: FileHeader{0x14c, 0x8, 0x69676572, 0x0, 0x0, 0xe0, 0x30f}, 114 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, 115 [16]DataDirectory{ 116 {0x0, 0x0}, 117 {0x6000, 0x378}, 118 {0x0, 0x0}, 119 {0x0, 0x0}, 120 {0x0, 0x0}, 121 {0x0, 0x0}, 122 {0x0, 0x0}, 123 {0x0, 0x0}, 124 {0x0, 0x0}, 125 {0x8004, 0x18}, 126 {0x0, 0x0}, 127 {0x0, 0x0}, 128 {0x60b8, 0x7c}, 129 {0x0, 0x0}, 130 {0x0, 0x0}, 131 {0x0, 0x0}, 132 }, 133 }, 134 sections: []*SectionHeader{ 135 {".text", 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060}, 136 {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 137 {".rdata", 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040}, 138 {".eh_fram", 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040}, 139 {".bss", 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080}, 140 {".idata", 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 141 {".CRT", 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 142 {".tls", 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 143 }, 144 hasNoDwarfInfo: true, 145 }, 146 { 147 file: "testdata/gcc-amd64-mingw-obj", 148 hdr: FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4}, 149 sections: []*SectionHeader{ 150 {".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020}, 151 {".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, 152 {".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080}, 153 {".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040}, 154 {".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040}, 155 {".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040}, 156 }, 157 symbols: []*Symbol{ 158 {".file", 0x0, -2, 0x0, 0x67}, 159 {"main", 0x0, 1, 0x20, 0x2}, 160 {".text", 0x0, 1, 0x0, 0x3}, 161 {".data", 0x0, 2, 0x0, 0x3}, 162 {".bss", 0x0, 3, 0x0, 0x3}, 163 {".rdata", 0x0, 4, 0x0, 0x3}, 164 {".xdata", 0x0, 5, 0x0, 0x3}, 165 {".pdata", 0x0, 6, 0x0, 0x3}, 166 {"__main", 0x0, 0, 0x20, 0x2}, 167 {"puts", 0x0, 0, 0x20, 0x2}, 168 }, 169 hasNoDwarfInfo: true, 170 }, 171 { 172 file: "testdata/gcc-amd64-mingw-exec", 173 hdr: FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27}, 174 opthdr: &OptionalHeader64{ 175 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, 176 [16]DataDirectory{ 177 {0x0, 0x0}, 178 {0xe000, 0x990}, 179 {0x0, 0x0}, 180 {0xa000, 0x498}, 181 {0x0, 0x0}, 182 {0x0, 0x0}, 183 {0x0, 0x0}, 184 {0x0, 0x0}, 185 {0x0, 0x0}, 186 {0x10000, 0x28}, 187 {0x0, 0x0}, 188 {0x0, 0x0}, 189 {0xe254, 0x218}, 190 {0x0, 0x0}, 191 {0x0, 0x0}, 192 {0x0, 0x0}, 193 }}, 194 sections: []*SectionHeader{ 195 {".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020}, 196 {".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, 197 {".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040}, 198 {".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040}, 199 {".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040}, 200 {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080}, 201 {".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, 202 {".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040}, 203 {".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040}, 204 {".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040}, 205 {".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 206 {".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 207 {".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 208 {".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040}, 209 {".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 210 {".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 211 {".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 212 }, 213 }, 214 { 215 // testdata/vmlinuz-4.15.0-47-generic is a trimmed down version of Linux Kernel image. 216 // The original Linux Kernel image is about 8M and it is not recommended to add such a big binary file to the repo. 217 // Moreover only a very small portion of the original Kernel image was being parsed by debug/pe package. 218 // In order to identify this portion, the original image was first parsed by modified debug/pe package. 219 // Modification essentially communicated reader's positions before and after parsing. 220 // Finally, bytes between those positions where written to a separate file, 221 // generating trimmed down version Linux Kernel image used in this test case. 222 file: "testdata/vmlinuz-4.15.0-47-generic", 223 hdr: FileHeader{0x8664, 0x4, 0x0, 0x0, 0x1, 0xa0, 0x206}, 224 opthdr: &OptionalHeader64{ 225 0x20b, 0x2, 0x14, 0x7c0590, 0x0, 0x168f870, 0x4680, 0x200, 0x0, 0x20, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e50000, 0x200, 0x7c3ab0, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 226 [16]DataDirectory{ 227 {0x0, 0x0}, 228 {0x0, 0x0}, 229 {0x0, 0x0}, 230 {0x0, 0x0}, 231 {0x7c07a0, 0x778}, 232 {0x0, 0x0}, 233 {0x0, 0x0}, 234 {0x0, 0x0}, 235 {0x0, 0x0}, 236 {0x0, 0x0}, 237 {0x0, 0x0}, 238 {0x0, 0x0}, 239 {0x0, 0x0}, 240 {0x0, 0x0}, 241 {0x0, 0x0}, 242 {0x0, 0x0}, 243 }}, 244 sections: []*SectionHeader{ 245 {".setup", 0x41e0, 0x200, 0x41e0, 0x200, 0x0, 0x0, 0x0, 0x0, 0x60500020}, 246 {".reloc", 0x20, 0x43e0, 0x20, 0x43e0, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 247 {".text", 0x7bc390, 0x4400, 0x7bc390, 0x4400, 0x0, 0x0, 0x0, 0x0, 0x60500020}, 248 {".bss", 0x168f870, 0x7c0790, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc8000080}, 249 }, 250 hasNoDwarfInfo: true, 251 }, 252 } 253 254 func isOptHdrEq(a, b interface{}) bool { 255 switch va := a.(type) { 256 case *OptionalHeader32: 257 vb, ok := b.(*OptionalHeader32) 258 if !ok { 259 return false 260 } 261 return *vb == *va 262 case *OptionalHeader64: 263 vb, ok := b.(*OptionalHeader64) 264 if !ok { 265 return false 266 } 267 return *vb == *va 268 case nil: 269 return b == nil 270 } 271 return false 272 } 273 274 func TestOpen(t *testing.T) { 275 for i := range fileTests { 276 tt := &fileTests[i] 277 278 f, err := Open(tt.file) 279 if err != nil { 280 t.Error(err) 281 continue 282 } 283 if !reflect.DeepEqual(f.FileHeader, tt.hdr) { 284 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr) 285 continue 286 } 287 if !isOptHdrEq(tt.opthdr, f.OptionalHeader) { 288 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr) 289 continue 290 } 291 292 for i, sh := range f.Sections { 293 if i >= len(tt.sections) { 294 break 295 } 296 have := &sh.SectionHeader 297 want := tt.sections[i] 298 if !reflect.DeepEqual(have, want) { 299 t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 300 } 301 } 302 tn := len(tt.sections) 303 fn := len(f.Sections) 304 if tn != fn { 305 t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn) 306 } 307 for i, have := range f.Symbols { 308 if i >= len(tt.symbols) { 309 break 310 } 311 want := tt.symbols[i] 312 if !reflect.DeepEqual(have, want) { 313 t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 314 } 315 } 316 if !tt.hasNoDwarfInfo { 317 _, err = f.DWARF() 318 if err != nil { 319 t.Errorf("fetching %s dwarf details failed: %v", tt.file, err) 320 } 321 } 322 } 323 } 324 325 func TestOpenFailure(t *testing.T) { 326 filename := "file.go" // not a PE file 327 _, err := Open(filename) // don't crash 328 if err == nil { 329 t.Errorf("open %s: succeeded unexpectedly", filename) 330 } 331 } 332 333 const ( 334 linkNoCgo = iota 335 linkCgoDefault 336 linkCgoInternal 337 linkCgoExternal 338 ) 339 340 func getImageBase(f *File) uintptr { 341 switch oh := f.OptionalHeader.(type) { 342 case *OptionalHeader32: 343 return uintptr(oh.ImageBase) 344 case *OptionalHeader64: 345 return uintptr(oh.ImageBase) 346 default: 347 panic("unexpected optionalheader type") 348 } 349 } 350 351 func testDWARF(t *testing.T, linktype int) { 352 if runtime.GOOS != "windows" { 353 t.Skip("skipping windows only test") 354 } 355 testenv.MustHaveGoRun(t) 356 357 tmpdir, err := ioutil.TempDir("", "TestDWARF") 358 if err != nil { 359 t.Fatal(err) 360 } 361 defer os.RemoveAll(tmpdir) 362 363 src := filepath.Join(tmpdir, "a.go") 364 file, err := os.Create(src) 365 if err != nil { 366 t.Fatal(err) 367 } 368 err = template.Must(template.New("main").Parse(testprog)).Execute(file, linktype != linkNoCgo) 369 if err != nil { 370 if err := file.Close(); err != nil { 371 t.Error(err) 372 } 373 t.Fatal(err) 374 } 375 if err := file.Close(); err != nil { 376 t.Fatal(err) 377 } 378 379 exe := filepath.Join(tmpdir, "a.exe") 380 args := []string{"build", "-o", exe} 381 switch linktype { 382 case linkNoCgo: 383 case linkCgoDefault: 384 case linkCgoInternal: 385 args = append(args, "-ldflags", "-linkmode=internal") 386 case linkCgoExternal: 387 args = append(args, "-ldflags", "-linkmode=external") 388 default: 389 t.Fatalf("invalid linktype parameter of %v", linktype) 390 } 391 args = append(args, src) 392 out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput() 393 if err != nil { 394 t.Fatalf("building test executable for linktype %d failed: %s %s", linktype, err, out) 395 } 396 out, err = exec.Command(exe).CombinedOutput() 397 if err != nil { 398 t.Fatalf("running test executable failed: %s %s", err, out) 399 } 400 t.Logf("Testprog output:\n%s", string(out)) 401 402 matches := regexp.MustCompile("offset=(.*)\n").FindStringSubmatch(string(out)) 403 if len(matches) < 2 { 404 t.Fatalf("unexpected program output: %s", out) 405 } 406 wantoffset, err := strconv.ParseUint(matches[1], 0, 64) 407 if err != nil { 408 t.Fatalf("unexpected main offset %q: %s", matches[1], err) 409 } 410 411 f, err := Open(exe) 412 if err != nil { 413 t.Fatal(err) 414 } 415 defer f.Close() 416 417 imageBase := getImageBase(f) 418 419 var foundDebugGDBScriptsSection bool 420 for _, sect := range f.Sections { 421 if sect.Name == ".debug_gdb_scripts" { 422 foundDebugGDBScriptsSection = true 423 } 424 } 425 if !foundDebugGDBScriptsSection { 426 t.Error(".debug_gdb_scripts section is not found") 427 } 428 429 d, err := f.DWARF() 430 if err != nil { 431 t.Fatal(err) 432 } 433 434 // look for main.main 435 r := d.Reader() 436 for { 437 e, err := r.Next() 438 if err != nil { 439 t.Fatal("r.Next:", err) 440 } 441 if e == nil { 442 break 443 } 444 if e.Tag == dwarf.TagSubprogram { 445 name, ok := e.Val(dwarf.AttrName).(string) 446 if ok && name == "main.main" { 447 t.Logf("Found main.main") 448 addr, ok := e.Val(dwarf.AttrLowpc).(uint64) 449 if !ok { 450 t.Fatal("Failed to get AttrLowpc") 451 } 452 offset := uintptr(addr) - imageBase 453 if offset != uintptr(wantoffset) { 454 t.Fatal("Runtime offset (0x%x) did "+ 455 "not match dwarf offset "+ 456 "(0x%x)", wantoffset, offset) 457 } 458 return 459 } 460 } 461 } 462 t.Fatal("main.main not found") 463 } 464 465 func TestBSSHasZeros(t *testing.T) { 466 testenv.MustHaveExec(t) 467 468 if runtime.GOOS != "windows" { 469 t.Skip("skipping windows only test") 470 } 471 gccpath, err := exec.LookPath("gcc") 472 if err != nil { 473 t.Skip("skipping test: gcc is missing") 474 } 475 476 tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros") 477 if err != nil { 478 t.Fatal(err) 479 } 480 defer os.RemoveAll(tmpdir) 481 482 srcpath := filepath.Join(tmpdir, "a.c") 483 src := ` 484 #include <stdio.h> 485 486 int zero = 0; 487 488 int 489 main(void) 490 { 491 printf("%d\n", zero); 492 return 0; 493 } 494 ` 495 err = ioutil.WriteFile(srcpath, []byte(src), 0644) 496 if err != nil { 497 t.Fatal(err) 498 } 499 500 objpath := filepath.Join(tmpdir, "a.obj") 501 cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath) 502 out, err := cmd.CombinedOutput() 503 if err != nil { 504 t.Fatalf("failed to build object file: %v - %v", err, string(out)) 505 } 506 507 f, err := Open(objpath) 508 if err != nil { 509 t.Fatal(err) 510 } 511 defer f.Close() 512 513 var bss *Section 514 for _, sect := range f.Sections { 515 if sect.Name == ".bss" { 516 bss = sect 517 break 518 } 519 } 520 if bss == nil { 521 t.Fatal("could not find .bss section") 522 } 523 data, err := bss.Data() 524 if err != nil { 525 t.Fatal(err) 526 } 527 if len(data) == 0 { 528 t.Fatalf("%s file .bss section cannot be empty", objpath) 529 } 530 for _, b := range data { 531 if b != 0 { 532 t.Fatalf(".bss section has non zero bytes: %v", data) 533 } 534 } 535 } 536 537 func TestDWARF(t *testing.T) { 538 testDWARF(t, linkNoCgo) 539 } 540 541 const testprog = ` 542 package main 543 544 import "fmt" 545 import "syscall" 546 import "unsafe" 547 {{if .}}import "C" 548 {{end}} 549 550 // struct MODULEINFO from the Windows SDK 551 type moduleinfo struct { 552 BaseOfDll uintptr 553 SizeOfImage uint32 554 EntryPoint uintptr 555 } 556 557 func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { 558 return unsafe.Pointer(uintptr(p) + x) 559 } 560 561 func funcPC(f interface{}) uintptr { 562 var a uintptr 563 return **(**uintptr)(add(unsafe.Pointer(&f), unsafe.Sizeof(a))) 564 } 565 566 func main() { 567 kernel32 := syscall.MustLoadDLL("kernel32.dll") 568 psapi := syscall.MustLoadDLL("psapi.dll") 569 getModuleHandle := kernel32.MustFindProc("GetModuleHandleW") 570 getCurrentProcess := kernel32.MustFindProc("GetCurrentProcess") 571 getModuleInformation := psapi.MustFindProc("GetModuleInformation") 572 573 procHandle, _, _ := getCurrentProcess.Call() 574 moduleHandle, _, err := getModuleHandle.Call(0) 575 if moduleHandle == 0 { 576 panic(fmt.Sprintf("GetModuleHandle() failed: %d", err)) 577 } 578 579 var info moduleinfo 580 ret, _, err := getModuleInformation.Call(procHandle, moduleHandle, 581 uintptr(unsafe.Pointer(&info)), unsafe.Sizeof(info)) 582 583 if ret == 0 { 584 panic(fmt.Sprintf("GetModuleInformation() failed: %d", err)) 585 } 586 587 offset := funcPC(main) - info.BaseOfDll 588 fmt.Printf("base=0x%x\n", info.BaseOfDll) 589 fmt.Printf("main=%p\n", main) 590 fmt.Printf("offset=0x%x\n", offset) 591 } 592 ` 593 594 func TestBuildingWindowsGUI(t *testing.T) { 595 testenv.MustHaveGoBuild(t) 596 597 if runtime.GOOS != "windows" { 598 t.Skip("skipping windows only test") 599 } 600 tmpdir, err := ioutil.TempDir("", "TestBuildingWindowsGUI") 601 if err != nil { 602 t.Fatal(err) 603 } 604 defer os.RemoveAll(tmpdir) 605 606 src := filepath.Join(tmpdir, "a.go") 607 err = ioutil.WriteFile(src, []byte(`package main; func main() {}`), 0644) 608 if err != nil { 609 t.Fatal(err) 610 } 611 exe := filepath.Join(tmpdir, "a.exe") 612 cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags", "-H=windowsgui", "-o", exe, src) 613 out, err := cmd.CombinedOutput() 614 if err != nil { 615 t.Fatalf("building test executable failed: %s %s", err, out) 616 } 617 618 f, err := Open(exe) 619 if err != nil { 620 t.Fatal(err) 621 } 622 defer f.Close() 623 624 const _IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 625 626 switch oh := f.OptionalHeader.(type) { 627 case *OptionalHeader32: 628 if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI { 629 t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI) 630 } 631 case *OptionalHeader64: 632 if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI { 633 t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI) 634 } 635 default: 636 t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh) 637 } 638 } 639 640 func TestImportTableInUnknownSection(t *testing.T) { 641 if runtime.GOOS != "windows" { 642 t.Skip("skipping Windows-only test") 643 } 644 645 // ws2_32.dll import table is located in ".rdata" section, 646 // so it is good enough to test issue #16103. 647 const filename = "ws2_32.dll" 648 path, err := exec.LookPath(filename) 649 if err != nil { 650 t.Fatalf("unable to locate required file %q in search path: %s", filename, err) 651 } 652 653 f, err := Open(path) 654 if err != nil { 655 t.Error(err) 656 } 657 defer f.Close() 658 659 // now we can extract its imports 660 symbols, err := f.ImportedSymbols() 661 if err != nil { 662 t.Error(err) 663 } 664 665 if len(symbols) == 0 { 666 t.Fatalf("unable to locate any imported symbols within file %q.", path) 667 } 668 } 669 670 func TestInvalidOptionalHeaderMagic(t *testing.T) { 671 // Files with invalid optional header magic should return error from NewFile() 672 // (see https://golang.org/issue/30250 and https://golang.org/issue/32126 for details). 673 // Input generated by gofuzz 674 data := []byte("\x00\x00\x00\x0000000\x00\x00\x00\x00\x00\x00\x000000" + 675 "00000000000000000000" + 676 "000000000\x00\x00\x0000000000" + 677 "00000000000000000000" + 678 "0000000000000000") 679 680 _, err := NewFile(bytes.NewReader(data)) 681 if err == nil { 682 t.Fatal("NewFile succeeded unexpectedly") 683 } 684 } 685 686 func TestImportedSymbolsNoPanicMissingOptionalHeader(t *testing.T) { 687 // https://golang.org/issue/30250 688 // ImportedSymbols shouldn't panic if optional headers is missing 689 data, err := ioutil.ReadFile("testdata/gcc-amd64-mingw-obj") 690 if err != nil { 691 t.Fatal(err) 692 } 693 694 f, err := NewFile(bytes.NewReader(data)) 695 if err != nil { 696 t.Fatal(err) 697 } 698 699 if f.OptionalHeader != nil { 700 t.Fatal("expected f.OptionalHeader to be nil, received non-nil optional header") 701 } 702 703 syms, err := f.ImportedSymbols() 704 if err != nil { 705 t.Fatal(err) 706 } 707 708 if len(syms) != 0 { 709 t.Fatalf("expected len(syms) == 0, received len(syms) = %d", len(syms)) 710 } 711 712 } 713 714 func TestImportedSymbolsNoPanicWithSliceOutOfBound(t *testing.T) { 715 // https://golang.org/issue/30253 716 // ImportedSymbols shouldn't panic with slice out of bounds 717 // Input generated by gofuzz 718 data := []byte("L\x01\b\x00regi\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x0f\x03" + 719 "\v\x01\x02\x18\x00\x0e\x00\x00\x00\x1e\x00\x00\x00\x02\x00\x00\x80\x12\x00\x00" + 720 "\x00\x10\x00\x00\x00 \x00\x00\x00\x00@\x00\x00\x10\x00\x00\x00\x02\x00\x00" + 721 "\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00" + 722 "\x00\x04\x00\x00\x06S\x00\x00\x03\x00\x00\x00\x00\x00 \x00\x00\x10\x00\x00" + 723 "\x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00" + 724 "\x00\x00\x00\x00\x00`\x00\x00x\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 725 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 726 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 727 "\x00\x00\x00\x00\x00\x00\x00\x00\x04\x80\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00" + 728 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8`\x00\x00|\x00\x00\x00" + 729 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 730 "\x00\x00\x00\x00.text\x00\x00\x00d\f\x00\x00\x00\x10\x00\x00" + 731 "\x00\x0e\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 732 "`\x00P`.data\x00\x00\x00\x10\x00\x00\x00\x00 \x00\x00" + 733 "\x00\x02\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 734 "@\x000\xc0.rdata\x00\x004\x01\x00\x00\x000\x00\x00" + 735 "\x00\x02\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 736 "@\x000@.eh_fram\xa0\x03\x00\x00\x00@\x00\x00" + 737 "\x00\x04\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 738 "@\x000@.bss\x00\x00\x00\x00`\x00\x00\x00\x00P\x00\x00" + 739 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 740 "\x80\x000\xc0.idata\x00\x00x\x03\x00\x00\x00`\x00\x00" + 741 "\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00" + 742 "0\xc0.CRT\x00\x00\x00\x00\x18\x00\x00\x00\x00p\x00\x00\x00\x02" + 743 "\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00" + 744 "0\xc0.tls\x00\x00\x00\x00 \x00\x00\x00\x00\x80\x00\x00\x00\x02" + 745 "\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\xc9" + 746 "H\x895\x1d") 747 748 f, err := NewFile(bytes.NewReader(data)) 749 if err != nil { 750 t.Fatal(err) 751 } 752 753 syms, err := f.ImportedSymbols() 754 if err != nil { 755 t.Fatal(err) 756 } 757 758 if len(syms) != 0 { 759 t.Fatalf("expected len(syms) == 0, received len(syms) = %d", len(syms)) 760 } 761 }