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