| // 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 ( | |
| "bytes" | |
| "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 { | |
| i := bytes.IndexByte(b, 0) | |
| if i == -1 { | |
| i = len(b) | |
| } | |
| 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), 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 | |
| } |