]> Cypherpunks repositories - gostls13.git/commitdiff
debug/elf: transparently decompress compressed sections
authorAustin Clements <austin@google.com>
Wed, 2 Dec 2015 17:20:29 +0000 (12:20 -0500)
committerAustin Clements <austin@google.com>
Thu, 3 Dec 2015 20:53:11 +0000 (20:53 +0000)
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>

src/debug/elf/elf.go
src/debug/elf/file.go
src/debug/elf/file_test.go
src/debug/elf/reader.go [new file with mode: 0644]
src/debug/elf/testdata/compressed-32.obj [new file with mode: 0644]
src/debug/elf/testdata/compressed-64.obj [new file with mode: 0644]

index 1c9dd7bc4ad8744e4c5ee2020ae3fba0b1c9a2c6..0c79b7a02fab42a0ad7415fd857141fb0ccae4ef 100644 (file)
@@ -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.
  */
index a42bde94f8f3a8a35fc17976eb6886c1ed30dac6..199aa4ec576eae02aa2aa49f38de59fc03e0c90e 100644 (file)
@@ -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
        }
 
index 6864b6df79f8b10b94272e1356b4684bf369edc9..5c0df0f1e9eb937b72761780508cd0edfd9efe6b 100644 (file)
@@ -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" {
diff --git a/src/debug/elf/reader.go b/src/debug/elf/reader.go
new file mode 100644 (file)
index 0000000..17b5716
--- /dev/null
@@ -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
+}
diff --git a/src/debug/elf/testdata/compressed-32.obj b/src/debug/elf/testdata/compressed-32.obj
new file mode 100644 (file)
index 0000000..2bfdb44
Binary files /dev/null and b/src/debug/elf/testdata/compressed-32.obj differ
diff --git a/src/debug/elf/testdata/compressed-64.obj b/src/debug/elf/testdata/compressed-64.obj
new file mode 100644 (file)
index 0000000..ffae56a
Binary files /dev/null and b/src/debug/elf/testdata/compressed-64.obj differ