mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-25 14:34:29 +00:00
630 lines
17 KiB
Go
630 lines
17 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package pe
|
|
|
|
import (
|
|
"debug/dwarf"
|
|
"internal/testenv"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"reflect"
|
|
"regexp"
|
|
"runtime"
|
|
"strconv"
|
|
"testing"
|
|
"text/template"
|
|
)
|
|
|
|
type fileTest struct {
|
|
file string
|
|
hdr FileHeader
|
|
opthdr interface{}
|
|
sections []*SectionHeader
|
|
symbols []*Symbol
|
|
hasNoDwarfInfo bool
|
|
}
|
|
|
|
var fileTests = []fileTest{
|
|
{
|
|
file: "testdata/gcc-386-mingw-obj",
|
|
hdr: FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
|
|
sections: []*SectionHeader{
|
|
{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
|
|
{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
|
|
{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
|
|
{".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
|
|
{".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
|
|
{".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
|
|
{".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
|
|
{".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
|
|
{".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
|
|
{".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
|
|
{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
|
|
{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
|
|
},
|
|
symbols: []*Symbol{
|
|
{".file", 0x0, -2, 0x0, 0x67},
|
|
{"_main", 0x0, 1, 0x20, 0x2},
|
|
{".text", 0x0, 1, 0x0, 0x3},
|
|
{".data", 0x0, 2, 0x0, 0x3},
|
|
{".bss", 0x0, 3, 0x0, 0x3},
|
|
{".debug_abbrev", 0x0, 4, 0x0, 0x3},
|
|
{".debug_info", 0x0, 5, 0x0, 0x3},
|
|
{".debug_line", 0x0, 6, 0x0, 0x3},
|
|
{".rdata", 0x0, 7, 0x0, 0x3},
|
|
{".debug_frame", 0x0, 8, 0x0, 0x3},
|
|
{".debug_loc", 0x0, 9, 0x0, 0x3},
|
|
{".debug_pubnames", 0x0, 10, 0x0, 0x3},
|
|
{".debug_pubtypes", 0x0, 11, 0x0, 0x3},
|
|
{".debug_aranges", 0x0, 12, 0x0, 0x3},
|
|
{"___main", 0x0, 0, 0x20, 0x2},
|
|
{"_puts", 0x0, 0, 0x20, 0x2},
|
|
},
|
|
},
|
|
{
|
|
file: "testdata/gcc-386-mingw-exec",
|
|
hdr: FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
|
|
opthdr: &OptionalHeader32{
|
|
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,
|
|
[16]DataDirectory{
|
|
{0x0, 0x0},
|
|
{0x5000, 0x3c8},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x7000, 0x18},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
},
|
|
},
|
|
sections: []*SectionHeader{
|
|
{".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
|
|
{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
|
{".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
|
|
{".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080},
|
|
{".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
|
{".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
|
{".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
|
{".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
|
|
{".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000},
|
|
{".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000},
|
|
{".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
|
|
{".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
|
|
{".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000},
|
|
{".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000},
|
|
{".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
|
|
},
|
|
},
|
|
{
|
|
file: "testdata/gcc-386-mingw-no-symbols-exec",
|
|
hdr: FileHeader{0x14c, 0x8, 0x69676572, 0x0, 0x0, 0xe0, 0x30f},
|
|
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,
|
|
[16]DataDirectory{
|
|
{0x0, 0x0},
|
|
{0x6000, 0x378},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x8004, 0x18},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x60b8, 0x7c},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
},
|
|
},
|
|
sections: []*SectionHeader{
|
|
{".text", 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
|
|
{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
|
{".rdata", 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
|
|
{".eh_fram", 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040},
|
|
{".bss", 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080},
|
|
{".idata", 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
|
{".CRT", 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
|
{".tls", 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
|
},
|
|
hasNoDwarfInfo: true,
|
|
},
|
|
{
|
|
file: "testdata/gcc-amd64-mingw-obj",
|
|
hdr: FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
|
|
sections: []*SectionHeader{
|
|
{".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020},
|
|
{".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
|
|
{".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080},
|
|
{".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040},
|
|
{".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
|
|
{".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
|
|
},
|
|
symbols: []*Symbol{
|
|
{".file", 0x0, -2, 0x0, 0x67},
|
|
{"main", 0x0, 1, 0x20, 0x2},
|
|
{".text", 0x0, 1, 0x0, 0x3},
|
|
{".data", 0x0, 2, 0x0, 0x3},
|
|
{".bss", 0x0, 3, 0x0, 0x3},
|
|
{".rdata", 0x0, 4, 0x0, 0x3},
|
|
{".xdata", 0x0, 5, 0x0, 0x3},
|
|
{".pdata", 0x0, 6, 0x0, 0x3},
|
|
{"__main", 0x0, 0, 0x20, 0x2},
|
|
{"puts", 0x0, 0, 0x20, 0x2},
|
|
},
|
|
hasNoDwarfInfo: true,
|
|
},
|
|
{
|
|
file: "testdata/gcc-amd64-mingw-exec",
|
|
hdr: FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
|
|
opthdr: &OptionalHeader64{
|
|
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,
|
|
[16]DataDirectory{
|
|
{0x0, 0x0},
|
|
{0xe000, 0x990},
|
|
{0x0, 0x0},
|
|
{0xa000, 0x498},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x10000, 0x28},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0xe254, 0x218},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
{0x0, 0x0},
|
|
}},
|
|
sections: []*SectionHeader{
|
|
{".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020},
|
|
{".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
|
|
{".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040},
|
|
{".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
|
|
{".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040},
|
|
{".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
|
|
{".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
|
{".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
|
|
{".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
|
|
{".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040},
|
|
{".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
|
|
{".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
|
|
{".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
|
|
{".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040},
|
|
{".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040},
|
|
{".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040},
|
|
{".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
|
|
},
|
|
},
|
|
}
|
|
|
|
func isOptHdrEq(a, b interface{}) bool {
|
|
switch va := a.(type) {
|
|
case *OptionalHeader32:
|
|
vb, ok := b.(*OptionalHeader32)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return *vb == *va
|
|
case *OptionalHeader64:
|
|
vb, ok := b.(*OptionalHeader64)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return *vb == *va
|
|
case nil:
|
|
return b == nil
|
|
}
|
|
return false
|
|
}
|
|
|
|
func TestOpen(t *testing.T) {
|
|
for i := range fileTests {
|
|
tt := &fileTests[i]
|
|
|
|
f, err := Open(tt.file)
|
|
if err != nil {
|
|
t.Error(err)
|
|
continue
|
|
}
|
|
if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
|
|
t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
|
|
continue
|
|
}
|
|
if !isOptHdrEq(tt.opthdr, f.OptionalHeader) {
|
|
t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr)
|
|
continue
|
|
}
|
|
|
|
for i, sh := range f.Sections {
|
|
if i >= len(tt.sections) {
|
|
break
|
|
}
|
|
have := &sh.SectionHeader
|
|
want := tt.sections[i]
|
|
if !reflect.DeepEqual(have, want) {
|
|
t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
|
|
}
|
|
}
|
|
tn := len(tt.sections)
|
|
fn := len(f.Sections)
|
|
if tn != fn {
|
|
t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
|
|
}
|
|
for i, have := range f.Symbols {
|
|
if i >= len(tt.symbols) {
|
|
break
|
|
}
|
|
want := tt.symbols[i]
|
|
if !reflect.DeepEqual(have, want) {
|
|
t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
|
|
}
|
|
}
|
|
if !tt.hasNoDwarfInfo {
|
|
_, err = f.DWARF()
|
|
if err != nil {
|
|
t.Errorf("fetching %s dwarf details failed: %v", tt.file, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOpenFailure(t *testing.T) {
|
|
filename := "file.go" // not a PE file
|
|
_, err := Open(filename) // don't crash
|
|
if err == nil {
|
|
t.Errorf("open %s: succeeded unexpectedly", filename)
|
|
}
|
|
}
|
|
|
|
const (
|
|
linkNoCgo = iota
|
|
linkCgoDefault
|
|
linkCgoInternal
|
|
linkCgoExternal
|
|
)
|
|
|
|
func getImageBase(f *File) uintptr {
|
|
switch oh := f.OptionalHeader.(type) {
|
|
case *OptionalHeader32:
|
|
return uintptr(oh.ImageBase)
|
|
case *OptionalHeader64:
|
|
return uintptr(oh.ImageBase)
|
|
default:
|
|
panic("unexpected optionalheader type")
|
|
}
|
|
}
|
|
|
|
func testDWARF(t *testing.T, linktype int) {
|
|
if runtime.GOOS != "windows" {
|
|
t.Skip("skipping windows only test")
|
|
}
|
|
testenv.MustHaveGoRun(t)
|
|
|
|
tmpdir, err := ioutil.TempDir("", "TestDWARF")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
src := filepath.Join(tmpdir, "a.go")
|
|
file, err := os.Create(src)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = template.Must(template.New("main").Parse(testprog)).Execute(file, linktype != linkNoCgo)
|
|
if err != nil {
|
|
if err := file.Close(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
t.Fatal(err)
|
|
}
|
|
if err := file.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
exe := filepath.Join(tmpdir, "a.exe")
|
|
args := []string{"build", "-o", exe}
|
|
switch linktype {
|
|
case linkNoCgo:
|
|
case linkCgoDefault:
|
|
case linkCgoInternal:
|
|
args = append(args, "-ldflags", "-linkmode=internal")
|
|
case linkCgoExternal:
|
|
args = append(args, "-ldflags", "-linkmode=external")
|
|
default:
|
|
t.Fatalf("invalid linktype parameter of %v", linktype)
|
|
}
|
|
args = append(args, src)
|
|
out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("building test executable for linktype %d failed: %s %s", linktype, err, out)
|
|
}
|
|
out, err = exec.Command(exe).CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("running test executable failed: %s %s", err, out)
|
|
}
|
|
t.Logf("Testprog output:\n%s", string(out))
|
|
|
|
matches := regexp.MustCompile("offset=(.*)\n").FindStringSubmatch(string(out))
|
|
if len(matches) < 2 {
|
|
t.Fatalf("unexpected program output: %s", out)
|
|
}
|
|
wantoffset, err := strconv.ParseUint(matches[1], 0, 64)
|
|
if err != nil {
|
|
t.Fatalf("unexpected main offset %q: %s", matches[1], err)
|
|
}
|
|
|
|
f, err := Open(exe)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
imageBase := getImageBase(f)
|
|
|
|
var foundDebugGDBScriptsSection bool
|
|
for _, sect := range f.Sections {
|
|
if sect.Name == ".debug_gdb_scripts" {
|
|
foundDebugGDBScriptsSection = true
|
|
}
|
|
}
|
|
if !foundDebugGDBScriptsSection {
|
|
t.Error(".debug_gdb_scripts section is not found")
|
|
}
|
|
|
|
d, err := f.DWARF()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// look for main.main
|
|
r := d.Reader()
|
|
for {
|
|
e, err := r.Next()
|
|
if err != nil {
|
|
t.Fatal("r.Next:", err)
|
|
}
|
|
if e == nil {
|
|
break
|
|
}
|
|
if e.Tag == dwarf.TagSubprogram {
|
|
name, ok := e.Val(dwarf.AttrName).(string)
|
|
if ok && name == "main.main" {
|
|
t.Logf("Found main.main")
|
|
addr, ok := e.Val(dwarf.AttrLowpc).(uint64)
|
|
if !ok {
|
|
t.Fatal("Failed to get AttrLowpc")
|
|
}
|
|
offset := uintptr(addr) - imageBase
|
|
if offset != uintptr(wantoffset) {
|
|
t.Fatal("Runtime offset (0x%x) did "+
|
|
"not match dwarf offset "+
|
|
"(0x%x)", wantoffset, offset)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
t.Fatal("main.main not found")
|
|
}
|
|
|
|
func TestBSSHasZeros(t *testing.T) {
|
|
testenv.MustHaveExec(t)
|
|
|
|
if runtime.GOOS != "windows" {
|
|
t.Skip("skipping windows only test")
|
|
}
|
|
gccpath, err := exec.LookPath("gcc")
|
|
if err != nil {
|
|
t.Skip("skipping test: gcc is missing")
|
|
}
|
|
|
|
tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
srcpath := filepath.Join(tmpdir, "a.c")
|
|
src := `
|
|
#include <stdio.h>
|
|
|
|
int zero = 0;
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
printf("%d\n", zero);
|
|
return 0;
|
|
}
|
|
`
|
|
err = ioutil.WriteFile(srcpath, []byte(src), 0644)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
objpath := filepath.Join(tmpdir, "a.obj")
|
|
cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("failed to build object file: %v - %v", err, string(out))
|
|
}
|
|
|
|
f, err := Open(objpath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
var bss *Section
|
|
for _, sect := range f.Sections {
|
|
if sect.Name == ".bss" {
|
|
bss = sect
|
|
break
|
|
}
|
|
}
|
|
if bss == nil {
|
|
t.Fatal("could not find .bss section")
|
|
}
|
|
data, err := bss.Data()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(data) == 0 {
|
|
t.Fatalf("%s file .bss section cannot be empty", objpath)
|
|
}
|
|
for _, b := range data {
|
|
if b != 0 {
|
|
t.Fatalf(".bss section has non zero bytes: %v", data)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDWARF(t *testing.T) {
|
|
testDWARF(t, linkNoCgo)
|
|
}
|
|
|
|
const testprog = `
|
|
package main
|
|
|
|
import "fmt"
|
|
import "syscall"
|
|
import "unsafe"
|
|
{{if .}}import "C"
|
|
{{end}}
|
|
|
|
// struct MODULEINFO from the Windows SDK
|
|
type moduleinfo struct {
|
|
BaseOfDll uintptr
|
|
SizeOfImage uint32
|
|
EntryPoint uintptr
|
|
}
|
|
|
|
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
|
|
return unsafe.Pointer(uintptr(p) + x)
|
|
}
|
|
|
|
func funcPC(f interface{}) uintptr {
|
|
var a uintptr
|
|
return **(**uintptr)(add(unsafe.Pointer(&f), unsafe.Sizeof(a)))
|
|
}
|
|
|
|
func main() {
|
|
kernel32 := syscall.MustLoadDLL("kernel32.dll")
|
|
psapi := syscall.MustLoadDLL("psapi.dll")
|
|
getModuleHandle := kernel32.MustFindProc("GetModuleHandleW")
|
|
getCurrentProcess := kernel32.MustFindProc("GetCurrentProcess")
|
|
getModuleInformation := psapi.MustFindProc("GetModuleInformation")
|
|
|
|
procHandle, _, _ := getCurrentProcess.Call()
|
|
moduleHandle, _, err := getModuleHandle.Call(0)
|
|
if moduleHandle == 0 {
|
|
panic(fmt.Sprintf("GetModuleHandle() failed: %d", err))
|
|
}
|
|
|
|
var info moduleinfo
|
|
ret, _, err := getModuleInformation.Call(procHandle, moduleHandle,
|
|
uintptr(unsafe.Pointer(&info)), unsafe.Sizeof(info))
|
|
|
|
if ret == 0 {
|
|
panic(fmt.Sprintf("GetModuleInformation() failed: %d", err))
|
|
}
|
|
|
|
offset := funcPC(main) - info.BaseOfDll
|
|
fmt.Printf("base=0x%x\n", info.BaseOfDll)
|
|
fmt.Printf("main=%p\n", main)
|
|
fmt.Printf("offset=0x%x\n", offset)
|
|
}
|
|
`
|
|
|
|
func TestBuildingWindowsGUI(t *testing.T) {
|
|
testenv.MustHaveGoBuild(t)
|
|
|
|
if runtime.GOOS != "windows" {
|
|
t.Skip("skipping windows only test")
|
|
}
|
|
tmpdir, err := ioutil.TempDir("", "TestBuildingWindowsGUI")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmpdir)
|
|
|
|
src := filepath.Join(tmpdir, "a.go")
|
|
err = ioutil.WriteFile(src, []byte(`package main; func main() {}`), 0644)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
exe := filepath.Join(tmpdir, "a.exe")
|
|
cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags", "-H=windowsgui", "-o", exe, src)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("building test executable failed: %s %s", err, out)
|
|
}
|
|
|
|
f, err := Open(exe)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
const _IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
|
|
|
|
switch oh := f.OptionalHeader.(type) {
|
|
case *OptionalHeader32:
|
|
if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
|
|
t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
|
|
}
|
|
case *OptionalHeader64:
|
|
if oh.Subsystem != _IMAGE_SUBSYSTEM_WINDOWS_GUI {
|
|
t.Errorf("unexpected Subsystem value: have %d, but want %d", oh.Subsystem, _IMAGE_SUBSYSTEM_WINDOWS_GUI)
|
|
}
|
|
default:
|
|
t.Fatalf("unexpected OptionalHeader type: have %T, but want *pe.OptionalHeader32 or *pe.OptionalHeader64", oh)
|
|
}
|
|
}
|
|
|
|
func TestImportTableInUnknownSection(t *testing.T) {
|
|
if runtime.GOOS != "windows" {
|
|
t.Skip("skipping Windows-only test")
|
|
}
|
|
|
|
// ws2_32.dll import table is located in ".rdata" section,
|
|
// so it is good enough to test issue #16103.
|
|
const filename = "ws2_32.dll"
|
|
path, err := exec.LookPath(filename)
|
|
if err != nil {
|
|
t.Fatalf("unable to locate required file %q in search path: %s", filename, err)
|
|
}
|
|
|
|
f, err := Open(path)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
// now we can extract its imports
|
|
symbols, err := f.ImportedSymbols()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
if len(symbols) == 0 {
|
|
t.Fatalf("unable to locate any imported symbols within file %q.", path)
|
|
}
|
|
}
|