aboutsummaryrefslogtreecommitdiff
path: root/src/debug
diff options
context:
space:
mode:
authorRick Hudson <rlh@golang.org>2016-04-27 18:19:16 -0400
committerRick Hudson <rlh@golang.org>2016-04-27 18:46:52 -0400
commit23aeb34df172b17b7bfaa85fb59ca64bef9073bb (patch)
treea8ab866f1e50f0059856ce628f036d93ab620155 /src/debug
parent1354b32cd70f2702381764fd595dd2faa996840c (diff)
parentd3c79d324acd7300b6f705e66af8ca711af00d9f (diff)
downloadgo-23aeb34df172b17b7bfaa85fb59ca64bef9073bb.tar.xz
[dev.garbage] Merge remote-tracking branch 'origin/master' into HEAD
Change-Id: I282fd9ce9db435dfd35e882a9502ab1abc185297
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/dwarf/buf.go2
-rw-r--r--src/debug/dwarf/line.go2
-rw-r--r--src/debug/dwarf/typeunit.go4
-rw-r--r--src/debug/elf/elf.go4
-rw-r--r--src/debug/elf/file.go40
-rw-r--r--src/debug/gosym/pclntab.go6
-rw-r--r--src/debug/gosym/symtab.go4
-rw-r--r--src/debug/pe/file.go199
-rw-r--r--src/debug/pe/pe.go24
-rw-r--r--src/debug/pe/section.go111
-rw-r--r--src/debug/pe/string.go63
-rw-r--r--src/debug/pe/symbol.go95
12 files changed, 365 insertions, 189 deletions
diff --git a/src/debug/dwarf/buf.go b/src/debug/dwarf/buf.go
index 7443043c11..24d266db10 100644
--- a/src/debug/dwarf/buf.go
+++ b/src/debug/dwarf/buf.go
@@ -157,7 +157,7 @@ func (b *buf) addr() uint64 {
case 4:
return uint64(b.uint32())
case 8:
- return uint64(b.uint64())
+ return b.uint64()
}
b.error("unknown address size")
return 0
diff --git a/src/debug/dwarf/line.go b/src/debug/dwarf/line.go
index b3b91ade62..ed82feef92 100644
--- a/src/debug/dwarf/line.go
+++ b/src/debug/dwarf/line.go
@@ -361,7 +361,7 @@ func (r *LineReader) step(entry *LineEntry) bool {
// Special opcode [DWARF2 6.2.5.1, DWARF4 6.2.5.1]
adjustedOpcode := opcode - r.opcodeBase
r.advancePC(adjustedOpcode / r.lineRange)
- lineDelta := r.lineBase + int(adjustedOpcode)%r.lineRange
+ lineDelta := r.lineBase + adjustedOpcode%r.lineRange
r.state.Line += lineDelta
goto emit
}
diff --git a/src/debug/dwarf/typeunit.go b/src/debug/dwarf/typeunit.go
index ed42547386..652e02d917 100644
--- a/src/debug/dwarf/typeunit.go
+++ b/src/debug/dwarf/typeunit.go
@@ -76,7 +76,7 @@ func (d *Data) parseTypes(name string, types []byte) error {
data: b.bytes(int(n - (b.off - hdroff))),
atable: atable,
asize: int(asize),
- vers: int(vers),
+ vers: vers,
is64: dwarf64,
},
toff: Offset(toff),
@@ -101,7 +101,7 @@ func (d *Data) sigToType(sig uint64) (Type, error) {
b := makeBuf(d, tu, tu.name, tu.off, tu.data)
r := &typeUnitReader{d: d, tu: tu, b: b}
- t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type), nil)
+ t, err := d.readType(tu.name, r, tu.toff, make(map[Offset]Type), nil)
if err != nil {
return nil, err
}
diff --git a/src/debug/elf/elf.go b/src/debug/elf/elf.go
index af881c2495..3f43d4d896 100644
--- a/src/debug/elf/elf.go
+++ b/src/debug/elf/elf.go
@@ -2060,8 +2060,8 @@ type Rela32 struct {
Addend int32 /* Addend. */
}
-func R_SYM32(info uint32) uint32 { return uint32(info >> 8) }
-func R_TYPE32(info uint32) uint32 { return uint32(info & 0xff) }
+func R_SYM32(info uint32) uint32 { return info >> 8 }
+func R_TYPE32(info uint32) uint32 { return info & 0xff }
func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ }
// ELF32 Symbol.
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index c28a964b73..c173ea9331 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -269,7 +269,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
switch f.Class {
case ELFCLASS32:
hdr := new(Header32)
- sr.Seek(0, os.SEEK_SET)
+ sr.Seek(0, io.SeekStart)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err
}
@@ -288,13 +288,13 @@ func NewFile(r io.ReaderAt) (*File, error) {
shstrndx = int(hdr.Shstrndx)
case ELFCLASS64:
hdr := new(Header64)
- sr.Seek(0, os.SEEK_SET)
+ sr.Seek(0, io.SeekStart)
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
return nil, err
}
f.Type = Type(hdr.Type)
f.Machine = Machine(hdr.Machine)
- f.Entry = uint64(hdr.Entry)
+ f.Entry = hdr.Entry
if v := Version(hdr.Version); v != f.Version {
return nil, &FormatError{0, "mismatched ELF version", v}
}
@@ -315,7 +315,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
f.Progs = make([]*Prog, phnum)
for i := 0; i < phnum; i++ {
off := phoff + int64(i)*int64(phentsize)
- sr.Seek(off, os.SEEK_SET)
+ sr.Seek(off, io.SeekStart)
p := new(Prog)
switch f.Class {
case ELFCLASS32:
@@ -341,12 +341,12 @@ func NewFile(r io.ReaderAt) (*File, error) {
p.ProgHeader = ProgHeader{
Type: ProgType(ph.Type),
Flags: ProgFlag(ph.Flags),
- Off: uint64(ph.Off),
- Vaddr: uint64(ph.Vaddr),
- Paddr: uint64(ph.Paddr),
- Filesz: uint64(ph.Filesz),
- Memsz: uint64(ph.Memsz),
- Align: uint64(ph.Align),
+ Off: ph.Off,
+ Vaddr: ph.Vaddr,
+ Paddr: ph.Paddr,
+ Filesz: ph.Filesz,
+ Memsz: ph.Memsz,
+ Align: ph.Align,
}
}
p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
@@ -359,7 +359,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
names := make([]uint32, shnum)
for i := 0; i < shnum; i++ {
off := shoff + int64(i)*int64(shentsize)
- sr.Seek(off, os.SEEK_SET)
+ sr.Seek(off, io.SeekStart)
s := new(Section)
switch f.Class {
case ELFCLASS32:
@@ -374,8 +374,8 @@ func NewFile(r io.ReaderAt) (*File, error) {
Addr: uint64(sh.Addr),
Offset: uint64(sh.Off),
FileSize: uint64(sh.Size),
- Link: uint32(sh.Link),
- Info: uint32(sh.Info),
+ Link: sh.Link,
+ Info: sh.Info,
Addralign: uint64(sh.Addralign),
Entsize: uint64(sh.Entsize),
}
@@ -388,13 +388,13 @@ func NewFile(r io.ReaderAt) (*File, error) {
s.SectionHeader = SectionHeader{
Type: SectionType(sh.Type),
Flags: SectionFlag(sh.Flags),
- Offset: uint64(sh.Off),
- FileSize: uint64(sh.Size),
- Addr: uint64(sh.Addr),
- Link: uint32(sh.Link),
- Info: uint32(sh.Info),
- Addralign: uint64(sh.Addralign),
- Entsize: uint64(sh.Entsize),
+ Offset: sh.Off,
+ FileSize: sh.Size,
+ Addr: sh.Addr,
+ Link: sh.Link,
+ Info: sh.Info,
+ Addralign: sh.Addralign,
+ Entsize: sh.Entsize,
}
}
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
diff --git a/src/debug/gosym/pclntab.go b/src/debug/gosym/pclntab.go
index 01a9f11f05..e859d5aed5 100644
--- a/src/debug/gosym/pclntab.go
+++ b/src/debug/gosym/pclntab.go
@@ -167,7 +167,7 @@ func (t *LineTable) go12Init() {
// Check header: 4-byte magic, two zeros, pc quantum, pointer size.
t.go12 = -1 // not Go 1.2 until proven otherwise
if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 ||
- (t.Data[6] != 1 && t.Data[6] != 4) || // pc quantum
+ (t.Data[6] != 1 && t.Data[6] != 2 && t.Data[6] != 4) || // pc quantum
(t.Data[7] != 4 && t.Data[7] != 8) { // pointer size
return
}
@@ -207,8 +207,8 @@ func (t *LineTable) go12Funcs() []Func {
funcs := make([]Func, n)
for i := range funcs {
f := &funcs[i]
- f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
- f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
+ f.Entry = t.uintptr(t.functab[2*i*int(t.ptrsize):])
+ f.End = t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):])
info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
f.LineTable = t
f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
diff --git a/src/debug/gosym/symtab.go b/src/debug/gosym/symtab.go
index 49e154fd8e..c8fa9a0b38 100644
--- a/src/debug/gosym/symtab.go
+++ b/src/debug/gosym/symtab.go
@@ -294,8 +294,8 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
t.Syms = t.Syms[0 : n+1]
ts := &t.Syms[n]
ts.Type = s.typ
- ts.Value = uint64(s.value)
- ts.GoType = uint64(s.gotype)
+ ts.Value = s.value
+ ts.GoType = s.gotype
switch s.typ {
default:
// rewrite name to use . instead of ยท (c2 b7)
diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go
index 1acc368e1b..1cd84d5727 100644
--- a/src/debug/pe/file.go
+++ b/src/debug/pe/file.go
@@ -8,11 +8,9 @@ package pe
import (
"debug/dwarf"
"encoding/binary"
- "errors"
"fmt"
"io"
"os"
- "strconv"
)
// A File represents an open PE file.
@@ -20,83 +18,13 @@ type File struct {
FileHeader
OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
Sections []*Section
- Symbols []*Symbol
+ Symbols []*Symbol // COFF symbols with auxiliary symbol records removed
+ COFFSymbols []COFFSymbol // all COFF symbols (including auxiliary symbol records)
+ StringTable StringTable
closer io.Closer
}
-type SectionHeader struct {
- Name string
- VirtualSize uint32
- VirtualAddress uint32
- Size uint32
- Offset uint32
- PointerToRelocations uint32
- PointerToLineNumbers uint32
- NumberOfRelocations uint16
- NumberOfLineNumbers uint16
- Characteristics uint32
-}
-
-type Section struct {
- SectionHeader
-
- // 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
-}
-
-type Symbol struct {
- Name string
- Value uint32
- SectionNumber int16
- Type uint16
- StorageClass uint8
-}
-
-type ImportDirectory struct {
- OriginalFirstThunk uint32
- TimeDateStamp uint32
- ForwarderChain uint32
- Name uint32
- FirstThunk uint32
-
- dll string
-}
-
-// Data reads and returns the contents of the PE section.
-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.
-func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
-
-type FormatError struct {
- off int64
- msg string
- val interface{}
-}
-
-func (e *FormatError) Error() string {
- msg := e.msg
- if e.val != nil {
- msg += fmt.Sprintf(" '%v'", e.val)
- }
- msg += fmt.Sprintf(" in record at byte %#x", e.off)
- return msg
-}
-
// 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)
@@ -129,6 +57,8 @@ var (
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)
@@ -144,66 +74,42 @@ func NewFile(r io.ReaderAt) (*File, error) {
var sign [4]byte
r.ReadAt(sign[:], signoff)
if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
- return nil, errors.New("Invalid PE File Format.")
+ 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)
+ sr.Seek(base, io.SeekStart)
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
return nil, err
}
- if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
- return nil, errors.New("Invalid PE File Format.")
+ 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 ss []byte
- if f.FileHeader.NumberOfSymbols > 0 {
- // Get COFF string table, which is located at the end of the COFF symbol table.
- sr.Seek(int64(f.FileHeader.PointerToSymbolTable+COFFSymbolSize*f.FileHeader.NumberOfSymbols), os.SEEK_SET)
- var l uint32
- if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
- return nil, err
- }
- ss = make([]byte, l)
- if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+COFFSymbolSize*f.FileHeader.NumberOfSymbols)); err != nil {
- return nil, err
- }
+ var err error
- // Process COFF symbol table.
- sr.Seek(int64(f.FileHeader.PointerToSymbolTable), os.SEEK_SET)
- aux := uint8(0)
- for i := 0; i < int(f.FileHeader.NumberOfSymbols); i++ {
- cs := new(COFFSymbol)
- if err := binary.Read(sr, binary.LittleEndian, cs); err != nil {
- return nil, err
- }
- if aux > 0 {
- aux--
- continue
- }
- var name string
- if cs.Name[0] == 0 && cs.Name[1] == 0 && cs.Name[2] == 0 && cs.Name[3] == 0 {
- si := int(binary.LittleEndian.Uint32(cs.Name[4:]))
- name, _ = getString(ss, si)
- } else {
- name = cstring(cs.Name[:])
- }
- aux = cs.NumberOfAuxSymbols
- s := &Symbol{
- Name: name,
- Value: cs.Value,
- SectionNumber: cs.SectionNumber,
- Type: cs.Type,
- StorageClass: cs.StorageClass,
- }
- f.Symbols = append(f.Symbols, s)
- }
+ // 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)
+ sr.Seek(base, io.SeekStart)
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
return nil, err
}
@@ -235,12 +141,9 @@ func NewFile(r io.ReaderAt) (*File, error) {
if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
return nil, err
}
- var name string
- if sh.Name[0] == '\x2F' {
- si, _ := strconv.Atoi(cstring(sh.Name[1:]))
- name, _ = getString(ss, si)
- } else {
- name = cstring(sh.Name[0:])
+ name, err := sh.fullName(f.StringTable)
+ if err != nil {
+ return nil, err
}
s := new(Section)
s.SectionHeader = SectionHeader{
@@ -259,14 +162,15 @@ func NewFile(r io.ReaderAt) (*File, error) {
s.ReaderAt = s.sr
f.Sections[i] = s
}
- return f, nil
-}
-
-func cstring(b []byte) string {
- var i int
- for i = 0; i < len(b) && b[i] != 0; i++ {
+ 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 string(b[0:i])
+
+ return f, nil
}
// getString extracts a string from symbol string table.
@@ -320,6 +224,18 @@ func (f *File) DWARF() (*dwarf.Data, error) {
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.
@@ -347,6 +263,12 @@ func (f *File) ImportedSymbols() ([]string, error) {
}
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 {
@@ -395,3 +317,12 @@ func (f *File) ImportedLibraries() ([]string, error) {
// 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"
+}
diff --git a/src/debug/pe/pe.go b/src/debug/pe/pe.go
index 6af40e2c78..8050d59c70 100644
--- a/src/debug/pe/pe.go
+++ b/src/debug/pe/pe.go
@@ -86,30 +86,6 @@ type OptionalHeader64 struct {
DataDirectory [16]DataDirectory
}
-type SectionHeader32 struct {
- Name [8]uint8
- VirtualSize uint32
- VirtualAddress uint32
- SizeOfRawData uint32
- PointerToRawData uint32
- PointerToRelocations uint32
- PointerToLineNumbers uint32
- NumberOfRelocations uint16
- NumberOfLineNumbers uint16
- Characteristics uint32
-}
-
-const COFFSymbolSize = 18
-
-type COFFSymbol struct {
- Name [8]uint8
- Value uint32
- SectionNumber int16
- Type uint16
- StorageClass uint8
- NumberOfAuxSymbols uint8
-}
-
const (
IMAGE_FILE_MACHINE_UNKNOWN = 0x0
IMAGE_FILE_MACHINE_AM33 = 0x1d3
diff --git a/src/debug/pe/section.go b/src/debug/pe/section.go
new file mode 100644
index 0000000000..5d881577d3
--- /dev/null
+++ b/src/debug/pe/section.go
@@ -0,0 +1,111 @@
+// 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"
+ "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), io.SeekStart)
+ 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)
+}
diff --git a/src/debug/pe/string.go b/src/debug/pe/string.go
new file mode 100644
index 0000000000..e00bd97dd4
--- /dev/null
+++ b/src/debug/pe/string.go
@@ -0,0 +1,63 @@
+// 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"
+)
+
+// 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.
+ offset := fh.PointerToSymbolTable + COFFSymbolSize*fh.NumberOfSymbols
+ _, err := r.Seek(int64(offset), io.SeekStart)
+ 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
+}
diff --git a/src/debug/pe/symbol.go b/src/debug/pe/symbol.go
new file mode 100644
index 0000000000..3cf5a101e7
--- /dev/null
+++ b/src/debug/pe/symbol.go
@@ -0,0 +1,95 @@
+// 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"
+)
+
+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), io.SeekStart)
+ 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
+}