diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go index bfc4cf8a18..f7b74e92a4 100644 --- a/src/debug/pe/file.go +++ b/src/debug/pe/file.go @@ -21,6 +21,7 @@ type File struct { OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64 Sections []*Section Symbols []*Symbol + StringTable StringTable closer io.Closer } @@ -133,6 +134,14 @@ func NewFile(r io.ReaderAt) (*File, error) { return nil, errors.New("Invalid PE File Format.") } + var err error + + // Read string table. + f.StringTable, err = readStringTable(&f.FileHeader, sr) + if err != nil { + return nil, err + } + var ss []byte if f.FileHeader.NumberOfSymbols > 0 { // Get COFF string table, which is located at the end of the COFF symbol table. @@ -237,13 +246,6 @@ func NewFile(r io.ReaderAt) (*File, error) { return f, nil } -func cstring(b []byte) string { - var i int - for i = 0; i < len(b) && b[i] != 0; i++ { - } - return string(b[0:i]) -} - // getString extracts a string from symbol string table. func getString(section []byte, start int) (string, bool) { if start < 0 || start >= len(section) { diff --git a/src/debug/pe/string.go b/src/debug/pe/string.go new file mode 100644 index 0000000000..f0928d09c5 --- /dev/null +++ b/src/debug/pe/string.go @@ -0,0 +1,64 @@ +// 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" +) + +// TODO(brainman): return error from cstring and see what errors we get and what to do about it + +// cstring converts ASCII byte sequence b to string. It stops once it finds 0. +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 +}