diff options
Diffstat (limited to 'src/pkg/debug/elf')
-rw-r--r-- | src/pkg/debug/elf/elf.go | 2 | ||||
-rw-r--r-- | src/pkg/debug/elf/elf_test.go | 2 | ||||
-rw-r--r-- | src/pkg/debug/elf/file.go | 106 | ||||
-rw-r--r-- | src/pkg/debug/elf/file_test.go | 6 | ||||
-rw-r--r-- | src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj | bin | 0 -> 1900 bytes | |||
-rw-r--r-- | src/pkg/debug/elf/testdata/hello.c | 7 |
6 files changed, 115 insertions, 8 deletions
diff --git a/src/pkg/debug/elf/elf.go b/src/pkg/debug/elf/elf.go index 03e42b034..d622dae2a 100644 --- a/src/pkg/debug/elf/elf.go +++ b/src/pkg/debug/elf/elf.go @@ -517,7 +517,7 @@ const ( DT_INIT_ARRAY DynTag = 25 /* Address of the array of pointers to initialization functions */ DT_FINI_ARRAY DynTag = 26 /* Address of the array of pointers to termination functions */ DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */ - DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of terminationfunctions. */ + DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of termination functions. */ DT_RUNPATH DynTag = 29 /* String table offset of a null-terminated library search path string. */ DT_FLAGS DynTag = 30 /* Object specific flag values. */ DT_ENCODING DynTag = 32 /* Values greater than or equal to DT_ENCODING diff --git a/src/pkg/debug/elf/elf_test.go b/src/pkg/debug/elf/elf_test.go index 67b961b5c..e3c51bb71 100644 --- a/src/pkg/debug/elf/elf_test.go +++ b/src/pkg/debug/elf/elf_test.go @@ -43,7 +43,7 @@ func TestNames(t *testing.T) { for i, tt := range nameTests { s := fmt.Sprint(tt.val) if s != tt.str { - t.Errorf("#%d: want %q have %q", i, s, tt.str) + t.Errorf("#%d: Sprint(%d) = %q, want %q", i, tt.val, s, tt.str) } } } diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go index a55c37ea9..423932fe0 100644 --- a/src/pkg/debug/elf/file.go +++ b/src/pkg/debug/elf/file.go @@ -76,6 +76,9 @@ type Section struct { 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 + } return dat[0:n], err } @@ -412,7 +415,7 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { if err != nil { return nil, nil, errors.New("cannot load symbol section") } - symtab := bytes.NewBuffer(data) + symtab := bytes.NewReader(data) if symtab.Len()%Sym32Size != 0 { return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") } @@ -455,7 +458,7 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { if err != nil { return nil, nil, errors.New("cannot load symbol section") } - symtab := bytes.NewBuffer(data) + symtab := bytes.NewReader(data) if symtab.Len()%Sym64Size != 0 { return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") } @@ -519,13 +522,17 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error { if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 { return f.applyRelocationsAMD64(dst, rels) } + if f.Class == ELFCLASS32 && f.Machine == EM_386 { + return f.applyRelocations386(dst, rels) + } return errors.New("not implemented") } func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { - if len(rels)%Sym64Size != 0 { - return errors.New("length of relocation section is not a multiple of Sym64Size") + // 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) @@ -533,7 +540,7 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { return err } - b := bytes.NewBuffer(rels) + b := bytes.NewReader(rels) var rela Rela64 for b.Len() > 0 { @@ -567,6 +574,43 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { return nil } +func (f *File) applyRelocations386(dst []byte, rels []byte) error { + // 8 is the size of Rel32. + if len(rels)%8 != 0 { + return errors.New("length of relocation section is not a multiple of 8") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rel Rel32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rel) + symNo := rel.Info >> 8 + t := R_386(rel.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + if t == R_386_32 { + if rel.Off+4 >= uint32(len(dst)) { + continue + } + val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) + val += uint32(sym.Value) + f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) + } + } + + return nil +} + func (f *File) DWARF() (*dwarf.Data, error) { // There are many other DWARF sections, but these // are the required ones, and the debug/dwarf package @@ -600,8 +644,58 @@ func (f *File) DWARF() (*dwarf.Data, error) { } } + // When using clang we need to process relocations even for 386. + rel := f.Section(".rel.debug_info") + if rel != nil && rel.Type == SHT_REL && f.Machine == EM_386 { + data, err := rel.Data() + if err != nil { + return nil, err + } + err = f.applyRelocations(dat[1], data) + if err != nil { + return nil, err + } + } + abbrev, info, str := dat[0], dat[1], dat[2] - return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) + d, err := dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) + if err != nil { + return nil, err + } + + // Look for DWARF4 .debug_types sections. + for i, s := range f.Sections { + if s.Name == ".debug_types" { + b, err := s.Data() + if err != nil && uint64(len(b)) < s.Size { + return nil, err + } + + for _, r := range f.Sections { + if r.Type != SHT_RELA && r.Type != SHT_REL { + continue + } + if int(r.Info) != i { + continue + } + rd, err := r.Data() + if err != nil { + return nil, err + } + err = f.applyRelocations(b, rd) + if err != nil { + return nil, err + } + } + + err = d.AddTypes(fmt.Sprintf("types-%d", i), b) + if err != nil { + return nil, err + } + } + } + + return d, nil } // Symbols returns the symbol table for f. diff --git a/src/pkg/debug/elf/file_test.go b/src/pkg/debug/elf/file_test.go index 38b5f9e70..7f88a54bc 100644 --- a/src/pkg/debug/elf/file_test.go +++ b/src/pkg/debug/elf/file_test.go @@ -261,6 +261,12 @@ var relocationTests = []relocationTest{ }, }, { + "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)"}, {Attr: dwarf.AttrLanguage, Val: int64(12)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, {Attr: dwarf.AttrStmtList, Val: int64(0)}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}}}}, + }, + }, + { "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"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}}, diff --git a/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj b/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj Binary files differnew file mode 100644 index 000000000..e909cf4e6 --- /dev/null +++ b/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj diff --git a/src/pkg/debug/elf/testdata/hello.c b/src/pkg/debug/elf/testdata/hello.c new file mode 100644 index 000000000..34d9ee792 --- /dev/null +++ b/src/pkg/debug/elf/testdata/hello.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +void +main(int argc, char *argv[]) +{ + printf("hello, world\n"); +} |