]> Cypherpunks repositories - gostls13.git/commitdiff
debug/pe: add optional header to File
authorAlex Brainman <alex.brainman@gmail.com>
Thu, 17 Apr 2014 02:10:59 +0000 (22:10 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 17 Apr 2014 02:10:59 +0000 (22:10 -0400)
This information is required by cmd/nm
to calculate absolute symbol addresses.

Update #6936
Update #7738

LGTM=rsc
R=golang-codereviews, bradfitz, gobot, rsc
CC=golang-codereviews
https://golang.org/cl/87500043

src/pkg/debug/pe/file.go
src/pkg/debug/pe/file_test.go
src/pkg/debug/pe/pe.go
src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec [new file with mode: 0644]
src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj [new file with mode: 0644]

index d0005bacf383ee9e6ff4107092ba07e3827eb184..ce6f1408fe98f43e1c2afe516482b9c4dc098928 100644 (file)
@@ -13,13 +13,15 @@ import (
        "io"
        "os"
        "strconv"
+       "unsafe"
 )
 
 // A File represents an open PE file.
 type File struct {
        FileHeader
-       Sections []*Section
-       Symbols  []*Symbol
+       OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
+       Sections       []*Section
+       Symbols        []*Symbol
 
        closer io.Closer
 }
@@ -196,10 +198,33 @@ func NewFile(r io.ReaderAt) (*File, error) {
                }
        }
 
-       // Process sections.
+       // Read optional header.
        sr.Seek(base, os.SEEK_SET)
-       binary.Read(sr, binary.LittleEndian, &f.FileHeader)
-       sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), os.SEEK_CUR) //Skip OptionalHeader
+       if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
+               return nil, err
+       }
+       var oh32 OptionalHeader32
+       var oh64 OptionalHeader64
+       switch uintptr(f.FileHeader.SizeOfOptionalHeader) {
+       case unsafe.Sizeof(oh32):
+               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 unsafe.Sizeof(oh64):
+               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)
index c0f9fcb95db770e999f5a24186d6cde42e4ef73b..ddbb271744146c8b052740e9fc251f1acfc29dd9 100644 (file)
@@ -12,6 +12,7 @@ import (
 type fileTest struct {
        file     string
        hdr      FileHeader
+       opthdr   interface{}
        sections []*SectionHeader
        symbols  []*Symbol
 }
@@ -20,6 +21,7 @@ var fileTests = []fileTest{
        {
                "testdata/gcc-386-mingw-obj",
                FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
+               nil,
                []*SectionHeader{
                        {".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
                        {".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
@@ -56,27 +58,130 @@ var fileTests = []fileTest{
        {
                "testdata/gcc-386-mingw-exec",
                FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
+               &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},
+                       },
+               },
+               []*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},
+               },
+               []*Symbol{},
+       },
+       {
+               "testdata/gcc-amd64-mingw-obj",
+               FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
+               nil,
+               []*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},
+               },
+               []*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},
+               },
+       },
+       {
+               "testdata/gcc-amd64-mingw-exec",
+               FileHeader{0x8664, 0x9, 0x53472993, 0x0, 0x0, 0xf0, 0x22f},
+               &OptionalHeader64{
+                       0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x11000, 0x400, 0x1841e, 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},
+                       },
+               },
                []*SectionHeader{
-                       {Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
-                       {Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
-                       {Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
-                       {Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
-                       {Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
-                       {Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
-                       {Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
-                       {Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-                       {Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-                       {Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-                       {Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-                       {Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-                       {Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-                       {Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
-                       {Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+                       {".text", 0x6860, 0x1000, 0x6a00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500020},
+                       {".data", 0xe0, 0x8000, 0x200, 0x6e00, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
+                       {".rdata", 0x6b0, 0x9000, 0x800, 0x7000, 0x0, 0x0, 0x0, 0x0, 0x40600040},
+                       {".pdata", 0x498, 0xa000, 0x600, 0x7800, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+                       {".xdata", 0x488, 0xb000, 0x600, 0x7e00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+                       {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
+                       {".idata", 0x990, 0xe000, 0xa00, 0x8400, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+                       {".CRT", 0x68, 0xf000, 0x200, 0x8e00, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
+                       {".tls", 0x48, 0x10000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
                },
                []*Symbol{},
        },
 }
 
+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]
@@ -90,6 +195,10 @@ func TestOpen(t *testing.T) {
                        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) {
index 0606217b3bfdf3f9c641dfd57acebd5ae09e9c63..8e90b1b513acb1b687eae99099fbdcb041e9b442 100644 (file)
@@ -14,6 +14,78 @@ type FileHeader struct {
        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
+}
+
 type SectionHeader32 struct {
        Name                 [8]uint8
        VirtualSize          uint32
diff --git a/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec
new file mode 100644 (file)
index 0000000..78d4e5f
Binary files /dev/null and b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec differ
diff --git a/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj
new file mode 100644 (file)
index 0000000..48ae792
Binary files /dev/null and b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj differ