diff options
Diffstat (limited to 'libgo/go/debug/elf/file.go')
-rw-r--r-- | libgo/go/debug/elf/file.go | 273 |
1 files changed, 263 insertions, 10 deletions
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go index f6e7e31a8e..0135f7f8db 100644 --- a/libgo/go/debug/elf/file.go +++ b/libgo/go/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 } @@ -402,17 +405,21 @@ func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { return nil, nil, errors.New("not implemented") } +// ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols +// if there is no such section in the File. +var ErrNoSymbols = errors.New("no symbol section") + func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { symtabSection := f.SectionByType(typ) if symtabSection == nil { - return nil, nil, errors.New("no symbol section") + return nil, nil, ErrNoSymbols } data, err := symtabSection.Data() 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") } @@ -448,14 +455,14 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { symtabSection := f.SectionByType(typ) if symtabSection == nil { - return nil, nil, errors.New("no symbol section") + return nil, nil, ErrNoSymbols } data, err := symtabSection.Data() 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,16 +526,29 @@ 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) + } if f.Class == ELFCLASS64 && f.Machine == EM_AARCH64 { return f.applyRelocationsARM64(dst, rels) } + if f.Class == ELFCLASS32 && f.Machine == EM_PPC { + return f.applyRelocationsPPC(dst, rels) + } + if f.Class == ELFCLASS64 && f.Machine == EM_PPC64 { + return f.applyRelocationsPPC64(dst, rels) + } + if f.Class == ELFCLASS64 && f.Machine == EM_S390 { + return f.applyRelocationsS390x(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) @@ -536,7 +556,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 { @@ -553,6 +573,10 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { continue } + // There are relocations, so this must be a normal + // object file, and we only look at section symbols, + // so we assume that the symbol value is 0. + switch t { case R_X86_64_64: if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { @@ -570,6 +594,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) applyRelocationsARM64(dst []byte, rels []byte) error { // 24 is the size of Rela64. if len(rels)%24 != 0 { @@ -598,6 +659,10 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { continue } + // There are relocations, so this must be a normal + // object file, and we only look at section symbols, + // so we assume that the symbol value is 0. + switch t { case R_AARCH64_ABS64: if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { @@ -615,6 +680,132 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { return nil } +func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error { + // 12 is the size of Rela32. + if len(rels)%12 != 0 { + return errors.New("length of relocation section is not a multiple of 12") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 8 + t := R_PPC(rela.Info & 0xff) + + if symNo == 0 || symNo > uint32(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_PPC_ADDR32: + if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) + } + } + + return nil +} + +func (f *File) applyRelocationsPPC64(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) + symNo := rela.Info >> 32 + t := R_PPC64(rela.Info & 0xffff) + + 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_PPC64_ADDR64: + 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_PPC64_ADDR32: + 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 { + 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.NewBuffer(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_390(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + switch t { + case R_390_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)+uint64(sym.Value)) + case R_390_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)+uint32(sym.Value)) + } + } + + 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 @@ -637,7 +828,7 @@ func (f *File) DWARF() (*dwarf.Data, error) { // If there's a relocation table for .debug_info, we have to process it // now otherwise the data in .debug_info is invalid for x86-64 objects. rela := f.Section(".rela.debug_info") - if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64) { + if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64 || f.Machine == EM_PPC || f.Machine == EM_PPC64 || f.Machine == EM_S390) { data, err := rela.Data() if err != nil { return nil, err @@ -648,11 +839,62 @@ 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, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4] - return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str) + d, err := dwarf.New(abbrev, nil, nil, info, line, nil, ranges, 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. +// Symbols returns the symbol table for f. The symbols will be listed in the order +// they appear in f. // // For compatibility with Go 1.0, Symbols omits the null symbol at index 0. // After retrieving the symbols as symtab, an externally supplied index x @@ -662,6 +904,17 @@ func (f *File) Symbols() ([]Symbol, error) { return sym, err } +// DynamicSymbols returns the dynamic symbol table for f. The symbols +// will be listed in the order they appear in f. +// +// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0. +// After retrieving the symbols as symtab, an externally supplied index x +// corresponds to symtab[x-1], not symtab[x]. +func (f *File) DynamicSymbols() ([]Symbol, error) { + sym, _, err := f.getSymbols(SHT_DYNSYM) + return sym, err +} + type ImportedSymbol struct { Name string Version string |