github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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 "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 any 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 // testdata/vmlinuz-4.15.0-47-generic is a trimmed down version of Linux Kernel image. 215 // The original Linux Kernel image is about 8M and it is not recommended to add such a big binary file to the repo. 216 // Moreover only a very small portion of the original Kernel image was being parsed by debug/pe package. 217 // In order to identify this portion, the original image was first parsed by modified debug/pe package. 218 // Modification essentially communicated reader's positions before and after parsing. 219 // Finally, bytes between those positions where written to a separate file, 220 // generating trimmed down version Linux Kernel image used in this test case. 221 file: "testdata/vmlinuz-4.15.0-47-generic", 222 hdr: FileHeader{0x8664, 0x4, 0x0, 0x0, 0x1, 0xa0, 0x206}, 223 opthdr: &OptionalHeader64{ 224 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, 225 [16]DataDirectory{ 226 {0x0, 0x0}, 227 {0x0, 0x0}, 228 {0x0, 0x0}, 229 {0x0, 0x0}, 230 {0x7c07a0, 0x778}, 231 {0x0, 0x0}, 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 }}, 243 sections: []*SectionHeader{ 244 {".setup", 0x41e0, 0x200, 0x41e0, 0x200, 0x0, 0x0, 0x0, 0x0, 0x60500020}, 245 {".reloc", 0x20, 0x43e0, 0x20, 0x43e0, 0x0, 0x0, 0x0, 0x0, 0x42100040}, 246 {".text", 0x7bc390, 0x4400, 0x7bc390, 0x4400, 0x0, 0x0, 0x0, 0x0, 0x60500020}, 247 {".bss", 0x168f870, 0x7c0790, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc8000080}, 248 }, 249 hasNoDwarfInfo: true, 250 }, 251 } 252 253 func isOptHdrEq(a, b any) bool { 254 switch va := a.(type) { 255 case *OptionalHeader32: 256 vb, ok := b.(*OptionalHeader32) 257 if !ok { 258 return false 259 } 260 return *vb == *va 261 case *OptionalHeader64: 262 vb, ok := b.(*OptionalHeader64) 263 if !ok { 264 return false 265 } 266 return *vb == *va 267 case nil: 268 return b == nil 269 } 270 return false 271 } 272 273 func TestOpen(t *testing.T) { 274 for i := range fileTests { 275 tt := &fileTests[i] 276 277 f, err := Open(tt.file) 278 if err != nil { 279 t.Error(err) 280 continue 281 } 282 if !reflect.DeepEqual(f.FileHeader, tt.hdr) { 283 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr) 284 continue 285 } 286 if !isOptHdrEq(tt.opthdr, f.OptionalHeader) { 287 t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr) 288 continue 289 } 290 291 for i, sh := range f.Sections { 292 if i >= len(tt.sections) { 293 break 294 } 295 have := &sh.SectionHeader 296 want := tt.sections[i] 297 if !reflect.DeepEqual(have, want) { 298 t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 299 } 300 } 301 tn := len(tt.sections) 302 fn := len(f.Sections) 303 if tn != fn { 304 t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn) 305 } 306 for i, have := range f.Symbols { 307 if i >= len(tt.symbols) { 308 break 309 } 310 want := tt.symbols[i] 311 if !reflect.DeepEqual(have, want) { 312 t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 313 } 314 } 315 if !tt.hasNoDwarfInfo { 316 _, err = f.DWARF() 317 if err != nil { 318 t.Errorf("fetching %s dwarf details failed: %v", tt.file, err) 319 } 320 } 321 } 322 } 323 324 func TestOpenFailure(t *testing.T) { 325 filename := "file.go" // not a PE file 326 _, err := Open(filename) // don't crash 327 if err == nil { 328 t.Errorf("open %s: succeeded unexpectedly", filename) 329 } 330 } 331 332 const ( 333 linkNoCgo = iota 334 linkCgoDefault 335 linkCgoInternal 336 linkCgoExternal 337 ) 338 339 func getImageBase(f *File) uintptr { 340 switch oh := f.OptionalHeader.(type) { 341 case *OptionalHeader32: 342 return uintptr(oh.ImageBase) 343 case *OptionalHeader64: 344 return uintptr(oh.ImageBase) 345 default: 346 panic("unexpected optionalheader type") 347 } 348 } 349 350 func testDWARF(t *testing.T, linktype int) { 351 if runtime.GOOS != "windows" { 352 t.Skip("skipping windows only test") 353 } 354 testenv.MustHaveGoRun(t) 355 356 tmpdir := t.TempDir() 357 358 src := filepath.Join(tmpdir, "a.go") 359 file, err := os.Create(src) 360 if err != nil { 361 t.Fatal(err) 362 } 363 err = template.Must(template.New("main").Parse(testprog)).Execute(file, linktype != linkNoCgo) 364 if err != nil { 365 if err := file.Close(); err != nil { 366 t.Error(err) 367 } 368 t.Fatal(err) 369 } 370 if err := file.Close(); err != nil { 371 t.Fatal(err) 372 } 373 374 exe := filepath.Join(tmpdir, "a.exe") 375 args := []string{"build", "-o", exe} 376 switch linktype { 377 case linkNoCgo: 378 case linkCgoDefault: 379 case linkCgoInternal: 380 args = append(args, "-ldflags", "-linkmode=internal") 381 case linkCgoExternal: 382 args = append(args, "-ldflags", "-linkmode=external") 383 default: 384 t.Fatalf("invalid linktype parameter of %v", linktype) 385 } 386 args = append(args, src) 387 out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput() 388 if err != nil { 389 t.Fatalf("building test executable for linktype %d failed: %s %s", linktype, err, out) 390 } 391 out, err = exec.Command(exe).CombinedOutput() 392 if err != nil { 393 t.Fatalf("running test executable failed: %s %s", err, out) 394 } 395 t.Logf("Testprog output:\n%s", string(out)) 396 397 matches := regexp.MustCompile("offset=(.*)\n").FindStringSubmatch(string(out)) 398 if len(matches) < 2 { 399 t.Fatalf("unexpected program output: %s", out) 400 } 401 wantoffset, err := strconv.ParseUint(matches[1], 0, 64) 402 if err != nil { 403 t.Fatalf("unexpected main offset %q: %s", matches[1], err) 404 } 405 406 f, err := Open(exe) 407 if err != nil { 408 t.Fatal(err) 409 } 410 defer f.Close() 411 412 imageBase := getImageBase(f) 413 414 var foundDebugGDBScriptsSection bool 415 for _, sect := range f.Sections { 416 if sect.Name == ".debug_gdb_scripts" { 417 foundDebugGDBScriptsSection = true 418 } 419 } 420 if !foundDebugGDBScriptsSection { 421 t.Error(".debug_gdb_scripts section is not found") 422 } 423 424 d, err := f.DWARF() 425 if err != nil { 426 t.Fatal(err) 427 } 428 429 // look for main.main 430 r := d.Reader() 431 for { 432 e, err := r.Next() 433 if err != nil { 434 t.Fatal("r.Next:", err) 435 } 436 if e == nil { 437 break 438 } 439 if e.Tag == dwarf.TagSubprogram { 440 name, ok := e.Val(dwarf.AttrName).(string) 441 if ok && name == "main.main" { 442 t.Logf("Found main.main") 443 addr, ok := e.Val(dwarf.AttrLowpc).(uint64) 444 if !ok { 445 t.Fatal("Failed to get AttrLowpc") 446 } 447 offset := uintptr(addr) - imageBase 448 if offset != uintptr(wantoffset) { 449 t.Fatalf("Runtime offset (0x%x) did "+ 450 "not match dwarf offset "+ 451 "(0x%x)", wantoffset, offset) 452 } 453 return 454 } 455 } 456 } 457 t.Fatal("main.main not found") 458 } 459 460 func TestBSSHasZeros(t *testing.T) { 461 testenv.MustHaveExec(t) 462 463 if runtime.GOOS != "windows" { 464 t.Skip("skipping windows only test") 465 } 466 gccpath, err := exec.LookPath("gcc") 467 if err != nil { 468 t.Skip("skipping test: gcc is missing") 469 } 470 471 tmpdir := t.TempDir() 472 473 srcpath := filepath.Join(tmpdir, "a.c") 474 src := ` 475 #include <stdio.h> 476 477 int zero = 0; 478 479 int 480 main(void) 481 { 482 printf("%d\n", zero); 483 return 0; 484 } 485 ` 486 err = os.WriteFile(srcpath, []byte(src), 0644) 487 if err != nil { 488 t.Fatal(err) 489 } 490 491 objpath := filepath.Join(tmpdir, "a.obj") 492 cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath) 493 out, err := cmd.CombinedOutput() 494 if err != nil { 495 t.Fatalf("failed to build object file: %v - %v", err, string(out)) 496 } 497 498 f, err := Open(objpath) 499 if err != nil { 500 t.Fatal(err) 501 } 502 defer f.Close() 503 504 var bss *Section 505 for _, sect := range f.Sections { 506 if sect.Name == ".bss" { 507 bss = sect 508 break 509 } 510 } 511 if bss == nil { 512 t.Fatal("could not find .bss section") 513 } 514 // We expect an error from bss.Data, as there are no contents. 515 if _, err := bss.Data(); err == nil { 516 t.Error("bss.Data succeeded, expected error") 517 } 518 } 519 520 func TestDWARF(t *testing.T) { 521 testDWARF(t, linkNoCgo) 522 } 523 524 const testprog = ` 525 package main 526 527 import "fmt" 528 import "syscall" 529 import "unsafe" 530 {{if .}}import "C" 531 {{end}} 532 533 // struct MODULEINFO from the Windows SDK 534 type moduleinfo struct { 535 BaseOfDll uintptr 536 SizeOfImage uint32 537 EntryPoint uintptr 538 } 539 540 func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { 541 return unsafe.Pointer(uintptr(p) + x) 542 } 543 544 func funcPC(f interface{}) uintptr { 545 var a uintptr 546 return **(**uintptr)(add(unsafe.Pointer(&f), unsafe.Sizeof(a))) 547 } 548 549 func main() { 550 kernel32 := syscall.MustLoadDLL("kernel32.dll") 551 psapi := syscall.MustLoadDLL("psapi.dll") 552 getModuleHandle := kernel32.MustFindProc("GetModuleHandleW") 553 getCurrentProcess := kernel32.MustFindProc("GetCurrentProcess") 554 getModuleInformation := psapi.MustFindProc("GetModuleInformation") 555 556 procHandle, _, _ := getCurrentProcess.Call() 557 moduleHandle, _, err := getModuleHandle.Call(0) 558 if moduleHandle == 0 { 559 panic(fmt.Sprintf("GetModuleHandle() failed: %d", err)) 560 } 561 562 var info moduleinfo 563 ret, _, err := getModuleInformation.Call(procHandle, moduleHandle, 564 uintptr(unsafe.Pointer(&info)), unsafe.Sizeof(info)) 565 566 if ret == 0 { 567 panic(fmt.Sprintf("GetModuleInformation() failed: %d", err)) 568 } 569 570 offset := funcPC(main) - info.BaseOfDll 571 fmt.Printf("base=0x%x\n", info.BaseOfDll) 572 fmt.Printf("main=%p\n", main) 573 fmt.Printf("offset=0x%x\n", offset) 574 } 575 ` 576 577 func TestBuildingWindowsGUI(t *testing.T) { 578 testenv.MustHaveGoBuild(t) 579 580 if runtime.GOOS != "windows" { 581 t.Skip("skipping windows only test") 582 } 583 tmpdir := t.TempDir() 584 585 src := filepath.Join(tmpdir, "a.go") 586 if err := os.WriteFile(src, []byte(`package main; func main() {}`), 0644); err != nil { 587 t.Fatal(err) 588 } 589 exe := filepath.Join(tmpdir, "a.exe") 590 cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags", "-H=windowsgui", "-o", exe, src) 591 out, err := cmd.CombinedOutput() 592 if err != nil { 593 t.Fatalf("building test executable failed: %s %s", err, out) 594 } 595 596 f, err := Open(exe) 597 if err != nil { 598 t.Fatal(err) 599 } 600 defer f.Close() 601 602 switch oh := f.OptionalHeader.(type) { 603 case *OptionalHeader32: 604 if oh.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI { 605 t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI) 606 } 607 case *OptionalHeader64: 608 if oh.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI { 609 t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI) 610 } 611 default: 612 t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh) 613 } 614 } 615 616 func TestImportTableInUnknownSection(t *testing.T) { 617 if runtime.GOOS != "windows" { 618 t.Skip("skipping Windows-only test") 619 } 620 621 // ws2_32.dll import table is located in ".rdata" section, 622 // so it is good enough to test issue #16103. 623 const filename = "ws2_32.dll" 624 path, err := exec.LookPath(filename) 625 if err != nil { 626 t.Fatalf("unable to locate required file %q in search path: %s", filename, err) 627 } 628 629 f, err := Open(path) 630 if err != nil { 631 t.Error(err) 632 } 633 defer f.Close() 634 635 // now we can extract its imports 636 symbols, err := f.ImportedSymbols() 637 if err != nil { 638 t.Error(err) 639 } 640 641 if len(symbols) == 0 { 642 t.Fatalf("unable to locate any imported symbols within file %q.", path) 643 } 644 } 645 646 func TestInvalidOptionalHeaderMagic(t *testing.T) { 647 // Files with invalid optional header magic should return error from NewFile() 648 // (see https://golang.org/issue/30250 and https://golang.org/issue/32126 for details). 649 // Input generated by gofuzz 650 data := []byte("\x00\x00\x00\x0000000\x00\x00\x00\x00\x00\x00\x000000" + 651 "00000000000000000000" + 652 "000000000\x00\x00\x0000000000" + 653 "00000000000000000000" + 654 "0000000000000000") 655 656 _, err := NewFile(bytes.NewReader(data)) 657 if err == nil { 658 t.Fatal("NewFile succeeded unexpectedly") 659 } 660 } 661 662 func TestImportedSymbolsNoPanicMissingOptionalHeader(t *testing.T) { 663 // https://golang.org/issue/30250 664 // ImportedSymbols shouldn't panic if optional headers is missing 665 data, err := os.ReadFile("testdata/gcc-amd64-mingw-obj") 666 if err != nil { 667 t.Fatal(err) 668 } 669 670 f, err := NewFile(bytes.NewReader(data)) 671 if err != nil { 672 t.Fatal(err) 673 } 674 675 if f.OptionalHeader != nil { 676 t.Fatal("expected f.OptionalHeader to be nil, received non-nil optional header") 677 } 678 679 syms, err := f.ImportedSymbols() 680 if err != nil { 681 t.Fatal(err) 682 } 683 684 if len(syms) != 0 { 685 t.Fatalf("expected len(syms) == 0, received len(syms) = %d", len(syms)) 686 } 687 688 } 689 690 func TestImportedSymbolsNoPanicWithSliceOutOfBound(t *testing.T) { 691 // https://golang.org/issue/30253 692 // ImportedSymbols shouldn't panic with slice out of bounds 693 // Input generated by gofuzz 694 data := []byte("L\x01\b\x00regi\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x0f\x03" + 695 "\v\x01\x02\x18\x00\x0e\x00\x00\x00\x1e\x00\x00\x00\x02\x00\x00\x80\x12\x00\x00" + 696 "\x00\x10\x00\x00\x00 \x00\x00\x00\x00@\x00\x00\x10\x00\x00\x00\x02\x00\x00" + 697 "\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00" + 698 "\x00\x04\x00\x00\x06S\x00\x00\x03\x00\x00\x00\x00\x00 \x00\x00\x10\x00\x00" + 699 "\x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00" + 700 "\x00\x00\x00\x00\x00`\x00\x00x\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 701 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 702 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 703 "\x00\x00\x00\x00\x00\x00\x00\x00\x04\x80\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00" + 704 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8`\x00\x00|\x00\x00\x00" + 705 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 706 "\x00\x00\x00\x00.text\x00\x00\x00d\f\x00\x00\x00\x10\x00\x00" + 707 "\x00\x0e\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 708 "`\x00P`.data\x00\x00\x00\x10\x00\x00\x00\x00 \x00\x00" + 709 "\x00\x02\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 710 "@\x000\xc0.rdata\x00\x004\x01\x00\x00\x000\x00\x00" + 711 "\x00\x02\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 712 "@\x000@.eh_fram\xa0\x03\x00\x00\x00@\x00\x00" + 713 "\x00\x04\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 714 "@\x000@.bss\x00\x00\x00\x00`\x00\x00\x00\x00P\x00\x00" + 715 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + 716 "\x80\x000\xc0.idata\x00\x00x\x03\x00\x00\x00`\x00\x00" + 717 "\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00" + 718 "0\xc0.CRT\x00\x00\x00\x00\x18\x00\x00\x00\x00p\x00\x00\x00\x02" + 719 "\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00" + 720 "0\xc0.tls\x00\x00\x00\x00 \x00\x00\x00\x00\x80\x00\x00\x00\x02" + 721 "\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\xc9" + 722 "H\x895\x1d") 723 724 f, err := NewFile(bytes.NewReader(data)) 725 if err != nil { 726 t.Fatal(err) 727 } 728 729 syms, err := f.ImportedSymbols() 730 if err != nil { 731 t.Fatal(err) 732 } 733 734 if len(syms) != 0 { 735 t.Fatalf("expected len(syms) == 0, received len(syms) = %d", len(syms)) 736 } 737 }