mirror of https://github.com/golang/go.git
cmd/dist: use debug/pe directly for cmd/link
Delete vendored copy. Change-Id: I06e9d3b709553a1a8d06275e99bd8f617aac5788 Reviewed-on: https://go-review.googlesource.com/31011 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
15040c11b9
commit
237d7e34bc
|
|
@ -36,11 +36,6 @@ go src=..
|
|||
gofmt_test.go
|
||||
testdata
|
||||
+
|
||||
link
|
||||
internal
|
||||
pe
|
||||
testdata
|
||||
+
|
||||
vendor
|
||||
golang.org
|
||||
x
|
||||
|
|
|
|||
|
|
@ -60,10 +60,10 @@ var bootstrapDirs = []string{
|
|||
"cmd/link/internal/arm64",
|
||||
"cmd/link/internal/ld",
|
||||
"cmd/link/internal/mips64",
|
||||
"cmd/link/internal/pe",
|
||||
"cmd/link/internal/ppc64",
|
||||
"cmd/link/internal/s390x",
|
||||
"cmd/link/internal/x86",
|
||||
"debug/pe",
|
||||
"math/big",
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"cmd/internal/bio"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/sys"
|
||||
"cmd/link/internal/pe"
|
||||
"debug/pe"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
|
|||
|
|
@ -1,343 +0,0 @@
|
|||
// 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 implements access to PE (Microsoft Windows Portable Executable) files.
|
||||
package pe
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A File represents an open PE file.
|
||||
type File struct {
|
||||
FileHeader
|
||||
OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
|
||||
Sections []*Section
|
||||
Symbols []*Symbol // COFF symbols with auxiliary symbol records removed
|
||||
COFFSymbols []COFFSymbol // all COFF symbols (including auxiliary symbol records)
|
||||
StringTable StringTable
|
||||
|
||||
closer io.Closer
|
||||
}
|
||||
|
||||
// Open opens the named file using os.Open and prepares it for use as a PE binary.
|
||||
func Open(name string) (*File, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ff, err := NewFile(f)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
ff.closer = f
|
||||
return ff, nil
|
||||
}
|
||||
|
||||
// Close closes the File.
|
||||
// If the File was created using NewFile directly instead of Open,
|
||||
// Close has no effect.
|
||||
func (f *File) Close() error {
|
||||
var err error
|
||||
if f.closer != nil {
|
||||
err = f.closer.Close()
|
||||
f.closer = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
sizeofOptionalHeader32 = uint16(binary.Size(OptionalHeader32{}))
|
||||
sizeofOptionalHeader64 = uint16(binary.Size(OptionalHeader64{}))
|
||||
)
|
||||
|
||||
// TODO(brainman): add Load function, as a replacement for NewFile, that does not call removeAuxSymbols (for performance)
|
||||
|
||||
// NewFile creates a new File for accessing a PE binary in an underlying reader.
|
||||
func NewFile(r io.ReaderAt) (*File, error) {
|
||||
f := new(File)
|
||||
sr := io.NewSectionReader(r, 0, 1<<63-1)
|
||||
|
||||
var dosheader [96]byte
|
||||
if _, err := r.ReadAt(dosheader[0:], 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var base int64
|
||||
if dosheader[0] == 'M' && dosheader[1] == 'Z' {
|
||||
signoff := int64(binary.LittleEndian.Uint32(dosheader[0x3c:]))
|
||||
var sign [4]byte
|
||||
r.ReadAt(sign[:], signoff)
|
||||
if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
|
||||
return nil, fmt.Errorf("Invalid PE COFF file signature of %v.", sign)
|
||||
}
|
||||
base = signoff + 4
|
||||
} else {
|
||||
base = int64(0)
|
||||
}
|
||||
sr.Seek(base, os.SEEK_SET)
|
||||
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch f.FileHeader.Machine {
|
||||
case IMAGE_FILE_MACHINE_UNKNOWN, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386:
|
||||
default:
|
||||
return nil, fmt.Errorf("Unrecognised COFF file header machine value of 0x%x.", f.FileHeader.Machine)
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
// Read string table.
|
||||
f.StringTable, err = readStringTable(&f.FileHeader, sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read symbol table.
|
||||
f.COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Symbols, err = removeAuxSymbols(f.COFFSymbols, f.StringTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read optional header.
|
||||
sr.Seek(base, os.SEEK_SET)
|
||||
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var oh32 OptionalHeader32
|
||||
var oh64 OptionalHeader64
|
||||
switch f.FileHeader.SizeOfOptionalHeader {
|
||||
case sizeofOptionalHeader32:
|
||||
if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if oh32.Magic != 0x10b { // PE32
|
||||
return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic)
|
||||
}
|
||||
f.OptionalHeader = &oh32
|
||||
case sizeofOptionalHeader64:
|
||||
if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if oh64.Magic != 0x20b { // PE32+
|
||||
return nil, fmt.Errorf("pe32+ optional header has unexpected Magic of 0x%x", oh64.Magic)
|
||||
}
|
||||
f.OptionalHeader = &oh64
|
||||
}
|
||||
|
||||
// Process sections.
|
||||
f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
|
||||
for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
|
||||
sh := new(SectionHeader32)
|
||||
if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name, err := sh.fullName(f.StringTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := new(Section)
|
||||
s.SectionHeader = SectionHeader{
|
||||
Name: name,
|
||||
VirtualSize: sh.VirtualSize,
|
||||
VirtualAddress: sh.VirtualAddress,
|
||||
Size: sh.SizeOfRawData,
|
||||
Offset: sh.PointerToRawData,
|
||||
PointerToRelocations: sh.PointerToRelocations,
|
||||
PointerToLineNumbers: sh.PointerToLineNumbers,
|
||||
NumberOfRelocations: sh.NumberOfRelocations,
|
||||
NumberOfLineNumbers: sh.NumberOfLineNumbers,
|
||||
Characteristics: sh.Characteristics,
|
||||
}
|
||||
r2 := r
|
||||
if sh.PointerToRawData == 0 { // .bss must have all 0s
|
||||
r2 = zeroReaderAt{}
|
||||
}
|
||||
s.sr = io.NewSectionReader(r2, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
|
||||
s.ReaderAt = s.sr
|
||||
f.Sections[i] = s
|
||||
}
|
||||
for i := range f.Sections {
|
||||
var err error
|
||||
f.Sections[i].Relocs, err = readRelocs(&f.Sections[i].SectionHeader, sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// zeroReaderAt is ReaderAt that reads 0s.
|
||||
type zeroReaderAt struct{}
|
||||
|
||||
// ReadAt writes len(p) 0s into p.
|
||||
func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
for i := range p {
|
||||
p[i] = 0
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// getString extracts a string from symbol string table.
|
||||
func getString(section []byte, start int) (string, bool) {
|
||||
if start < 0 || start >= len(section) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for end := start; end < len(section); end++ {
|
||||
if section[end] == 0 {
|
||||
return string(section[start:end]), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Section returns the first section with the given name, or nil if no such
|
||||
// section exists.
|
||||
func (f *File) Section(name string) *Section {
|
||||
for _, s := range f.Sections {
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
// There are many other DWARF sections, but these
|
||||
// are the ones the debug/dwarf package uses.
|
||||
// Don't bother loading others.
|
||||
var names = [...]string{"abbrev", "info", "line", "ranges", "str"}
|
||||
var dat [len(names)][]byte
|
||||
for i, name := range names {
|
||||
name = ".debug_" + name
|
||||
s := f.Section(name)
|
||||
if s == nil {
|
||||
continue
|
||||
}
|
||||
b, err := s.Data()
|
||||
if err != nil && uint32(len(b)) < s.Size {
|
||||
return nil, err
|
||||
}
|
||||
if 0 < s.VirtualSize && s.VirtualSize < s.Size {
|
||||
b = b[:s.VirtualSize]
|
||||
}
|
||||
dat[i] = b
|
||||
}
|
||||
|
||||
abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
|
||||
return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
|
||||
}
|
||||
|
||||
// TODO(brainman): document ImportDirectory once we decide what to do with it.
|
||||
|
||||
type ImportDirectory struct {
|
||||
OriginalFirstThunk uint32
|
||||
TimeDateStamp uint32
|
||||
ForwarderChain uint32
|
||||
Name uint32
|
||||
FirstThunk uint32
|
||||
|
||||
dll string
|
||||
}
|
||||
|
||||
// ImportedSymbols returns the names of all symbols
|
||||
// referred to by the binary f that are expected to be
|
||||
// satisfied by other libraries at dynamic load time.
|
||||
// It does not return weak symbols.
|
||||
func (f *File) ImportedSymbols() ([]string, error) {
|
||||
pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
|
||||
ds := f.Section(".idata")
|
||||
if ds == nil {
|
||||
// not dynamic, so no libraries
|
||||
return nil, nil
|
||||
}
|
||||
d, err := ds.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ida []ImportDirectory
|
||||
for len(d) > 0 {
|
||||
var dt ImportDirectory
|
||||
dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4])
|
||||
dt.Name = binary.LittleEndian.Uint32(d[12:16])
|
||||
dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20])
|
||||
d = d[20:]
|
||||
if dt.OriginalFirstThunk == 0 {
|
||||
break
|
||||
}
|
||||
ida = append(ida, dt)
|
||||
}
|
||||
// TODO(brainman): this needs to be rewritten
|
||||
// ds.Data() return contets of .idata section. Why store in variable called "names"?
|
||||
// Why we are retrieving it second time? We already have it in "d", and it is not modified anywhere.
|
||||
// getString does not extracts a string from symbol string table (as getString doco says).
|
||||
// Why ds.Data() called again and again in the loop?
|
||||
// Needs test before rewrite.
|
||||
names, _ := ds.Data()
|
||||
var all []string
|
||||
for _, dt := range ida {
|
||||
dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress))
|
||||
d, _ = ds.Data()
|
||||
// seek to OriginalFirstThunk
|
||||
d = d[dt.OriginalFirstThunk-ds.VirtualAddress:]
|
||||
for len(d) > 0 {
|
||||
if pe64 { // 64bit
|
||||
va := binary.LittleEndian.Uint64(d[0:8])
|
||||
d = d[8:]
|
||||
if va == 0 {
|
||||
break
|
||||
}
|
||||
if va&0x8000000000000000 > 0 { // is Ordinal
|
||||
// TODO add dynimport ordinal support.
|
||||
} else {
|
||||
fn, _ := getString(names, int(uint32(va)-ds.VirtualAddress+2))
|
||||
all = append(all, fn+":"+dt.dll)
|
||||
}
|
||||
} else { // 32bit
|
||||
va := binary.LittleEndian.Uint32(d[0:4])
|
||||
d = d[4:]
|
||||
if va == 0 {
|
||||
break
|
||||
}
|
||||
if va&0x80000000 > 0 { // is Ordinal
|
||||
// TODO add dynimport ordinal support.
|
||||
//ord := va&0x0000FFFF
|
||||
} else {
|
||||
fn, _ := getString(names, int(va-ds.VirtualAddress+2))
|
||||
all = append(all, fn+":"+dt.dll)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// ImportedLibraries returns the names of all libraries
|
||||
// referred to by the binary f that are expected to be
|
||||
// linked with the binary at dynamic link time.
|
||||
func (f *File) ImportedLibraries() ([]string, error) {
|
||||
// TODO
|
||||
// cgo -dynimport don't use this for windows PE, so just return.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// FormatError is unused.
|
||||
// The type is retained for compatibility.
|
||||
type FormatError struct {
|
||||
}
|
||||
|
||||
func (e *FormatError) Error() string {
|
||||
return "unknown error"
|
||||
}
|
||||
|
|
@ -1,417 +0,0 @@
|
|||
// 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"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDWARF(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("skipping windows only test")
|
||||
}
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "TestDWARF")
|
||||
if err != nil {
|
||||
t.Fatal("TempDir failed: ", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
prog := `
|
||||
package main
|
||||
func main() {
|
||||
}
|
||||
`
|
||||
src := filepath.Join(tmpdir, "a.go")
|
||||
exe := filepath.Join(tmpdir, "a.exe")
|
||||
err = ioutil.WriteFile(src, []byte(prog), 0644)
|
||||
output, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("building test executable failed: %s %s", err, output)
|
||||
}
|
||||
|
||||
f, err := Open(exe)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
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 {
|
||||
for _, f := range e.Field {
|
||||
if f.Attr == dwarf.AttrName && e.Val(dwarf.AttrName) == "main.main" {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
// 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
|
||||
|
||||
type FileHeader struct {
|
||||
Machine uint16
|
||||
NumberOfSections uint16
|
||||
TimeDateStamp uint32
|
||||
PointerToSymbolTable uint32
|
||||
NumberOfSymbols uint32
|
||||
SizeOfOptionalHeader uint16
|
||||
Characteristics uint16
|
||||
}
|
||||
|
||||
type DataDirectory struct {
|
||||
VirtualAddress uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
type OptionalHeader32 struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
BaseOfData uint32
|
||||
ImageBase uint32
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uint32
|
||||
SizeOfStackCommit uint32
|
||||
SizeOfHeapReserve uint32
|
||||
SizeOfHeapCommit uint32
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [16]DataDirectory
|
||||
}
|
||||
|
||||
type OptionalHeader64 struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
ImageBase uint64
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uint64
|
||||
SizeOfStackCommit uint64
|
||||
SizeOfHeapReserve uint64
|
||||
SizeOfHeapCommit uint64
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [16]DataDirectory
|
||||
}
|
||||
|
||||
const (
|
||||
IMAGE_FILE_MACHINE_UNKNOWN = 0x0
|
||||
IMAGE_FILE_MACHINE_AM33 = 0x1d3
|
||||
IMAGE_FILE_MACHINE_AMD64 = 0x8664
|
||||
IMAGE_FILE_MACHINE_ARM = 0x1c0
|
||||
IMAGE_FILE_MACHINE_EBC = 0xebc
|
||||
IMAGE_FILE_MACHINE_I386 = 0x14c
|
||||
IMAGE_FILE_MACHINE_IA64 = 0x200
|
||||
IMAGE_FILE_MACHINE_M32R = 0x9041
|
||||
IMAGE_FILE_MACHINE_MIPS16 = 0x266
|
||||
IMAGE_FILE_MACHINE_MIPSFPU = 0x366
|
||||
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466
|
||||
IMAGE_FILE_MACHINE_POWERPC = 0x1f0
|
||||
IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1
|
||||
IMAGE_FILE_MACHINE_R4000 = 0x166
|
||||
IMAGE_FILE_MACHINE_SH3 = 0x1a2
|
||||
IMAGE_FILE_MACHINE_SH3DSP = 0x1a3
|
||||
IMAGE_FILE_MACHINE_SH4 = 0x1a6
|
||||
IMAGE_FILE_MACHINE_SH5 = 0x1a8
|
||||
IMAGE_FILE_MACHINE_THUMB = 0x1c2
|
||||
IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
|
||||
)
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
// Copyright 2016 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 (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// SectionHeader32 represents real PE COFF section header.
|
||||
type SectionHeader32 struct {
|
||||
Name [8]uint8
|
||||
VirtualSize uint32
|
||||
VirtualAddress uint32
|
||||
SizeOfRawData uint32
|
||||
PointerToRawData uint32
|
||||
PointerToRelocations uint32
|
||||
PointerToLineNumbers uint32
|
||||
NumberOfRelocations uint16
|
||||
NumberOfLineNumbers uint16
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
// fullName finds real name of section sh. Normally name is stored
|
||||
// in sh.Name, but if it is longer then 8 characters, it is stored
|
||||
// in COFF string table st instead.
|
||||
func (sh *SectionHeader32) fullName(st StringTable) (string, error) {
|
||||
if sh.Name[0] != '/' {
|
||||
return cstring(sh.Name[:]), nil
|
||||
}
|
||||
i, err := strconv.Atoi(cstring(sh.Name[1:]))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return st.String(uint32(i))
|
||||
}
|
||||
|
||||
// TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here
|
||||
|
||||
// Reloc represents a PE COFF relocation.
|
||||
// Each section contains its own relocation list.
|
||||
type Reloc struct {
|
||||
VirtualAddress uint32
|
||||
SymbolTableIndex uint32
|
||||
Type uint16
|
||||
}
|
||||
|
||||
func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) {
|
||||
if sh.NumberOfRelocations <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
_, err := r.Seek(int64(sh.PointerToRelocations), os.SEEK_SET)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err)
|
||||
}
|
||||
relocs := make([]Reloc, sh.NumberOfRelocations)
|
||||
err = binary.Read(r, binary.LittleEndian, relocs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read section relocations: %v", err)
|
||||
}
|
||||
return relocs, nil
|
||||
}
|
||||
|
||||
// SectionHeader is similar to SectionHeader32 with Name
|
||||
// field replaced by Go string.
|
||||
type SectionHeader struct {
|
||||
Name string
|
||||
VirtualSize uint32
|
||||
VirtualAddress uint32
|
||||
Size uint32
|
||||
Offset uint32
|
||||
PointerToRelocations uint32
|
||||
PointerToLineNumbers uint32
|
||||
NumberOfRelocations uint16
|
||||
NumberOfLineNumbers uint16
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
// Section provides access to PE COFF section.
|
||||
type Section struct {
|
||||
SectionHeader
|
||||
Relocs []Reloc
|
||||
|
||||
// Embed ReaderAt for ReadAt method.
|
||||
// Do not embed SectionReader directly
|
||||
// to avoid having Read and Seek.
|
||||
// If a client wants Read and Seek it must use
|
||||
// Open() to avoid fighting over the seek offset
|
||||
// with other clients.
|
||||
io.ReaderAt
|
||||
sr *io.SectionReader
|
||||
}
|
||||
|
||||
// Data reads and returns the contents of the PE section s.
|
||||
func (s *Section) Data() ([]byte, error) {
|
||||
dat := make([]byte, s.sr.Size())
|
||||
n, err := s.sr.ReadAt(dat, 0)
|
||||
if n == len(dat) {
|
||||
err = nil
|
||||
}
|
||||
return dat[0:n], err
|
||||
}
|
||||
|
||||
// Open returns a new ReadSeeker reading the PE section s.
|
||||
func (s *Section) Open() io.ReadSeeker {
|
||||
return io.NewSectionReader(s.sr, 0, 1<<63-1)
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright 2016 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 (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// cstring converts ASCII byte sequence b to string.
|
||||
// It stops once it finds 0 or reaches end of b.
|
||||
func cstring(b []byte) string {
|
||||
var i int
|
||||
for i = 0; i < len(b) && b[i] != 0; i++ {
|
||||
}
|
||||
return string(b[:i])
|
||||
}
|
||||
|
||||
// StringTable is a COFF string table.
|
||||
type StringTable []byte
|
||||
|
||||
func readStringTable(fh *FileHeader, r io.ReadSeeker) (StringTable, error) {
|
||||
// COFF string table is located right after COFF symbol table.
|
||||
if fh.PointerToSymbolTable <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
offset := fh.PointerToSymbolTable + COFFSymbolSize*fh.NumberOfSymbols
|
||||
_, err := r.Seek(int64(offset), os.SEEK_SET)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to string table: %v", err)
|
||||
}
|
||||
var l uint32
|
||||
err = binary.Read(r, binary.LittleEndian, &l)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read string table length: %v", err)
|
||||
}
|
||||
// string table length includes itself
|
||||
if l <= 4 {
|
||||
return nil, nil
|
||||
}
|
||||
l -= 4
|
||||
buf := make([]byte, l)
|
||||
_, err = io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read string table: %v", err)
|
||||
}
|
||||
return StringTable(buf), nil
|
||||
}
|
||||
|
||||
// TODO(brainman): decide if start parameter should be int instead of uint32
|
||||
|
||||
// String extracts string from COFF string table st at offset start.
|
||||
func (st StringTable) String(start uint32) (string, error) {
|
||||
// start includes 4 bytes of string table length
|
||||
if start < 4 {
|
||||
return "", fmt.Errorf("offset %d is before the start of string table", start)
|
||||
}
|
||||
start -= 4
|
||||
if int(start) > len(st) {
|
||||
return "", fmt.Errorf("offset %d is beyond the end of string table", start)
|
||||
}
|
||||
return cstring(st[start:]), nil
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
// Copyright 2016 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 (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
const COFFSymbolSize = 18
|
||||
|
||||
// COFFSymbol represents single COFF symbol table record.
|
||||
type COFFSymbol struct {
|
||||
Name [8]uint8
|
||||
Value uint32
|
||||
SectionNumber int16
|
||||
Type uint16
|
||||
StorageClass uint8
|
||||
NumberOfAuxSymbols uint8
|
||||
}
|
||||
|
||||
func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
|
||||
if fh.NumberOfSymbols <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
_, err := r.Seek(int64(fh.PointerToSymbolTable), os.SEEK_SET)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to symbol table: %v", err)
|
||||
}
|
||||
syms := make([]COFFSymbol, fh.NumberOfSymbols)
|
||||
err = binary.Read(r, binary.LittleEndian, syms)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read symbol table: %v", err)
|
||||
}
|
||||
return syms, nil
|
||||
}
|
||||
|
||||
// isSymNameOffset checks symbol name if it is encoded as offset into string table.
|
||||
func isSymNameOffset(name [8]byte) (bool, uint32) {
|
||||
if name[0] == 0 && name[1] == 0 && name[2] == 0 && name[3] == 0 {
|
||||
return true, binary.LittleEndian.Uint32(name[4:])
|
||||
}
|
||||
return false, 0
|
||||
}
|
||||
|
||||
// FullName finds real name of symbol sym. Normally name is stored
|
||||
// in sym.Name, but if it is longer then 8 characters, it is stored
|
||||
// in COFF string table st instead.
|
||||
func (sym *COFFSymbol) FullName(st StringTable) (string, error) {
|
||||
if ok, offset := isSymNameOffset(sym.Name); ok {
|
||||
return st.String(offset)
|
||||
}
|
||||
return cstring(sym.Name[:]), nil
|
||||
}
|
||||
|
||||
func removeAuxSymbols(allsyms []COFFSymbol, st StringTable) ([]*Symbol, error) {
|
||||
if len(allsyms) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
syms := make([]*Symbol, 0)
|
||||
aux := uint8(0)
|
||||
for _, sym := range allsyms {
|
||||
if aux > 0 {
|
||||
aux--
|
||||
continue
|
||||
}
|
||||
name, err := sym.FullName(st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aux = sym.NumberOfAuxSymbols
|
||||
s := &Symbol{
|
||||
Name: name,
|
||||
Value: sym.Value,
|
||||
SectionNumber: sym.SectionNumber,
|
||||
Type: sym.Type,
|
||||
StorageClass: sym.StorageClass,
|
||||
}
|
||||
syms = append(syms, s)
|
||||
}
|
||||
return syms, nil
|
||||
}
|
||||
|
||||
// Symbol is similar to COFFSymbol with Name field replaced
|
||||
// by Go string. Symbol also does not have NumberOfAuxSymbols.
|
||||
type Symbol struct {
|
||||
Name string
|
||||
Value uint32
|
||||
SectionNumber int16
|
||||
Type uint16
|
||||
StorageClass uint8
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,8 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
printf("hello, world\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2016 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.
|
||||
|
||||
# Run this script to obtain an up-to-date vendored version of debug/pe
|
||||
|
||||
PEDIR=../../../../debug/pe
|
||||
|
||||
# Start from scratch.
|
||||
rm testdata/*
|
||||
rm *.go
|
||||
rmdir testdata
|
||||
|
||||
# Copy all files.
|
||||
mkdir testdata
|
||||
cp $PEDIR/*.go .
|
||||
cp $PEDIR/testdata/* ./testdata
|
||||
|
||||
# go1.4 (bootstrap) does not know what io.SeekStart is.
|
||||
sed -i 's|io.SeekStart|os.SEEK_SET|' *.go
|
||||
|
||||
# goimports to clean up after sed
|
||||
goimports -w .
|
||||
|
||||
# gofmt to clean up after sed
|
||||
gofmt -w .
|
||||
|
||||
# Test that it works
|
||||
go test -short
|
||||
|
|
@ -13,6 +13,9 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
// Avoid use of post-Go 1.4 io features, to make safe for toolchain bootstrap.
|
||||
const seekStart = 0
|
||||
|
||||
// A File represents an open PE file.
|
||||
type File struct {
|
||||
FileHeader
|
||||
|
|
@ -80,7 +83,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||
} else {
|
||||
base = int64(0)
|
||||
}
|
||||
sr.Seek(base, io.SeekStart)
|
||||
sr.Seek(base, seekStart)
|
||||
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -109,7 +112,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||
}
|
||||
|
||||
// Read optional header.
|
||||
sr.Seek(base, io.SeekStart)
|
||||
sr.Seek(base, seekStart)
|
||||
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) {
|
|||
if sh.NumberOfRelocations <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
_, err := r.Seek(int64(sh.PointerToRelocations), io.SeekStart)
|
||||
_, err := r.Seek(int64(sh.PointerToRelocations), seekStart)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ func readStringTable(fh *FileHeader, r io.ReadSeeker) (StringTable, error) {
|
|||
return nil, nil
|
||||
}
|
||||
offset := fh.PointerToSymbolTable + COFFSymbolSize*fh.NumberOfSymbols
|
||||
_, err := r.Seek(int64(offset), io.SeekStart)
|
||||
_, err := r.Seek(int64(offset), seekStart)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to string table: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
|
|||
if fh.NumberOfSymbols <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
_, err := r.Seek(int64(fh.PointerToSymbolTable), io.SeekStart)
|
||||
_, err := r.Seek(int64(fh.PointerToSymbolTable), seekStart)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to symbol table: %v", err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue