Files
archived-llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h
Lang Hames ab3dba86f9 [ExecutionEngine] Make RuntimeDyld::MemoryManager responsible for tracking EH
frames.

RuntimeDyld was previously responsible for tracking allocated EH frames, but it
makes more sense to have the RuntimeDyld::MemoryManager track them (since the
frames are allocated through the memory manager, and written to memory owned by
the memory manager). This patch moves the frame tracking into
RTDyldMemoryManager, and changes the deregisterFrames method on
RuntimeDyld::MemoryManager from:

void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size);

to:

void deregisterEHFrames();

Separating this responsibility will allow ORC to continue to throw the
RuntimeDyld instances away post-link (saving a few dozen bytes per lazy
function) while properly deregistering frames when modules are unloaded.

This patch also updates ORC to call deregisterEHFrames when modules are
unloaded. This fixes a bug where an exception that tears down the JIT can then
unwind through dangling EH frames that have been deallocated but not
deregistered, resulting in UB.

For people using SectionMemoryManager this should be pretty much a no-op. For
people with custom allocators that override registerEHFrames/deregisterEHFrames,
you will now be responsible for tracking allocated EH frames.

Reviewed in https://reviews.llvm.org/D32829



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302589 91177308-0d34-0410-b5e6-96231b3b80d8
2017-05-09 21:32:18 +00:00

761 lines
28 KiB
C++

//===---- OrcRemoteTargetClient.h - Orc Remote-target Client ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the OrcRemoteTargetClient class and helpers. This class
// can be used to communicate over an RawByteChannel with an
// OrcRemoteTargetServer instance to support remote-JITing.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
#include "IndirectionUtils.h"
#include "OrcRemoteTargetRPCAPI.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include <system_error>
#define DEBUG_TYPE "orc-remote"
namespace llvm {
namespace orc {
namespace remote {
/// This class provides utilities (including memory manager, indirect stubs
/// manager, and compile callback manager types) that support remote JITing
/// in ORC.
///
/// Each of the utility classes talks to a JIT server (an instance of the
/// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
/// its actions.
template <typename ChannelT>
class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
public:
/// Remote memory manager.
class RCMemoryManager : public RuntimeDyld::MemoryManager {
public:
RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id)
: Client(Client), Id(Id) {
DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
}
RCMemoryManager(const RCMemoryManager &) = delete;
RCMemoryManager &operator=(const RCMemoryManager &) = delete;
RCMemoryManager(RCMemoryManager &&) = default;
RCMemoryManager &operator=(RCMemoryManager &&) = default;
~RCMemoryManager() override {
Client.destroyRemoteAllocator(Id);
DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
}
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID,
StringRef SectionName) override {
Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
uint8_t *Alloc = reinterpret_cast<uint8_t *>(
Unmapped.back().CodeAllocs.back().getLocalAddress());
DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
<< SectionName << ": " << Alloc << " (" << Size
<< " bytes, alignment " << Alignment << ")\n");
return Alloc;
}
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID, StringRef SectionName,
bool IsReadOnly) override {
if (IsReadOnly) {
Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
uint8_t *Alloc = reinterpret_cast<uint8_t *>(
Unmapped.back().RODataAllocs.back().getLocalAddress());
DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
<< SectionName << ": " << Alloc << " (" << Size
<< " bytes, alignment " << Alignment << ")\n");
return Alloc;
} // else...
Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
uint8_t *Alloc = reinterpret_cast<uint8_t *>(
Unmapped.back().RWDataAllocs.back().getLocalAddress());
DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
<< SectionName << ": " << Alloc << " (" << Size
<< " bytes, alignment " << Alignment << ")\n");
return Alloc;
}
void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
uintptr_t RODataSize, uint32_t RODataAlign,
uintptr_t RWDataSize,
uint32_t RWDataAlign) override {
Unmapped.push_back(ObjectAllocs());
DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
if (CodeSize != 0) {
if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign))
Unmapped.back().RemoteCodeAddr = *AddrOrErr;
else {
// FIXME; Add error to poll.
assert(!AddrOrErr.takeError() && "Failed reserving remote memory.");
}
DEBUG(dbgs() << " code: "
<< format("0x%016x", Unmapped.back().RemoteCodeAddr)
<< " (" << CodeSize << " bytes, alignment " << CodeAlign
<< ")\n");
}
if (RODataSize != 0) {
if (auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign))
Unmapped.back().RemoteRODataAddr = *AddrOrErr;
else {
// FIXME; Add error to poll.
assert(!AddrOrErr.takeError() && "Failed reserving remote memory.");
}
DEBUG(dbgs() << " ro-data: "
<< format("0x%016x", Unmapped.back().RemoteRODataAddr)
<< " (" << RODataSize << " bytes, alignment "
<< RODataAlign << ")\n");
}
if (RWDataSize != 0) {
if (auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign))
Unmapped.back().RemoteRWDataAddr = *AddrOrErr;
else {
// FIXME; Add error to poll.
assert(!AddrOrErr.takeError() && "Failed reserving remote memory.");
}
DEBUG(dbgs() << " rw-data: "
<< format("0x%016x", Unmapped.back().RemoteRWDataAddr)
<< " (" << RWDataSize << " bytes, alignment "
<< RWDataAlign << ")\n");
}
}
bool needsToReserveAllocationSpace() override { return true; }
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
size_t Size) override {
UnfinalizedEHFrames.push_back({LoadAddr, Size});
}
void deregisterEHFrames() override {
for (auto &Frame : RegisteredEHFrames) {
auto Err = Client.deregisterEHFrames(Frame.Addr, Frame.Size);
// FIXME: Add error poll.
assert(!Err && "Failed to register remote EH frames.");
(void)Err;
}
}
void notifyObjectLoaded(RuntimeDyld &Dyld,
const object::ObjectFile &Obj) override {
DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
for (auto &ObjAllocs : Unmapped) {
{
JITTargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr;
for (auto &Alloc : ObjAllocs.CodeAllocs) {
NextCodeAddr = alignTo(NextCodeAddr, Alloc.getAlign());
Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr);
DEBUG(dbgs() << " code: "
<< static_cast<void *>(Alloc.getLocalAddress())
<< " -> " << format("0x%016x", NextCodeAddr) << "\n");
Alloc.setRemoteAddress(NextCodeAddr);
NextCodeAddr += Alloc.getSize();
}
}
{
JITTargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr;
for (auto &Alloc : ObjAllocs.RODataAllocs) {
NextRODataAddr = alignTo(NextRODataAddr, Alloc.getAlign());
Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr);
DEBUG(dbgs() << " ro-data: "
<< static_cast<void *>(Alloc.getLocalAddress())
<< " -> " << format("0x%016x", NextRODataAddr)
<< "\n");
Alloc.setRemoteAddress(NextRODataAddr);
NextRODataAddr += Alloc.getSize();
}
}
{
JITTargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr;
for (auto &Alloc : ObjAllocs.RWDataAllocs) {
NextRWDataAddr = alignTo(NextRWDataAddr, Alloc.getAlign());
Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr);
DEBUG(dbgs() << " rw-data: "
<< static_cast<void *>(Alloc.getLocalAddress())
<< " -> " << format("0x%016x", NextRWDataAddr)
<< "\n");
Alloc.setRemoteAddress(NextRWDataAddr);
NextRWDataAddr += Alloc.getSize();
}
}
Unfinalized.push_back(std::move(ObjAllocs));
}
Unmapped.clear();
}
bool finalizeMemory(std::string *ErrMsg = nullptr) override {
DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
for (auto &ObjAllocs : Unfinalized) {
for (auto &Alloc : ObjAllocs.CodeAllocs) {
DEBUG(dbgs() << " copying code: "
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
<< Alloc.getSize() << " bytes)\n");
if (auto Err =
Client.writeMem(Alloc.getRemoteAddress(),
Alloc.getLocalAddress(), Alloc.getSize())) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return true;
}
}
if (ObjAllocs.RemoteCodeAddr) {
DEBUG(dbgs() << " setting R-X permissions on code block: "
<< format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n");
if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
sys::Memory::MF_READ |
sys::Memory::MF_EXEC)) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return true;
}
}
for (auto &Alloc : ObjAllocs.RODataAllocs) {
DEBUG(dbgs() << " copying ro-data: "
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
<< Alloc.getSize() << " bytes)\n");
if (auto Err =
Client.writeMem(Alloc.getRemoteAddress(),
Alloc.getLocalAddress(), Alloc.getSize())) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return true;
}
}
if (ObjAllocs.RemoteRODataAddr) {
DEBUG(dbgs() << " setting R-- permissions on ro-data block: "
<< format("0x%016x", ObjAllocs.RemoteRODataAddr)
<< "\n");
if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
sys::Memory::MF_READ)) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return false;
}
}
for (auto &Alloc : ObjAllocs.RWDataAllocs) {
DEBUG(dbgs() << " copying rw-data: "
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
<< Alloc.getSize() << " bytes)\n");
if (auto Err =
Client.writeMem(Alloc.getRemoteAddress(),
Alloc.getLocalAddress(), Alloc.getSize())) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return false;
}
}
if (ObjAllocs.RemoteRWDataAddr) {
DEBUG(dbgs() << " setting RW- permissions on rw-data block: "
<< format("0x%016x", ObjAllocs.RemoteRWDataAddr)
<< "\n");
if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
sys::Memory::MF_READ |
sys::Memory::MF_WRITE)) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return false;
}
}
}
Unfinalized.clear();
for (auto &EHFrame : UnfinalizedEHFrames) {
if (auto Err = Client.registerEHFrames(EHFrame.Addr, EHFrame.Size)) {
// FIXME: Replace this once finalizeMemory can return an Error.
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
if (ErrMsg) {
raw_string_ostream ErrOut(*ErrMsg);
EIB.log(ErrOut);
}
});
return false;
}
}
RegisteredEHFrames = std::move(UnfinalizedEHFrames);
UnfinalizedEHFrames = {};
return false;
}
private:
class Alloc {
public:
Alloc(uint64_t Size, unsigned Align)
: Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
Alloc(const Alloc &) = delete;
Alloc &operator=(const Alloc &) = delete;
Alloc(Alloc &&) = default;
Alloc &operator=(Alloc &&) = default;
uint64_t getSize() const { return Size; }
unsigned getAlign() const { return Align; }
char *getLocalAddress() const {
uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
LocalAddr = alignTo(LocalAddr, Align);
return reinterpret_cast<char *>(LocalAddr);
}
void setRemoteAddress(JITTargetAddress RemoteAddr) {
this->RemoteAddr = RemoteAddr;
}
JITTargetAddress getRemoteAddress() const { return RemoteAddr; }
private:
uint64_t Size;
unsigned Align;
std::unique_ptr<char[]> Contents;
JITTargetAddress RemoteAddr = 0;
};
struct ObjectAllocs {
ObjectAllocs() = default;
ObjectAllocs(const ObjectAllocs &) = delete;
ObjectAllocs &operator=(const ObjectAllocs &) = delete;
ObjectAllocs(ObjectAllocs &&) = default;
ObjectAllocs &operator=(ObjectAllocs &&) = default;
JITTargetAddress RemoteCodeAddr = 0;
JITTargetAddress RemoteRODataAddr = 0;
JITTargetAddress RemoteRWDataAddr = 0;
std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
};
OrcRemoteTargetClient &Client;
ResourceIdMgr::ResourceId Id;
std::vector<ObjectAllocs> Unmapped;
std::vector<ObjectAllocs> Unfinalized;
struct EHFrame {
JITTargetAddress Addr;
uint64_t Size;
};
std::vector<EHFrame> UnfinalizedEHFrames;
std::vector<EHFrame> RegisteredEHFrames;
};
/// Remote indirect stubs manager.
class RCIndirectStubsManager : public IndirectStubsManager {
public:
RCIndirectStubsManager(OrcRemoteTargetClient &Remote,
ResourceIdMgr::ResourceId Id)
: Remote(Remote), Id(Id) {}
~RCIndirectStubsManager() override {
if (auto Err = Remote.destroyIndirectStubsManager(Id)) {
// FIXME: Thread this error back to clients.
consumeError(std::move(Err));
}
}
Error createStub(StringRef StubName, JITTargetAddress StubAddr,
JITSymbolFlags StubFlags) override {
if (auto Err = reserveStubs(1))
return Err;
return createStubInternal(StubName, StubAddr, StubFlags);
}
Error createStubs(const StubInitsMap &StubInits) override {
if (auto Err = reserveStubs(StubInits.size()))
return Err;
for (auto &Entry : StubInits)
if (auto Err = createStubInternal(Entry.first(), Entry.second.first,
Entry.second.second))
return Err;
return Error::success();
}
JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
auto I = StubIndexes.find(Name);
if (I == StubIndexes.end())
return nullptr;
auto Key = I->second.first;
auto Flags = I->second.second;
auto StubSymbol = JITSymbol(getStubAddr(Key), Flags);
if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
return nullptr;
return StubSymbol;
}
JITSymbol findPointer(StringRef Name) override {
auto I = StubIndexes.find(Name);
if (I == StubIndexes.end())
return nullptr;
auto Key = I->second.first;
auto Flags = I->second.second;
return JITSymbol(getPtrAddr(Key), Flags);
}
Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
auto I = StubIndexes.find(Name);
assert(I != StubIndexes.end() && "No stub pointer for symbol");
auto Key = I->second.first;
return Remote.writePointer(getPtrAddr(Key), NewAddr);
}
private:
struct RemoteIndirectStubsInfo {
JITTargetAddress StubBase;
JITTargetAddress PtrBase;
unsigned NumStubs;
};
OrcRemoteTargetClient &Remote;
ResourceIdMgr::ResourceId Id;
std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
typedef std::pair<uint16_t, uint16_t> StubKey;
std::vector<StubKey> FreeStubs;
StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
Error reserveStubs(unsigned NumStubs) {
if (NumStubs <= FreeStubs.size())
return Error::success();
unsigned NewStubsRequired = NumStubs - FreeStubs.size();
JITTargetAddress StubBase;
JITTargetAddress PtrBase;
unsigned NumStubsEmitted;
if (auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired))
std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
else
return StubInfoOrErr.takeError();
unsigned NewBlockId = RemoteIndirectStubsInfos.size();
RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
for (unsigned I = 0; I < NumStubsEmitted; ++I)
FreeStubs.push_back(std::make_pair(NewBlockId, I));
return Error::success();
}
Error createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
JITSymbolFlags StubFlags) {
auto Key = FreeStubs.back();
FreeStubs.pop_back();
StubIndexes[StubName] = std::make_pair(Key, StubFlags);
return Remote.writePointer(getPtrAddr(Key), InitAddr);
}
JITTargetAddress getStubAddr(StubKey K) {
assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
"Missing stub address");
return RemoteIndirectStubsInfos[K.first].StubBase +
K.second * Remote.getIndirectStubSize();
}
JITTargetAddress getPtrAddr(StubKey K) {
assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
"Missing pointer address");
return RemoteIndirectStubsInfos[K.first].PtrBase +
K.second * Remote.getPointerSize();
}
};
/// Remote compile callback manager.
class RCCompileCallbackManager : public JITCompileCallbackManager {
public:
RCCompileCallbackManager(JITTargetAddress ErrorHandlerAddress,
OrcRemoteTargetClient &Remote)
: JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {}
private:
void grow() override {
JITTargetAddress BlockAddr = 0;
uint32_t NumTrampolines = 0;
if (auto TrampolineInfoOrErr = Remote.emitTrampolineBlock())
std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
else {
// FIXME: Return error.
llvm_unreachable("Failed to create trampolines");
}
uint32_t TrampolineSize = Remote.getTrampolineSize();
for (unsigned I = 0; I < NumTrampolines; ++I)
this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
}
OrcRemoteTargetClient &Remote;
};
/// Create an OrcRemoteTargetClient.
/// Channel is the ChannelT instance to communicate on. It is assumed that
/// the channel is ready to be read from and written to.
static Expected<std::unique_ptr<OrcRemoteTargetClient>>
Create(ChannelT &Channel) {
Error Err = Error::success();
std::unique_ptr<OrcRemoteTargetClient> Client(
new OrcRemoteTargetClient(Channel, Err));
if (Err)
return std::move(Err);
return std::move(Client);
}
/// Call the int(void) function at the given address in the target and return
/// its result.
Expected<int> callIntVoid(JITTargetAddress Addr) {
DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
return callB<CallIntVoid>(Addr);
}
/// Call the int(int, char*[]) function at the given address in the target and
/// return its result.
Expected<int> callMain(JITTargetAddress Addr,
const std::vector<std::string> &Args) {
DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
<< "\n");
return callB<CallMain>(Addr, Args);
}
/// Call the void() function at the given address in the target and wait for
/// it to finish.
Error callVoidVoid(JITTargetAddress Addr) {
DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
<< "\n");
return callB<CallVoidVoid>(Addr);
}
/// Create an RCMemoryManager which will allocate its memory on the remote
/// target.
Error createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) {
assert(!MM && "MemoryManager should be null before creation.");
auto Id = AllocatorIds.getNext();
if (auto Err = callB<CreateRemoteAllocator>(Id))
return Err;
MM = llvm::make_unique<RCMemoryManager>(*this, Id);
return Error::success();
}
/// Create an RCIndirectStubsManager that will allocate stubs on the remote
/// target.
Error createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {
assert(!I && "Indirect stubs manager should be null before creation.");
auto Id = IndirectStubOwnerIds.getNext();
if (auto Err = callB<CreateIndirectStubsOwner>(Id))
return Err;
I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);
return Error::success();
}
Expected<RCCompileCallbackManager &>
enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return std::move(ExistingError);
// Emit the resolver block on the JIT server.
if (auto Err = callB<EmitResolverBlock>())
return std::move(Err);
// Create the callback manager.
CallbackManager.emplace(ErrorHandlerAddress, *this);
RCCompileCallbackManager &Mgr = *CallbackManager;
return Mgr;
}
/// Search for symbols in the remote process. Note: This should be used by
/// symbol resolvers *after* they've searched the local symbol table in the
/// JIT stack.
Expected<JITTargetAddress> getSymbolAddress(StringRef Name) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return std::move(ExistingError);
return callB<GetSymbolAddress>(Name);
}
/// Get the triple for the remote target.
const std::string &getTargetTriple() const { return RemoteTargetTriple; }
Error terminateSession() { return callB<TerminateSession>(); }
private:
OrcRemoteTargetClient(ChannelT &Channel, Error &Err)
: OrcRemoteTargetRPCAPI(Channel) {
ErrorAsOutParameter EAO(&Err);
addHandler<RequestCompile>(
[this](JITTargetAddress Addr) -> JITTargetAddress {
if (CallbackManager)
return CallbackManager->executeCompileCallback(Addr);
return 0;
});
if (auto RIOrErr = callB<GetRemoteInfo>()) {
std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
Err = Error::success();
} else {
Err = joinErrors(RIOrErr.takeError(), std::move(ExistingError));
}
}
Error deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
return callB<RegisterEHFrames>(Addr, Size);
}
void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
if (auto Err = callB<DestroyRemoteAllocator>(Id)) {
// FIXME: This will be triggered by a removeModuleSet call: Propagate
// error return up through that.
llvm_unreachable("Failed to destroy remote allocator.");
AllocatorIds.release(Id);
}
}
Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
IndirectStubOwnerIds.release(Id);
return callB<DestroyIndirectStubsOwner>(Id);
}
Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
return callB<EmitIndirectStubs>(Id, NumStubsRequired);
}
Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return std::move(ExistingError);
return callB<EmitTrampolineBlock>();
}
uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
uint32_t getPageSize() const { return RemotePageSize; }
uint32_t getPointerSize() const { return RemotePointerSize; }
uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
Expected<std::vector<char>> readMem(char *Dst, JITTargetAddress Src,
uint64_t Size) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return std::move(ExistingError);
return callB<ReadMem>(Src, Size);
}
Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) {
return callB<RegisterEHFrames>(RAddr, Size);
}
Expected<JITTargetAddress> reserveMem(ResourceIdMgr::ResourceId Id,
uint64_t Size, uint32_t Align) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return std::move(ExistingError);
return callB<ReserveMem>(Id, Size, Align);
}
Error setProtections(ResourceIdMgr::ResourceId Id,
JITTargetAddress RemoteSegAddr, unsigned ProtFlags) {
return callB<SetProtections>(Id, RemoteSegAddr, ProtFlags);
}
Error writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return std::move(ExistingError);
return callB<WriteMem>(DirectBufferWriter(Src, Addr, Size));
}
Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return std::move(ExistingError);
return callB<WritePtr>(Addr, PtrVal);
}
static Error doNothing() { return Error::success(); }
Error ExistingError = Error::success();
std::string RemoteTargetTriple;
uint32_t RemotePointerSize = 0;
uint32_t RemotePageSize = 0;
uint32_t RemoteTrampolineSize = 0;
uint32_t RemoteIndirectStubSize = 0;
ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
Optional<RCCompileCallbackManager> CallbackManager;
};
} // end namespace remote
} // end namespace orc
} // end namespace llvm
#undef DEBUG_TYPE
#endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H