forked from OSchip/llvm-project
[RuntimeDyld] Decouple RuntimeDyldChecker from RuntimeDyld.
This will allow RuntimeDyldChecker (and rtdyld-check tests) to test a new JIT linker: JITLink (https://reviews.llvm.org/D58704). llvm-svn: 357947
This commit is contained in:
parent
fecbf5918b
commit
941f247d30
|
@ -52,18 +52,20 @@ private:
|
|||
std::string ErrMsg;
|
||||
};
|
||||
|
||||
class RuntimeDyldCheckerImpl;
|
||||
class RuntimeDyldImpl;
|
||||
|
||||
class RuntimeDyld {
|
||||
friend class RuntimeDyldCheckerImpl;
|
||||
|
||||
protected:
|
||||
// Change the address associated with a section when resolving relocations.
|
||||
// Any relocations already associated with the symbol will be re-resolved.
|
||||
void reassignSectionAddress(unsigned SectionID, uint64_t Addr);
|
||||
|
||||
public:
|
||||
|
||||
using NotifyStubEmittedFunction =
|
||||
std::function<void(StringRef FileName, StringRef SectionName,
|
||||
StringRef SymbolName, uint32_t StubOffset)>;
|
||||
|
||||
/// Information about the loaded object.
|
||||
class LoadedObjectInfo : public llvm::LoadedObjectInfo {
|
||||
friend class RuntimeDyldImpl;
|
||||
|
@ -184,6 +186,9 @@ public:
|
|||
/// and resolve relocatons based on where they put it).
|
||||
void *getSymbolLocalAddress(StringRef Name) const;
|
||||
|
||||
/// Get the section ID for the section containing the given symbol.
|
||||
unsigned getSymbolSectionID(StringRef Name) const;
|
||||
|
||||
/// Get the target address and flags for the named symbol.
|
||||
/// This address is the one used for relocation.
|
||||
JITEvaluatedSymbol getSymbol(StringRef Name) const;
|
||||
|
@ -204,6 +209,19 @@ public:
|
|||
/// This is the address which will be used for relocation resolution.
|
||||
void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress);
|
||||
|
||||
/// Returns the section's working memory.
|
||||
StringRef getSectionContent(unsigned SectionID) const;
|
||||
|
||||
/// If the section was loaded, return the section's load address,
|
||||
/// otherwise return None.
|
||||
uint64_t getSectionLoadAddress(unsigned SectionID) const;
|
||||
|
||||
/// Set the NotifyStubEmitted callback. This is used for debugging
|
||||
/// purposes. A callback is made for each stub that is generated.
|
||||
void setNotifyStubEmitted(NotifyStubEmittedFunction NotifyStubEmitted) {
|
||||
this->NotifyStubEmitted = std::move(NotifyStubEmitted);
|
||||
}
|
||||
|
||||
/// Register any EH frame sections that have been loaded but not previously
|
||||
/// registered with the memory manager. Note, RuntimeDyld is responsible
|
||||
/// for identifying the EH frame and calling the memory manager with the
|
||||
|
@ -265,7 +283,7 @@ private:
|
|||
MemoryManager &MemMgr;
|
||||
JITSymbolResolver &Resolver;
|
||||
bool ProcessAllSections;
|
||||
RuntimeDyldCheckerImpl *Checker;
|
||||
NotifyStubEmittedFunction NotifyStubEmitted;
|
||||
};
|
||||
|
||||
// Asynchronous JIT link for ORC.
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
#ifndef LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H
|
||||
#define LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
@ -69,16 +72,34 @@ class raw_ostream;
|
|||
///
|
||||
class RuntimeDyldChecker {
|
||||
public:
|
||||
RuntimeDyldChecker(RuntimeDyld &RTDyld, MCDisassembler *Disassembler,
|
||||
|
||||
using IsSymbolValidFunction = std::function<bool(StringRef Symbol)>;
|
||||
using GetSymbolAddressFunction =
|
||||
std::function<Expected<JITTargetAddress>(StringRef Symbol)>;
|
||||
using GetSymbolContentFunction =
|
||||
std::function<Expected<StringRef>(StringRef Symbol)>;
|
||||
using GetSectionLoadAddressFunction =
|
||||
std::function<Optional<JITTargetAddress>(StringRef FileName,
|
||||
StringRef SectionName)>;
|
||||
using GetSectionContentFunction =
|
||||
std::function<Expected<StringRef>(StringRef FileName,
|
||||
StringRef SectionName)>;
|
||||
using GetStubOffsetInSectionFunction =
|
||||
std::function<Expected<uint32_t>(StringRef FileName,
|
||||
StringRef SectionName,
|
||||
StringRef SymbolName)>;
|
||||
|
||||
RuntimeDyldChecker(IsSymbolValidFunction IsSymbolValid,
|
||||
GetSymbolAddressFunction GetSymbolAddress,
|
||||
GetSymbolContentFunction GetSymbolContent,
|
||||
GetSectionLoadAddressFunction GetSectionLoadAddresss,
|
||||
GetSectionContentFunction GetSectionContent,
|
||||
GetStubOffsetInSectionFunction GetStubOffsetInSection,
|
||||
support::endianness Endianness,
|
||||
MCDisassembler *Disassembler,
|
||||
MCInstPrinter *InstPrinter, raw_ostream &ErrStream);
|
||||
~RuntimeDyldChecker();
|
||||
|
||||
// Get the associated RTDyld instance.
|
||||
RuntimeDyld& getRTDyld();
|
||||
|
||||
// Get the associated RTDyld instance.
|
||||
const RuntimeDyld& getRTDyld() const;
|
||||
|
||||
/// Check a single expression against the attached RuntimeDyld
|
||||
/// instance.
|
||||
bool check(StringRef CheckExpr) const;
|
||||
|
@ -99,7 +120,7 @@ public:
|
|||
bool LocalAddress);
|
||||
|
||||
/// If there is a section at the given local address, return its load
|
||||
/// address, otherwise return none.
|
||||
/// address, otherwise return none.
|
||||
Optional<uint64_t> getSectionLoadAddress(void *LocalAddress) const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
||||
#include "RuntimeDyldCOFF.h"
|
||||
#include "RuntimeDyldCheckerImpl.h"
|
||||
#include "RuntimeDyldELF.h"
|
||||
#include "RuntimeDyldImpl.h"
|
||||
#include "RuntimeDyldMachO.h"
|
||||
|
@ -375,10 +374,34 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
|
|||
else
|
||||
return IOrErr.takeError();
|
||||
|
||||
// If there is an attached checker, notify it about the stubs for this
|
||||
// section so that they can be verified.
|
||||
if (Checker)
|
||||
Checker->registerStubMap(Obj.getFileName(), SectionID, Stubs);
|
||||
// If there is a NotifyStubEmitted callback set, call it to register any
|
||||
// stubs created for this section.
|
||||
if (NotifyStubEmitted) {
|
||||
StringRef FileName = Obj.getFileName();
|
||||
StringRef SectionName = Sections[SectionID].getName();
|
||||
for (auto &KV : Stubs) {
|
||||
|
||||
auto &VR = KV.first;
|
||||
uint64_t StubAddr = KV.second;
|
||||
|
||||
// If this is a named stub, just call NotifyStubEmitted.
|
||||
if (VR.SymbolName) {
|
||||
NotifyStubEmitted(FileName, SectionName, VR.SymbolName, StubAddr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise we will have to try a reverse lookup on the globla symbol table.
|
||||
for (auto &GSTMapEntry : GlobalSymbolTable) {
|
||||
StringRef SymbolName = GSTMapEntry.first();
|
||||
auto &GSTEntry = GSTMapEntry.second;
|
||||
if (GSTEntry.getSectionID() == VR.SectionID &&
|
||||
GSTEntry.getOffset() == VR.Offset) {
|
||||
NotifyStubEmitted(FileName, SectionName, SymbolName, StubAddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process remaining sections
|
||||
|
@ -721,9 +744,6 @@ Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj,
|
|||
Addr += Size;
|
||||
}
|
||||
|
||||
if (Checker)
|
||||
Checker->registerSection(Obj.getFileName(), SectionID);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
|
@ -840,9 +860,6 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj,
|
|||
if (!IsRequired)
|
||||
Sections.back().setLoadAddress(0);
|
||||
|
||||
if (Checker)
|
||||
Checker->registerSection(Obj.getFileName(), SectionID);
|
||||
|
||||
return SectionID;
|
||||
}
|
||||
|
||||
|
@ -1225,42 +1242,43 @@ RuntimeDyld::RuntimeDyld(RuntimeDyld::MemoryManager &MemMgr,
|
|||
// permissions are applied.
|
||||
Dyld = nullptr;
|
||||
ProcessAllSections = false;
|
||||
Checker = nullptr;
|
||||
}
|
||||
|
||||
RuntimeDyld::~RuntimeDyld() {}
|
||||
|
||||
static std::unique_ptr<RuntimeDyldCOFF>
|
||||
createRuntimeDyldCOFF(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver, bool ProcessAllSections,
|
||||
RuntimeDyldCheckerImpl *Checker) {
|
||||
createRuntimeDyldCOFF(
|
||||
Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver, bool ProcessAllSections,
|
||||
RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) {
|
||||
std::unique_ptr<RuntimeDyldCOFF> Dyld =
|
||||
RuntimeDyldCOFF::create(Arch, MM, Resolver);
|
||||
Dyld->setProcessAllSections(ProcessAllSections);
|
||||
Dyld->setRuntimeDyldChecker(Checker);
|
||||
Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted));
|
||||
return Dyld;
|
||||
}
|
||||
|
||||
static std::unique_ptr<RuntimeDyldELF>
|
||||
createRuntimeDyldELF(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver, bool ProcessAllSections,
|
||||
RuntimeDyldCheckerImpl *Checker) {
|
||||
RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) {
|
||||
std::unique_ptr<RuntimeDyldELF> Dyld =
|
||||
RuntimeDyldELF::create(Arch, MM, Resolver);
|
||||
Dyld->setProcessAllSections(ProcessAllSections);
|
||||
Dyld->setRuntimeDyldChecker(Checker);
|
||||
Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted));
|
||||
return Dyld;
|
||||
}
|
||||
|
||||
static std::unique_ptr<RuntimeDyldMachO>
|
||||
createRuntimeDyldMachO(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver,
|
||||
bool ProcessAllSections,
|
||||
RuntimeDyldCheckerImpl *Checker) {
|
||||
createRuntimeDyldMachO(
|
||||
Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM,
|
||||
JITSymbolResolver &Resolver,
|
||||
bool ProcessAllSections,
|
||||
RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) {
|
||||
std::unique_ptr<RuntimeDyldMachO> Dyld =
|
||||
RuntimeDyldMachO::create(Arch, MM, Resolver);
|
||||
Dyld->setProcessAllSections(ProcessAllSections);
|
||||
Dyld->setRuntimeDyldChecker(Checker);
|
||||
Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted));
|
||||
return Dyld;
|
||||
}
|
||||
|
||||
|
@ -1270,15 +1288,16 @@ RuntimeDyld::loadObject(const ObjectFile &Obj) {
|
|||
if (Obj.isELF())
|
||||
Dyld =
|
||||
createRuntimeDyldELF(static_cast<Triple::ArchType>(Obj.getArch()),
|
||||
MemMgr, Resolver, ProcessAllSections, Checker);
|
||||
MemMgr, Resolver, ProcessAllSections,
|
||||
std::move(NotifyStubEmitted));
|
||||
else if (Obj.isMachO())
|
||||
Dyld = createRuntimeDyldMachO(
|
||||
static_cast<Triple::ArchType>(Obj.getArch()), MemMgr, Resolver,
|
||||
ProcessAllSections, Checker);
|
||||
ProcessAllSections, std::move(NotifyStubEmitted));
|
||||
else if (Obj.isCOFF())
|
||||
Dyld = createRuntimeDyldCOFF(
|
||||
static_cast<Triple::ArchType>(Obj.getArch()), MemMgr, Resolver,
|
||||
ProcessAllSections, Checker);
|
||||
ProcessAllSections, std::move(NotifyStubEmitted));
|
||||
else
|
||||
report_fatal_error("Incompatible object format!");
|
||||
}
|
||||
|
@ -1297,6 +1316,11 @@ void *RuntimeDyld::getSymbolLocalAddress(StringRef Name) const {
|
|||
return Dyld->getSymbolLocalAddress(Name);
|
||||
}
|
||||
|
||||
unsigned RuntimeDyld::getSymbolSectionID(StringRef Name) const {
|
||||
assert(Dyld && "No RuntimeDyld instance attached");
|
||||
return Dyld->getSymbolSectionID(Name);
|
||||
}
|
||||
|
||||
JITEvaluatedSymbol RuntimeDyld::getSymbol(StringRef Name) const {
|
||||
if (!Dyld)
|
||||
return nullptr;
|
||||
|
@ -1335,6 +1359,16 @@ void RuntimeDyld::finalizeWithMemoryManagerLocking() {
|
|||
}
|
||||
}
|
||||
|
||||
StringRef RuntimeDyld::getSectionContent(unsigned SectionID) const {
|
||||
assert(Dyld && "No Dyld instance attached");
|
||||
return Dyld->getSectionContent(SectionID);
|
||||
}
|
||||
|
||||
uint64_t RuntimeDyld::getSectionLoadAddress(unsigned SectionID) const {
|
||||
assert(Dyld && "No Dyld instance attached");
|
||||
return Dyld->getSectionLoadAddress(SectionID);
|
||||
}
|
||||
|
||||
void RuntimeDyld::registerEHFrames() {
|
||||
if (Dyld)
|
||||
Dyld->registerEHFrames();
|
||||
|
|
|
@ -8,15 +8,14 @@
|
|||
|
||||
#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
|
||||
#include "RuntimeDyldCheckerImpl.h"
|
||||
#include "RuntimeDyldImpl.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/MSVCErrorWorkarounds.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <cctype>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
|
@ -665,25 +664,36 @@ private:
|
|||
|
||||
bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const {
|
||||
MCDisassembler *Dis = Checker.Disassembler;
|
||||
StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol);
|
||||
ArrayRef<uint8_t> SectionBytes(SectionMem.bytes_begin(), SectionMem.size());
|
||||
StringRef SymbolMem = Checker.getSymbolContent(Symbol);
|
||||
ArrayRef<uint8_t> SymbolBytes(SymbolMem.bytes_begin(), SymbolMem.size());
|
||||
|
||||
MCDisassembler::DecodeStatus S =
|
||||
Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls());
|
||||
Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls(), nulls());
|
||||
|
||||
return (S == MCDisassembler::Success);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld,
|
||||
MCDisassembler *Disassembler,
|
||||
MCInstPrinter *InstPrinter,
|
||||
raw_ostream &ErrStream)
|
||||
: RTDyld(RTDyld), Disassembler(Disassembler), InstPrinter(InstPrinter),
|
||||
ErrStream(ErrStream) {
|
||||
RTDyld.Checker = this;
|
||||
}
|
||||
RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(
|
||||
IsSymbolValidFunction IsSymbolValid,
|
||||
GetSymbolAddressFunction GetSymbolAddress,
|
||||
GetSymbolContentFunction GetSymbolContent,
|
||||
GetSectionLoadAddressFunction GetSectionLoadAddress,
|
||||
GetSectionContentFunction GetSectionContent,
|
||||
GetStubOffsetInSectionFunction GetStubOffsetInSection,
|
||||
support::endianness Endianness,
|
||||
MCDisassembler *Disassembler,
|
||||
MCInstPrinter *InstPrinter,
|
||||
raw_ostream &ErrStream)
|
||||
: IsSymbolValid(std::move(IsSymbolValid)),
|
||||
GetSymbolAddress(std::move(GetSymbolAddress)),
|
||||
GetSymbolContent(std::move(GetSymbolContent)),
|
||||
GetSectionLoadAddress(std::move(GetSectionLoadAddress)),
|
||||
GetSectionContent(std::move(GetSectionContent)),
|
||||
GetStubOffsetInSection(std::move(GetStubOffsetInSection)),
|
||||
Endianness(Endianness), Disassembler(Disassembler),
|
||||
InstPrinter(InstPrinter), ErrStream(ErrStream) {}
|
||||
|
||||
bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const {
|
||||
CheckExpr = CheckExpr.trim();
|
||||
|
@ -728,243 +738,133 @@ bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix,
|
|||
return DidAllTestsPass && (NumRules != 0);
|
||||
}
|
||||
|
||||
Expected<JITSymbolResolver::LookupResult> RuntimeDyldCheckerImpl::lookup(
|
||||
const JITSymbolResolver::LookupSet &Symbols) const {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
using ExpectedLookupResult = MSVCPExpected<JITSymbolResolver::LookupResult>;
|
||||
#else
|
||||
using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>;
|
||||
#endif
|
||||
|
||||
auto ResultP = std::make_shared<std::promise<ExpectedLookupResult>>();
|
||||
auto ResultF = ResultP->get_future();
|
||||
|
||||
getRTDyld().Resolver.lookup(
|
||||
Symbols, [=](Expected<JITSymbolResolver::LookupResult> Result) {
|
||||
ResultP->set_value(std::move(Result));
|
||||
});
|
||||
return ResultF.get();
|
||||
}
|
||||
|
||||
bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const {
|
||||
if (getRTDyld().getSymbol(Symbol))
|
||||
return true;
|
||||
auto Result = lookup({Symbol});
|
||||
|
||||
if (!Result) {
|
||||
logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(Result->count(Symbol) && "Missing symbol result");
|
||||
return true;
|
||||
return IsSymbolValid(Symbol);
|
||||
}
|
||||
|
||||
uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const {
|
||||
return static_cast<uint64_t>(
|
||||
reinterpret_cast<uintptr_t>(getRTDyld().getSymbolLocalAddress(Symbol)));
|
||||
auto Contents = GetSymbolContent(Symbol);
|
||||
if (!Contents) {
|
||||
logAllUnhandledErrors(Contents.takeError(), errs(), "RTDyldChecker: ");
|
||||
return 0;
|
||||
}
|
||||
return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Contents->data()));
|
||||
}
|
||||
|
||||
uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const {
|
||||
if (auto InternalSymbol = getRTDyld().getSymbol(Symbol))
|
||||
return InternalSymbol.getAddress();
|
||||
|
||||
auto Result = lookup({Symbol});
|
||||
if (!Result) {
|
||||
logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: ");
|
||||
auto Addr = GetSymbolAddress(Symbol);
|
||||
if (!Addr) {
|
||||
logAllUnhandledErrors(Addr.takeError(), errs(), "RTDyldChecker: ");
|
||||
return 0;
|
||||
}
|
||||
auto I = Result->find(Symbol);
|
||||
assert(I != Result->end() && "Missing symbol result");
|
||||
return I->second.getAddress();
|
||||
|
||||
return *Addr;
|
||||
}
|
||||
|
||||
uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr,
|
||||
unsigned Size) const {
|
||||
uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr);
|
||||
assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range.");
|
||||
uint8_t *Src = reinterpret_cast<uint8_t*>(PtrSizedAddr);
|
||||
return getRTDyld().readBytesUnaligned(Src, Size);
|
||||
void *Ptr = reinterpret_cast<void*>(PtrSizedAddr);
|
||||
|
||||
switch (Size) {
|
||||
case 1:
|
||||
return support::endian::read<uint8_t>(Ptr, Endianness);
|
||||
case 2:
|
||||
return support::endian::read<uint16_t>(Ptr, Endianness);
|
||||
case 4:
|
||||
return support::endian::read<uint32_t>(Ptr, Endianness);
|
||||
case 8:
|
||||
return support::endian::read<uint64_t>(Ptr, Endianness);
|
||||
}
|
||||
llvm_unreachable("Unsupported read size");
|
||||
}
|
||||
|
||||
|
||||
std::pair<const RuntimeDyldCheckerImpl::SectionAddressInfo*, std::string>
|
||||
RuntimeDyldCheckerImpl::findSectionAddrInfo(StringRef FileName,
|
||||
StringRef SectionName) const {
|
||||
|
||||
auto SectionMapItr = Stubs.find(FileName);
|
||||
if (SectionMapItr == Stubs.end()) {
|
||||
std::string ErrorMsg = "File '";
|
||||
ErrorMsg += FileName;
|
||||
ErrorMsg += "' not found. ";
|
||||
if (Stubs.empty())
|
||||
ErrorMsg += "No stubs registered.";
|
||||
else {
|
||||
ErrorMsg += "Available files are:";
|
||||
for (const auto& StubEntry : Stubs) {
|
||||
ErrorMsg += " '";
|
||||
ErrorMsg += StubEntry.first;
|
||||
ErrorMsg += "'";
|
||||
}
|
||||
}
|
||||
ErrorMsg += "\n";
|
||||
return std::make_pair(nullptr, ErrorMsg);
|
||||
StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const {
|
||||
auto Content = GetSymbolContent(Symbol);
|
||||
if (!Content) {
|
||||
logAllUnhandledErrors(Content.takeError(), errs(), "RTDyldChecker: ");
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
auto SectionInfoItr = SectionMapItr->second.find(SectionName);
|
||||
if (SectionInfoItr == SectionMapItr->second.end())
|
||||
return std::make_pair(nullptr,
|
||||
("Section '" + SectionName + "' not found in file '" +
|
||||
FileName + "'\n").str());
|
||||
|
||||
return std::make_pair(&SectionInfoItr->second, std::string(""));
|
||||
return *Content;
|
||||
}
|
||||
|
||||
std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr(
|
||||
StringRef FileName, StringRef SectionName, bool IsInsideLoad) const {
|
||||
|
||||
const SectionAddressInfo *SectionInfo = nullptr;
|
||||
{
|
||||
std::string ErrorMsg;
|
||||
std::tie(SectionInfo, ErrorMsg) =
|
||||
findSectionAddrInfo(FileName, SectionName);
|
||||
if (ErrorMsg != "")
|
||||
return std::make_pair(0, ErrorMsg);
|
||||
uint64_t Addr = 0;
|
||||
std::string ErrMsg;
|
||||
|
||||
// If this address is being looked up in "load" mode, return the content
|
||||
// pointer.
|
||||
if (IsInsideLoad) {
|
||||
if (auto Content = GetSectionContent(FileName, SectionName))
|
||||
Addr = pointerToJITTargetAddress(Content->data());
|
||||
else {
|
||||
raw_string_ostream ErrMsgStream(ErrMsg);
|
||||
logAllUnhandledErrors(Content.takeError(), ErrMsgStream,
|
||||
"RTDyldChecker: ");
|
||||
}
|
||||
return std::make_pair(Addr, std::move(ErrMsg));
|
||||
}
|
||||
|
||||
unsigned SectionID = SectionInfo->SectionID;
|
||||
uint64_t Addr;
|
||||
if (IsInsideLoad)
|
||||
Addr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(
|
||||
getRTDyld().Sections[SectionID].getAddress()));
|
||||
// ... otherwise return the target pointer.
|
||||
if (auto LoadAddr = GetSectionLoadAddress(FileName, SectionName))
|
||||
Addr = *LoadAddr;
|
||||
else
|
||||
Addr = getRTDyld().Sections[SectionID].getLoadAddress();
|
||||
return std::make_pair(Addr, ("Section (" + FileName + ", " +
|
||||
SectionName + ") does not exist").str());
|
||||
|
||||
return std::make_pair(Addr, std::string(""));
|
||||
return std::make_pair(Addr, std::move(ErrMsg));
|
||||
}
|
||||
|
||||
std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubAddrFor(
|
||||
StringRef FileName, StringRef SectionName, StringRef SymbolName,
|
||||
bool IsInsideLoad) const {
|
||||
|
||||
const SectionAddressInfo *SectionInfo = nullptr;
|
||||
{
|
||||
std::string ErrorMsg;
|
||||
std::tie(SectionInfo, ErrorMsg) =
|
||||
findSectionAddrInfo(FileName, SectionName);
|
||||
if (ErrorMsg != "")
|
||||
return std::make_pair(0, ErrorMsg);
|
||||
}
|
||||
auto SectionAddr = getSectionAddr(FileName, SectionName, IsInsideLoad);
|
||||
|
||||
unsigned SectionID = SectionInfo->SectionID;
|
||||
const StubOffsetsMap &SymbolStubs = SectionInfo->StubOffsets;
|
||||
auto StubOffsetItr = SymbolStubs.find(SymbolName);
|
||||
if (StubOffsetItr == SymbolStubs.end())
|
||||
return std::make_pair(0,
|
||||
("Stub for symbol '" + SymbolName + "' not found. "
|
||||
"If '" + SymbolName + "' is an internal symbol this "
|
||||
"may indicate that the stub target offset is being "
|
||||
"computed incorrectly.\n").str());
|
||||
if (!SectionAddr.second.empty())
|
||||
return SectionAddr;
|
||||
|
||||
uint64_t StubOffset = StubOffsetItr->second;
|
||||
auto StubOffset = GetStubOffsetInSection(FileName, SectionName, SymbolName);
|
||||
|
||||
uint64_t Addr;
|
||||
if (IsInsideLoad) {
|
||||
uintptr_t SectionBase = reinterpret_cast<uintptr_t>(
|
||||
getRTDyld().Sections[SectionID].getAddress());
|
||||
Addr = static_cast<uint64_t>(SectionBase) + StubOffset;
|
||||
} else {
|
||||
uint64_t SectionBase = getRTDyld().Sections[SectionID].getLoadAddress();
|
||||
Addr = SectionBase + StubOffset;
|
||||
}
|
||||
|
||||
return std::make_pair(Addr, std::string(""));
|
||||
}
|
||||
|
||||
StringRef
|
||||
RuntimeDyldCheckerImpl::getSubsectionStartingAt(StringRef Name) const {
|
||||
RTDyldSymbolTable::const_iterator pos =
|
||||
getRTDyld().GlobalSymbolTable.find(Name);
|
||||
if (pos == getRTDyld().GlobalSymbolTable.end())
|
||||
return StringRef();
|
||||
const auto &SymInfo = pos->second;
|
||||
uint8_t *SectionAddr = getRTDyld().getSectionAddress(SymInfo.getSectionID());
|
||||
return StringRef(reinterpret_cast<const char *>(SectionAddr) +
|
||||
SymInfo.getOffset(),
|
||||
getRTDyld().Sections[SymInfo.getSectionID()].getSize() -
|
||||
SymInfo.getOffset());
|
||||
}
|
||||
|
||||
Optional<uint64_t>
|
||||
RuntimeDyldCheckerImpl::getSectionLoadAddress(void *LocalAddress) const {
|
||||
for (auto &S : getRTDyld().Sections) {
|
||||
if (S.getAddress() == LocalAddress)
|
||||
return S.getLoadAddress();
|
||||
}
|
||||
return Optional<uint64_t>();
|
||||
}
|
||||
|
||||
void RuntimeDyldCheckerImpl::registerSection(
|
||||
StringRef FilePath, unsigned SectionID) {
|
||||
StringRef FileName = sys::path::filename(FilePath);
|
||||
const SectionEntry &Section = getRTDyld().Sections[SectionID];
|
||||
StringRef SectionName = Section.getName();
|
||||
|
||||
Stubs[FileName][SectionName].SectionID = SectionID;
|
||||
}
|
||||
|
||||
void RuntimeDyldCheckerImpl::registerStubMap(
|
||||
StringRef FilePath, unsigned SectionID,
|
||||
const RuntimeDyldImpl::StubMap &RTDyldStubs) {
|
||||
StringRef FileName = sys::path::filename(FilePath);
|
||||
const SectionEntry &Section = getRTDyld().Sections[SectionID];
|
||||
StringRef SectionName = Section.getName();
|
||||
|
||||
Stubs[FileName][SectionName].SectionID = SectionID;
|
||||
|
||||
for (auto &StubMapEntry : RTDyldStubs) {
|
||||
std::string SymbolName = "";
|
||||
|
||||
if (StubMapEntry.first.SymbolName)
|
||||
SymbolName = StubMapEntry.first.SymbolName;
|
||||
else {
|
||||
// If this is a (Section, Offset) pair, do a reverse lookup in the
|
||||
// global symbol table to find the name.
|
||||
for (auto &GSTEntry : getRTDyld().GlobalSymbolTable) {
|
||||
const auto &SymInfo = GSTEntry.second;
|
||||
if (SymInfo.getSectionID() == StubMapEntry.first.SectionID &&
|
||||
SymInfo.getOffset() ==
|
||||
static_cast<uint64_t>(StubMapEntry.first.Offset)) {
|
||||
SymbolName = GSTEntry.first();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!StubOffset) {
|
||||
std::string ErrMsg;
|
||||
{
|
||||
raw_string_ostream ErrMsgStream(ErrMsg);
|
||||
logAllUnhandledErrors(StubOffset.takeError(), ErrMsgStream,
|
||||
"RTDyldChecker: ");
|
||||
}
|
||||
|
||||
if (SymbolName != "")
|
||||
Stubs[FileName][SectionName].StubOffsets[SymbolName] =
|
||||
StubMapEntry.second;
|
||||
return std::make_pair((uint64_t)0, std::move(ErrMsg));
|
||||
}
|
||||
|
||||
return std::make_pair(SectionAddr.first + *StubOffset, "");
|
||||
}
|
||||
|
||||
RuntimeDyldChecker::RuntimeDyldChecker(RuntimeDyld &RTDyld,
|
||||
MCDisassembler *Disassembler,
|
||||
MCInstPrinter *InstPrinter,
|
||||
raw_ostream &ErrStream)
|
||||
: Impl(make_unique<RuntimeDyldCheckerImpl>(RTDyld, Disassembler,
|
||||
InstPrinter, ErrStream)) {}
|
||||
RuntimeDyldChecker::RuntimeDyldChecker(
|
||||
IsSymbolValidFunction IsSymbolValid,
|
||||
GetSymbolAddressFunction GetSymbolAddress,
|
||||
GetSymbolContentFunction GetSymbolContent,
|
||||
GetSectionLoadAddressFunction GetSectionLoadAddress,
|
||||
GetSectionContentFunction GetSectionContent,
|
||||
GetStubOffsetInSectionFunction GetStubOffsetInSection,
|
||||
support::endianness Endianness,
|
||||
MCDisassembler *Disassembler,
|
||||
MCInstPrinter *InstPrinter,
|
||||
raw_ostream &ErrStream)
|
||||
: Impl(make_unique<RuntimeDyldCheckerImpl>(
|
||||
std::move(IsSymbolValid),
|
||||
std::move(GetSymbolAddress),
|
||||
std::move(GetSymbolContent),
|
||||
std::move(GetSectionLoadAddress),
|
||||
std::move(GetSectionContent),
|
||||
std::move(GetStubOffsetInSection),
|
||||
Endianness, Disassembler,
|
||||
InstPrinter, ErrStream)) {}
|
||||
|
||||
RuntimeDyldChecker::~RuntimeDyldChecker() {}
|
||||
|
||||
RuntimeDyld& RuntimeDyldChecker::getRTDyld() {
|
||||
return Impl->RTDyld;
|
||||
}
|
||||
|
||||
const RuntimeDyld& RuntimeDyldChecker::getRTDyld() const {
|
||||
return Impl->RTDyld;
|
||||
}
|
||||
|
||||
bool RuntimeDyldChecker::check(StringRef CheckExpr) const {
|
||||
return Impl->check(CheckExpr);
|
||||
}
|
||||
|
@ -979,8 +879,3 @@ RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName,
|
|||
bool LocalAddress) {
|
||||
return Impl->getSectionAddr(FileName, SectionName, LocalAddress);
|
||||
}
|
||||
|
||||
Optional<uint64_t>
|
||||
RuntimeDyldChecker::getSectionLoadAddress(void *LocalAddress) const {
|
||||
return Impl->getSectionLoadAddress(LocalAddress);
|
||||
}
|
||||
|
|
|
@ -15,14 +15,35 @@ namespace llvm {
|
|||
|
||||
class RuntimeDyldCheckerImpl {
|
||||
friend class RuntimeDyldChecker;
|
||||
friend class RuntimeDyldImpl;
|
||||
friend class RuntimeDyldCheckerExprEval;
|
||||
friend class RuntimeDyldELF;
|
||||
|
||||
using IsSymbolValidFunction =
|
||||
RuntimeDyldChecker::IsSymbolValidFunction;
|
||||
using GetSymbolAddressFunction =
|
||||
RuntimeDyldChecker::GetSymbolAddressFunction;
|
||||
using GetSymbolContentFunction =
|
||||
RuntimeDyldChecker::GetSymbolContentFunction;
|
||||
|
||||
using GetSectionLoadAddressFunction =
|
||||
RuntimeDyldChecker::GetSectionLoadAddressFunction;
|
||||
using GetSectionContentFunction =
|
||||
RuntimeDyldChecker::GetSectionContentFunction;
|
||||
|
||||
using GetStubOffsetInSectionFunction =
|
||||
RuntimeDyldChecker::GetStubOffsetInSectionFunction;
|
||||
|
||||
public:
|
||||
RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld, MCDisassembler *Disassembler,
|
||||
MCInstPrinter *InstPrinter,
|
||||
llvm::raw_ostream &ErrStream);
|
||||
RuntimeDyldCheckerImpl(
|
||||
IsSymbolValidFunction IsSymbolValid,
|
||||
GetSymbolAddressFunction GetSymbolAddress,
|
||||
GetSymbolContentFunction GetSymbolContent,
|
||||
GetSectionLoadAddressFunction GetSectionLoadAddress,
|
||||
GetSectionContentFunction GetSectionContent,
|
||||
GetStubOffsetInSectionFunction GetStubOffsetInSection,
|
||||
support::endianness Endianness,
|
||||
MCDisassembler *Disassembler,
|
||||
MCInstPrinter *InstPrinter,
|
||||
llvm::raw_ostream &ErrStream);
|
||||
|
||||
bool check(StringRef CheckExpr) const;
|
||||
bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const;
|
||||
|
@ -30,15 +51,6 @@ public:
|
|||
private:
|
||||
|
||||
// StubMap typedefs.
|
||||
typedef std::map<std::string, uint64_t> StubOffsetsMap;
|
||||
struct SectionAddressInfo {
|
||||
uint64_t SectionID;
|
||||
StubOffsetsMap StubOffsets;
|
||||
};
|
||||
typedef std::map<std::string, SectionAddressInfo> SectionMap;
|
||||
typedef std::map<std::string, SectionMap> StubMap;
|
||||
|
||||
RuntimeDyldImpl &getRTDyld() const { return *RTDyld.Dyld; }
|
||||
|
||||
Expected<JITSymbolResolver::LookupResult>
|
||||
lookup(const JITSymbolResolver::LookupSet &Symbols) const;
|
||||
|
@ -48,9 +60,7 @@ private:
|
|||
uint64_t getSymbolRemoteAddr(StringRef Symbol) const;
|
||||
uint64_t readMemoryAtAddr(uint64_t Addr, unsigned Size) const;
|
||||
|
||||
std::pair<const SectionAddressInfo*, std::string> findSectionAddrInfo(
|
||||
StringRef FileName,
|
||||
StringRef SectionName) const;
|
||||
StringRef getSymbolContent(StringRef Symbol) const;
|
||||
|
||||
std::pair<uint64_t, std::string> getSectionAddr(StringRef FileName,
|
||||
StringRef SectionName,
|
||||
|
@ -60,20 +70,19 @@ private:
|
|||
StringRef SectionName,
|
||||
StringRef Symbol,
|
||||
bool IsInsideLoad) const;
|
||||
StringRef getSubsectionStartingAt(StringRef Name) const;
|
||||
|
||||
Optional<uint64_t> getSectionLoadAddress(void *LocalAddr) const;
|
||||
|
||||
void registerSection(StringRef FilePath, unsigned SectionID);
|
||||
void registerStubMap(StringRef FilePath, unsigned SectionID,
|
||||
const RuntimeDyldImpl::StubMap &RTDyldStubs);
|
||||
|
||||
RuntimeDyld &RTDyld;
|
||||
IsSymbolValidFunction IsSymbolValid;
|
||||
GetSymbolAddressFunction GetSymbolAddress;
|
||||
GetSymbolContentFunction GetSymbolContent;
|
||||
GetSectionLoadAddressFunction GetSectionLoadAddress;
|
||||
GetSectionContentFunction GetSectionContent;
|
||||
GetStubOffsetInSectionFunction GetStubOffsetInSection;
|
||||
support::endianness Endianness;
|
||||
MCDisassembler *Disassembler;
|
||||
MCInstPrinter *InstPrinter;
|
||||
llvm::raw_ostream &ErrStream;
|
||||
|
||||
StubMap Stubs;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1856,9 +1856,6 @@ Error RuntimeDyldELF::finalizeLoad(const ObjectFile &Obj,
|
|||
Sections[GOTSectionID] =
|
||||
SectionEntry(".got", Addr, TotalSize, TotalSize, 0);
|
||||
|
||||
if (Checker)
|
||||
Checker->registerSection(Obj.getFileName(), GOTSectionID);
|
||||
|
||||
// For now, initialize all GOT entries to zero. We'll fill them in as
|
||||
// needed when GOT-based relocations are applied.
|
||||
memset(Addr, 0, TotalSize);
|
||||
|
|
|
@ -240,7 +240,6 @@ typedef StringMap<SymbolTableEntry> RTDyldSymbolTable;
|
|||
|
||||
class RuntimeDyldImpl {
|
||||
friend class RuntimeDyld::LoadedObjectInfo;
|
||||
friend class RuntimeDyldCheckerImpl;
|
||||
protected:
|
||||
static const unsigned AbsoluteSymbolSection = ~0U;
|
||||
|
||||
|
@ -250,9 +249,6 @@ protected:
|
|||
// The symbol resolver to use for external symbols.
|
||||
JITSymbolResolver &Resolver;
|
||||
|
||||
// Attached RuntimeDyldChecker instance. Null if no instance attached.
|
||||
RuntimeDyldCheckerImpl *Checker;
|
||||
|
||||
// A list of all sections emitted by the dynamic linker. These sections are
|
||||
// referenced in the code by means of their index in this list - SectionID.
|
||||
typedef SmallVector<SectionEntry, 64> SectionList;
|
||||
|
@ -312,20 +308,16 @@ protected:
|
|||
// the end of the list while the list is being processed.
|
||||
sys::Mutex lock;
|
||||
|
||||
using NotifyStubEmittedFunction =
|
||||
RuntimeDyld::NotifyStubEmittedFunction;
|
||||
NotifyStubEmittedFunction NotifyStubEmitted;
|
||||
|
||||
virtual unsigned getMaxStubSize() = 0;
|
||||
virtual unsigned getStubAlignment() = 0;
|
||||
|
||||
bool HasError;
|
||||
std::string ErrorStr;
|
||||
|
||||
uint64_t getSectionLoadAddress(unsigned SectionID) const {
|
||||
return Sections[SectionID].getLoadAddress();
|
||||
}
|
||||
|
||||
uint8_t *getSectionAddress(unsigned SectionID) const {
|
||||
return Sections[SectionID].getAddress();
|
||||
}
|
||||
|
||||
void writeInt16BE(uint8_t *Addr, uint16_t Value) {
|
||||
if (IsTargetLittleEndian)
|
||||
sys::swapByteOrder(Value);
|
||||
|
@ -471,7 +463,7 @@ protected:
|
|||
public:
|
||||
RuntimeDyldImpl(RuntimeDyld::MemoryManager &MemMgr,
|
||||
JITSymbolResolver &Resolver)
|
||||
: MemMgr(MemMgr), Resolver(Resolver), Checker(nullptr),
|
||||
: MemMgr(MemMgr), Resolver(Resolver),
|
||||
ProcessAllSections(false), HasError(false) {
|
||||
}
|
||||
|
||||
|
@ -481,13 +473,22 @@ public:
|
|||
this->ProcessAllSections = ProcessAllSections;
|
||||
}
|
||||
|
||||
void setRuntimeDyldChecker(RuntimeDyldCheckerImpl *Checker) {
|
||||
this->Checker = Checker;
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
|
||||
loadObject(const object::ObjectFile &Obj) = 0;
|
||||
|
||||
uint64_t getSectionLoadAddress(unsigned SectionID) const {
|
||||
return Sections[SectionID].getLoadAddress();
|
||||
}
|
||||
|
||||
uint8_t *getSectionAddress(unsigned SectionID) const {
|
||||
return Sections[SectionID].getAddress();
|
||||
}
|
||||
|
||||
StringRef getSectionContent(unsigned SectionID) const {
|
||||
return StringRef(reinterpret_cast<char*>(Sections[SectionID].getAddress()),
|
||||
Sections[SectionID].getSize());
|
||||
}
|
||||
|
||||
uint8_t* getSymbolLocalAddress(StringRef Name) const {
|
||||
// FIXME: Just look up as a function for now. Overly simple of course.
|
||||
// Work in progress.
|
||||
|
@ -501,6 +502,13 @@ public:
|
|||
return getSectionAddress(SymInfo.getSectionID()) + SymInfo.getOffset();
|
||||
}
|
||||
|
||||
unsigned getSymbolSectionID(StringRef Name) const {
|
||||
auto GSTItr = GlobalSymbolTable.find(Name);
|
||||
if (GSTItr == GlobalSymbolTable.end())
|
||||
return ~0U;
|
||||
return GSTItr->second.getSectionID();
|
||||
}
|
||||
|
||||
JITEvaluatedSymbol getSymbol(StringRef Name) const {
|
||||
// FIXME: Just look up as a function for now. Overly simple of course.
|
||||
// Work in progress.
|
||||
|
@ -559,6 +567,10 @@ public:
|
|||
|
||||
virtual bool isCompatibleFile(const ObjectFile &Obj) const = 0;
|
||||
|
||||
void setNotifyStubEmitted(NotifyStubEmittedFunction NotifyStubEmitted) {
|
||||
this->NotifyStubEmitted = std::move(NotifyStubEmitted);
|
||||
}
|
||||
|
||||
virtual void registerEHFrames();
|
||||
|
||||
void deregisterEHFrames();
|
||||
|
|
|
@ -29,9 +29,12 @@
|
|||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <future>
|
||||
#include <list>
|
||||
|
||||
using namespace llvm;
|
||||
|
@ -137,14 +140,50 @@ PrintAllocationRequests("print-alloc-requests",
|
|||
"manager by RuntimeDyld"),
|
||||
cl::Hidden);
|
||||
|
||||
ExitOnError ExitOnErr;
|
||||
|
||||
/* *** */
|
||||
|
||||
using SectionIDMap = StringMap<unsigned>;
|
||||
using FileToSectionIDMap = StringMap<SectionIDMap>;
|
||||
|
||||
void dumpFileToSectionIDMap(const FileToSectionIDMap &FileToSecIDMap) {
|
||||
for (const auto &KV : FileToSecIDMap) {
|
||||
llvm::dbgs() << "In " << KV.first() << "\n";
|
||||
for (auto &KV2 : KV.second)
|
||||
llvm::dbgs() << " \"" << KV2.first() << "\" -> " << KV2.second << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
Expected<unsigned> getSectionId(const FileToSectionIDMap &FileToSecIDMap,
|
||||
StringRef FileName, StringRef SectionName) {
|
||||
auto I = FileToSecIDMap.find(FileName);
|
||||
if (I == FileToSecIDMap.end())
|
||||
return make_error<StringError>("No file named " + FileName,
|
||||
inconvertibleErrorCode());
|
||||
auto &SectionIDs = I->second;
|
||||
auto J = SectionIDs.find(SectionName);
|
||||
if (J == SectionIDs.end())
|
||||
return make_error<StringError>("No section named \"" + SectionName +
|
||||
"\" in file " + FileName,
|
||||
inconvertibleErrorCode());
|
||||
return J->second;
|
||||
}
|
||||
|
||||
// A trivial memory manager that doesn't do anything fancy, just uses the
|
||||
// support library allocation routines directly.
|
||||
class TrivialMemoryManager : public RTDyldMemoryManager {
|
||||
public:
|
||||
SmallVector<sys::MemoryBlock, 16> FunctionMemory;
|
||||
SmallVector<sys::MemoryBlock, 16> DataMemory;
|
||||
struct SectionInfo {
|
||||
SectionInfo(StringRef Name, sys::MemoryBlock MB, unsigned SectionID)
|
||||
: Name(Name), MB(std::move(MB)), SectionID(SectionID) {}
|
||||
std::string Name;
|
||||
sys::MemoryBlock MB;
|
||||
unsigned SectionID = ~0U;
|
||||
};
|
||||
|
||||
SmallVector<SectionInfo, 16> FunctionMemory;
|
||||
SmallVector<SectionInfo, 16> DataMemory;
|
||||
|
||||
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID,
|
||||
|
@ -153,6 +192,11 @@ public:
|
|||
unsigned SectionID, StringRef SectionName,
|
||||
bool IsReadOnly) override;
|
||||
|
||||
/// If non null, records subsequent Name -> SectionID mappings.
|
||||
void setSectionIDsMap(SectionIDMap *SecIDMap) {
|
||||
this->SecIDMap = SecIDMap;
|
||||
}
|
||||
|
||||
void *getPointerToNamedFunction(const std::string &Name,
|
||||
bool AbortOnFailure = true) override {
|
||||
return nullptr;
|
||||
|
@ -192,7 +236,8 @@ public:
|
|||
SlabSize = Size;
|
||||
}
|
||||
|
||||
uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode) {
|
||||
uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode,
|
||||
StringRef SectionName, unsigned SectionID) {
|
||||
Size = alignTo(Size, Alignment);
|
||||
if (CurrentSlabOffset + Size > SlabSize)
|
||||
report_fatal_error("Can't allocate enough memory. Tune --preallocate");
|
||||
|
@ -200,9 +245,9 @@ public:
|
|||
uintptr_t OldSlabOffset = CurrentSlabOffset;
|
||||
sys::MemoryBlock MB((void *)OldSlabOffset, Size);
|
||||
if (isCode)
|
||||
FunctionMemory.push_back(MB);
|
||||
FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));
|
||||
else
|
||||
DataMemory.push_back(MB);
|
||||
DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));
|
||||
CurrentSlabOffset += Size;
|
||||
return (uint8_t*)OldSlabOffset;
|
||||
}
|
||||
|
@ -213,6 +258,7 @@ private:
|
|||
bool UsePreallocation = false;
|
||||
uintptr_t SlabSize = 0;
|
||||
uintptr_t CurrentSlabOffset = 0;
|
||||
SectionIDMap *SecIDMap = nullptr;
|
||||
};
|
||||
|
||||
uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
|
||||
|
@ -223,8 +269,13 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
|
|||
outs() << "allocateCodeSection(Size = " << Size << ", Alignment = "
|
||||
<< Alignment << ", SectionName = " << SectionName << ")\n";
|
||||
|
||||
dbgs() << " Registering code section \"" << SectionName << "\"\n";
|
||||
if (SecIDMap)
|
||||
(*SecIDMap)[SectionName] = SectionID;
|
||||
|
||||
if (UsePreallocation)
|
||||
return allocateFromSlab(Size, Alignment, true /* isCode */);
|
||||
return allocateFromSlab(Size, Alignment, true /* isCode */,
|
||||
SectionName, SectionID);
|
||||
|
||||
std::error_code EC;
|
||||
sys::MemoryBlock MB =
|
||||
|
@ -234,7 +285,7 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
|
|||
EC);
|
||||
if (!MB.base())
|
||||
report_fatal_error("MemoryManager allocation failed: " + EC.message());
|
||||
FunctionMemory.push_back(MB);
|
||||
FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));
|
||||
return (uint8_t*)MB.base();
|
||||
}
|
||||
|
||||
|
@ -247,8 +298,13 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
|
|||
outs() << "allocateDataSection(Size = " << Size << ", Alignment = "
|
||||
<< Alignment << ", SectionName = " << SectionName << ")\n";
|
||||
|
||||
dbgs() << " Registering code section \"" << SectionName << "\"\n";
|
||||
if (SecIDMap)
|
||||
(*SecIDMap)[SectionName] = SectionID;
|
||||
|
||||
if (UsePreallocation)
|
||||
return allocateFromSlab(Size, Alignment, false /* isCode */);
|
||||
return allocateFromSlab(Size, Alignment, false /* isCode */, SectionName,
|
||||
SectionID);
|
||||
|
||||
std::error_code EC;
|
||||
sys::MemoryBlock MB =
|
||||
|
@ -258,7 +314,7 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
|
|||
EC);
|
||||
if (!MB.base())
|
||||
report_fatal_error("MemoryManager allocation failed: " + EC.message());
|
||||
DataMemory.push_back(MB);
|
||||
DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));
|
||||
return (uint8_t*)MB.base();
|
||||
}
|
||||
|
||||
|
@ -469,9 +525,11 @@ static int executeInput() {
|
|||
// Invalidate the instruction cache for each loaded function.
|
||||
for (auto &FM : MemMgr.FunctionMemory) {
|
||||
|
||||
auto &FM_MB = FM.MB;
|
||||
|
||||
// Make sure the memory is executable.
|
||||
// setExecutable will call InvalidateInstructionCache.
|
||||
if (auto EC = sys::Memory::protectMappedMemory(FM,
|
||||
if (auto EC = sys::Memory::protectMappedMemory(FM_MB,
|
||||
sys::Memory::MF_READ |
|
||||
sys::Memory::MF_EXEC))
|
||||
ErrorAndExit("unable to mark function executable: '" + EC.message() +
|
||||
|
@ -505,10 +563,10 @@ static int checkAllExpressions(RuntimeDyldChecker &Checker) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
|
||||
void applySpecificSectionMappings(RuntimeDyld &Dyld,
|
||||
const FileToSectionIDMap &FileToSecIDMap) {
|
||||
|
||||
for (StringRef Mapping : SpecificSectionMappings) {
|
||||
|
||||
size_t EqualsIdx = Mapping.find_first_of("=");
|
||||
std::string SectionIDStr = Mapping.substr(0, EqualsIdx);
|
||||
size_t ComaIdx = Mapping.find_first_of(",");
|
||||
|
@ -519,17 +577,10 @@ void applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
|
|||
|
||||
std::string FileName = SectionIDStr.substr(0, ComaIdx);
|
||||
std::string SectionName = SectionIDStr.substr(ComaIdx + 1);
|
||||
unsigned SectionID =
|
||||
ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName));
|
||||
|
||||
uint64_t OldAddrInt;
|
||||
std::string ErrorMsg;
|
||||
std::tie(OldAddrInt, ErrorMsg) =
|
||||
Checker.getSectionAddr(FileName, SectionName, true);
|
||||
|
||||
if (ErrorMsg != "")
|
||||
report_fatal_error(ErrorMsg);
|
||||
|
||||
void* OldAddr = reinterpret_cast<void*>(static_cast<uintptr_t>(OldAddrInt));
|
||||
|
||||
auto* OldAddr = Dyld.getSectionContent(SectionID).data();
|
||||
std::string NewAddrStr = Mapping.substr(EqualsIdx + 1);
|
||||
uint64_t NewAddr;
|
||||
|
||||
|
@ -537,7 +588,7 @@ void applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
|
|||
report_fatal_error("Invalid section address in mapping '" + Mapping +
|
||||
"'.");
|
||||
|
||||
Checker.getRTDyld().mapSectionAddress(OldAddr, NewAddr);
|
||||
Dyld.mapSectionAddress(OldAddr, NewAddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,21 +604,17 @@ void applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
|
|||
// (e.g. 1 << 32) to stress-test stubs, GOTs, etc.
|
||||
//
|
||||
static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,
|
||||
TrivialMemoryManager &MemMgr,
|
||||
RuntimeDyldChecker &Checker) {
|
||||
RuntimeDyld &Dyld,
|
||||
TrivialMemoryManager &MemMgr) {
|
||||
|
||||
// Set up a work list (section addr/size pairs).
|
||||
typedef std::list<std::pair<void*, uint64_t>> WorklistT;
|
||||
typedef std::list<const TrivialMemoryManager::SectionInfo*> WorklistT;
|
||||
WorklistT Worklist;
|
||||
|
||||
for (const auto& CodeSection : MemMgr.FunctionMemory)
|
||||
Worklist.push_back(std::make_pair(CodeSection.base(), CodeSection.size()));
|
||||
Worklist.push_back(&CodeSection);
|
||||
for (const auto& DataSection : MemMgr.DataMemory)
|
||||
Worklist.push_back(std::make_pair(DataSection.base(), DataSection.size()));
|
||||
|
||||
// Apply any section-specific mappings that were requested on the command
|
||||
// line.
|
||||
applySpecificSectionMappings(Checker);
|
||||
Worklist.push_back(&DataSection);
|
||||
|
||||
// Keep an "already allocated" mapping of section target addresses to sizes.
|
||||
// Sections whose address mappings aren't specified on the command line will
|
||||
|
@ -582,16 +629,16 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,
|
|||
I != E;) {
|
||||
WorklistT::iterator Tmp = I;
|
||||
++I;
|
||||
auto LoadAddr = Checker.getSectionLoadAddress(Tmp->first);
|
||||
|
||||
if (LoadAddr &&
|
||||
*LoadAddr != static_cast<uint64_t>(
|
||||
reinterpret_cast<uintptr_t>(Tmp->first))) {
|
||||
auto LoadAddr = Dyld.getSectionLoadAddress((*Tmp)->SectionID);
|
||||
|
||||
if (LoadAddr != static_cast<uint64_t>(
|
||||
reinterpret_cast<uintptr_t>((*Tmp)->MB.base()))) {
|
||||
// A section will have a LoadAddr of 0 if it wasn't loaded for whatever
|
||||
// reason (e.g. zero byte COFF sections). Don't include those sections in
|
||||
// the allocation map.
|
||||
if (*LoadAddr != 0)
|
||||
AlreadyAllocated[*LoadAddr] = Tmp->second;
|
||||
if (LoadAddr != 0)
|
||||
AlreadyAllocated[LoadAddr] = (*Tmp)->MB.size();
|
||||
Worklist.erase(Tmp);
|
||||
}
|
||||
}
|
||||
|
@ -609,19 +656,19 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,
|
|||
|
||||
// Process any elements remaining in the worklist.
|
||||
while (!Worklist.empty()) {
|
||||
std::pair<void*, uint64_t> CurEntry = Worklist.front();
|
||||
auto *CurEntry = Worklist.front();
|
||||
Worklist.pop_front();
|
||||
|
||||
uint64_t NextSectionAddr = TargetAddrStart;
|
||||
|
||||
for (const auto &Alloc : AlreadyAllocated)
|
||||
if (NextSectionAddr + CurEntry.second + TargetSectionSep <= Alloc.first)
|
||||
if (NextSectionAddr + CurEntry->MB.size() + TargetSectionSep <= Alloc.first)
|
||||
break;
|
||||
else
|
||||
NextSectionAddr = Alloc.first + Alloc.second + TargetSectionSep;
|
||||
|
||||
AlreadyAllocated[NextSectionAddr] = CurEntry.second;
|
||||
Checker.getRTDyld().mapSectionAddress(CurEntry.first, NextSectionAddr);
|
||||
Dyld.mapSectionAddress(CurEntry->MB.base(), NextSectionAddr);
|
||||
AlreadyAllocated[NextSectionAddr] = CurEntry->MB.size();
|
||||
}
|
||||
|
||||
// Add dummy symbols to the memory manager.
|
||||
|
@ -693,18 +740,116 @@ static int linkAndVerify() {
|
|||
// Instantiate a dynamic linker.
|
||||
TrivialMemoryManager MemMgr;
|
||||
doPreallocation(MemMgr);
|
||||
|
||||
using StubOffsets = StringMap<uint32_t>;
|
||||
using SectionStubs = StringMap<StubOffsets>;
|
||||
using FileStubs = StringMap<SectionStubs>;
|
||||
|
||||
FileStubs StubMap;
|
||||
RuntimeDyld Dyld(MemMgr, MemMgr);
|
||||
Dyld.setProcessAllSections(true);
|
||||
RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),
|
||||
llvm::dbgs());
|
||||
|
||||
Dyld.setNotifyStubEmitted(
|
||||
[&StubMap](StringRef FilePath, StringRef SectionName,
|
||||
StringRef SymbolName, uint32_t StubOffset) {
|
||||
StubMap[sys::path::filename(FilePath)][SectionName][SymbolName] =
|
||||
StubOffset;
|
||||
});
|
||||
|
||||
auto GetSymbolAddress =
|
||||
[&Dyld, &MemMgr](StringRef Symbol) -> Expected<JITTargetAddress> {
|
||||
if (auto InternalSymbol = Dyld.getSymbol(Symbol))
|
||||
return InternalSymbol.getAddress();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
using ExpectedLookupResult = MSVCPExpected<JITSymbolResolver::LookupResult>;
|
||||
#else
|
||||
using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>;
|
||||
#endif
|
||||
|
||||
auto ResultP = std::make_shared<std::promise<ExpectedLookupResult>>();
|
||||
auto ResultF = ResultP->get_future();
|
||||
|
||||
MemMgr.lookup(
|
||||
JITSymbolResolver::LookupSet({Symbol}),
|
||||
[=](Expected<JITSymbolResolver::LookupResult> Result) {
|
||||
ResultP->set_value(std::move(Result));
|
||||
});
|
||||
|
||||
auto Result = ResultF.get();
|
||||
if (!Result)
|
||||
return Result.takeError();
|
||||
|
||||
auto I = Result->find(Symbol);
|
||||
assert(I != Result->end() &&
|
||||
"Expected symbol address if no error occurred");
|
||||
return I->second.getAddress();
|
||||
};
|
||||
|
||||
auto IsSymbolValid =
|
||||
[&Dyld, GetSymbolAddress](StringRef Symbol) {
|
||||
if (Dyld.getSymbol(Symbol))
|
||||
return true;
|
||||
auto Addr = GetSymbolAddress(Symbol);
|
||||
if (!Addr) {
|
||||
logAllUnhandledErrors(Addr.takeError(), errs(), "RTDyldChecker: ");
|
||||
return false;
|
||||
}
|
||||
return *Addr != 0;
|
||||
};
|
||||
|
||||
FileToSectionIDMap FileToSecIDMap;
|
||||
|
||||
auto GetSectionAddress =
|
||||
[&Dyld, &FileToSecIDMap](StringRef FileName, StringRef SectionName) {
|
||||
unsigned SectionID =
|
||||
ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName));
|
||||
return Dyld.getSectionLoadAddress(SectionID);
|
||||
};
|
||||
|
||||
auto GetSectionContent =
|
||||
[&Dyld, &FileToSecIDMap](StringRef FileName, StringRef SectionName) {
|
||||
unsigned SectionID =
|
||||
ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName));
|
||||
return Dyld.getSectionContent(SectionID);
|
||||
};
|
||||
|
||||
|
||||
auto GetSymbolContents =
|
||||
[&Dyld](StringRef Symbol) {
|
||||
auto *SymAddr = static_cast<char*>(Dyld.getSymbolLocalAddress(Symbol));
|
||||
if (!SymAddr)
|
||||
return StringRef();
|
||||
unsigned SectionID = Dyld.getSymbolSectionID(Symbol);
|
||||
if (SectionID == ~0U)
|
||||
return StringRef();
|
||||
StringRef SecContent = Dyld.getSectionContent(SectionID);
|
||||
uint64_t SymSize = SecContent.size() - (SymAddr - SecContent.data());
|
||||
return StringRef(SymAddr, SymSize);
|
||||
};
|
||||
|
||||
auto GetStubOffset =
|
||||
[&StubMap](StringRef FileName, StringRef SectionName, StringRef SymbolName) -> Expected<uint32_t> {
|
||||
if (!StubMap.count(FileName))
|
||||
return make_error<StringError>("File name not found", inconvertibleErrorCode());
|
||||
if (!StubMap[FileName].count(SectionName))
|
||||
return make_error<StringError>("Section name not found", inconvertibleErrorCode());
|
||||
if (!StubMap[FileName][SectionName].count(SymbolName))
|
||||
return make_error<StringError>("Symbol name not found", inconvertibleErrorCode());
|
||||
return StubMap[FileName][SectionName][SymbolName];
|
||||
};
|
||||
|
||||
// We will initialize this below once we have the first object file and can
|
||||
// know the endianness.
|
||||
std::unique_ptr<RuntimeDyldChecker> Checker;
|
||||
|
||||
// If we don't have any input files, read from stdin.
|
||||
if (!InputFileList.size())
|
||||
InputFileList.push_back("-");
|
||||
for (auto &Filename : InputFileList) {
|
||||
for (auto &InputFile : InputFileList) {
|
||||
// Load the input memory buffer.
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
|
||||
MemoryBuffer::getFileOrSTDIN(Filename);
|
||||
MemoryBuffer::getFileOrSTDIN(InputFile);
|
||||
|
||||
if (std::error_code EC = InputBuffer.getError())
|
||||
ErrorAndExit("unable to read input: '" + EC.message() + "'");
|
||||
|
@ -722,6 +867,22 @@ static int linkAndVerify() {
|
|||
|
||||
ObjectFile &Obj = **MaybeObj;
|
||||
|
||||
if (!Checker)
|
||||
Checker =
|
||||
llvm::make_unique<RuntimeDyldChecker>(IsSymbolValid, GetSymbolAddress,
|
||||
GetSymbolContents,
|
||||
GetSectionAddress,
|
||||
GetSectionContent, GetStubOffset,
|
||||
Obj.isLittleEndian()
|
||||
? support::little
|
||||
: support::big,
|
||||
Disassembler.get(),
|
||||
InstPrinter.get(), dbgs());
|
||||
|
||||
auto FileName = sys::path::filename(InputFile);
|
||||
dbgs() << "In " << FileName << ":\n";
|
||||
MemMgr.setSectionIDsMap(&FileToSecIDMap[FileName]);
|
||||
|
||||
// Load the object file
|
||||
Dyld.loadObject(Obj);
|
||||
if (Dyld.hasError()) {
|
||||
|
@ -731,7 +892,8 @@ static int linkAndVerify() {
|
|||
|
||||
// Re-map the section addresses into the phony target address space and add
|
||||
// dummy symbols.
|
||||
remapSectionsAndSymbols(TheTriple, MemMgr, Checker);
|
||||
applySpecificSectionMappings(Dyld, FileToSecIDMap);
|
||||
remapSectionsAndSymbols(TheTriple, Dyld, MemMgr);
|
||||
|
||||
// Resolve all the relocations we can.
|
||||
Dyld.resolveRelocations();
|
||||
|
@ -739,7 +901,7 @@ static int linkAndVerify() {
|
|||
// Register EH frames.
|
||||
Dyld.registerEHFrames();
|
||||
|
||||
int ErrorCode = checkAllExpressions(Checker);
|
||||
int ErrorCode = checkAllExpressions(*Checker);
|
||||
if (Dyld.hasError())
|
||||
ErrorAndExit("RTDyld reported an error applying relocations:\n " +
|
||||
Dyld.getErrorString());
|
||||
|
@ -757,6 +919,8 @@ int main(int argc, char **argv) {
|
|||
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");
|
||||
|
||||
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
|
||||
|
||||
switch (Action) {
|
||||
case AC_Execute:
|
||||
return executeInput();
|
||||
|
|
Loading…
Reference in New Issue