diff options
Diffstat (limited to 'gcc-4.8.1/libgo/go/debug/elf/file.go')
-rw-r--r-- | gcc-4.8.1/libgo/go/debug/elf/file.go | 775 |
1 files changed, 0 insertions, 775 deletions
diff --git a/gcc-4.8.1/libgo/go/debug/elf/file.go b/gcc-4.8.1/libgo/go/debug/elf/file.go deleted file mode 100644 index eb3d72f71..000000000 --- a/gcc-4.8.1/libgo/go/debug/elf/file.go +++ /dev/null @@ -1,775 +0,0 @@ -// 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 elf implements access to ELF object files. -package elf - -import ( - "bytes" - "debug/dwarf" - "encoding/binary" - "errors" - "fmt" - "io" - "os" -) - -// TODO: error reporting detail - -/* - * Internal ELF representation - */ - -// A FileHeader represents an ELF file header. -type FileHeader struct { - Class Class - Data Data - Version Version - OSABI OSABI - ABIVersion uint8 - ByteOrder binary.ByteOrder - Type Type - Machine Machine - Entry uint64 -} - -// A File represents an open ELF file. -type File struct { - FileHeader - Sections []*Section - Progs []*Prog - closer io.Closer - gnuNeed []verneed - gnuVersym []byte -} - -// A SectionHeader represents a single ELF section header. -type SectionHeader struct { - Name string - Type SectionType - Flags SectionFlag - Addr uint64 - Offset uint64 - Size uint64 - Link uint32 - Info uint32 - Addralign uint64 - Entsize uint64 -} - -// A Section represents a single section in an ELF file. -type Section struct { - SectionHeader - - // Embed ReaderAt for ReadAt method. - // Do not embed SectionReader directly - // to avoid having Read and Seek. - // If a client wants Read and Seek it must use - // Open() to avoid fighting over the seek offset - // with other clients. - io.ReaderAt - sr *io.SectionReader -} - -// Data reads and returns the contents of the ELF section. -func (s *Section) Data() ([]byte, error) { - dat := make([]byte, s.sr.Size()) - n, err := s.sr.ReadAt(dat, 0) - return dat[0:n], err -} - -// stringTable reads and returns the string table given by the -// specified link value. -func (f *File) stringTable(link uint32) ([]byte, error) { - if link <= 0 || link >= uint32(len(f.Sections)) { - return nil, errors.New("section has invalid string table link") - } - return f.Sections[link].Data() -} - -// Open returns a new ReadSeeker reading the ELF section. -func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } - -// A ProgHeader represents a single ELF program header. -type ProgHeader struct { - Type ProgType - Flags ProgFlag - Off uint64 - Vaddr uint64 - Paddr uint64 - Filesz uint64 - Memsz uint64 - Align uint64 -} - -// A Prog represents a single ELF program header in an ELF binary. -type Prog struct { - ProgHeader - - // Embed ReaderAt for ReadAt method. - // Do not embed SectionReader directly - // to avoid having Read and Seek. - // If a client wants Read and Seek it must use - // Open() to avoid fighting over the seek offset - // with other clients. - io.ReaderAt - sr *io.SectionReader -} - -// Open returns a new ReadSeeker reading the ELF program body. -func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } - -// A Symbol represents an entry in an ELF symbol table section. -type Symbol struct { - Name string - Info, Other byte - Section SectionIndex - Value, Size uint64 -} - -/* - * ELF reader - */ - -type FormatError struct { - off int64 - msg string - val interface{} -} - -func (e *FormatError) Error() string { - msg := e.msg - if e.val != nil { - msg += fmt.Sprintf(" '%v' ", e.val) - } - msg += fmt.Sprintf("in record at byte %#x", e.off) - return msg -} - -// Open opens the named file using os.Open and prepares it for use as an ELF binary. -func Open(name string) (*File, error) { - f, err := os.Open(name) - if err != nil { - return nil, err - } - ff, err := NewFile(f) - if err != nil { - f.Close() - return nil, err - } - ff.closer = f - return ff, nil -} - -// Close closes the File. -// If the File was created using NewFile directly instead of Open, -// Close has no effect. -func (f *File) Close() error { - var err error - if f.closer != nil { - err = f.closer.Close() - f.closer = nil - } - return err -} - -// SectionByType returns the first section in f with the -// given type, or nil if there is no such section. -func (f *File) SectionByType(typ SectionType) *Section { - for _, s := range f.Sections { - if s.Type == typ { - return s - } - } - return nil -} - -// NewFile creates a new File for accessing an ELF binary in an underlying reader. -// The ELF binary is expected to start at position 0 in the ReaderAt. -func NewFile(r io.ReaderAt) (*File, error) { - sr := io.NewSectionReader(r, 0, 1<<63-1) - // Read and decode ELF identifier - var ident [16]uint8 - if _, err := r.ReadAt(ident[0:], 0); err != nil { - return nil, err - } - if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { - return nil, &FormatError{0, "bad magic number", ident[0:4]} - } - - f := new(File) - f.Class = Class(ident[EI_CLASS]) - switch f.Class { - case ELFCLASS32: - case ELFCLASS64: - // ok - default: - return nil, &FormatError{0, "unknown ELF class", f.Class} - } - - f.Data = Data(ident[EI_DATA]) - switch f.Data { - case ELFDATA2LSB: - f.ByteOrder = binary.LittleEndian - case ELFDATA2MSB: - f.ByteOrder = binary.BigEndian - default: - return nil, &FormatError{0, "unknown ELF data encoding", f.Data} - } - - f.Version = Version(ident[EI_VERSION]) - if f.Version != EV_CURRENT { - return nil, &FormatError{0, "unknown ELF version", f.Version} - } - - f.OSABI = OSABI(ident[EI_OSABI]) - f.ABIVersion = ident[EI_ABIVERSION] - - // Read ELF file header - var phoff int64 - var phentsize, phnum int - var shoff int64 - var shentsize, shnum, shstrndx int - shstrndx = -1 - switch f.Class { - case ELFCLASS32: - hdr := new(Header32) - sr.Seek(0, os.SEEK_SET) - if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { - return nil, err - } - f.Type = Type(hdr.Type) - f.Machine = Machine(hdr.Machine) - f.Entry = uint64(hdr.Entry) - if v := Version(hdr.Version); v != f.Version { - return nil, &FormatError{0, "mismatched ELF version", v} - } - phoff = int64(hdr.Phoff) - phentsize = int(hdr.Phentsize) - phnum = int(hdr.Phnum) - shoff = int64(hdr.Shoff) - shentsize = int(hdr.Shentsize) - shnum = int(hdr.Shnum) - shstrndx = int(hdr.Shstrndx) - case ELFCLASS64: - hdr := new(Header64) - sr.Seek(0, os.SEEK_SET) - if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { - return nil, err - } - f.Type = Type(hdr.Type) - f.Machine = Machine(hdr.Machine) - f.Entry = uint64(hdr.Entry) - if v := Version(hdr.Version); v != f.Version { - return nil, &FormatError{0, "mismatched ELF version", v} - } - phoff = int64(hdr.Phoff) - phentsize = int(hdr.Phentsize) - phnum = int(hdr.Phnum) - shoff = int64(hdr.Shoff) - shentsize = int(hdr.Shentsize) - shnum = int(hdr.Shnum) - shstrndx = int(hdr.Shstrndx) - } - - if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) { - return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} - } - - // Read program headers - f.Progs = make([]*Prog, phnum) - for i := 0; i < phnum; i++ { - off := phoff + int64(i)*int64(phentsize) - sr.Seek(off, os.SEEK_SET) - p := new(Prog) - switch f.Class { - case ELFCLASS32: - ph := new(Prog32) - if err := binary.Read(sr, f.ByteOrder, ph); err != nil { - return nil, err - } - p.ProgHeader = ProgHeader{ - Type: ProgType(ph.Type), - Flags: ProgFlag(ph.Flags), - Off: uint64(ph.Off), - Vaddr: uint64(ph.Vaddr), - Paddr: uint64(ph.Paddr), - Filesz: uint64(ph.Filesz), - Memsz: uint64(ph.Memsz), - Align: uint64(ph.Align), - } - case ELFCLASS64: - ph := new(Prog64) - if err := binary.Read(sr, f.ByteOrder, ph); err != nil { - return nil, err - } - p.ProgHeader = ProgHeader{ - Type: ProgType(ph.Type), - Flags: ProgFlag(ph.Flags), - Off: uint64(ph.Off), - Vaddr: uint64(ph.Vaddr), - Paddr: uint64(ph.Paddr), - Filesz: uint64(ph.Filesz), - Memsz: uint64(ph.Memsz), - Align: uint64(ph.Align), - } - } - p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) - p.ReaderAt = p.sr - f.Progs[i] = p - } - - // Read section headers - f.Sections = make([]*Section, shnum) - names := make([]uint32, shnum) - for i := 0; i < shnum; i++ { - off := shoff + int64(i)*int64(shentsize) - sr.Seek(off, os.SEEK_SET) - s := new(Section) - switch f.Class { - case ELFCLASS32: - sh := new(Section32) - if err := binary.Read(sr, f.ByteOrder, sh); err != nil { - return nil, err - } - names[i] = sh.Name - s.SectionHeader = SectionHeader{ - Type: SectionType(sh.Type), - Flags: SectionFlag(sh.Flags), - Addr: uint64(sh.Addr), - Offset: uint64(sh.Off), - Size: uint64(sh.Size), - Link: uint32(sh.Link), - Info: uint32(sh.Info), - Addralign: uint64(sh.Addralign), - Entsize: uint64(sh.Entsize), - } - case ELFCLASS64: - sh := new(Section64) - if err := binary.Read(sr, f.ByteOrder, sh); err != nil { - return nil, err - } - names[i] = sh.Name - s.SectionHeader = SectionHeader{ - Type: SectionType(sh.Type), - Flags: SectionFlag(sh.Flags), - Offset: uint64(sh.Off), - Size: uint64(sh.Size), - Addr: uint64(sh.Addr), - Link: uint32(sh.Link), - Info: uint32(sh.Info), - Addralign: uint64(sh.Addralign), - Entsize: uint64(sh.Entsize), - } - } - s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size)) - s.ReaderAt = s.sr - f.Sections[i] = s - } - - if len(f.Sections) == 0 { - return f, nil - } - - // Load section header string table. - shstrtab, err := f.Sections[shstrndx].Data() - if err != nil { - return nil, err - } - for i, s := range f.Sections { - var ok bool - s.Name, ok = getString(shstrtab, int(names[i])) - if !ok { - return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} - } - } - - return f, nil -} - -// getSymbols returns a slice of Symbols from parsing the symbol table -// with the given type, along with the associated string table. -func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { - switch f.Class { - case ELFCLASS64: - return f.getSymbols64(typ) - - case ELFCLASS32: - return f.getSymbols32(typ) - } - - return nil, nil, errors.New("not implemented") -} - -func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { - symtabSection := f.SectionByType(typ) - if symtabSection == nil { - return nil, nil, errors.New("no symbol section") - } - - data, err := symtabSection.Data() - if err != nil { - return nil, nil, errors.New("cannot load symbol section") - } - symtab := bytes.NewBuffer(data) - if symtab.Len()%Sym32Size != 0 { - return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") - } - - strdata, err := f.stringTable(symtabSection.Link) - if err != nil { - return nil, nil, errors.New("cannot load string table section") - } - - symbols := make([]Symbol, symtab.Len()/Sym32Size) - - i := 0 - var sym Sym32 - for symtab.Len() > 0 { - binary.Read(symtab, f.ByteOrder, &sym) - str, _ := getString(strdata, int(sym.Name)) - symbols[i].Name = str - symbols[i].Info = sym.Info - symbols[i].Other = sym.Other - symbols[i].Section = SectionIndex(sym.Shndx) - symbols[i].Value = uint64(sym.Value) - symbols[i].Size = uint64(sym.Size) - i++ - } - - return symbols, strdata, nil -} - -func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { - symtabSection := f.SectionByType(typ) - if symtabSection == nil { - return nil, nil, errors.New("no symbol section") - } - - data, err := symtabSection.Data() - if err != nil { - return nil, nil, errors.New("cannot load symbol section") - } - symtab := bytes.NewBuffer(data) - if symtab.Len()%Sym64Size != 0 { - return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") - } - - strdata, err := f.stringTable(symtabSection.Link) - if err != nil { - return nil, nil, errors.New("cannot load string table section") - } - - symbols := make([]Symbol, symtab.Len()/Sym64Size) - - i := 0 - var sym Sym64 - for symtab.Len() > 0 { - binary.Read(symtab, f.ByteOrder, &sym) - str, _ := getString(strdata, int(sym.Name)) - symbols[i].Name = str - symbols[i].Info = sym.Info - symbols[i].Other = sym.Other - symbols[i].Section = SectionIndex(sym.Shndx) - symbols[i].Value = sym.Value - symbols[i].Size = sym.Size - i++ - } - - return symbols, strdata, nil -} - -// getString extracts a string from an ELF string table. -func getString(section []byte, start int) (string, bool) { - if start < 0 || start >= len(section) { - return "", false - } - - for end := start; end < len(section); end++ { - if section[end] == 0 { - return string(section[start:end]), true - } - } - return "", false -} - -// Section returns a section with the given name, or nil if no such -// section exists. -func (f *File) Section(name string) *Section { - for _, s := range f.Sections { - if s.Name == name { - return s - } - } - return nil -} - -// applyRelocations applies relocations to dst. rels is a relocations section -// in RELA format. -func (f *File) applyRelocations(dst []byte, rels []byte) error { - if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 { - return f.applyRelocationsAMD64(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") - } - - 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_X86_64(rela.Info & 0xffff) - - if symNo >= uint64(len(symbols)) { - continue - } - sym := &symbols[symNo] - if SymType(sym.Info&0xf) != STT_SECTION { - // We don't handle non-section relocations for now. - continue - } - - switch t { - case R_X86_64_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_X86_64_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) DWARF() (*dwarf.Data, error) { - // There are many other DWARF sections, but these - // are the required ones, and the debug/dwarf package - // does not use the others, so don't bother loading them. - var names = [...]string{"abbrev", "info", "line", "ranges", "str"} - var dat [len(names)][]byte - for i, name := range names { - name = ".debug_" + name - s := f.Section(name) - if s == nil { - continue - } - b, err := s.Data() - if err != nil && uint64(len(b)) < s.Size { - return nil, err - } - dat[i] = b - } - - // 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 { - data, err := rela.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) -} - -// Symbols returns the symbol table for f. -func (f *File) Symbols() ([]Symbol, error) { - sym, _, err := f.getSymbols(SHT_SYMTAB) - return sym, err -} - -type ImportedSymbol struct { - Name string - Version string - Library string -} - -// ImportedSymbols returns the names of all symbols -// referred to by the binary f that are expected to be -// satisfied by other libraries at dynamic load time. -// It does not return weak symbols. -func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { - sym, str, err := f.getSymbols(SHT_DYNSYM) - if err != nil { - return nil, err - } - f.gnuVersionInit(str) - var all []ImportedSymbol - for i, s := range sym { - if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { - all = append(all, ImportedSymbol{Name: s.Name}) - f.gnuVersion(i, &all[len(all)-1]) - } - } - return all, nil -} - -type verneed struct { - File string - Name string -} - -// gnuVersionInit parses the GNU version tables -// for use by calls to gnuVersion. -func (f *File) gnuVersionInit(str []byte) { - // Accumulate verneed information. - vn := f.SectionByType(SHT_GNU_VERNEED) - if vn == nil { - return - } - d, _ := vn.Data() - - var need []verneed - i := 0 - for { - if i+16 > len(d) { - break - } - vers := f.ByteOrder.Uint16(d[i : i+2]) - if vers != 1 { - break - } - cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) - fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) - aux := f.ByteOrder.Uint32(d[i+8 : i+12]) - next := f.ByteOrder.Uint32(d[i+12 : i+16]) - file, _ := getString(str, int(fileoff)) - - var name string - j := i + int(aux) - for c := 0; c < int(cnt); c++ { - if j+16 > len(d) { - break - } - // hash := f.ByteOrder.Uint32(d[j:j+4]) - // flags := f.ByteOrder.Uint16(d[j+4:j+6]) - other := f.ByteOrder.Uint16(d[j+6 : j+8]) - nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) - next := f.ByteOrder.Uint32(d[j+12 : j+16]) - name, _ = getString(str, int(nameoff)) - ndx := int(other) - if ndx >= len(need) { - a := make([]verneed, 2*(ndx+1)) - copy(a, need) - need = a - } - - need[ndx] = verneed{file, name} - if next == 0 { - break - } - j += int(next) - } - - if next == 0 { - break - } - i += int(next) - } - - // Versym parallels symbol table, indexing into verneed. - vs := f.SectionByType(SHT_GNU_VERSYM) - if vs == nil { - return - } - d, _ = vs.Data() - - f.gnuNeed = need - f.gnuVersym = d -} - -// gnuVersion adds Library and Version information to sym, -// which came from offset i of the symbol table. -func (f *File) gnuVersion(i int, sym *ImportedSymbol) { - // Each entry is two bytes. - i = i * 2 - if i >= len(f.gnuVersym) { - return - } - j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) - if j < 2 || j >= len(f.gnuNeed) { - return - } - n := &f.gnuNeed[j] - sym.Library = n.File - sym.Version = n.Name -} - -// ImportedLibraries returns the names of all libraries -// referred to by the binary f that are expected to be -// linked with the binary at dynamic link time. -func (f *File) ImportedLibraries() ([]string, error) { - return f.DynString(DT_NEEDED) -} - -// DynString returns the strings listed for the given tag in the file's dynamic -// section. -// -// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or -// DT_RUNPATH. -func (f *File) DynString(tag DynTag) ([]string, error) { - switch tag { - case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: - default: - return nil, fmt.Errorf("non-string-valued tag %v", tag) - } - ds := f.SectionByType(SHT_DYNAMIC) - if ds == nil { - // not dynamic, so no libraries - return nil, nil - } - d, err := ds.Data() - if err != nil { - return nil, err - } - str, err := f.stringTable(ds.Link) - if err != nil { - return nil, err - } - var all []string - for len(d) > 0 { - var t DynTag - var v uint64 - switch f.Class { - case ELFCLASS32: - t = DynTag(f.ByteOrder.Uint32(d[0:4])) - v = uint64(f.ByteOrder.Uint32(d[4:8])) - d = d[8:] - case ELFCLASS64: - t = DynTag(f.ByteOrder.Uint64(d[0:8])) - v = f.ByteOrder.Uint64(d[8:16]) - d = d[16:] - } - if t == tag { - s, ok := getString(str, int(v)) - if ok { - all = append(all, s) - } - } - } - return all, nil -} |