mirror of https://github.com/golang/go.git
debug/elf: transparently decompress compressed sections
This adds support for compressed ELF sections. This compression is treated as a framing issue and hence the package APIs all transparently decompress compressed sections. This requires some subtlety for (*Section).Open, which returns an io.ReadSeeker: since the decompressed data comes from an io.Reader, this commit introduces a Reader-to-ReadSeeker adapter that is efficient for common uses of Seek and does what it can otherwise. Fixes #11773. Change-Id: Ic0cb7255a85cadf4c1d15fb563d5a2e89dbd3c36 Reviewed-on: https://go-review.googlesource.com/17341 Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Austin Clements <austin@google.com>
This commit is contained in:
parent
e1544d3bb6
commit
7648387705
|
|
@ -411,6 +411,7 @@ const (
|
|||
SHF_OS_NONCONFORMING SectionFlag = 0x100 /* OS-specific processing required. */
|
||||
SHF_GROUP SectionFlag = 0x200 /* Member of section group. */
|
||||
SHF_TLS SectionFlag = 0x400 /* Section contains TLS data. */
|
||||
SHF_COMPRESSED SectionFlag = 0x800 /* Section is compressed. */
|
||||
SHF_MASKOS SectionFlag = 0x0ff00000 /* OS-specific semantics. */
|
||||
SHF_MASKPROC SectionFlag = 0xf0000000 /* Processor-specific semantics. */
|
||||
)
|
||||
|
|
@ -426,11 +427,34 @@ var shfStrings = []intName{
|
|||
{0x100, "SHF_OS_NONCONFORMING"},
|
||||
{0x200, "SHF_GROUP"},
|
||||
{0x400, "SHF_TLS"},
|
||||
{0x800, "SHF_COMPRESSED"},
|
||||
}
|
||||
|
||||
func (i SectionFlag) String() string { return flagName(uint32(i), shfStrings, false) }
|
||||
func (i SectionFlag) GoString() string { return flagName(uint32(i), shfStrings, true) }
|
||||
|
||||
// Section compression type.
|
||||
type CompressionType int
|
||||
|
||||
const (
|
||||
COMPRESS_ZLIB CompressionType = 1 /* ZLIB compression. */
|
||||
COMPRESS_LOOS CompressionType = 0x60000000 /* First OS-specific. */
|
||||
COMPRESS_HIOS CompressionType = 0x6fffffff /* Last OS-specific. */
|
||||
COMPRESS_LOPROC CompressionType = 0x70000000 /* First processor-specific type. */
|
||||
COMPRESS_HIPROC CompressionType = 0x7fffffff /* Last processor-specific type. */
|
||||
)
|
||||
|
||||
var compressionStrings = []intName{
|
||||
{0, "COMPRESS_ZLIB"},
|
||||
{0x60000000, "COMPRESS_LOOS"},
|
||||
{0x6fffffff, "COMPRESS_HIOS"},
|
||||
{0x70000000, "COMPRESS_LOPROC"},
|
||||
{0x7fffffff, "COMPRESS_HIPROC"},
|
||||
}
|
||||
|
||||
func (i CompressionType) String() string { return stringName(uint32(i), compressionStrings, false) }
|
||||
func (i CompressionType) GoString() string { return stringName(uint32(i), compressionStrings, true) }
|
||||
|
||||
// Prog.Type
|
||||
type ProgType int
|
||||
|
||||
|
|
@ -1878,6 +1902,13 @@ type Dyn32 struct {
|
|||
Val uint32 /* Integer/Address value. */
|
||||
}
|
||||
|
||||
// ELF32 Compression header.
|
||||
type Chdr32 struct {
|
||||
Type uint32
|
||||
Size uint32
|
||||
Addralign uint32
|
||||
}
|
||||
|
||||
/*
|
||||
* Relocation entries.
|
||||
*/
|
||||
|
|
@ -1972,6 +2003,14 @@ type Dyn64 struct {
|
|||
Val uint64 /* Integer/address value */
|
||||
}
|
||||
|
||||
// ELF64 Compression header.
|
||||
type Chdr64 struct {
|
||||
Type uint32
|
||||
Reserved uint32
|
||||
Size uint64
|
||||
Addralign uint64
|
||||
}
|
||||
|
||||
/*
|
||||
* Relocation entries.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -58,6 +58,12 @@ type SectionHeader struct {
|
|||
Info uint32
|
||||
Addralign uint64
|
||||
Entsize uint64
|
||||
|
||||
// FileSize is the size of this section in the file in bytes.
|
||||
// If a section is compressed, FileSize is the size of the
|
||||
// compressed data, while Size (above) is the size of the
|
||||
// uncompressed data.
|
||||
FileSize uint64
|
||||
}
|
||||
|
||||
// A Section represents a single section in an ELF file.
|
||||
|
|
@ -70,17 +76,23 @@ type Section struct {
|
|||
// If a client wants Read and Seek it must use
|
||||
// Open() to avoid fighting over the seek offset
|
||||
// with other clients.
|
||||
//
|
||||
// ReaderAt may be nil if the section is not easily available
|
||||
// in a random-access form. For example, a compressed section
|
||||
// may have a nil ReaderAt.
|
||||
io.ReaderAt
|
||||
sr *io.SectionReader
|
||||
|
||||
compressionType CompressionType
|
||||
compressionOffset int64
|
||||
}
|
||||
|
||||
// Data reads and returns the contents of the ELF section.
|
||||
// Even if the section is stored compressed in the ELF file,
|
||||
// Data returns uncompressed data.
|
||||
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
|
||||
}
|
||||
dat := make([]byte, s.Size)
|
||||
n, err := io.ReadFull(s.Open(), dat)
|
||||
return dat[0:n], err
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +106,24 @@ func (f *File) stringTable(link uint32) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Open returns a new ReadSeeker reading the ELF section.
|
||||
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
|
||||
// Even if the section is stored compressed in the ELF file,
|
||||
// the ReadSeeker reads uncompressed data.
|
||||
func (s *Section) Open() io.ReadSeeker {
|
||||
if s.Flags&SHF_COMPRESSED == 0 {
|
||||
return io.NewSectionReader(s.sr, 0, 1<<63-1)
|
||||
}
|
||||
if s.compressionType == COMPRESS_ZLIB {
|
||||
return &readSeekerFromReader{
|
||||
reset: func() (io.Reader, error) {
|
||||
fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)
|
||||
return zlib.NewReader(fr)
|
||||
},
|
||||
size: int64(s.Size),
|
||||
}
|
||||
}
|
||||
err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType}
|
||||
return errorReader{err}
|
||||
}
|
||||
|
||||
// A ProgHeader represents a single ELF program header.
|
||||
type ProgHeader struct {
|
||||
|
|
@ -344,7 +373,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||
Flags: SectionFlag(sh.Flags),
|
||||
Addr: uint64(sh.Addr),
|
||||
Offset: uint64(sh.Off),
|
||||
Size: uint64(sh.Size),
|
||||
FileSize: uint64(sh.Size),
|
||||
Link: uint32(sh.Link),
|
||||
Info: uint32(sh.Info),
|
||||
Addralign: uint64(sh.Addralign),
|
||||
|
|
@ -360,7 +389,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||
Type: SectionType(sh.Type),
|
||||
Flags: SectionFlag(sh.Flags),
|
||||
Offset: uint64(sh.Off),
|
||||
Size: uint64(sh.Size),
|
||||
FileSize: uint64(sh.Size),
|
||||
Addr: uint64(sh.Addr),
|
||||
Link: uint32(sh.Link),
|
||||
Info: uint32(sh.Info),
|
||||
|
|
@ -368,8 +397,35 @@ func NewFile(r io.ReaderAt) (*File, error) {
|
|||
Entsize: uint64(sh.Entsize),
|
||||
}
|
||||
}
|
||||
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
|
||||
s.ReaderAt = s.sr
|
||||
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
|
||||
|
||||
if s.Flags&SHF_COMPRESSED == 0 {
|
||||
s.ReaderAt = s.sr
|
||||
s.Size = s.FileSize
|
||||
} else {
|
||||
// Read the compression header.
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
ch := new(Chdr32)
|
||||
if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.compressionType = CompressionType(ch.Type)
|
||||
s.Size = uint64(ch.Size)
|
||||
s.Addralign = uint64(ch.Addralign)
|
||||
s.compressionOffset = int64(binary.Size(ch))
|
||||
case ELFCLASS64:
|
||||
ch := new(Chdr64)
|
||||
if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.compressionType = CompressionType(ch.Type)
|
||||
s.Size = ch.Size
|
||||
s.Addralign = ch.Addralign
|
||||
s.compressionOffset = int64(binary.Size(ch))
|
||||
}
|
||||
}
|
||||
|
||||
f.Sections[i] = s
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
|
|
@ -31,36 +32,36 @@ var fileTests = []fileTest{
|
|||
"testdata/gcc-386-freebsd-exec",
|
||||
FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc},
|
||||
[]SectionHeader{
|
||||
{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
|
||||
{".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
|
||||
{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
|
||||
{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
|
||||
{".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
|
||||
{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
|
||||
{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
|
||||
{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
|
||||
{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
|
||||
{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
|
||||
{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
|
||||
{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
|
||||
{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
|
||||
{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
|
||||
{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
|
||||
{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
|
||||
{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
|
||||
{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
|
||||
{".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
|
||||
{".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
|
||||
{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
|
||||
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
|
||||
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
|
||||
{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0, 0x15},
|
||||
{".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4, 0x90},
|
||||
{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10, 0x110},
|
||||
{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0, 0xbb},
|
||||
{".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8, 0x20},
|
||||
{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
|
||||
{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4, 0x50},
|
||||
{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0, 0x180},
|
||||
{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
|
||||
{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0, 0xa3},
|
||||
{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
|
||||
{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
|
||||
{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8, 0x98},
|
||||
{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
|
||||
{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
|
||||
{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
|
||||
{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4, 0x1c},
|
||||
{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
|
||||
{".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0, 0x12d},
|
||||
{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
|
||||
{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
|
||||
{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0, 0x11d},
|
||||
{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0, 0x41},
|
||||
{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0, 0x35},
|
||||
{".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0, 0x30},
|
||||
{".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
|
||||
{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0, 0xf8},
|
||||
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10, 0x4b0},
|
||||
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0, 0x206},
|
||||
},
|
||||
[]ProgHeader{
|
||||
{PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
|
||||
|
|
@ -75,43 +76,43 @@ var fileTests = []fileTest{
|
|||
"testdata/gcc-amd64-linux-exec",
|
||||
FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0},
|
||||
[]SectionHeader{
|
||||
{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
|
||||
{".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
|
||||
{".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
|
||||
{".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
|
||||
{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
|
||||
{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
|
||||
{".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
|
||||
{".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
|
||||
{".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
|
||||
{".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
|
||||
{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
|
||||
{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
|
||||
{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
|
||||
{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
|
||||
{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
|
||||
{".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
|
||||
{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
|
||||
{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
|
||||
{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
|
||||
{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
|
||||
{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
|
||||
{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
|
||||
{".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
|
||||
{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
|
||||
{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
|
||||
{".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
|
||||
{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
|
||||
{".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
|
||||
{".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
|
||||
{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
|
||||
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
|
||||
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
|
||||
{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0, 0x1c},
|
||||
{".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
|
||||
{".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4, 0x24},
|
||||
{".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0, 0x1c},
|
||||
{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18, 0x60},
|
||||
{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0, 0x3d},
|
||||
{".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2, 0x8},
|
||||
{".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0, 0x20},
|
||||
{".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18, 0x18},
|
||||
{".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18, 0x30},
|
||||
{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0, 0x18},
|
||||
{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10, 0x30},
|
||||
{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0, 0x1b4},
|
||||
{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0, 0xe},
|
||||
{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
|
||||
{".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0, 0x24},
|
||||
{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0, 0xa4},
|
||||
{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
|
||||
{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
|
||||
{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0, 0x8},
|
||||
{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10, 0x1a0},
|
||||
{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8},
|
||||
{".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8, 0x28},
|
||||
{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0, 0x18},
|
||||
{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
|
||||
{".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0, 0x126},
|
||||
{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
|
||||
{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0, 0x25},
|
||||
{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0, 0x1a7},
|
||||
{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0, 0x6f},
|
||||
{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0, 0x13f},
|
||||
{".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1, 0xb1},
|
||||
{".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
|
||||
{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0, 0x149},
|
||||
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18, 0x6f0},
|
||||
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0, 0x1fc},
|
||||
},
|
||||
[]ProgHeader{
|
||||
{PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
|
||||
|
|
@ -150,6 +151,64 @@ var fileTests = []fileTest{
|
|||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"testdata/compressed-32.obj",
|
||||
FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_386, 0x0},
|
||||
[]SectionHeader{
|
||||
{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x34, 0x17, 0x0, 0x0, 0x1, 0x0, 0x17},
|
||||
{".rel.text", SHT_REL, SHF_INFO_LINK, 0x0, 0x3dc, 0x10, 0x13, 0x1, 0x4, 0x8, 0x10},
|
||||
{".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
|
||||
{".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
|
||||
{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x4b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
|
||||
{".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x58, 0xb4, 0x0, 0x0, 0x1, 0x0, 0x84},
|
||||
{".rel.debug_info", SHT_REL, SHF_INFO_LINK, 0x0, 0x3ec, 0xa0, 0x13, 0x6, 0x4, 0x8, 0xa0},
|
||||
{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xdc, 0x5a, 0x0, 0x0, 0x1, 0x0, 0x5a},
|
||||
{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x136, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
|
||||
{".rel.debug_aranges", SHT_REL, SHF_INFO_LINK, 0x0, 0x48c, 0x10, 0x13, 0x9, 0x4, 0x8, 0x10},
|
||||
{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x156, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
|
||||
{".rel.debug_line", SHT_REL, SHF_INFO_LINK, 0x0, 0x49c, 0x8, 0x13, 0xb, 0x4, 0x8, 0x8},
|
||||
{".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1b2, 0x10f, 0x0, 0x0, 0x1, 0x1, 0xb3},
|
||||
{".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x265, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
|
||||
{".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x28f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
|
||||
{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x290, 0x38, 0x0, 0x0, 0x4, 0x0, 0x38},
|
||||
{".rel.eh_frame", SHT_REL, SHF_INFO_LINK, 0x0, 0x4a4, 0x8, 0x13, 0x10, 0x4, 0x8, 0x8},
|
||||
{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x4ac, 0xab, 0x0, 0x0, 0x1, 0x0, 0xab},
|
||||
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2c8, 0x100, 0x14, 0xe, 0x4, 0x10, 0x100},
|
||||
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x3c8, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
|
||||
},
|
||||
[]ProgHeader{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"testdata/compressed-64.obj",
|
||||
FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_X86_64, 0x0},
|
||||
[]SectionHeader{
|
||||
{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x40, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
|
||||
{".rela.text", SHT_RELA, SHF_INFO_LINK, 0x0, 0x488, 0x30, 0x13, 0x1, 0x8, 0x18, 0x30},
|
||||
{".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
|
||||
{".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
|
||||
{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x5b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
|
||||
{".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x68, 0xba, 0x0, 0x0, 0x1, 0x0, 0x72},
|
||||
{".rela.debug_info", SHT_RELA, SHF_INFO_LINK, 0x0, 0x4b8, 0x1c8, 0x13, 0x6, 0x8, 0x18, 0x1c8},
|
||||
{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xda, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
|
||||
{".debug_aranges", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x136, 0x30, 0x0, 0x0, 0x1, 0x0, 0x2f},
|
||||
{".rela.debug_aranges", SHT_RELA, SHF_INFO_LINK, 0x0, 0x680, 0x30, 0x13, 0x9, 0x8, 0x18, 0x30},
|
||||
{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x165, 0x60, 0x0, 0x0, 0x1, 0x0, 0x60},
|
||||
{".rela.debug_line", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6b0, 0x18, 0x13, 0xb, 0x8, 0x18, 0x18},
|
||||
{".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1c5, 0x104, 0x0, 0x0, 0x1, 0x1, 0xc3},
|
||||
{".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x288, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
|
||||
{".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x2b2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
|
||||
{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x2b8, 0x38, 0x0, 0x0, 0x8, 0x0, 0x38},
|
||||
{".rela.eh_frame", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6c8, 0x18, 0x13, 0x10, 0x8, 0x18, 0x18},
|
||||
{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x6e0, 0xb0, 0x0, 0x0, 0x1, 0x0, 0xb0},
|
||||
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2f0, 0x180, 0x14, 0xe, 0x8, 0x18, 0x180},
|
||||
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x470, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
|
||||
},
|
||||
[]ProgHeader{},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
func TestOpen(t *testing.T) {
|
||||
|
|
@ -542,6 +601,91 @@ func TestCompressedDWARF(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCompressedSection(t *testing.T) {
|
||||
// Test files built with gcc -g -S hello.c and assembled with
|
||||
// --compress-debug-sections=zlib-gabi.
|
||||
f, err := Open("testdata/compressed-64.obj")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sec := f.Section(".debug_info")
|
||||
wantData := []byte{
|
||||
182, 0, 0, 0, 4, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
|
||||
0, 0, 0, 0, 2, 1, 8, 0, 0, 0, 0, 2, 2, 7, 0, 0,
|
||||
0, 0, 2, 4, 7, 0, 0, 0, 0, 2, 1, 6, 0, 0, 0, 0,
|
||||
2, 2, 5, 0, 0, 0, 0, 3, 4, 5, 105, 110, 116, 0, 2, 8,
|
||||
5, 0, 0, 0, 0, 2, 8, 7, 0, 0, 0, 0, 4, 8, 114, 0,
|
||||
0, 0, 2, 1, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 156, 179, 0, 0, 0, 6, 0, 0, 0, 0, 1, 4, 87, 0, 0,
|
||||
0, 2, 145, 108, 6, 0, 0, 0, 0, 1, 4, 179, 0, 0, 0, 2,
|
||||
145, 96, 0, 4, 8, 108, 0, 0, 0, 0,
|
||||
}
|
||||
|
||||
// Test Data method.
|
||||
b, err := sec.Data()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(wantData, b) {
|
||||
t.Fatalf("want data %x, got %x", wantData, b)
|
||||
}
|
||||
|
||||
// Test Open method and seeking.
|
||||
buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
|
||||
sf := sec.Open()
|
||||
if got, err := sf.Seek(0, 2); got != int64(len(b)) || err != nil {
|
||||
t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
|
||||
}
|
||||
if n, err := sf.Read(buf); n != 0 || err != io.EOF {
|
||||
t.Fatalf("want EOF with 0 bytes, got %v with %d bytes", err, n)
|
||||
}
|
||||
pos := int64(len(buf))
|
||||
for count < len(buf) {
|
||||
// Construct random seek arguments.
|
||||
whence := rand.Intn(3)
|
||||
target := rand.Int63n(int64(len(buf)))
|
||||
var offset int64
|
||||
switch whence {
|
||||
case 0:
|
||||
offset = target
|
||||
case 1:
|
||||
offset = target - pos
|
||||
case 2:
|
||||
offset = target - int64(len(buf))
|
||||
}
|
||||
pos, err = sf.Seek(offset, whence)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pos != target {
|
||||
t.Fatalf("want position %d, got %d", target, pos)
|
||||
}
|
||||
|
||||
// Read data from the new position.
|
||||
end := pos + 16
|
||||
if end > int64(len(buf)) {
|
||||
end = int64(len(buf))
|
||||
}
|
||||
n, err := sf.Read(buf[pos:end])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if !have[pos] {
|
||||
have[pos] = true
|
||||
count++
|
||||
}
|
||||
pos++
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(wantData, buf) {
|
||||
t.Fatalf("want data %x, got %x", wantData, buf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoSectionOverlaps(t *testing.T) {
|
||||
// Ensure 6l outputs sections without overlaps.
|
||||
if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright 2015 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 elf
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// errorReader returns error from all operations.
|
||||
type errorReader struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (r errorReader) Read(p []byte) (n int, err error) {
|
||||
return 0, r.error
|
||||
}
|
||||
|
||||
func (r errorReader) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
return 0, r.error
|
||||
}
|
||||
|
||||
func (r errorReader) Seek(offset int64, whence int) (int64, error) {
|
||||
return 0, r.error
|
||||
}
|
||||
|
||||
func (r errorReader) Close() error {
|
||||
return r.error
|
||||
}
|
||||
|
||||
// readSeekerFromReader converts an io.Reader into an io.ReadSeeker.
|
||||
// In general Seek may not be efficient, but it is optimized for
|
||||
// common cases such as seeking to the end to find the length of the
|
||||
// data.
|
||||
type readSeekerFromReader struct {
|
||||
reset func() (io.Reader, error)
|
||||
r io.Reader
|
||||
size int64
|
||||
offset int64
|
||||
}
|
||||
|
||||
func (r *readSeekerFromReader) start() {
|
||||
x, err := r.reset()
|
||||
if err != nil {
|
||||
r.r = errorReader{err}
|
||||
} else {
|
||||
r.r = x
|
||||
}
|
||||
r.offset = 0
|
||||
}
|
||||
|
||||
func (r *readSeekerFromReader) Read(p []byte) (n int, err error) {
|
||||
if r.r == nil {
|
||||
r.start()
|
||||
}
|
||||
n, err = r.r.Read(p)
|
||||
r.offset += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) {
|
||||
var newOffset int64
|
||||
switch whence {
|
||||
case 0:
|
||||
newOffset = offset
|
||||
case 1:
|
||||
newOffset = r.offset + offset
|
||||
case 2:
|
||||
newOffset = r.size + offset
|
||||
default:
|
||||
return 0, os.ErrInvalid
|
||||
}
|
||||
|
||||
switch {
|
||||
case newOffset == r.offset:
|
||||
return newOffset, nil
|
||||
|
||||
case newOffset < 0, newOffset > r.size:
|
||||
return 0, os.ErrInvalid
|
||||
|
||||
case newOffset == 0:
|
||||
r.r = nil
|
||||
|
||||
case newOffset == r.size:
|
||||
r.r = errorReader{io.EOF}
|
||||
|
||||
default:
|
||||
if newOffset < r.offset {
|
||||
// Restart at the beginning.
|
||||
r.start()
|
||||
}
|
||||
// Read until we reach offset.
|
||||
var buf [512]byte
|
||||
for r.offset < newOffset {
|
||||
b := buf[:]
|
||||
if newOffset-r.offset < int64(len(buf)) {
|
||||
b = buf[:newOffset-r.offset]
|
||||
}
|
||||
if _, err := r.Read(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
r.offset = newOffset
|
||||
return r.offset, nil
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue