brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.2 KiB · 9c81a88 Raw
735 lines · cpp
1//===- ELFObjHandler.cpp --------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===-----------------------------------------------------------------------===/8 9#include "llvm/InterfaceStub/ELFObjHandler.h"10#include "llvm/InterfaceStub/IFSStub.h"11#include "llvm/MC/StringTableBuilder.h"12#include "llvm/Object/Binary.h"13#include "llvm/Object/ELFObjectFile.h"14#include "llvm/Object/ELFTypes.h"15#include "llvm/Support/Errc.h"16#include "llvm/Support/Error.h"17#include "llvm/Support/FileOutputBuffer.h"18#include "llvm/Support/MathExtras.h"19#include "llvm/Support/MemoryBuffer.h"20#include <optional>21 22using llvm::object::ELFObjectFile;23 24using namespace llvm;25using namespace llvm::object;26using namespace llvm::ELF;27 28namespace llvm {29namespace ifs {30 31// Simple struct to hold relevant .dynamic entries.32struct DynamicEntries {33  uint64_t StrTabAddr = 0;34  uint64_t StrSize = 0;35  std::optional<uint64_t> SONameOffset;36  std::vector<uint64_t> NeededLibNames;37  // Symbol table:38  uint64_t DynSymAddr = 0;39  // Hash tables:40  std::optional<uint64_t> ElfHash;41  std::optional<uint64_t> GnuHash;42};43 44/// This initializes an ELF file header with information specific to a binary45/// dynamic shared object.46/// Offsets, indexes, links, etc. for section and program headers are just47/// zero-initialized as they will be updated elsewhere.48///49/// @param ElfHeader Target ELFT::Ehdr to populate.50/// @param Machine Target architecture (e_machine from ELF specifications).51template <class ELFT>52static void initELFHeader(typename ELFT::Ehdr &ElfHeader, uint16_t Machine) {53  memset(&ElfHeader, 0, sizeof(ElfHeader));54  // ELF identification.55  ElfHeader.e_ident[EI_MAG0] = ElfMagic[EI_MAG0];56  ElfHeader.e_ident[EI_MAG1] = ElfMagic[EI_MAG1];57  ElfHeader.e_ident[EI_MAG2] = ElfMagic[EI_MAG2];58  ElfHeader.e_ident[EI_MAG3] = ElfMagic[EI_MAG3];59  ElfHeader.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;60  bool IsLittleEndian = ELFT::Endianness == llvm::endianness::little;61  ElfHeader.e_ident[EI_DATA] = IsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;62  ElfHeader.e_ident[EI_VERSION] = EV_CURRENT;63  ElfHeader.e_ident[EI_OSABI] = ELFOSABI_NONE;64 65  // Remainder of ELF header.66  ElfHeader.e_type = ET_DYN;67  ElfHeader.e_machine = Machine;68  ElfHeader.e_version = EV_CURRENT;69  ElfHeader.e_ehsize = sizeof(typename ELFT::Ehdr);70  ElfHeader.e_phentsize = sizeof(typename ELFT::Phdr);71  ElfHeader.e_shentsize = sizeof(typename ELFT::Shdr);72}73 74namespace {75template <class ELFT> struct OutputSection {76  using Elf_Shdr = typename ELFT::Shdr;77  std::string Name;78  Elf_Shdr Shdr;79  uint64_t Addr;80  uint64_t Offset;81  uint64_t Size;82  uint64_t Align;83  uint32_t Index;84  bool NoBits = true;85};86 87template <class T, class ELFT>88struct ContentSection : public OutputSection<ELFT> {89  T Content;90  ContentSection() { this->NoBits = false; }91};92 93// This class just wraps StringTableBuilder for the purpose of adding a94// default constructor.95class ELFStringTableBuilder : public StringTableBuilder {96public:97  ELFStringTableBuilder() : StringTableBuilder(StringTableBuilder::ELF) {}98};99 100template <class ELFT> class ELFSymbolTableBuilder {101public:102  using Elf_Sym = typename ELFT::Sym;103 104  ELFSymbolTableBuilder() { Symbols.push_back({}); }105 106  void add(size_t StNameOffset, uint64_t StSize, uint8_t StBind, uint8_t StType,107           uint8_t StOther, uint16_t StShndx) {108    Elf_Sym S{};109    S.st_name = StNameOffset;110    S.st_size = StSize;111    S.st_info = (StBind << 4) | (StType & 0xf);112    S.st_other = StOther;113    S.st_shndx = StShndx;114    Symbols.push_back(S);115  }116 117  size_t getSize() const { return Symbols.size() * sizeof(Elf_Sym); }118 119  void write(uint8_t *Buf) const {120    memcpy(Buf, Symbols.data(), sizeof(Elf_Sym) * Symbols.size());121  }122 123private:124  llvm::SmallVector<Elf_Sym, 8> Symbols;125};126 127template <class ELFT> class ELFDynamicTableBuilder {128public:129  using Elf_Dyn = typename ELFT::Dyn;130 131  size_t addAddr(uint64_t Tag, uint64_t Addr) {132    Elf_Dyn Entry;133    Entry.d_tag = Tag;134    Entry.d_un.d_ptr = Addr;135    Entries.push_back(Entry);136    return Entries.size() - 1;137  }138 139  void modifyAddr(size_t Index, uint64_t Addr) {140    Entries[Index].d_un.d_ptr = Addr;141  }142 143  size_t addValue(uint64_t Tag, uint64_t Value) {144    Elf_Dyn Entry;145    Entry.d_tag = Tag;146    Entry.d_un.d_val = Value;147    Entries.push_back(Entry);148    return Entries.size() - 1;149  }150 151  void modifyValue(size_t Index, uint64_t Value) {152    Entries[Index].d_un.d_val = Value;153  }154 155  size_t getSize() const {156    // Add DT_NULL entry at the end.157    return (Entries.size() + 1) * sizeof(Elf_Dyn);158  }159 160  void write(uint8_t *Buf) const {161    memcpy(Buf, Entries.data(), sizeof(Elf_Dyn) * Entries.size());162    // Add DT_NULL entry at the end.163    memset(Buf + sizeof(Elf_Dyn) * Entries.size(), 0, sizeof(Elf_Dyn));164  }165 166private:167  llvm::SmallVector<Elf_Dyn, 8> Entries;168};169 170template <class ELFT> class ELFStubBuilder {171public:172  using Elf_Ehdr = typename ELFT::Ehdr;173  using Elf_Shdr = typename ELFT::Shdr;174  using Elf_Phdr = typename ELFT::Phdr;175  using Elf_Sym = typename ELFT::Sym;176  using Elf_Addr = typename ELFT::Addr;177  using Elf_Dyn = typename ELFT::Dyn;178 179  ELFStubBuilder(const ELFStubBuilder &) = delete;180  ELFStubBuilder(ELFStubBuilder &&) = default;181 182  explicit ELFStubBuilder(const IFSStub &Stub) {183    DynSym.Name = ".dynsym";184    DynSym.Align = sizeof(Elf_Addr);185    DynStr.Name = ".dynstr";186    DynStr.Align = 1;187    DynTab.Name = ".dynamic";188    DynTab.Align = sizeof(Elf_Addr);189    ShStrTab.Name = ".shstrtab";190    ShStrTab.Align = 1;191 192    // Populate string tables.193    for (const IFSSymbol &Sym : Stub.Symbols)194      DynStr.Content.add(Sym.Name);195    for (const std::string &Lib : Stub.NeededLibs)196      DynStr.Content.add(Lib);197    if (Stub.SoName)198      DynStr.Content.add(*Stub.SoName);199 200    std::vector<OutputSection<ELFT> *> Sections = {&DynSym, &DynStr, &DynTab,201                                                   &ShStrTab};202    const OutputSection<ELFT> *LastSection = Sections.back();203    // Now set the Index and put sections names into ".shstrtab".204    uint64_t Index = 1;205    for (OutputSection<ELFT> *Sec : Sections) {206      Sec->Index = Index++;207      ShStrTab.Content.add(Sec->Name);208    }209    ShStrTab.Content.finalize();210    ShStrTab.Size = ShStrTab.Content.getSize();211    DynStr.Content.finalize();212    DynStr.Size = DynStr.Content.getSize();213 214    // Populate dynamic symbol table.215    for (const IFSSymbol &Sym : Stub.Symbols) {216      uint8_t Bind = Sym.Weak ? STB_WEAK : STB_GLOBAL;217      // For non-undefined symbols, value of the shndx is not relevant at link218      // time as long as it is not SHN_UNDEF. Set shndx to 1, which219      // points to ".dynsym".220      uint16_t Shndx = Sym.Undefined ? SHN_UNDEF : 1;221      uint64_t Size = Sym.Size.value_or(0);222      DynSym.Content.add(DynStr.Content.getOffset(Sym.Name), Size, Bind,223                         convertIFSSymbolTypeToELF(Sym.Type), 0, Shndx);224    }225    DynSym.Size = DynSym.Content.getSize();226 227    // Poplulate dynamic table.228    size_t DynSymIndex = DynTab.Content.addAddr(DT_SYMTAB, 0);229    size_t DynStrIndex = DynTab.Content.addAddr(DT_STRTAB, 0);230    DynTab.Content.addValue(DT_STRSZ, DynSym.Size);231    for (const std::string &Lib : Stub.NeededLibs)232      DynTab.Content.addValue(DT_NEEDED, DynStr.Content.getOffset(Lib));233    if (Stub.SoName)234      DynTab.Content.addValue(DT_SONAME,235                              DynStr.Content.getOffset(*Stub.SoName));236    DynTab.Size = DynTab.Content.getSize();237    // Calculate sections' addresses and offsets.238    uint64_t CurrentOffset = sizeof(Elf_Ehdr);239    for (OutputSection<ELFT> *Sec : Sections) {240      Sec->Offset = alignTo(CurrentOffset, Sec->Align);241      Sec->Addr = Sec->Offset;242      CurrentOffset = Sec->Offset + Sec->Size;243    }244    // Fill Addr back to dynamic table.245    DynTab.Content.modifyAddr(DynSymIndex, DynSym.Addr);246    DynTab.Content.modifyAddr(DynStrIndex, DynStr.Addr);247    // Write section headers of string tables.248    fillSymTabShdr(DynSym, SHT_DYNSYM);249    fillStrTabShdr(DynStr, SHF_ALLOC);250    fillDynTabShdr(DynTab);251    fillStrTabShdr(ShStrTab);252 253    // Finish initializing the ELF header.254    initELFHeader<ELFT>(ElfHeader, static_cast<uint16_t>(*Stub.Target.Arch));255    ElfHeader.e_shstrndx = ShStrTab.Index;256    ElfHeader.e_shnum = LastSection->Index + 1;257    ElfHeader.e_shoff =258        alignTo(LastSection->Offset + LastSection->Size, sizeof(Elf_Addr));259  }260 261  size_t getSize() const {262    return ElfHeader.e_shoff + ElfHeader.e_shnum * sizeof(Elf_Shdr);263  }264 265  void write(uint8_t *Data) const {266    write(Data, ElfHeader);267    DynSym.Content.write(Data + DynSym.Shdr.sh_offset);268    DynStr.Content.write(Data + DynStr.Shdr.sh_offset);269    DynTab.Content.write(Data + DynTab.Shdr.sh_offset);270    ShStrTab.Content.write(Data + ShStrTab.Shdr.sh_offset);271    writeShdr(Data, DynSym);272    writeShdr(Data, DynStr);273    writeShdr(Data, DynTab);274    writeShdr(Data, ShStrTab);275  }276 277private:278  Elf_Ehdr ElfHeader;279  ContentSection<ELFStringTableBuilder, ELFT> DynStr;280  ContentSection<ELFStringTableBuilder, ELFT> ShStrTab;281  ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> DynSym;282  ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> DynTab;283 284  template <class T> static void write(uint8_t *Data, const T &Value) {285    *reinterpret_cast<T *>(Data) = Value;286  }287 288  void fillStrTabShdr(ContentSection<ELFStringTableBuilder, ELFT> &StrTab,289                      uint32_t ShFlags = 0) const {290    StrTab.Shdr.sh_type = SHT_STRTAB;291    StrTab.Shdr.sh_flags = ShFlags;292    StrTab.Shdr.sh_addr = StrTab.Addr;293    StrTab.Shdr.sh_offset = StrTab.Offset;294    StrTab.Shdr.sh_info = 0;295    StrTab.Shdr.sh_size = StrTab.Size;296    StrTab.Shdr.sh_name = ShStrTab.Content.getOffset(StrTab.Name);297    StrTab.Shdr.sh_addralign = StrTab.Align;298    StrTab.Shdr.sh_entsize = 0;299    StrTab.Shdr.sh_link = 0;300  }301  void fillSymTabShdr(ContentSection<ELFSymbolTableBuilder<ELFT>, ELFT> &SymTab,302                      uint32_t ShType) const {303    SymTab.Shdr.sh_type = ShType;304    SymTab.Shdr.sh_flags = SHF_ALLOC;305    SymTab.Shdr.sh_addr = SymTab.Addr;306    SymTab.Shdr.sh_offset = SymTab.Offset;307    // Only non-local symbols are included in the tbe file, so .dynsym only308    // contains 1 local symbol (the undefined symbol at index 0). The sh_info309    // should always be 1.310    SymTab.Shdr.sh_info = 1;311    SymTab.Shdr.sh_size = SymTab.Size;312    SymTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(SymTab.Name);313    SymTab.Shdr.sh_addralign = SymTab.Align;314    SymTab.Shdr.sh_entsize = sizeof(Elf_Sym);315    SymTab.Shdr.sh_link = this->DynStr.Index;316  }317  void fillDynTabShdr(318      ContentSection<ELFDynamicTableBuilder<ELFT>, ELFT> &DynTab) const {319    DynTab.Shdr.sh_type = SHT_DYNAMIC;320    DynTab.Shdr.sh_flags = SHF_ALLOC;321    DynTab.Shdr.sh_addr = DynTab.Addr;322    DynTab.Shdr.sh_offset = DynTab.Offset;323    DynTab.Shdr.sh_info = 0;324    DynTab.Shdr.sh_size = DynTab.Size;325    DynTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(DynTab.Name);326    DynTab.Shdr.sh_addralign = DynTab.Align;327    DynTab.Shdr.sh_entsize = sizeof(Elf_Dyn);328    DynTab.Shdr.sh_link = this->DynStr.Index;329  }330  uint64_t shdrOffset(const OutputSection<ELFT> &Sec) const {331    return ElfHeader.e_shoff + Sec.Index * sizeof(Elf_Shdr);332  }333 334  void writeShdr(uint8_t *Data, const OutputSection<ELFT> &Sec) const {335    write(Data + shdrOffset(Sec), Sec.Shdr);336  }337};338 339/// This function takes an error, and appends a string of text to the end of340/// that error. Since "appending" to an Error isn't supported behavior of an341/// Error, this function technically creates a new error with the combined342/// message and consumes the old error.343///344/// @param Err Source error.345/// @param After Text to append at the end of Err's error message.346Error appendToError(Error Err, StringRef After) {347  std::string Message;348  raw_string_ostream Stream(Message);349  Stream << Err;350  Stream << " " << After;351  consumeError(std::move(Err));352  return createError(Stream.str());353}354 355template <class ELFT> class DynSym {356  using Elf_Shdr_Range = typename ELFT::ShdrRange;357  using Elf_Shdr = typename ELFT::Shdr;358 359public:360  static Expected<DynSym> create(const ELFFile<ELFT> &ElfFile,361                                 const DynamicEntries &DynEnt) {362    Expected<Elf_Shdr_Range> Shdrs = ElfFile.sections();363    if (!Shdrs)364      return Shdrs.takeError();365    return DynSym(ElfFile, DynEnt, *Shdrs);366  }367 368  Expected<const uint8_t *> getDynSym() {369    if (DynSymHdr)370      return ElfFile.base() + DynSymHdr->sh_offset;371    return getDynamicData(DynEnt.DynSymAddr, "dynamic symbol table");372  }373 374  Expected<StringRef> getDynStr() {375    if (DynSymHdr)376      return ElfFile.getStringTableForSymtab(*DynSymHdr, Shdrs);377    Expected<const uint8_t *> DataOrErr = getDynamicData(378        DynEnt.StrTabAddr, "dynamic string table", DynEnt.StrSize);379    if (!DataOrErr)380      return DataOrErr.takeError();381    return StringRef(reinterpret_cast<const char *>(*DataOrErr),382                     DynEnt.StrSize);383  }384 385private:386  DynSym(const ELFFile<ELFT> &ElfFile, const DynamicEntries &DynEnt,387         Elf_Shdr_Range Shdrs)388      : ElfFile(ElfFile), DynEnt(DynEnt), Shdrs(Shdrs),389        DynSymHdr(findDynSymHdr()) {}390 391  const Elf_Shdr *findDynSymHdr() {392    for (const Elf_Shdr &Sec : Shdrs)393      if (Sec.sh_type == SHT_DYNSYM) {394        // If multiple .dynsym are present, use the first one.395        // This behavior aligns with llvm::object::ELFFile::getDynSymtabSize()396        return &Sec;397      }398    return nullptr;399  }400 401  Expected<const uint8_t *> getDynamicData(uint64_t EntAddr, StringRef Name,402                                           uint64_t Size = 0) {403    Expected<const uint8_t *> SecPtr = ElfFile.toMappedAddr(EntAddr);404    if (!SecPtr)405      return appendToError(406          SecPtr.takeError(),407          ("when locating " + Name + " section contents").str());408    Expected<const uint8_t *> SecEndPtr = ElfFile.toMappedAddr(EntAddr + Size);409    if (!SecEndPtr)410      return appendToError(411          SecEndPtr.takeError(),412          ("when locating " + Name + " section contents").str());413    return *SecPtr;414  }415 416  const ELFFile<ELFT> &ElfFile;417  const DynamicEntries &DynEnt;418  Elf_Shdr_Range Shdrs;419  const Elf_Shdr *DynSymHdr;420};421} // end anonymous namespace422 423/// This function behaves similarly to StringRef::substr(), but attempts to424/// terminate the returned StringRef at the first null terminator. If no null425/// terminator is found, an error is returned.426///427/// @param Str Source string to create a substring from.428/// @param Offset The start index of the desired substring.429static Expected<StringRef> terminatedSubstr(StringRef Str, size_t Offset) {430  size_t StrEnd = Str.find('\0', Offset);431  if (StrEnd == StringLiteral::npos) {432    return createError(433        "String overran bounds of string table (no null terminator)");434  }435 436  size_t StrLen = StrEnd - Offset;437  return Str.substr(Offset, StrLen);438}439 440/// This function populates a DynamicEntries struct using an ELFT::DynRange.441/// After populating the struct, the members are validated with442/// some basic correctness checks.443///444/// @param Dyn Target DynamicEntries struct to populate.445/// @param DynTable Source dynamic table.446template <class ELFT>447static Error populateDynamic(DynamicEntries &Dyn,448                             typename ELFT::DynRange DynTable) {449  if (DynTable.empty())450    return createError("No .dynamic section found");451 452  // Search .dynamic for relevant entries.453  bool FoundDynStr = false;454  bool FoundDynStrSz = false;455  bool FoundDynSym = false;456  for (auto &Entry : DynTable) {457    switch (Entry.d_tag) {458    case DT_SONAME:459      Dyn.SONameOffset = Entry.d_un.d_val;460      break;461    case DT_STRTAB:462      Dyn.StrTabAddr = Entry.d_un.d_ptr;463      FoundDynStr = true;464      break;465    case DT_STRSZ:466      Dyn.StrSize = Entry.d_un.d_val;467      FoundDynStrSz = true;468      break;469    case DT_NEEDED:470      Dyn.NeededLibNames.push_back(Entry.d_un.d_val);471      break;472    case DT_SYMTAB:473      Dyn.DynSymAddr = Entry.d_un.d_ptr;474      FoundDynSym = true;475      break;476    case DT_HASH:477      Dyn.ElfHash = Entry.d_un.d_ptr;478      break;479    case DT_GNU_HASH:480      Dyn.GnuHash = Entry.d_un.d_ptr;481    }482  }483 484  if (!FoundDynStr) {485    return createError(486        "Couldn't locate dynamic string table (no DT_STRTAB entry)");487  }488  if (!FoundDynStrSz) {489    return createError(490        "Couldn't determine dynamic string table size (no DT_STRSZ entry)");491  }492  if (!FoundDynSym) {493    return createError(494        "Couldn't locate dynamic symbol table (no DT_SYMTAB entry)");495  }496  if (Dyn.SONameOffset && *Dyn.SONameOffset >= Dyn.StrSize) {497    return createStringError(object_error::parse_failed,498                             "DT_SONAME string offset (0x%016" PRIx64499                             ") outside of dynamic string table",500                             *Dyn.SONameOffset);501  }502  for (uint64_t Offset : Dyn.NeededLibNames) {503    if (Offset >= Dyn.StrSize) {504      return createStringError(object_error::parse_failed,505                               "DT_NEEDED string offset (0x%016" PRIx64506                               ") outside of dynamic string table",507                               Offset);508    }509  }510 511  return Error::success();512}513 514/// This function creates an IFSSymbol and populates all members using515/// information from a binary ELFT::Sym.516///517/// @param SymName The desired name of the IFSSymbol.518/// @param RawSym ELFT::Sym to extract symbol information from.519template <class ELFT>520static IFSSymbol createELFSym(StringRef SymName,521                              const typename ELFT::Sym &RawSym) {522  IFSSymbol TargetSym{std::string(SymName)};523  uint8_t Binding = RawSym.getBinding();524  if (Binding == STB_WEAK)525    TargetSym.Weak = true;526  else527    TargetSym.Weak = false;528 529  TargetSym.Undefined = RawSym.isUndefined();530  TargetSym.Type = convertELFSymbolTypeToIFS(RawSym.st_info);531 532  if (TargetSym.Type == IFSSymbolType::Func) {533    TargetSym.Size = 0;534  } else {535    TargetSym.Size = RawSym.st_size;536  }537  return TargetSym;538}539 540/// This function populates an IFSStub with symbols using information read541/// from an ELF binary.542///543/// @param TargetStub IFSStub to add symbols to.544/// @param DynSym Range of dynamic symbols to add to TargetStub.545/// @param DynStr StringRef to the dynamic string table.546template <class ELFT>547static Error populateSymbols(IFSStub &TargetStub,548                             const typename ELFT::SymRange DynSym,549                             StringRef DynStr) {550  // Skips the first symbol since it's the NULL symbol.551  for (auto RawSym : DynSym.drop_front(1)) {552    // If a symbol does not have global or weak binding, ignore it.553    uint8_t Binding = RawSym.getBinding();554    if (!(Binding == STB_GLOBAL || Binding == STB_WEAK))555      continue;556    // If a symbol doesn't have default or protected visibility, ignore it.557    uint8_t Visibility = RawSym.getVisibility();558    if (!(Visibility == STV_DEFAULT || Visibility == STV_PROTECTED))559      continue;560    // Create an IFSSymbol and populate it with information from the symbol561    // table entry.562    Expected<StringRef> SymName = terminatedSubstr(DynStr, RawSym.st_name);563    if (!SymName)564      return SymName.takeError();565    IFSSymbol Sym = createELFSym<ELFT>(*SymName, RawSym);566    TargetStub.Symbols.push_back(std::move(Sym));567    // TODO: Populate symbol warning.568  }569  return Error::success();570}571 572/// Returns a new IFSStub with all members populated from an ELFObjectFile.573/// @param ElfObj Source ELFObjectFile.574template <class ELFT>575static Expected<std::unique_ptr<IFSStub>>576buildStub(const ELFObjectFile<ELFT> &ElfObj) {577  using Elf_Dyn_Range = typename ELFT::DynRange;578  using Elf_Sym_Range = typename ELFT::SymRange;579  using Elf_Sym = typename ELFT::Sym;580  std::unique_ptr<IFSStub> DestStub = std::make_unique<IFSStub>();581  const ELFFile<ELFT> &ElfFile = ElfObj.getELFFile();582  // Fetch .dynamic table.583  Expected<Elf_Dyn_Range> DynTable = ElfFile.dynamicEntries();584  if (!DynTable) {585    return DynTable.takeError();586  }587 588  // Collect relevant .dynamic entries.589  DynamicEntries DynEnt;590  if (Error Err = populateDynamic<ELFT>(DynEnt, *DynTable))591    return std::move(Err);592  Expected<DynSym<ELFT>> EDynSym = DynSym<ELFT>::create(ElfFile, DynEnt);593  if (!EDynSym)594    return EDynSym.takeError();595 596  Expected<StringRef> EDynStr = EDynSym->getDynStr();597  if (!EDynStr)598    return EDynStr.takeError();599 600  StringRef DynStr = *EDynStr;601 602  // Populate Arch from ELF header.603  DestStub->Target.Arch = static_cast<IFSArch>(ElfFile.getHeader().e_machine);604  DestStub->Target.BitWidth =605      convertELFBitWidthToIFS(ElfFile.getHeader().e_ident[EI_CLASS]);606  DestStub->Target.Endianness =607      convertELFEndiannessToIFS(ElfFile.getHeader().e_ident[EI_DATA]);608  DestStub->Target.ObjectFormat = "ELF";609 610  // Populate SoName from .dynamic entries and dynamic string table.611  if (DynEnt.SONameOffset) {612    Expected<StringRef> NameOrErr =613        terminatedSubstr(DynStr, *DynEnt.SONameOffset);614    if (!NameOrErr) {615      return appendToError(NameOrErr.takeError(), "when reading DT_SONAME");616    }617    DestStub->SoName = std::string(*NameOrErr);618  }619 620  // Populate NeededLibs from .dynamic entries and dynamic string table.621  for (uint64_t NeededStrOffset : DynEnt.NeededLibNames) {622    Expected<StringRef> LibNameOrErr =623        terminatedSubstr(DynStr, NeededStrOffset);624    if (!LibNameOrErr) {625      return appendToError(LibNameOrErr.takeError(), "when reading DT_NEEDED");626    }627    DestStub->NeededLibs.push_back(std::string(*LibNameOrErr));628  }629 630  // Populate Symbols from .dynsym table and dynamic string table.631  Expected<uint64_t> SymCount = ElfFile.getDynSymtabSize();632  if (!SymCount)633    return SymCount.takeError();634  if (*SymCount > 0) {635    // Get pointer to in-memory location of .dynsym section.636    Expected<const uint8_t *> DynSymPtr = EDynSym->getDynSym();637    if (!DynSymPtr)638      return appendToError(DynSymPtr.takeError(),639                           "when locating .dynsym section contents");640    Elf_Sym_Range DynSyms = ArrayRef<Elf_Sym>(641        reinterpret_cast<const Elf_Sym *>(*DynSymPtr), *SymCount);642    Error SymReadError = populateSymbols<ELFT>(*DestStub, DynSyms, DynStr);643    if (SymReadError)644      return appendToError(std::move(SymReadError),645                           "when reading dynamic symbols");646  }647 648  return std::move(DestStub);649}650 651/// This function opens a file for writing and then writes a binary ELF stub to652/// the file.653///654/// @param FilePath File path for writing the ELF binary.655/// @param Stub Source InterFace Stub to generate a binary ELF stub from.656template <class ELFT>657static Error writeELFBinaryToFile(StringRef FilePath, const IFSStub &Stub,658                                  bool WriteIfChanged) {659  ELFStubBuilder<ELFT> Builder{Stub};660  // Write Stub to memory first.661  std::vector<uint8_t> Buf(Builder.getSize());662  Builder.write(Buf.data());663 664  if (WriteIfChanged) {665    if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =666            MemoryBuffer::getFile(FilePath)) {667      // Compare Stub output with existing Stub file.668      // If Stub file unchanged, abort updating.669      if ((*BufOrError)->getBufferSize() == Builder.getSize() &&670          !memcmp((*BufOrError)->getBufferStart(), Buf.data(),671                  Builder.getSize()))672        return Error::success();673    }674  }675 676  Expected<std::unique_ptr<FileOutputBuffer>> BufOrError =677      FileOutputBuffer::create(FilePath, Builder.getSize());678  if (!BufOrError)679    return createStringError(errc::invalid_argument,680                             toString(BufOrError.takeError()) +681                                 " when trying to open `" + FilePath +682                                 "` for writing");683 684  // Write binary to file.685  std::unique_ptr<FileOutputBuffer> FileBuf = std::move(*BufOrError);686  memcpy(FileBuf->getBufferStart(), Buf.data(), Buf.size());687 688  return FileBuf->commit();689}690 691Expected<std::unique_ptr<IFSStub>> readELFFile(MemoryBufferRef Buf) {692  Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buf);693  if (!BinOrErr) {694    return BinOrErr.takeError();695  }696 697  Binary *Bin = BinOrErr->get();698  if (auto Obj = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {699    return buildStub(*Obj);700  } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {701    return buildStub(*Obj);702  } else if (auto Obj = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {703    return buildStub(*Obj);704  } else if (auto Obj = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {705    return buildStub(*Obj);706  }707  return createStringError(errc::not_supported, "unsupported binary format");708}709 710// This function wraps the ELFT writeELFBinaryToFile() so writeBinaryStub()711// can be called without having to use ELFType templates directly.712Error writeBinaryStub(StringRef FilePath, const IFSStub &Stub,713                      bool WriteIfChanged) {714  assert(Stub.Target.Arch);715  assert(Stub.Target.BitWidth);716  assert(Stub.Target.Endianness);717  if (Stub.Target.BitWidth == IFSBitWidthType::IFS32) {718    if (Stub.Target.Endianness == IFSEndiannessType::Little) {719      return writeELFBinaryToFile<ELF32LE>(FilePath, Stub, WriteIfChanged);720    } else {721      return writeELFBinaryToFile<ELF32BE>(FilePath, Stub, WriteIfChanged);722    }723  } else {724    if (Stub.Target.Endianness == IFSEndiannessType::Little) {725      return writeELFBinaryToFile<ELF64LE>(FilePath, Stub, WriteIfChanged);726    } else {727      return writeELFBinaryToFile<ELF64BE>(FilePath, Stub, WriteIfChanged);728    }729  }730  llvm_unreachable("invalid binary output target");731}732 733} // end namespace ifs734} // end namespace llvm735