write(Data + shdrOffset(Sec), Sec.Shdr);
}
};
+
+/// This function takes an error, and appends a string of text to the end of
+/// that error. Since "appending" to an Error isn't supported behavior of an
+/// Error, this function technically creates a new error with the combined
+/// message and consumes the old error.
+///
+/// @param Err Source error.
+/// @param After Text to append at the end of Err's error message.
+Error appendToError(Error Err, StringRef After) {
+ std::string Message;
+ raw_string_ostream Stream(Message);
+ Stream << Err;
+ Stream << " " << After;
+ consumeError(std::move(Err));
+ return createError(Stream.str());
+}
+
+template <class ELFT> class DynSym {
+ using Elf_Shdr_Range = typename ELFT::ShdrRange;
+ using Elf_Shdr = typename ELFT::Shdr;
+
+public:
+ static Expected<DynSym> create(const ELFFile<ELFT> &ElfFile,
+ const DynamicEntries &DynEnt) {
+ Expected<Elf_Shdr_Range> Shdrs = ElfFile.sections();
+ if (!Shdrs)
+ return Shdrs.takeError();
+ return DynSym(ElfFile, DynEnt, *Shdrs);
+ }
+
+ Expected<const uint8_t *> getDynSym() {
+ if (DynSymHdr)
+ return ElfFile.base() + DynSymHdr->sh_offset;
+ return getDynamicData(DynEnt.DynSymAddr, "dynamic symbol table");
+ }
+
+ Expected<StringRef> getDynStr() {
+ if (DynSymHdr)
+ return ElfFile.getStringTableForSymtab(*DynSymHdr, Shdrs);
+ Expected<const uint8_t *> DataOrErr = getDynamicData(
+ DynEnt.StrTabAddr, "dynamic string table", DynEnt.StrSize);
+ if (!DataOrErr)
+ return DataOrErr.takeError();
+ return StringRef(reinterpret_cast<const char *>(*DataOrErr),
+ DynEnt.StrSize);
+ }
+
+private:
+ DynSym(const ELFFile<ELFT> &ElfFile, const DynamicEntries &DynEnt,
+ Elf_Shdr_Range Shdrs)
+ : ElfFile(ElfFile), DynEnt(DynEnt), Shdrs(Shdrs),
+ DynSymHdr(findDynSymHdr()) {}
+
+ const Elf_Shdr *findDynSymHdr() {
+ for (const Elf_Shdr &Sec : Shdrs)
+ if (Sec.sh_type == SHT_DYNSYM) {
+ // If multiple .dynsym are present, use the first one.
+ // This behavior aligns with llvm::object::ELFFile::getDynSymtabSize()
+ return &Sec;
+ }
+ return nullptr;
+ }
+
+ Expected<const uint8_t *> getDynamicData(uint64_t EntAddr, StringRef Name,
+ uint64_t Size = 0) {
+ Expected<const uint8_t *> SecPtr = ElfFile.toMappedAddr(EntAddr);
+ if (!SecPtr)
+ return appendToError(
+ SecPtr.takeError(),
+ ("when locating " + Name + " section contents").str());
+ Expected<const uint8_t *> SecEndPtr = ElfFile.toMappedAddr(EntAddr + Size);
+ if (!SecEndPtr)
+ return appendToError(
+ SecEndPtr.takeError(),
+ ("when locating " + Name + " section contents").str());
+ return *SecPtr;
+ }
+
+ const ELFFile<ELFT> &ElfFile;
+ const DynamicEntries &DynEnt;
+ Elf_Shdr_Range Shdrs;
+ const Elf_Shdr *DynSymHdr;
+};
} // end anonymous namespace
/// This function behaves similarly to StringRef::substr(), but attempts to
return Str.substr(Offset, StrLen);
}
-/// This function takes an error, and appends a string of text to the end of
-/// that error. Since "appending" to an Error isn't supported behavior of an
-/// Error, this function technically creates a new error with the combined
-/// message and consumes the old error.
-///
-/// @param Err Source error.
-/// @param After Text to append at the end of Err's error message.
-Error appendToError(Error Err, StringRef After) {
- std::string Message;
- raw_string_ostream Stream(Message);
- Stream << Err;
- Stream << " " << After;
- consumeError(std::move(Err));
- return createError(Stream.str());
-}
-
/// This function populates a DynamicEntries struct using an ELFT::DynRange.
/// After populating the struct, the members are validated with
/// some basic correctness checks.
static Expected<std::unique_ptr<IFSStub>>
buildStub(const ELFObjectFile<ELFT> &ElfObj) {
using Elf_Dyn_Range = typename ELFT::DynRange;
- using Elf_Phdr_Range = typename ELFT::PhdrRange;
using Elf_Sym_Range = typename ELFT::SymRange;
using Elf_Sym = typename ELFT::Sym;
std::unique_ptr<IFSStub> DestStub = std::make_unique<IFSStub>();
return DynTable.takeError();
}
- // Fetch program headers.
- Expected<Elf_Phdr_Range> PHdrs = ElfFile.program_headers();
- if (!PHdrs) {
- return PHdrs.takeError();
- }
-
// Collect relevant .dynamic entries.
DynamicEntries DynEnt;
if (Error Err = populateDynamic<ELFT>(DynEnt, *DynTable))
return std::move(Err);
+ Expected<DynSym<ELFT>> EDynSym = DynSym<ELFT>::create(ElfFile, DynEnt);
+ if (!EDynSym)
+ return EDynSym.takeError();
- // Get pointer to in-memory location of .dynstr section.
- Expected<const uint8_t *> DynStrPtr = ElfFile.toMappedAddr(DynEnt.StrTabAddr);
- if (!DynStrPtr)
- return appendToError(DynStrPtr.takeError(),
- "when locating .dynstr section contents");
+ Expected<StringRef> EDynStr = EDynSym->getDynStr();
+ if (!EDynStr)
+ return EDynStr.takeError();
- StringRef DynStr(reinterpret_cast<const char *>(DynStrPtr.get()),
- DynEnt.StrSize);
+ StringRef DynStr = *EDynStr;
// Populate Arch from ELF header.
DestStub->Target.Arch = static_cast<IFSArch>(ElfFile.getHeader().e_machine);
return SymCount.takeError();
if (*SymCount > 0) {
// Get pointer to in-memory location of .dynsym section.
- Expected<const uint8_t *> DynSymPtr =
- ElfFile.toMappedAddr(DynEnt.DynSymAddr);
+ Expected<const uint8_t *> DynSymPtr = EDynSym->getDynSym();
if (!DynSymPtr)
return appendToError(DynSymPtr.takeError(),
"when locating .dynsym section contents");