#ifndef LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
#define LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#define DEBUG_TYPE "jitlink"
namespace llvm {
namespace jitlink {
class ELFLinkGraphBuilderBase {
public:
ELFLinkGraphBuilderBase(std::unique_ptr<LinkGraph> G) : G(std::move(G)) {}
virtual ~ELFLinkGraphBuilderBase();
protected:
static bool isDwarfSection(StringRef SectionName) {
return llvm::is_contained(DwarfSectionNames, SectionName);
}
Section &getCommonSection() {
if (!CommonSection)
CommonSection =
&G->createSection(CommonSectionName, MemProt::Read | MemProt::Write);
return *CommonSection;
}
std::unique_ptr<LinkGraph> G;
private:
static StringRef CommonSectionName;
static ArrayRef<const char *> DwarfSectionNames;
Section *CommonSection = nullptr;
};
template <typename ELFT>
class ELFLinkGraphBuilder : public ELFLinkGraphBuilderBase {
using ELFFile = object::ELFFile<ELFT>;
public:
ELFLinkGraphBuilder(const object::ELFFile<ELFT> &Obj, Triple TT,
StringRef FileName,
LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);
Expected<std::unique_ptr<LinkGraph>> buildGraph();
virtual Error addRelocations() = 0;
protected:
using ELFSectionIndex = unsigned;
using ELFSymbolIndex = unsigned;
bool isRelocatable() const {
return Obj.getHeader().e_type == llvm::ELF::ET_REL;
}
void setGraphBlock(ELFSectionIndex SecIndex, Block *B) {
assert(!GraphBlocks.count(SecIndex) && "Duplicate section at index");
GraphBlocks[SecIndex] = B;
}
Block *getGraphBlock(ELFSectionIndex SecIndex) {
auto I = GraphBlocks.find(SecIndex);
if (I == GraphBlocks.end())
return nullptr;
return I->second;
}
void setGraphSymbol(ELFSymbolIndex SymIndex, Symbol &Sym) {
assert(!GraphSymbols.count(SymIndex) && "Duplicate symbol at index");
GraphSymbols[SymIndex] = &Sym;
}
Symbol *getGraphSymbol(ELFSymbolIndex SymIndex) {
auto I = GraphSymbols.find(SymIndex);
if (I == GraphSymbols.end())
return nullptr;
return I->second;
}
Expected<std::pair<Linkage, Scope>>
getSymbolLinkageAndScope(const typename ELFT::Sym &Sym, StringRef Name);
Error prepare();
Error graphifySections();
Error graphifySymbols();
template <typename RelocHandlerFunction>
Error forEachRelocation(const typename ELFT::Shdr &RelSect,
RelocHandlerFunction &&Func,
bool ProcessDebugSections = false);
template <typename ClassT, typename RelocHandlerMethod>
Error forEachRelocation(const typename ELFT::Shdr &RelSect, ClassT *Instance,
RelocHandlerMethod &&Method,
bool ProcessDebugSections = false) {
return forEachRelocation(
RelSect,
[Instance, Method](const auto &Rel, const auto &Target, auto &GS) {
return (Instance->*Method)(Rel, Target, GS);
},
ProcessDebugSections);
}
const ELFFile &Obj;
typename ELFFile::Elf_Shdr_Range Sections;
const typename ELFFile::Elf_Shdr *SymTabSec = nullptr;
StringRef SectionStringTab;
DenseMap<ELFSectionIndex, Block *> GraphBlocks;
DenseMap<ELFSymbolIndex, Symbol *> GraphSymbols;
DenseMap<const typename ELFFile::Elf_Shdr *,
ArrayRef<typename ELFFile::Elf_Word>>
ShndxTables;
};
template <typename ELFT>
ELFLinkGraphBuilder<ELFT>::ELFLinkGraphBuilder(
const ELFFile &Obj, Triple TT, StringRef FileName,
LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)
: ELFLinkGraphBuilderBase(std::make_unique<LinkGraph>(
FileName.str(), Triple(std::move(TT)), ELFT::Is64Bits ? 8 : 4,
support::endianness(ELFT::TargetEndianness),
std::move(GetEdgeKindName))),
Obj(Obj) {
LLVM_DEBUG(
{ dbgs() << "Created ELFLinkGraphBuilder for \"" << FileName << "\""; });
}
template <typename ELFT>
Expected<std::unique_ptr<LinkGraph>> ELFLinkGraphBuilder<ELFT>::buildGraph() {
if (!isRelocatable())
return make_error<JITLinkError>("Object is not a relocatable ELF file");
if (auto Err = prepare())
return std::move(Err);
if (auto Err = graphifySections())
return std::move(Err);
if (auto Err = graphifySymbols())
return std::move(Err);
if (auto Err = addRelocations())
return std::move(Err);
return std::move(G);
}
template <typename ELFT>
Expected<std::pair<Linkage, Scope>>
ELFLinkGraphBuilder<ELFT>::getSymbolLinkageAndScope(
const typename ELFT::Sym &Sym, StringRef Name) {
Linkage L = Linkage::Strong;
Scope S = Scope::Default;
switch (Sym.getBinding()) {
case ELF::STB_LOCAL:
S = Scope::Local;
break;
case ELF::STB_GLOBAL:
break;
case ELF::STB_WEAK:
case ELF::STB_GNU_UNIQUE:
L = Linkage::Weak;
break;
default:
return make_error<StringError>(
"Unrecognized symbol binding " +
Twine(static_cast<int>(Sym.getBinding())) + " for " + Name,
inconvertibleErrorCode());
}
switch (Sym.getVisibility()) {
case ELF::STV_DEFAULT:
case ELF::STV_PROTECTED:
break;
case ELF::STV_HIDDEN:
if (S == Scope::Default)
S = Scope::Hidden;
break;
case ELF::STV_INTERNAL:
return make_error<StringError>(
"Unrecognized symbol visibility " +
Twine(static_cast<int>(Sym.getVisibility())) + " for " + Name,
inconvertibleErrorCode());
}
return std::make_pair(L, S);
}
template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::prepare() {
LLVM_DEBUG(dbgs() << " Preparing to build...\n");
if (auto SectionsOrErr = Obj.sections())
Sections = *SectionsOrErr;
else
return SectionsOrErr.takeError();
if (auto SectionStringTabOrErr = Obj.getSectionStringTable(Sections))
SectionStringTab = *SectionStringTabOrErr;
else
return SectionStringTabOrErr.takeError();
for (auto &Sec : Sections) {
if (Sec.sh_type == ELF::SHT_SYMTAB) {
if (!SymTabSec)
SymTabSec = &Sec;
else
return make_error<JITLinkError>("Multiple SHT_SYMTAB sections in " +
G->getName());
}
if (Sec.sh_type == ELF::SHT_SYMTAB_SHNDX) {
uint32_t SymtabNdx = Sec.sh_link;
if (SymtabNdx >= Sections.size())
return make_error<JITLinkError>("sh_link is out of bound");
auto ShndxTable = Obj.getSHNDXTable(Sec);
if (!ShndxTable)
return ShndxTable.takeError();
ShndxTables.insert({&Sections[SymtabNdx], *ShndxTable});
}
}
return Error::success();
}
template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySections() {
LLVM_DEBUG(dbgs() << " Creating graph sections...\n");
for (ELFSectionIndex SecIndex = 0; SecIndex != Sections.size(); ++SecIndex) {
auto &Sec = Sections[SecIndex];
auto Name = Obj.getSectionName(Sec, SectionStringTab);
if (!Name)
return Name.takeError();
if (isDwarfSection(*Name)) {
LLVM_DEBUG({
dbgs() << " " << SecIndex << ": \"" << *Name
<< "\" is a debug section: "
"No graph section will be created.\n";
});
continue;
}
if (!(Sec.sh_flags & ELF::SHF_ALLOC)) {
LLVM_DEBUG({
dbgs() << " " << SecIndex << ": \"" << *Name
<< "\" is not an SHF_ALLOC section: "
"No graph section will be created.\n";
});
continue;
}
LLVM_DEBUG({
dbgs() << " " << SecIndex << ": Creating section for \"" << *Name
<< "\"\n";
});
MemProt Prot;
if (Sec.sh_flags & ELF::SHF_EXECINSTR)
Prot = MemProt::Read | MemProt::Exec;
else
Prot = MemProt::Read | MemProt::Write;
auto *GraphSec = G->findSectionByName(*Name);
if (!GraphSec)
GraphSec = &G->createSection(*Name, Prot);
assert(GraphSec->getMemProt() == Prot && "MemProt should match");
Block *B = nullptr;
if (Sec.sh_type != ELF::SHT_NOBITS) {
auto Data = Obj.template getSectionContentsAsArray<char>(Sec);
if (!Data)
return Data.takeError();
B = &G->createContentBlock(*GraphSec, *Data,
orc::ExecutorAddr(Sec.sh_addr),
Sec.sh_addralign, 0);
} else
B = &G->createZeroFillBlock(*GraphSec, Sec.sh_size,
orc::ExecutorAddr(Sec.sh_addr),
Sec.sh_addralign, 0);
setGraphBlock(SecIndex, B);
}
return Error::success();
}
template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySymbols() {
LLVM_DEBUG(dbgs() << " Creating graph symbols...\n");
if (!SymTabSec)
return Error::success();
auto Symbols = Obj.symbols(SymTabSec);
if (!Symbols)
return Symbols.takeError();
auto StringTab = Obj.getStringTableForSymtab(*SymTabSec, Sections);
if (!StringTab)
return StringTab.takeError();
LLVM_DEBUG({
StringRef SymTabName;
if (auto SymTabNameOrErr = Obj.getSectionName(*SymTabSec, SectionStringTab))
SymTabName = *SymTabNameOrErr;
else {
dbgs() << "Could not get ELF SHT_SYMTAB section name for logging: "
<< toString(SymTabNameOrErr.takeError()) << "\n";
SymTabName = "<SHT_SYMTAB section with invalid name>";
}
dbgs() << " Adding symbols from symtab section \"" << SymTabName
<< "\"\n";
});
for (ELFSymbolIndex SymIndex = 0; SymIndex != Symbols->size(); ++SymIndex) {
auto &Sym = (*Symbols)[SymIndex];
switch (Sym.getType()) {
case ELF::STT_FILE:
LLVM_DEBUG({
if (auto Name = Sym.getName(*StringTab))
dbgs() << " " << SymIndex << ": Skipping STT_FILE symbol \""
<< *Name << "\"\n";
else {
dbgs() << "Could not get STT_FILE symbol name: "
<< toString(Name.takeError()) << "\n";
dbgs() << " " << SymIndex
<< ": Skipping STT_FILE symbol with invalid name\n";
}
});
continue;
break;
}
auto Name = Sym.getName(*StringTab);
if (!Name)
return Name.takeError();
if (Sym.isCommon()) {
Symbol &GSym = G->addCommonSymbol(*Name, Scope::Default,
getCommonSection(), orc::ExecutorAddr(),
Sym.st_size, Sym.getValue(), false);
setGraphSymbol(SymIndex, GSym);
continue;
}
Linkage L;
Scope S;
if (auto LSOrErr = getSymbolLinkageAndScope(Sym, *Name))
std::tie(L, S) = *LSOrErr;
else
return LSOrErr.takeError();
if (Sym.isDefined() &&
(Sym.getType() == ELF::STT_NOTYPE || Sym.getType() == ELF::STT_FUNC ||
Sym.getType() == ELF::STT_OBJECT ||
Sym.getType() == ELF::STT_SECTION || Sym.getType() == ELF::STT_TLS)) {
unsigned Shndx = Sym.st_shndx;
if (Shndx == ELF::SHN_XINDEX) {
auto ShndxTable = ShndxTables.find(SymTabSec);
if (ShndxTable == ShndxTables.end())
continue;
auto NdxOrErr = object::getExtendedSymbolTableIndex<ELFT>(
Sym, SymIndex, ShndxTable->second);
if (!NdxOrErr)
return NdxOrErr.takeError();
Shndx = *NdxOrErr;
}
if (auto *B = getGraphBlock(Shndx)) {
LLVM_DEBUG({
dbgs() << " " << SymIndex
<< ": Creating defined graph symbol for ELF symbol \"" << *Name
<< "\"\n";
});
auto &GSym =
Name->empty()
? G->addAnonymousSymbol(*B, Sym.getValue(), Sym.st_size,
false, false)
: G->addDefinedSymbol(*B, Sym.getValue(), *Name, Sym.st_size, L,
S, Sym.getType() == ELF::STT_FUNC, false);
setGraphSymbol(SymIndex, GSym);
}
} else if (Sym.isUndefined() && Sym.isExternal()) {
LLVM_DEBUG({
dbgs() << " " << SymIndex
<< ": Creating external graph symbol for ELF symbol \"" << *Name
<< "\"\n";
});
auto &GSym = G->addExternalSymbol(*Name, Sym.st_size, L);
setGraphSymbol(SymIndex, GSym);
} else {
LLVM_DEBUG({
dbgs() << " " << SymIndex
<< ": Not creating graph symbol for ELF symbol \"" << *Name
<< "\" with unrecognized type\n";
});
}
}
return Error::success();
}
template <typename ELFT>
template <typename RelocHandlerFunction>
Error ELFLinkGraphBuilder<ELFT>::forEachRelocation(
const typename ELFT::Shdr &RelSect, RelocHandlerFunction &&Func,
bool ProcessDebugSections) {
if (RelSect.sh_type != ELF::SHT_RELA && RelSect.sh_type != ELF::SHT_REL)
return Error::success();
auto FixupSection = Obj.getSection(RelSect.sh_info);
if (!FixupSection)
return FixupSection.takeError();
Expected<StringRef> Name = Obj.getSectionName(**FixupSection);
if (!Name)
return Name.takeError();
LLVM_DEBUG(dbgs() << " " << *Name << ":\n");
if (!ProcessDebugSections && isDwarfSection(*Name)) {
LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n");
return Error::success();
}
auto *BlockToFix = getGraphBlock(RelSect.sh_info);
if (!BlockToFix)
return make_error<StringError>(
"Refencing a section that wasn't added to the graph: " + *Name,
inconvertibleErrorCode());
auto RelEntries = Obj.relas(RelSect);
if (!RelEntries)
return RelEntries.takeError();
for (const typename ELFT::Rela &R : *RelEntries)
if (Error Err = Func(R, **FixupSection, *BlockToFix))
return Err;
LLVM_DEBUG(dbgs() << "\n");
return Error::success();
}
} }
#undef DEBUG_TYPE
#endif