+++ /dev/null
-// 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"
-}
+++ /dev/null
-// 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)
- }
- }
-}