diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2011-10-20 21:10:27 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2011-10-20 21:10:27 +0000 | 
| commit | 30815c536baacc07e925f0aef23a5395883173dc (patch) | |
| tree | 2cbcf22585e99f8a87d12d5ff94f392c0d266819 /lib/Object/ELFObjectFile.cpp | |
| parent | 411bd29eea3c360d5b48a18a17b5e87f5671af0e (diff) | |
Notes
Diffstat (limited to 'lib/Object/ELFObjectFile.cpp')
| -rw-r--r-- | lib/Object/ELFObjectFile.cpp | 773 | 
1 files changed, 722 insertions, 51 deletions
| diff --git a/lib/Object/ELFObjectFile.cpp b/lib/Object/ELFObjectFile.cpp index e2ff4dfc0384..257d08cadff3 100644 --- a/lib/Object/ELFObjectFile.cpp +++ b/lib/Object/ELFObjectFile.cpp @@ -14,11 +14,14 @@  #include "llvm/ADT/SmallVector.h"  #include "llvm/ADT/StringSwitch.h"  #include "llvm/ADT/Triple.h" +#include "llvm/ADT/DenseMap.h"  #include "llvm/Object/ObjectFile.h"  #include "llvm/Support/ELF.h"  #include "llvm/Support/Endian.h"  #include "llvm/Support/ErrorHandling.h"  #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm>  #include <limits>  #include <utility> @@ -176,12 +179,89 @@ struct Elf_Sym_Impl : Elf_Sym_Base<target_endianness, is64Bits> {  }  namespace { +template<support::endianness target_endianness, bool is64Bits, bool isRela> +struct Elf_Rel_Base; + +template<support::endianness target_endianness> +struct Elf_Rel_Base<target_endianness, false, false> { +  LLVM_ELF_IMPORT_TYPES(target_endianness, false) +  Elf_Addr      r_offset; // Location (file byte offset, or program virtual addr) +  Elf_Word      r_info;  // Symbol table index and type of relocation to apply +}; + +template<support::endianness target_endianness> +struct Elf_Rel_Base<target_endianness, true, false> { +  LLVM_ELF_IMPORT_TYPES(target_endianness, true) +  Elf_Addr      r_offset; // Location (file byte offset, or program virtual addr) +  Elf_Xword     r_info;   // Symbol table index and type of relocation to apply +}; + +template<support::endianness target_endianness> +struct Elf_Rel_Base<target_endianness, false, true> { +  LLVM_ELF_IMPORT_TYPES(target_endianness, false) +  Elf_Addr      r_offset; // Location (file byte offset, or program virtual addr) +  Elf_Word      r_info;   // Symbol table index and type of relocation to apply +  Elf_Sword     r_addend; // Compute value for relocatable field by adding this +}; + +template<support::endianness target_endianness> +struct Elf_Rel_Base<target_endianness, true, true> { +  LLVM_ELF_IMPORT_TYPES(target_endianness, true) +  Elf_Addr      r_offset; // Location (file byte offset, or program virtual addr) +  Elf_Xword     r_info;   // Symbol table index and type of relocation to apply +  Elf_Sxword    r_addend; // Compute value for relocatable field by adding this. +}; + +template<support::endianness target_endianness, bool is64Bits, bool isRela> +struct Elf_Rel_Impl; + +template<support::endianness target_endianness, bool isRela> +struct Elf_Rel_Impl<target_endianness, true, isRela> +       : Elf_Rel_Base<target_endianness, true, isRela> { +  using Elf_Rel_Base<target_endianness, true, isRela>::r_info; +  LLVM_ELF_IMPORT_TYPES(target_endianness, true) + +  // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE, +  // and ELF64_R_INFO macros defined in the ELF specification: +  uint64_t getSymbol() const { return (r_info >> 32); } +  unsigned char getType() const { +    return (unsigned char) (r_info & 0xffffffffL); +  } +  void setSymbol(uint64_t s) { setSymbolAndType(s, getType()); } +  void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); } +  void setSymbolAndType(uint64_t s, unsigned char t) { +    r_info = (s << 32) + (t&0xffffffffL); +  } +}; + +template<support::endianness target_endianness, bool isRela> +struct Elf_Rel_Impl<target_endianness, false, isRela> +       : Elf_Rel_Base<target_endianness, false, isRela> { +  using Elf_Rel_Base<target_endianness, false, isRela>::r_info; +  LLVM_ELF_IMPORT_TYPES(target_endianness, false) + +  // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE, +  // and ELF32_R_INFO macros defined in the ELF specification: +  uint32_t getSymbol() const { return (r_info >> 8); } +  unsigned char getType() const { return (unsigned char) (r_info & 0x0ff); } +  void setSymbol(uint32_t s) { setSymbolAndType(s, getType()); } +  void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); } +  void setSymbolAndType(uint32_t s, unsigned char t) { +    r_info = (s << 8) + t; +  } +}; + +} + +namespace {  template<support::endianness target_endianness, bool is64Bits>  class ELFObjectFile : public ObjectFile {    LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)    typedef Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr;    typedef Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym; +  typedef Elf_Rel_Impl<target_endianness, is64Bits, false> Elf_Rel; +  typedef Elf_Rel_Impl<target_endianness, is64Bits, true> Elf_Rela;    struct Elf_Ehdr {      unsigned char e_ident[ELF::EI_NIDENT]; // ELF Identification bytes @@ -206,37 +286,81 @@ class ELFObjectFile : public ObjectFile {      unsigned char getDataEncoding() const { return e_ident[ELF::EI_DATA]; }    }; -  typedef SmallVector<const Elf_Shdr*, 1> SymbolTableSections_t; +  typedef SmallVector<const Elf_Shdr*, 1> Sections_t; +  typedef DenseMap<unsigned, unsigned> IndexMap_t; +  typedef DenseMap<const Elf_Shdr*, SmallVector<uint32_t, 1> > RelocMap_t;    const Elf_Ehdr *Header;    const Elf_Shdr *SectionHeaderTable;    const Elf_Shdr *dot_shstrtab_sec; // Section header string table.    const Elf_Shdr *dot_strtab_sec;   // Symbol header string table. -  SymbolTableSections_t SymbolTableSections; +  Sections_t SymbolTableSections; +  IndexMap_t SymbolTableSectionsIndexMap; +  DenseMap<const Elf_Sym*, ELF::Elf64_Word> ExtendedSymbolTable; + +  /// @brief Map sections to an array of relocation sections that reference +  ///        them sorted by section index. +  RelocMap_t SectionRelocMap; + +  /// @brief Get the relocation section that contains \a Rel. +  const Elf_Shdr *getRelSection(DataRefImpl Rel) const { +    return getSection(Rel.w.b); +  }    void            validateSymbol(DataRefImpl Symb) const; +  bool            isRelocationHasAddend(DataRefImpl Rel) const; +  template<typename T> +  const T        *getEntry(uint16_t Section, uint32_t Entry) const; +  template<typename T> +  const T        *getEntry(const Elf_Shdr *Section, uint32_t Entry) const;    const Elf_Sym  *getSymbol(DataRefImpl Symb) const;    const Elf_Shdr *getSection(DataRefImpl index) const; -  const Elf_Shdr *getSection(uint16_t index) const; -  const char     *getString(uint16_t section, uint32_t offset) const; +  const Elf_Shdr *getSection(uint32_t index) const; +  const Elf_Rel  *getRel(DataRefImpl Rel) const; +  const Elf_Rela *getRela(DataRefImpl Rela) const; +  const char     *getString(uint32_t section, uint32_t offset) const;    const char     *getString(const Elf_Shdr *section, uint32_t offset) const; +  error_code      getSymbolName(const Elf_Sym *Symb, StringRef &Res) const;  protected:    virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const;    virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const; +  virtual error_code getSymbolOffset(DataRefImpl Symb, uint64_t &Res) const;    virtual error_code getSymbolAddress(DataRefImpl Symb, uint64_t &Res) const;    virtual error_code getSymbolSize(DataRefImpl Symb, uint64_t &Res) const;    virtual error_code getSymbolNMTypeChar(DataRefImpl Symb, char &Res) const;    virtual error_code isSymbolInternal(DataRefImpl Symb, bool &Res) const; +  virtual error_code isSymbolGlobal(DataRefImpl Symb, bool &Res) const; +  virtual error_code getSymbolType(DataRefImpl Symb, SymbolRef::SymbolType &Res) const;    virtual error_code getSectionNext(DataRefImpl Sec, SectionRef &Res) const;    virtual error_code getSectionName(DataRefImpl Sec, StringRef &Res) const;    virtual error_code getSectionAddress(DataRefImpl Sec, uint64_t &Res) const;    virtual error_code getSectionSize(DataRefImpl Sec, uint64_t &Res) const;    virtual error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const; +  virtual error_code getSectionAlignment(DataRefImpl Sec, uint64_t &Res) const;    virtual error_code isSectionText(DataRefImpl Sec, bool &Res) const; +  virtual error_code isSectionData(DataRefImpl Sec, bool &Res) const; +  virtual error_code isSectionBSS(DataRefImpl Sec, bool &Res) const;    virtual error_code sectionContainsSymbol(DataRefImpl Sec, DataRefImpl Symb,                                             bool &Result) const; +  virtual relocation_iterator getSectionRelBegin(DataRefImpl Sec) const; +  virtual relocation_iterator getSectionRelEnd(DataRefImpl Sec) const; + +  virtual error_code getRelocationNext(DataRefImpl Rel, +                                       RelocationRef &Res) const; +  virtual error_code getRelocationAddress(DataRefImpl Rel, +                                          uint64_t &Res) const; +  virtual error_code getRelocationSymbol(DataRefImpl Rel, +                                         SymbolRef &Res) const; +  virtual error_code getRelocationType(DataRefImpl Rel, +                                       uint32_t &Res) const; +  virtual error_code getRelocationTypeName(DataRefImpl Rel, +                                           SmallVectorImpl<char> &Result) const; +  virtual error_code getRelocationAdditionalInfo(DataRefImpl Rel, +                                                 int64_t &Res) const; +  virtual error_code getRelocationValueString(DataRefImpl Rel, +                                           SmallVectorImpl<char> &Result) const;  public:    ELFObjectFile(MemoryBuffer *Object, error_code &ec); @@ -248,6 +372,11 @@ public:    virtual uint8_t getBytesInAddress() const;    virtual StringRef getFileFormatName() const;    virtual unsigned getArch() const; + +  uint64_t getNumSections() const; +  uint64_t getStringTableIndex() const; +  ELF::Elf64_Word getSymbolTableIndex(const Elf_Sym *symb) const; +  const Elf_Shdr *getSection(const Elf_Sym *symb) const;  };  } // end namespace @@ -299,29 +428,37 @@ error_code ELFObjectFile<target_endianness, is64Bits>                          ::getSymbolName(DataRefImpl Symb,                                          StringRef &Result) const {    validateSymbol(Symb); -  const Elf_Sym  *symb = getSymbol(Symb); -  if (symb->st_name == 0) { -    const Elf_Shdr *section = getSection(symb->st_shndx); -    if (!section) -      Result = ""; -    else -      Result = getString(dot_shstrtab_sec, section->sh_name); -    return object_error::success; -  } +  const Elf_Sym *symb = getSymbol(Symb); +  return getSymbolName(symb, Result); +} -  // Use the default symbol table name section. -  Result = getString(dot_strtab_sec, symb->st_name); -  return object_error::success; +template<support::endianness target_endianness, bool is64Bits> +ELF::Elf64_Word ELFObjectFile<target_endianness, is64Bits> +                      ::getSymbolTableIndex(const Elf_Sym *symb) const { +  if (symb->st_shndx == ELF::SHN_XINDEX) +    return ExtendedSymbolTable.lookup(symb); +  return symb->st_shndx; +} + +template<support::endianness target_endianness, bool is64Bits> +const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Shdr * +ELFObjectFile<target_endianness, is64Bits> +                             ::getSection(const Elf_Sym *symb) const { +  if (symb->st_shndx == ELF::SHN_XINDEX) +    return getSection(ExtendedSymbolTable.lookup(symb)); +  if (symb->st_shndx >= ELF::SHN_LORESERVE) +    return 0; +  return getSection(symb->st_shndx);  }  template<support::endianness target_endianness, bool is64Bits>  error_code ELFObjectFile<target_endianness, is64Bits> -                        ::getSymbolAddress(DataRefImpl Symb, -                                           uint64_t &Result) const { +                        ::getSymbolOffset(DataRefImpl Symb, +                                          uint64_t &Result) const {    validateSymbol(Symb);    const Elf_Sym  *symb = getSymbol(Symb);    const Elf_Shdr *Section; -  switch (symb->st_shndx) { +  switch (getSymbolTableIndex(symb)) {    case ELF::SHN_COMMON:     // Undefined symbols have no address yet.    case ELF::SHN_UNDEF: @@ -330,7 +467,7 @@ error_code ELFObjectFile<target_endianness, is64Bits>    case ELF::SHN_ABS:      Result = symb->st_value;      return object_error::success; -  default: Section = getSection(symb->st_shndx); +  default: Section = getSection(symb);    }    switch (symb->getType()) { @@ -350,6 +487,43 @@ error_code ELFObjectFile<target_endianness, is64Bits>  template<support::endianness target_endianness, bool is64Bits>  error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getSymbolAddress(DataRefImpl Symb, +                                           uint64_t &Result) const { +  validateSymbol(Symb); +  const Elf_Sym  *symb = getSymbol(Symb); +  const Elf_Shdr *Section; +  switch (getSymbolTableIndex(symb)) { +  case ELF::SHN_COMMON: // Fall through. +   // Undefined symbols have no address yet. +  case ELF::SHN_UNDEF: +    Result = UnknownAddressOrSize; +    return object_error::success; +  case ELF::SHN_ABS: +    Result = reinterpret_cast<uintptr_t>(base()+symb->st_value); +    return object_error::success; +  default: Section = getSection(symb); +  } +  const uint8_t* addr = base(); +  if (Section) +    addr += Section->sh_offset; +  switch (symb->getType()) { +  case ELF::STT_SECTION: +    Result = reinterpret_cast<uintptr_t>(addr); +    return object_error::success; +  case ELF::STT_FUNC: // Fall through. +  case ELF::STT_OBJECT: // Fall through. +  case ELF::STT_NOTYPE: +    addr += symb->st_value; +    Result = reinterpret_cast<uintptr_t>(addr); +    return object_error::success; +  default: +    Result = UnknownAddressOrSize; +    return object_error::success; +  } +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits>                          ::getSymbolSize(DataRefImpl Symb,                                          uint64_t &Result) const {    validateSymbol(Symb); @@ -366,7 +540,7 @@ error_code ELFObjectFile<target_endianness, is64Bits>                                                char &Result) const {    validateSymbol(Symb);    const Elf_Sym  *symb = getSymbol(Symb); -  const Elf_Shdr *Section = getSection(symb->st_shndx); +  const Elf_Shdr *Section = getSection(symb);    char ret = '?'; @@ -389,7 +563,7 @@ error_code ELFObjectFile<target_endianness, is64Bits>      }    } -  switch (symb->st_shndx) { +  switch (getSymbolTableIndex(symb)) {    case ELF::SHN_UNDEF:      if (ret == '?')        ret = 'U'; @@ -401,7 +575,7 @@ error_code ELFObjectFile<target_endianness, is64Bits>    switch (symb->getBinding()) {    case ELF::STB_GLOBAL: ret = ::toupper(ret); break;    case ELF::STB_WEAK: -    if (symb->st_shndx == ELF::SHN_UNDEF) +    if (getSymbolTableIndex(symb) == ELF::SHN_UNDEF)        ret = 'w';      else        if (symb->getType() == ELF::STT_OBJECT) @@ -416,7 +590,8 @@ error_code ELFObjectFile<target_endianness, is64Bits>        return ec;      Result = StringSwitch<char>(name)        .StartsWith(".debug", 'N') -      .StartsWith(".note", 'n'); +      .StartsWith(".note", 'n') +      .Default('?');      return object_error::success;    } @@ -426,6 +601,43 @@ error_code ELFObjectFile<target_endianness, is64Bits>  template<support::endianness target_endianness, bool is64Bits>  error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getSymbolType(DataRefImpl Symb, +                                        SymbolRef::SymbolType &Result) const { +  validateSymbol(Symb); +  const Elf_Sym  *symb = getSymbol(Symb); + +  if (getSymbolTableIndex(symb) == ELF::SHN_UNDEF) { +    Result = SymbolRef::ST_External; +    return object_error::success; +  } + +  switch (symb->getType()) { +  case ELF::STT_FUNC: +    Result = SymbolRef::ST_Function; +    break; +  case ELF::STT_OBJECT: +    Result = SymbolRef::ST_Data; +    break; +  default: +    Result = SymbolRef::ST_Other; +    break; +  } +  return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::isSymbolGlobal(DataRefImpl Symb, +                                        bool &Result) const { +  validateSymbol(Symb); +  const Elf_Sym  *symb = getSymbol(Symb); + +  Result = symb->getBinding() == ELF::STB_GLOBAL; +  return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits>                          ::isSymbolInternal(DataRefImpl Symb,                                             bool &Result) const {    validateSymbol(Symb); @@ -487,6 +699,15 @@ error_code ELFObjectFile<target_endianness, is64Bits>  template<support::endianness target_endianness, bool is64Bits>  error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getSectionAlignment(DataRefImpl Sec, +                                              uint64_t &Result) const { +  const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); +  Result = sec->sh_addralign; +  return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits>                          ::isSectionText(DataRefImpl Sec,                                          bool &Result) const {    const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); @@ -499,6 +720,32 @@ error_code ELFObjectFile<target_endianness, is64Bits>  template<support::endianness target_endianness, bool is64Bits>  error_code ELFObjectFile<target_endianness, is64Bits> +                        ::isSectionData(DataRefImpl Sec, +                                        bool &Result) const { +  const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); +  if (sec->sh_flags & (ELF::SHF_ALLOC | ELF::SHF_WRITE) +      && sec->sh_type == ELF::SHT_PROGBITS) +    Result = true; +  else +    Result = false; +  return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::isSectionBSS(DataRefImpl Sec, +                                       bool &Result) const { +  const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); +  if (sec->sh_flags & (ELF::SHF_ALLOC | ELF::SHF_WRITE) +      && sec->sh_type == ELF::SHT_NOBITS) +    Result = true; +  else +    Result = false; +  return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits>                            ::sectionContainsSymbol(DataRefImpl Sec,                                                    DataRefImpl Symb,                                                    bool &Result) const { @@ -508,6 +755,330 @@ error_code ELFObjectFile<target_endianness, is64Bits>  }  template<support::endianness target_endianness, bool is64Bits> +relocation_iterator ELFObjectFile<target_endianness, is64Bits> +                                 ::getSectionRelBegin(DataRefImpl Sec) const { +  DataRefImpl RelData; +  memset(&RelData, 0, sizeof(RelData)); +  const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); +  typename RelocMap_t::const_iterator ittr = SectionRelocMap.find(sec); +  if (sec != 0 && ittr != SectionRelocMap.end()) { +    RelData.w.a = getSection(ittr->second[0])->sh_info; +    RelData.w.b = ittr->second[0]; +    RelData.w.c = 0; +  } +  return relocation_iterator(RelocationRef(RelData, this)); +} + +template<support::endianness target_endianness, bool is64Bits> +relocation_iterator ELFObjectFile<target_endianness, is64Bits> +                                 ::getSectionRelEnd(DataRefImpl Sec) const { +  DataRefImpl RelData; +  memset(&RelData, 0, sizeof(RelData)); +  const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); +  typename RelocMap_t::const_iterator ittr = SectionRelocMap.find(sec); +  if (sec != 0 && ittr != SectionRelocMap.end()) { +    // Get the index of the last relocation section for this section. +    std::size_t relocsecindex = ittr->second[ittr->second.size() - 1]; +    const Elf_Shdr *relocsec = getSection(relocsecindex); +    RelData.w.a = relocsec->sh_info; +    RelData.w.b = relocsecindex; +    RelData.w.c = relocsec->sh_size / relocsec->sh_entsize; +  } +  return relocation_iterator(RelocationRef(RelData, this)); +} + +// Relocations +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getRelocationNext(DataRefImpl Rel, +                                            RelocationRef &Result) const { +  ++Rel.w.c; +  const Elf_Shdr *relocsec = getSection(Rel.w.b); +  if (Rel.w.c >= (relocsec->sh_size / relocsec->sh_entsize)) { +    // We have reached the end of the relocations for this section. See if there +    // is another relocation section. +    typename RelocMap_t::mapped_type relocseclist = +      SectionRelocMap.lookup(getSection(Rel.w.a)); + +    // Do a binary search for the current reloc section index (which must be +    // present). Then get the next one. +    typename RelocMap_t::mapped_type::const_iterator loc = +      std::lower_bound(relocseclist.begin(), relocseclist.end(), Rel.w.b); +    ++loc; + +    // If there is no next one, don't do anything. The ++Rel.w.c above sets Rel +    // to the end iterator. +    if (loc != relocseclist.end()) { +      Rel.w.b = *loc; +      Rel.w.a = 0; +    } +  } +  Result = RelocationRef(Rel, this); +  return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getRelocationSymbol(DataRefImpl Rel, +                                              SymbolRef &Result) const { +  uint32_t symbolIdx; +  const Elf_Shdr *sec = getSection(Rel.w.b); +  switch (sec->sh_type) { +    default : +      report_fatal_error("Invalid section type in Rel!"); +    case ELF::SHT_REL : { +      symbolIdx = getRel(Rel)->getSymbol(); +      break; +    } +    case ELF::SHT_RELA : { +      symbolIdx = getRela(Rel)->getSymbol(); +      break; +    } +  } +  DataRefImpl SymbolData; +  IndexMap_t::const_iterator it = SymbolTableSectionsIndexMap.find(sec->sh_link); +  if (it == SymbolTableSectionsIndexMap.end()) +    report_fatal_error("Relocation symbol table not found!"); +  SymbolData.d.a = symbolIdx; +  SymbolData.d.b = it->second; +  Result = SymbolRef(SymbolData, this); +  return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getRelocationAddress(DataRefImpl Rel, +                                               uint64_t &Result) const { +  uint64_t offset; +  const Elf_Shdr *sec = getSection(Rel.w.b); +  switch (sec->sh_type) { +    default : +      report_fatal_error("Invalid section type in Rel!"); +    case ELF::SHT_REL : { +      offset = getRel(Rel)->r_offset; +      break; +    } +    case ELF::SHT_RELA : { +      offset = getRela(Rel)->r_offset; +      break; +    } +  } + +  Result = offset; +  return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getRelocationType(DataRefImpl Rel, +                                            uint32_t &Result) const { +  const Elf_Shdr *sec = getSection(Rel.w.b); +  switch (sec->sh_type) { +    default : +      report_fatal_error("Invalid section type in Rel!"); +    case ELF::SHT_REL : { +      Result = getRel(Rel)->getType(); +      break; +    } +    case ELF::SHT_RELA : { +      Result = getRela(Rel)->getType(); +      break; +    } +  } +  return object_error::success; +} + +#define LLVM_ELF_SWITCH_RELOC_TYPE_NAME(enum) \ +  case ELF::enum: res = #enum; break; + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getRelocationTypeName(DataRefImpl Rel, +                                          SmallVectorImpl<char> &Result) const { +  const Elf_Shdr *sec = getSection(Rel.w.b); +  uint8_t type; +  StringRef res; +  switch (sec->sh_type) { +    default : +      return object_error::parse_failed; +    case ELF::SHT_REL : { +      type = getRel(Rel)->getType(); +      break; +    } +    case ELF::SHT_RELA : { +      type = getRela(Rel)->getType(); +      break; +    } +  } +  switch (Header->e_machine) { +  case ELF::EM_X86_64: +    switch (type) { +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_NONE); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_64); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PC32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOT32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PLT32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_COPY); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GLOB_DAT); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_JUMP_SLOT); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_RELATIVE); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTPCREL); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_32S); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_16); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PC16); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_8); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PC8); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_DTPMOD64); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_DTPOFF64); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TPOFF64); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TLSGD); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TLSLD); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_DTPOFF32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTTPOFF); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TPOFF32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PC64); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTOFF64); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTPC32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_SIZE32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_SIZE64); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTPC32_TLSDESC); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TLSDESC_CALL); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TLSDESC); +    default: +      res = "Unknown"; +    } +    break; +  case ELF::EM_386: +    switch (type) { +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_NONE); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_PC32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_GOT32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_PLT32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_COPY); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_GLOB_DAT); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_JUMP_SLOT); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_RELATIVE); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_GOTOFF); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_GOTPC); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_32PLT); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_TPOFF); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_IE); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GOTIE); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LE); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_16); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_PC16); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_8); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_PC8); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD_32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD_PUSH); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD_CALL); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD_POP); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM_32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM_PUSH); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM_CALL); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM_POP); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDO_32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_IE_32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LE_32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_DTPMOD32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_DTPOFF32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_TPOFF32); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GOTDESC); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_DESC_CALL); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_DESC); +      LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_IRELATIVE); +    default: +      res = "Unknown"; +    } +    break; +  default: +    res = "Unknown"; +  } +  Result.append(res.begin(), res.end()); +  return object_error::success; +} + +#undef LLVM_ELF_SWITCH_RELOC_TYPE_NAME + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getRelocationAdditionalInfo(DataRefImpl Rel, +                                                      int64_t &Result) const { +  const Elf_Shdr *sec = getSection(Rel.w.b); +  switch (sec->sh_type) { +    default : +      report_fatal_error("Invalid section type in Rel!"); +    case ELF::SHT_REL : { +      Result = 0; +      return object_error::success; +    } +    case ELF::SHT_RELA : { +      Result = getRela(Rel)->r_addend; +      return object_error::success; +    } +  } +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getRelocationValueString(DataRefImpl Rel, +                                          SmallVectorImpl<char> &Result) const { +  const Elf_Shdr *sec = getSection(Rel.w.b); +  uint8_t type; +  StringRef res; +  int64_t addend = 0; +  uint16_t symbol_index = 0; +  switch (sec->sh_type) { +    default : +      return object_error::parse_failed; +    case ELF::SHT_REL : { +      type = getRel(Rel)->getType(); +      symbol_index = getRel(Rel)->getSymbol(); +      // TODO: Read implicit addend from section data. +      break; +    } +    case ELF::SHT_RELA : { +      type = getRela(Rel)->getType(); +      symbol_index = getRela(Rel)->getSymbol(); +      addend = getRela(Rel)->r_addend; +      break; +    } +  } +  const Elf_Sym *symb = getEntry<Elf_Sym>(sec->sh_link, symbol_index); +  StringRef symname; +  if (error_code ec = getSymbolName(symb, symname)) +    return ec; +  switch (Header->e_machine) { +  case ELF::EM_X86_64: +    switch (type) { +    case ELF::R_X86_64_32S: +      res = symname; +      break; +    case ELF::R_X86_64_PC32: { +        std::string fmtbuf; +        raw_string_ostream fmt(fmtbuf); +        fmt << symname << (addend < 0 ? "" : "+") << addend << "-P"; +        fmt.flush(); +        Result.append(fmtbuf.begin(), fmtbuf.end()); +      } +      break; +    default: +      res = "Unknown"; +    } +    break; +  default: +    res = "Unknown"; +  } +  if (Result.empty()) +    Result.append(res.begin(), res.end()); +  return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits>  ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object                                                            , error_code &ec)    : ObjectFile(Binary::isELF, Object, ec) @@ -521,25 +1092,41 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object    SectionHeaderTable =      reinterpret_cast<const Elf_Shdr *>(base() + Header->e_shoff); -  uint32_t SectionTableSize = Header->e_shnum * Header->e_shentsize; +  uint64_t SectionTableSize = getNumSections() * Header->e_shentsize;    if (!(  (const uint8_t *)SectionHeaderTable + SectionTableSize           <= base() + Data->getBufferSize()))      // FIXME: Proper error handling.      report_fatal_error("Section table goes past end of file!"); -  // To find the symbol tables we walk the section table to find SHT_STMTAB. -  for (const char *i = reinterpret_cast<const char *>(SectionHeaderTable), -                  *e = i + Header->e_shnum * Header->e_shentsize; -                   i != e; i += Header->e_shentsize) { -    const Elf_Shdr *sh = reinterpret_cast<const Elf_Shdr*>(i); +  // To find the symbol tables we walk the section table to find SHT_SYMTAB. +  const Elf_Shdr* SymbolTableSectionHeaderIndex = 0; +  const Elf_Shdr* sh = reinterpret_cast<const Elf_Shdr*>(SectionHeaderTable); +  for (uint64_t i = 0, e = getNumSections(); i != e; ++i) { +    if (sh->sh_type == ELF::SHT_SYMTAB_SHNDX) { +      if (SymbolTableSectionHeaderIndex) +        // FIXME: Proper error handling. +        report_fatal_error("More than one .symtab_shndx!"); +      SymbolTableSectionHeaderIndex = sh; +    }      if (sh->sh_type == ELF::SHT_SYMTAB) { +      SymbolTableSectionsIndexMap[i] = SymbolTableSections.size();        SymbolTableSections.push_back(sh);      } +    if (sh->sh_type == ELF::SHT_REL || sh->sh_type == ELF::SHT_RELA) { +      SectionRelocMap[getSection(sh->sh_info)].push_back(i); +    } +    ++sh; +  } + +  // Sort section relocation lists by index. +  for (typename RelocMap_t::iterator i = SectionRelocMap.begin(), +                                     e = SectionRelocMap.end(); i != e; ++i) { +    std::sort(i->second.begin(), i->second.end());    }    // Get string table sections. -  dot_shstrtab_sec = getSection(Header->e_shstrndx); +  dot_shstrtab_sec = getSection(getStringTableIndex());    if (dot_shstrtab_sec) {      // Verify that the last byte in the string table in a null.      if (((const char*)base() + dot_shstrtab_sec->sh_offset) @@ -550,7 +1137,7 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object    // Merge this into the above loop.    for (const char *i = reinterpret_cast<const char *>(SectionHeaderTable), -                  *e = i + Header->e_shnum * Header->e_shentsize; +                  *e = i + getNumSections() * Header->e_shentsize;                     i != e; i += Header->e_shentsize) {      const Elf_Shdr *sh = reinterpret_cast<const Elf_Shdr*>(i);      if (sh->sh_type == ELF::SHT_STRTAB) { @@ -567,11 +1154,26 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object        }      }    } + +  // Build symbol name side-mapping if there is one. +  if (SymbolTableSectionHeaderIndex) { +    const Elf_Word *ShndxTable = reinterpret_cast<const Elf_Word*>(base() + +                                      SymbolTableSectionHeaderIndex->sh_offset); +    error_code ec; +    for (symbol_iterator si = begin_symbols(), +                         se = end_symbols(); si != se; si.increment(ec)) { +      if (ec) +        report_fatal_error("Fewer extended symbol table entries than symbols!"); +      if (*ShndxTable != ELF::SHN_UNDEF) +        ExtendedSymbolTable[getSymbol(si->getRawDataRefImpl())] = *ShndxTable; +      ++ShndxTable; +    } +  }  }  template<support::endianness target_endianness, bool is64Bits> -ObjectFile::symbol_iterator ELFObjectFile<target_endianness, is64Bits> -                                         ::begin_symbols() const { +symbol_iterator ELFObjectFile<target_endianness, is64Bits> +                             ::begin_symbols() const {    DataRefImpl SymbolData;    memset(&SymbolData, 0, sizeof(SymbolData));    if (SymbolTableSections.size() == 0) { @@ -585,8 +1187,8 @@ ObjectFile::symbol_iterator ELFObjectFile<target_endianness, is64Bits>  }  template<support::endianness target_endianness, bool is64Bits> -ObjectFile::symbol_iterator ELFObjectFile<target_endianness, is64Bits> -                                         ::end_symbols() const { +symbol_iterator ELFObjectFile<target_endianness, is64Bits> +                             ::end_symbols() const {    DataRefImpl SymbolData;    memset(&SymbolData, 0, sizeof(SymbolData));    SymbolData.d.a = std::numeric_limits<uint32_t>::max(); @@ -595,8 +1197,8 @@ ObjectFile::symbol_iterator ELFObjectFile<target_endianness, is64Bits>  }  template<support::endianness target_endianness, bool is64Bits> -ObjectFile::section_iterator ELFObjectFile<target_endianness, is64Bits> -                                          ::begin_sections() const { +section_iterator ELFObjectFile<target_endianness, is64Bits> +                              ::begin_sections() const {    DataRefImpl ret;    memset(&ret, 0, sizeof(DataRefImpl));    ret.p = reinterpret_cast<intptr_t>(base() + Header->e_shoff); @@ -604,13 +1206,13 @@ ObjectFile::section_iterator ELFObjectFile<target_endianness, is64Bits>  }  template<support::endianness target_endianness, bool is64Bits> -ObjectFile::section_iterator ELFObjectFile<target_endianness, is64Bits> -                                          ::end_sections() const { +section_iterator ELFObjectFile<target_endianness, is64Bits> +                              ::end_sections() const {    DataRefImpl ret;    memset(&ret, 0, sizeof(DataRefImpl));    ret.p = reinterpret_cast<intptr_t>(base()                                       + Header->e_shoff -                                     + (Header->e_shentsize * Header->e_shnum)); +                                     + (Header->e_shentsize*getNumSections()));    return section_iterator(SectionRef(ret, this));  } @@ -629,6 +1231,8 @@ StringRef ELFObjectFile<target_endianness, is64Bits>        return "ELF32-i386";      case ELF::EM_X86_64:        return "ELF32-x86-64"; +    case ELF::EM_ARM: +      return "ELF32-arm";      default:        return "ELF32-unknown";      } @@ -654,26 +1258,75 @@ unsigned ELFObjectFile<target_endianness, is64Bits>::getArch() const {      return Triple::x86;    case ELF::EM_X86_64:      return Triple::x86_64; +  case ELF::EM_ARM: +    return Triple::arm;    default:      return Triple::UnknownArch;    }  }  template<support::endianness target_endianness, bool is64Bits> +uint64_t ELFObjectFile<target_endianness, is64Bits>::getNumSections() const { +  if (Header->e_shnum == ELF::SHN_UNDEF) +    return SectionHeaderTable->sh_size; +  return Header->e_shnum; +} + +template<support::endianness target_endianness, bool is64Bits> +uint64_t +ELFObjectFile<target_endianness, is64Bits>::getStringTableIndex() const { +  if (Header->e_shnum == ELF::SHN_UNDEF) { +    if (Header->e_shstrndx == ELF::SHN_HIRESERVE) +      return SectionHeaderTable->sh_link; +    if (Header->e_shstrndx >= getNumSections()) +      return 0; +  } +  return Header->e_shstrndx; +} + + +template<support::endianness target_endianness, bool is64Bits> +template<typename T> +inline const T * +ELFObjectFile<target_endianness, is64Bits>::getEntry(uint16_t Section, +                                                     uint32_t Entry) const { +  return getEntry<T>(getSection(Section), Entry); +} + +template<support::endianness target_endianness, bool is64Bits> +template<typename T> +inline const T * +ELFObjectFile<target_endianness, is64Bits>::getEntry(const Elf_Shdr * Section, +                                                     uint32_t Entry) const { +  return reinterpret_cast<const T *>( +           base() +           + Section->sh_offset +           + (Entry * Section->sh_entsize)); +} + +template<support::endianness target_endianness, bool is64Bits>  const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Sym *  ELFObjectFile<target_endianness, is64Bits>::getSymbol(DataRefImpl Symb) const { -  const Elf_Shdr *sec = SymbolTableSections[Symb.d.b]; -  return reinterpret_cast<const Elf_Sym *>( -           base() -           + sec->sh_offset -           + (Symb.d.a * sec->sh_entsize)); +  return getEntry<Elf_Sym>(SymbolTableSections[Symb.d.b], Symb.d.a); +} + +template<support::endianness target_endianness, bool is64Bits> +const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Rel * +ELFObjectFile<target_endianness, is64Bits>::getRel(DataRefImpl Rel) const { +  return getEntry<Elf_Rel>(Rel.w.b, Rel.w.c); +} + +template<support::endianness target_endianness, bool is64Bits> +const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Rela * +ELFObjectFile<target_endianness, is64Bits>::getRela(DataRefImpl Rela) const { +  return getEntry<Elf_Rela>(Rela.w.b, Rela.w.c);  }  template<support::endianness target_endianness, bool is64Bits>  const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Shdr *  ELFObjectFile<target_endianness, is64Bits>::getSection(DataRefImpl Symb) const {    const Elf_Shdr *sec = getSection(Symb.d.b); -  if (sec->sh_type != ELF::SHT_SYMTAB) +  if (sec->sh_type != ELF::SHT_SYMTAB || sec->sh_type != ELF::SHT_DYNSYM)      // FIXME: Proper error handling.      report_fatal_error("Invalid symbol table section!");    return sec; @@ -681,10 +1334,10 @@ ELFObjectFile<target_endianness, is64Bits>::getSection(DataRefImpl Symb) const {  template<support::endianness target_endianness, bool is64Bits>  const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Shdr * -ELFObjectFile<target_endianness, is64Bits>::getSection(uint16_t index) const { -  if (index == 0 || index >= ELF::SHN_LORESERVE) +ELFObjectFile<target_endianness, is64Bits>::getSection(uint32_t index) const { +  if (index == 0)      return 0; -  if (!SectionHeaderTable || index >= Header->e_shnum) +  if (!SectionHeaderTable || index >= getNumSections())      // FIXME: Proper error handling.      report_fatal_error("Invalid section index!"); @@ -695,7 +1348,7 @@ ELFObjectFile<target_endianness, is64Bits>::getSection(uint16_t index) const {  template<support::endianness target_endianness, bool is64Bits>  const char *ELFObjectFile<target_endianness, is64Bits> -                         ::getString(uint16_t section, +                         ::getString(uint32_t section,                                       ELF::Elf32_Word offset) const {    return getString(getSection(section), offset);  } @@ -711,6 +1364,24 @@ const char *ELFObjectFile<target_endianness, is64Bits>    return (const char *)base() + section->sh_offset + offset;  } +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> +                        ::getSymbolName(const Elf_Sym *symb, +                                        StringRef &Result) const { +  if (symb->st_name == 0) { +    const Elf_Shdr *section = getSection(symb); +    if (!section) +      Result = ""; +    else +      Result = getString(dot_shstrtab_sec, section->sh_name); +    return object_error::success; +  } + +  // Use the default symbol table name section. +  Result = getString(dot_strtab_sec, symb->st_name); +  return object_error::success; +} +  // EI_CLASS, EI_DATA.  static std::pair<unsigned char, unsigned char>  getElfArchType(MemoryBuffer *Object) { | 
