diff options
author | Ian Lance Taylor <iant@google.com> | 2016-02-03 21:58:02 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-02-03 21:58:02 +0000 |
commit | f98dd1a338867a408f7c72d73fbad7fe7fc93e3a (patch) | |
tree | 2f8da9862a9c1fe0df138917f997b03439c02773 /libgo/go/debug | |
parent | b081ed4efc144da0c45a6484aebfd10e0eb9fda3 (diff) | |
download | gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.zip gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.gz gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.bz2 |
libgo: Update to go1.6rc1.
Reviewed-on: https://go-review.googlesource.com/19200
From-SVN: r233110
Diffstat (limited to 'libgo/go/debug')
20 files changed, 969 insertions, 133 deletions
diff --git a/libgo/go/debug/dwarf/class_string.go b/libgo/go/debug/dwarf/class_string.go index 0b1206b..d57d9f7 100644 --- a/libgo/go/debug/dwarf/class_string.go +++ b/libgo/go/debug/dwarf/class_string.go @@ -4,14 +4,13 @@ package dwarf import "fmt" -const _Class_name = "ClassAddressClassBlockClassConstantClassExprLocClassFlagClassLinePtrClassLocListPtrClassMacPtrClassRangeListPtrClassReferenceClassReferenceSigClassStringClassReferenceAltClassStringAlt" +const _Class_name = "ClassUnknownClassAddressClassBlockClassConstantClassExprLocClassFlagClassLinePtrClassLocListPtrClassMacPtrClassRangeListPtrClassReferenceClassReferenceSigClassStringClassReferenceAltClassStringAlt" -var _Class_index = [...]uint8{0, 12, 22, 35, 47, 56, 68, 83, 94, 111, 125, 142, 153, 170, 184} +var _Class_index = [...]uint8{0, 12, 24, 34, 47, 59, 68, 80, 95, 106, 123, 137, 154, 165, 182, 196} func (i Class) String() string { - i -= 1 if i < 0 || i+1 >= Class(len(_Class_index)) { - return fmt.Sprintf("Class(%d)", i+1) + return fmt.Sprintf("Class(%d)", i) } return _Class_name[_Class_index[i]:_Class_index[i+1]] } diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go index d607e5b..5ca8667 100644 --- a/libgo/go/debug/dwarf/entry.go +++ b/libgo/go/debug/dwarf/entry.go @@ -193,8 +193,7 @@ func formToClass(form format, attr Attr, vers int, b *buf) Class { if class, ok := attrPtrClass[attr]; ok { return class } - b.error("cannot determine class of unknown attribute with formSecOffset") - return 0 + return ClassUnknown case formExprloc: return ClassExprLoc @@ -235,6 +234,9 @@ type Entry struct { // loclistptr int64 ClassLocListPtr // macptr int64 ClassMacPtr // rangelistptr int64 ClassRangeListPtr +// +// For unrecognized or vendor-defined attributes, Class may be +// ClassUnknown. type Field struct { Attr Attr Val interface{} @@ -258,9 +260,12 @@ type Field struct { type Class int const ( + // ClassUnknown represents values of unknown DWARF class. + ClassUnknown Class = iota + // ClassAddress represents values of type uint64 that are // addresses on the target machine. - ClassAddress Class = 1 + iota + ClassAddress // ClassBlock represents values of type []byte whose // interpretation depends on the attribute. diff --git a/libgo/go/debug/dwarf/entry_test.go b/libgo/go/debug/dwarf/entry_test.go new file mode 100644 index 0000000..8bd2d2a --- /dev/null +++ b/libgo/go/debug/dwarf/entry_test.go @@ -0,0 +1,36 @@ +// Copyright 2009 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 dwarf_test + +import ( + . "debug/dwarf" + "testing" +) + +func TestSplit(t *testing.T) { + // debug/dwarf doesn't (currently) support split DWARF, but + // the attributes that pointed to the split DWARF used to + // cause loading the DWARF data to fail entirely (issue + // #12592). Test that we can at least read the DWARF data. + d := elfData(t, "testdata/split.elf") + r := d.Reader() + e, err := r.Next() + if err != nil { + t.Fatal(err) + } + if e.Tag != TagCompileUnit { + t.Fatalf("bad tag: have %s, want %s", e.Tag, TagCompileUnit) + } + // Check that we were able to parse the unknown section offset + // field, even if we can't figure out its DWARF class. + const AttrGNUAddrBase Attr = 0x2133 + f := e.AttrField(AttrGNUAddrBase) + if _, ok := f.Val.(int64); !ok { + t.Fatalf("bad attribute value type: have %T, want int64", f.Val) + } + if f.Class != ClassUnknown { + t.Fatalf("bad class: have %s, want %s", f.Class, ClassUnknown) + } +} diff --git a/libgo/go/debug/dwarf/testdata/cycle.c b/libgo/go/debug/dwarf/testdata/cycle.c new file mode 100644 index 0000000..a0b53df --- /dev/null +++ b/libgo/go/debug/dwarf/testdata/cycle.c @@ -0,0 +1,7 @@ +typedef struct aaa *AAA; +typedef AAA BBB; +struct aaa { BBB val; }; + +AAA x(void) { + return (AAA)0; +} diff --git a/libgo/go/debug/dwarf/testdata/cycle.elf b/libgo/go/debug/dwarf/testdata/cycle.elf Binary files differnew file mode 100644 index 0000000..e0b66ca --- /dev/null +++ b/libgo/go/debug/dwarf/testdata/cycle.elf diff --git a/libgo/go/debug/dwarf/testdata/split.c b/libgo/go/debug/dwarf/testdata/split.c new file mode 100644 index 0000000..0ef3427 --- /dev/null +++ b/libgo/go/debug/dwarf/testdata/split.c @@ -0,0 +1,5 @@ +// gcc -gsplit-dwarf split.c -o split.elf + +int main() +{ +} diff --git a/libgo/go/debug/dwarf/testdata/split.elf b/libgo/go/debug/dwarf/testdata/split.elf Binary files differnew file mode 100644 index 0000000..99ee2c2 --- /dev/null +++ b/libgo/go/debug/dwarf/testdata/split.elf diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go index a5daa1d..c76a472 100644 --- a/libgo/go/debug/dwarf/type.go +++ b/libgo/go/debug/dwarf/type.go @@ -275,12 +275,14 @@ type typeReader interface { // Type reads the type at off in the DWARF ``info'' section. func (d *Data) Type(off Offset) (Type, error) { - return d.readType("info", d.Reader(), off, d.typeCache) + return d.readType("info", d.Reader(), off, d.typeCache, nil) } -// readType reads a type from r at off of name using and updating a -// type cache. -func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) { +// readType reads a type from r at off of name. It adds types to the +// type cache, appends new typedef types to typedefs, and computes the +// sizes of types. Callers should pass nil for typedefs; this is used +// for internal recursion. +func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, typedefs *[]*TypedefType) (Type, error) { if t, ok := typeCache[off]; ok { return t, nil } @@ -294,9 +296,24 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off return nil, DecodeError{name, off, "no type at offset"} } + // If this is the root of the recursion, prepare to resolve + // typedef sizes once the recursion is done. This must be done + // after the type graph is constructed because it may need to + // resolve cycles in a different order than readType + // encounters them. + if typedefs == nil { + var typedefList []*TypedefType + defer func() { + for _, t := range typedefList { + t.Common().ByteSize = t.Type.Size() + } + }() + typedefs = &typedefList + } + // Parse type from Entry. // Must always set typeCache[off] before calling - // d.Type recursively, to handle circular types correctly. + // d.readType recursively, to handle circular types correctly. var typ Type nextDepth := 0 @@ -345,7 +362,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off var t Type switch toff := tval.(type) { case Offset: - if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil { + if t, err = d.readType(name, r.clone(), toff, typeCache, typedefs); err != nil { return nil } case uint64: @@ -674,7 +691,10 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off b = -1 switch t := typ.(type) { case *TypedefType: - b = t.Type.Size() + // Record that we need to resolve this + // type's size once the type graph is + // constructed. + *typedefs = append(*typedefs, t) case *PtrType: b = int64(addressSize) } diff --git a/libgo/go/debug/dwarf/type_test.go b/libgo/go/debug/dwarf/type_test.go index 2cb85e7..ad6308d 100644 --- a/libgo/go/debug/dwarf/type_test.go +++ b/libgo/go/debug/dwarf/type_test.go @@ -120,3 +120,37 @@ func testTypedefs(t *testing.T, d *Data, kind string) { } } } + +func TestTypedefCycle(t *testing.T) { + // See issue #13039: reading a typedef cycle starting from a + // different place than the size needed to be computed from + // used to crash. + // + // cycle.elf built with GCC 4.8.4: + // gcc -g -c -o cycle.elf cycle.c + d := elfData(t, "testdata/cycle.elf") + r := d.Reader() + offsets := []Offset{} + for { + e, err := r.Next() + if err != nil { + t.Fatal("r.Next:", err) + } + if e == nil { + break + } + switch e.Tag { + case TagBaseType, TagTypedef, TagPointerType, TagStructType: + offsets = append(offsets, e.Offset) + } + } + + // Parse each type with a fresh type cache. + for _, offset := range offsets { + d := elfData(t, "testdata/cycle.elf") + _, err := d.Type(offset) + if err != nil { + t.Fatalf("d.Type(0x%x): %s", offset, err) + } + } +} diff --git a/libgo/go/debug/dwarf/typeunit.go b/libgo/go/debug/dwarf/typeunit.go index 9cfb4a8..0f4e07e 100644 --- a/libgo/go/debug/dwarf/typeunit.go +++ b/libgo/go/debug/dwarf/typeunit.go @@ -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)) + t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type), nil) if err != nil { return nil, err } diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go index c97ccaa..6086b54 100644 --- a/libgo/go/debug/elf/elf.go +++ b/libgo/go/debug/elf/elf.go @@ -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 @@ -1246,6 +1270,115 @@ var r386Strings = []intName{ func (i R_386) String() string { return stringName(uint32(i), r386Strings, false) } func (i R_386) GoString() string { return stringName(uint32(i), r386Strings, true) } +// Relocation types for MIPS. +type R_MIPS int + +const ( + R_MIPS_NONE R_MIPS = 0 + R_MIPS_16 R_MIPS = 1 + R_MIPS_32 R_MIPS = 2 + R_MIPS_REL32 R_MIPS = 3 + R_MIPS_26 R_MIPS = 4 + R_MIPS_HI16 R_MIPS = 5 /* high 16 bits of symbol value */ + R_MIPS_LO16 R_MIPS = 6 /* low 16 bits of symbol value */ + R_MIPS_GPREL16 R_MIPS = 7 /* GP-relative reference */ + R_MIPS_LITERAL R_MIPS = 8 /* Reference to literal section */ + R_MIPS_GOT16 R_MIPS = 9 /* Reference to global offset table */ + R_MIPS_PC16 R_MIPS = 10 /* 16 bit PC relative reference */ + R_MIPS_CALL16 R_MIPS = 11 /* 16 bit call thru glbl offset tbl */ + R_MIPS_GPREL32 R_MIPS = 12 + R_MIPS_SHIFT5 R_MIPS = 16 + R_MIPS_SHIFT6 R_MIPS = 17 + R_MIPS_64 R_MIPS = 18 + R_MIPS_GOT_DISP R_MIPS = 19 + R_MIPS_GOT_PAGE R_MIPS = 20 + R_MIPS_GOT_OFST R_MIPS = 21 + R_MIPS_GOT_HI16 R_MIPS = 22 + R_MIPS_GOT_LO16 R_MIPS = 23 + R_MIPS_SUB R_MIPS = 24 + R_MIPS_INSERT_A R_MIPS = 25 + R_MIPS_INSERT_B R_MIPS = 26 + R_MIPS_DELETE R_MIPS = 27 + R_MIPS_HIGHER R_MIPS = 28 + R_MIPS_HIGHEST R_MIPS = 29 + R_MIPS_CALL_HI16 R_MIPS = 30 + R_MIPS_CALL_LO16 R_MIPS = 31 + R_MIPS_SCN_DISP R_MIPS = 32 + R_MIPS_REL16 R_MIPS = 33 + R_MIPS_ADD_IMMEDIATE R_MIPS = 34 + R_MIPS_PJUMP R_MIPS = 35 + R_MIPS_RELGOT R_MIPS = 36 + R_MIPS_JALR R_MIPS = 37 + + R_MIPS_TLS_DTPMOD32 R_MIPS = 38 /* Module number 32 bit */ + R_MIPS_TLS_DTPREL32 R_MIPS = 39 /* Module-relative offset 32 bit */ + R_MIPS_TLS_DTPMOD64 R_MIPS = 40 /* Module number 64 bit */ + R_MIPS_TLS_DTPREL64 R_MIPS = 41 /* Module-relative offset 64 bit */ + R_MIPS_TLS_GD R_MIPS = 42 /* 16 bit GOT offset for GD */ + R_MIPS_TLS_LDM R_MIPS = 43 /* 16 bit GOT offset for LDM */ + R_MIPS_TLS_DTPREL_HI16 R_MIPS = 44 /* Module-relative offset, high 16 bits */ + R_MIPS_TLS_DTPREL_LO16 R_MIPS = 45 /* Module-relative offset, low 16 bits */ + R_MIPS_TLS_GOTTPREL R_MIPS = 46 /* 16 bit GOT offset for IE */ + R_MIPS_TLS_TPREL32 R_MIPS = 47 /* TP-relative offset, 32 bit */ + R_MIPS_TLS_TPREL64 R_MIPS = 48 /* TP-relative offset, 64 bit */ + R_MIPS_TLS_TPREL_HI16 R_MIPS = 49 /* TP-relative offset, high 16 bits */ + R_MIPS_TLS_TPREL_LO16 R_MIPS = 50 /* TP-relative offset, low 16 bits */ +) + +var rmipsStrings = []intName{ + {0, "R_MIPS_NONE"}, + {1, "R_MIPS_16"}, + {2, "R_MIPS_32"}, + {3, "R_MIPS_REL32"}, + {4, "R_MIPS_26"}, + {5, "R_MIPS_HI16"}, + {6, "R_MIPS_LO16"}, + {7, "R_MIPS_GPREL16"}, + {8, "R_MIPS_LITERAL"}, + {9, "R_MIPS_GOT16"}, + {10, "R_MIPS_PC16"}, + {11, "R_MIPS_CALL16"}, + {12, "R_MIPS_GPREL32"}, + {16, "R_MIPS_SHIFT5"}, + {17, "R_MIPS_SHIFT6"}, + {18, "R_MIPS_64"}, + {19, "R_MIPS_GOT_DISP"}, + {20, "R_MIPS_GOT_PAGE"}, + {21, "R_MIPS_GOT_OFST"}, + {22, "R_MIPS_GOT_HI16"}, + {23, "R_MIPS_GOT_LO16"}, + {24, "R_MIPS_SUB"}, + {25, "R_MIPS_INSERT_A"}, + {26, "R_MIPS_INSERT_B"}, + {27, "R_MIPS_DELETE"}, + {28, "R_MIPS_HIGHER"}, + {29, "R_MIPS_HIGHEST"}, + {30, "R_MIPS_CALL_HI16"}, + {31, "R_MIPS_CALL_LO16"}, + {32, "R_MIPS_SCN_DISP"}, + {33, "R_MIPS_REL16"}, + {34, "R_MIPS_ADD_IMMEDIATE"}, + {35, "R_MIPS_PJUMP"}, + {36, "R_MIPS_RELGOT"}, + {37, "R_MIPS_JALR"}, + {38, "R_MIPS_TLS_DTPMOD32"}, + {39, "R_MIPS_TLS_DTPREL32"}, + {40, "R_MIPS_TLS_DTPMOD64"}, + {41, "R_MIPS_TLS_DTPREL64"}, + {42, "R_MIPS_TLS_GD"}, + {43, "R_MIPS_TLS_LDM"}, + {44, "R_MIPS_TLS_DTPREL_HI16"}, + {45, "R_MIPS_TLS_DTPREL_LO16"}, + {46, "R_MIPS_TLS_GOTTPREL"}, + {47, "R_MIPS_TLS_TPREL32"}, + {48, "R_MIPS_TLS_TPREL64"}, + {49, "R_MIPS_TLS_TPREL_HI16"}, + {50, "R_MIPS_TLS_TPREL_LO16"}, +} + +func (i R_MIPS) String() string { return stringName(uint32(i), rmipsStrings, false) } +func (i R_MIPS) GoString() string { return stringName(uint32(i), rmipsStrings, true) } + // Relocation types for PowerPC. type R_PPC int @@ -1835,6 +1968,13 @@ type Dyn32 struct { Val uint32 /* Integer/Address value. */ } +// ELF32 Compression header. +type Chdr32 struct { + Type uint32 + Size uint32 + Addralign uint32 +} + /* * Relocation entries. */ @@ -1929,6 +2069,14 @@ type Dyn64 struct { Val uint64 /* Integer/address value */ } +// ELF64 Compression header. +type Chdr64 struct { + Type uint32 + _ uint32 /* Reserved. */ + Size uint64 + Addralign uint64 +} + /* * Relocation entries. */ diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go index 370c5e6..b028772 100644 --- a/libgo/go/debug/elf/file.go +++ b/libgo/go/debug/elf/file.go @@ -7,6 +7,7 @@ package elf import ( "bytes" + "compress/zlib" "debug/dwarf" "encoding/binary" "errors" @@ -57,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. @@ -69,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 } @@ -93,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 { @@ -343,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), @@ -359,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), @@ -367,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 } @@ -537,6 +594,8 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error { return f.applyRelocationsPPC(dst, rels) case f.Class == ELFCLASS64 && f.Machine == EM_PPC64: return f.applyRelocationsPPC64(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_MIPS: + return f.applyRelocationsMIPS64(dst, rels) case f.Class == ELFCLASS64 && f.Machine == EM_S390: return f.applyRelocationsS390x(dst, rels) default: @@ -802,6 +861,58 @@ func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error { return nil } +func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + var symNo uint64 + var t R_MIPS + if f.ByteOrder == binary.BigEndian { + symNo = rela.Info >> 32 + t = R_MIPS(rela.Info & 0xff) + } else { + symNo = rela.Info & 0xffffffff + t = R_MIPS(rela.Info >> 56) + } + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if SymType(sym.Info&0xf) != STT_SECTION { + // We don't handle non-section relocations for now. + continue + } + + switch t { + case R_MIPS_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) + case R_MIPS_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) + } + } + + return nil +} + func (f *File) applyRelocationsS390x(dst []byte, rels []byte) error { // 24 is the size of Rela64. if len(rels)%24 != 0 { @@ -852,6 +963,22 @@ func (f *File) DWARF() (*dwarf.Data, error) { return nil, err } + if len(b) >= 12 && string(b[:4]) == "ZLIB" { + dlen := binary.BigEndian.Uint64(b[4:12]) + dbuf := make([]byte, dlen) + r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) + if err != nil { + return nil, err + } + if _, err := io.ReadFull(r, dbuf); err != nil { + return nil, err + } + if err := r.Close(); err != nil { + return nil, err + } + b = dbuf + } + for _, r := range f.Sections { if r.Type != SHT_RELA && r.Type != SHT_REL { continue @@ -876,17 +1003,23 @@ func (f *File) DWARF() (*dwarf.Data, error) { // Don't bother loading others. var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} for i, s := range f.Sections { - if !strings.HasPrefix(s.Name, ".debug_") { + suffix := "" + switch { + case strings.HasPrefix(s.Name, ".debug_"): + suffix = s.Name[7:] + case strings.HasPrefix(s.Name, ".zdebug_"): + suffix = s.Name[8:] + default: continue } - if _, ok := dat[s.Name[7:]]; !ok { + if _, ok := dat[suffix]; !ok { continue } b, err := sectionData(i, s) if err != nil { return nil, err } - dat[s.Name[7:]] = b + dat[suffix] = b } d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go index 1ad4314..5c0df0f 100644 --- a/libgo/go/debug/elf/file_test.go +++ b/libgo/go/debug/elf/file_test.go @@ -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) { @@ -245,62 +304,237 @@ var relocationTests = []relocationTest{ { "testdata/go-relocation-test-gcc441-x86-64.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + }, + }}, }, }, { "testdata/go-relocation-test-gcc441-x86.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + }, + }}, }, }, { "testdata/go-relocation-test-gcc424-x86-64.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + }, + }}, }, }, { "testdata/go-relocation-test-gcc482-aarch64.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + }, + }}, }, }, { "testdata/go-relocation-test-gcc492-arm.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + }, + }}, }, }, { "testdata/go-relocation-test-clang-arm.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(48), Class: dwarf.ClassConstant}}}}, + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: int64(48), Class: dwarf.ClassConstant}, + }, + }}, }, }, { "testdata/go-relocation-test-gcc5-ppc.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + }, + }}, }, }, { "testdata/go-relocation-test-gcc482-ppc64le.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc492-mips64.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -meb -mabi=64 -march=mips3 -mtune=mips64 -mllsc -mno-shared -g", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: int64(100), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc493-mips64le.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.3 -mel -mabi=64 -mllsc -mno-shared -g -fstack-protector-strong", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, + {Attr: dwarf.AttrHighpc, Val: int64(100), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + }, + }}, }, }, { "testdata/go-relocation-test-clang-x86.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}}}}, + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString}, + {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString}, + {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, + {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, + }, + }}, }, }, { "testdata/gcc-amd64-openbsd-debug-with-rela.obj", []relocationTestEntry{ - {203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc}}}}, - {204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc}}}}, + {203, &dwarf.Entry{ + Offset: 0xc62, + Tag: dwarf.TagMember, + Children: false, + Field: []dwarf.Field{ + {Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString}, + {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, + {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc}, + }, + }}, + {204, &dwarf.Entry{ + Offset: 0xc70, + Tag: dwarf.TagMember, + Children: false, + Field: []dwarf.Field{ + {Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString}, + {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant}, + {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, + {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc}, + }, + }}, }, }, } @@ -339,6 +573,119 @@ func TestDWARFRelocations(t *testing.T) { } } +func TestCompressedDWARF(t *testing.T) { + // Test file built with GCC 4.8.4 and as 2.24 using: + // gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c + f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj") + if err != nil { + t.Fatal(err) + } + dwarf, err := f.DWARF() + if err != nil { + t.Fatal(err) + } + reader := dwarf.Reader() + n := 0 + for { + entry, err := reader.Next() + if err != nil { + t.Fatal(err) + } + if entry == nil { + break + } + n++ + } + if n != 18 { + t.Fatalf("want %d DWARF entries, got %d", 18, n) + } +} + +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/libgo/go/debug/elf/reader.go b/libgo/go/debug/elf/reader.go new file mode 100644 index 0000000..17b5716 --- /dev/null +++ b/libgo/go/debug/elf/reader.go @@ -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/libgo/go/debug/elf/testdata/compressed-32.obj b/libgo/go/debug/elf/testdata/compressed-32.obj Binary files differnew file mode 100644 index 0000000..2bfdb44 --- /dev/null +++ b/libgo/go/debug/elf/testdata/compressed-32.obj diff --git a/libgo/go/debug/elf/testdata/compressed-64.obj b/libgo/go/debug/elf/testdata/compressed-64.obj Binary files differnew file mode 100644 index 0000000..ffae56a --- /dev/null +++ b/libgo/go/debug/elf/testdata/compressed-64.obj diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj Binary files differnew file mode 100644 index 0000000..68febe1 --- /dev/null +++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj Binary files differnew file mode 100644 index 0000000..20bbd6c --- /dev/null +++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj diff --git a/libgo/go/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj b/libgo/go/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj Binary files differnew file mode 100644 index 0000000..a595a01 --- /dev/null +++ b/libgo/go/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj diff --git a/libgo/go/debug/gosym/pclntab_test.go b/libgo/go/debug/gosym/pclntab_test.go index 53f3e95..8d4aa54 100644 --- a/libgo/go/debug/gosym/pclntab_test.go +++ b/libgo/go/debug/gosym/pclntab_test.go @@ -6,6 +6,7 @@ package gosym import ( "debug/elf" + "internal/testenv" "io/ioutil" "os" "os/exec" @@ -20,25 +21,16 @@ var ( pclinetestBinary string ) -func dotest(self bool) bool { +func dotest(t *testing.T) { + testenv.MustHaveGoBuild(t) // For now, only works on amd64 platforms. if runtime.GOARCH != "amd64" { - return false - } - // Self test reads test binary; only works on Linux. - if self && runtime.GOOS != "linux" { - return false - } - if pclinetestBinary != "" { - return true + t.Skipf("skipping on non-AMD64 system %s", runtime.GOARCH) } var err error pclineTempDir, err = ioutil.TempDir("", "pclinetest") if err != nil { - panic(err) - } - if strings.Contains(pclineTempDir, " ") { - panic("unexpected space in tempdir") + t.Fatal(err) } // This command builds pclinetest from pclinetest.asm; // the resulting binary looks like it was built from pclinetest.s, @@ -48,16 +40,15 @@ func dotest(self bool) bool { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - panic(err) + t.Fatal(err) } cmd = exec.Command("go", "tool", "link", "-H", "linux", "-E", "main", "-o", pclinetestBinary, pclinetestBinary+".o") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - panic(err) + t.Fatal(err) } - return true } func endtest() { @@ -68,6 +59,17 @@ func endtest() { } } +// skipIfNotELF skips the test if we are not running on an ELF system. +// These tests open and examine the test binary, and use elf.Open to do so. +func skipIfNotELF(t *testing.T) { + switch runtime.GOOS { + case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": + // OK. + default: + t.Skipf("skipping on non-ELF system %s", runtime.GOOS) + } +} + func getTable(t *testing.T) *Table { f, tab := crack(os.Args[0], t) f.Close() @@ -112,10 +114,7 @@ func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) { var goarch = os.Getenv("O") func TestLineFromAline(t *testing.T) { - if !dotest(true) { - return - } - defer endtest() + skipIfNotELF(t) tab := getTable(t) if tab.go12line != nil { @@ -164,10 +163,7 @@ func TestLineFromAline(t *testing.T) { } func TestLineAline(t *testing.T) { - if !dotest(true) { - return - } - defer endtest() + skipIfNotELF(t) tab := getTable(t) if tab.go12line != nil { @@ -210,9 +206,7 @@ func TestLineAline(t *testing.T) { } func TestPCLine(t *testing.T) { - if !dotest(false) { - return - } + dotest(t) defer endtest() f, tab := crack(pclinetestBinary, t) |