codekingpro/portable-devtools
114k
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package pe6 7import (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 22type fileTest struct {23 file string24 hdr FileHeader25 opthdr any26 sections []*SectionHeader27 symbols []*Symbol28 hasNoDwarfInfo bool29}30 31var 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 253func isOptHdrEq(a, b any) bool {254 switch va := a.(type) {255 case *OptionalHeader32:256 vb, ok := b.(*OptionalHeader32)257 if !ok {258 return false259 }260 return *vb == *va261 case *OptionalHeader64:262 vb, ok := b.(*OptionalHeader64)263 if !ok {264 return false265 }266 return *vb == *va267 case nil:268 return b == nil269 }270 return false271}272 273func 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 continue281 }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 continue285 }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 continue289 }290 291 for i, sh := range f.Sections {292 if i >= len(tt.sections) {293 break294 }295 have := &sh.SectionHeader296 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 break309 }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 324func TestOpenFailure(t *testing.T) {325 filename := "file.go" // not a PE file326 _, err := Open(filename) // don't crash327 if err == nil {328 t.Errorf("open %s: succeeded unexpectedly", filename)329 }330}331 332const (333 linkNoCgo = iota334 linkCgoDefault335 linkCgoInternal336 linkCgoExternal337)338 339func 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 350func 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 bool415 for _, sect := range f.Sections {416 if sect.Name == ".debug_gdb_scripts" || sect.Name == ".zdebug_gdb_scripts" {417 foundDebugGDBScriptsSection = true418 }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.main430 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 break438 }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) - imageBase448 if offset != uintptr(wantoffset) {449 t.Fatalf("Runtime offset (0x%x) did "+450 "not match dwarf offset "+451 "(0x%x)", wantoffset, offset)452 }453 return454 }455 }456 }457 t.Fatal("main.main not found")458}459 460func 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 477int zero = 0;478 479int480main(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 *Section505 for _, sect := range f.Sections {506 if sect.Name == ".bss" {507 bss = sect508 break509 }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 520func TestDWARF(t *testing.T) {521 testDWARF(t, linkNoCgo)522}523 524const testprog = `525package main526 527import "fmt"528import "syscall"529import "unsafe"530{{if .}}import "C"531{{end}}532 533// struct MODULEINFO from the Windows SDK534type moduleinfo struct {535 BaseOfDll uintptr536 SizeOfImage uint32537 EntryPoint uintptr538}539 540func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {541 return unsafe.Pointer(uintptr(p) + x)542}543 544func funcPC(f interface{}) uintptr {545 var a uintptr546 return **(**uintptr)(add(unsafe.Pointer(&f), unsafe.Sizeof(a)))547}548 549func 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 moduleinfo563 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.BaseOfDll571 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 577func 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 616func 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 imports636 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 646func 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 gofuzz650 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 662func TestImportedSymbolsNoPanicMissingOptionalHeader(t *testing.T) {663 // https://golang.org/issue/30250664 // ImportedSymbols shouldn't panic if optional headers is missing665 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 690func TestImportedSymbolsNoPanicWithSliceOutOfBound(t *testing.T) {691 // https://golang.org/issue/30253692 // ImportedSymbols shouldn't panic with slice out of bounds693 // Input generated by gofuzz694 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}738 