forked from OSchip/llvm-project
[ORC] Break up OrcJIT library, add Orc-RPC based remote TargetProcessControl
implementation. This patch aims to improve support for out-of-process JITing using OrcV2. It introduces two new class templates, OrcRPCTargetProcessControlBase and OrcRPCTPCServer, which together implement the TargetProcessControl API by forwarding operations to an execution process via an Orc-RPC Endpoint. These utilities are used to implement out-of-process JITing from llvm-jitlink to a new llvm-jitlink-executor tool. This patch also breaks the OrcJIT library into three parts: -- OrcTargetProcess: Contains code needed by the JIT execution process. -- OrcShared: Contains code needed by the JIT execution and compiler processes -- OrcJIT: Everything else. This break-up allows JIT executor processes to link against OrcTargetProcess and OrcShared only, without having to link in all of OrcJIT. Clients executing JIT'd code in-process should start linking against OrcTargetProcess as well as OrcJIT. In the near future these changes will enable: -- Removal of the OrcRemoteTargetClient/OrcRemoteTargetServer class templates which provided similar functionality in OrcV1. -- Restoration of Chapter 5 of the Building-A-JIT tutorial series, which will serve as a simple usage example for these APIs. -- Implementation of lazy, cross-target compilation in lli's -jit-kind=orc-lazy mode.
This commit is contained in:
parent
9606ef03f0
commit
1d0676b54c
|
@ -134,7 +134,8 @@ int main(int argc, char *argv[]) {
|
|||
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
|
||||
|
||||
// (1) Create LLJIT instance.
|
||||
auto TPC = ExitOnErr(SelfTargetProcessControl::Create());
|
||||
auto SSP = std::make_shared<SymbolStringPool>();
|
||||
auto TPC = ExitOnErr(SelfTargetProcessControl::Create(std::move(SSP)));
|
||||
auto J = ExitOnErr(LLJITBuilder().setTargetProcessControl(*TPC).create());
|
||||
|
||||
// (2) Install transform to print modules as they are compiled:
|
||||
|
|
|
@ -21,14 +21,6 @@
|
|||
namespace llvm {
|
||||
namespace jitlink {
|
||||
|
||||
/// Registers all FDEs in the given eh-frame section with the current process.
|
||||
Error registerEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize);
|
||||
|
||||
/// Deregisters all FDEs in the given eh-frame section with the current process.
|
||||
Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize);
|
||||
|
||||
/// Supports registration/deregistration of EH-frames in a target process.
|
||||
class EHFrameRegistrar {
|
||||
public:
|
||||
|
|
|
@ -801,6 +801,17 @@ public:
|
|||
/// Returns the endianness of content in this graph.
|
||||
support::endianness getEndianness() const { return Endianness; }
|
||||
|
||||
/// Allocate a copy of the given String using the LinkGraph's allocator.
|
||||
/// This can be useful when renaming symbols or adding new content to the
|
||||
/// graph.
|
||||
StringRef allocateString(Twine Source) {
|
||||
SmallString<256> TmpBuffer;
|
||||
auto SourceStr = Source.toStringRef(TmpBuffer);
|
||||
auto *AllocatedBuffer = Allocator.Allocate<char>(SourceStr.size());
|
||||
llvm::copy(SourceStr, AllocatedBuffer);
|
||||
return StringRef(AllocatedBuffer, SourceStr.size());
|
||||
}
|
||||
|
||||
/// Create a section with the given name, protection flags, and alignment.
|
||||
Section &createSection(StringRef Name, sys::Memory::ProtectionFlags Prot) {
|
||||
std::unique_ptr<Section> Sec(new Section(Name, Prot, Sections.size()));
|
||||
|
|
|
@ -41,17 +41,6 @@ namespace orc {
|
|||
|
||||
class ObjectLayer;
|
||||
|
||||
/// Run a main function, returning the result.
|
||||
///
|
||||
/// If the optional ProgramName argument is given then it will be inserted
|
||||
/// before the strings in Args as the first argument to the called function.
|
||||
///
|
||||
/// It is legal to have an empty argument list and no program name, however
|
||||
/// many main functions will expect a name argument at least, and will fail
|
||||
/// if none is provided.
|
||||
int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
|
||||
Optional<StringRef> ProgramName = None);
|
||||
|
||||
/// This iterator provides a convenient way to iterate over the elements
|
||||
/// of an llvm.global_ctors/llvm.global_dtors instance.
|
||||
///
|
||||
|
|
|
@ -0,0 +1,411 @@
|
|||
//===--- OrcRPCTargetProcessControl.h - Remote target control ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Utilities for interacting with target processes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/RPC/RPCUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
|
||||
#include "llvm/Support/MSVCErrorWorkarounds.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// JITLinkMemoryManager implementation for a process connected via an ORC RPC
|
||||
/// endpoint.
|
||||
template <typename OrcRPCTPCImplT>
|
||||
class OrcRPCTPCJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
|
||||
private:
|
||||
struct HostAlloc {
|
||||
std::unique_ptr<char[]> Mem;
|
||||
uint64_t Size;
|
||||
};
|
||||
|
||||
struct TargetAlloc {
|
||||
JITTargetAddress Address = 0;
|
||||
uint64_t AllocatedSize = 0;
|
||||
};
|
||||
|
||||
using HostAllocMap = DenseMap<int, HostAlloc>;
|
||||
using TargetAllocMap = DenseMap<int, TargetAlloc>;
|
||||
|
||||
public:
|
||||
class OrcRPCAllocation : public Allocation {
|
||||
public:
|
||||
OrcRPCAllocation(OrcRPCTPCJITLinkMemoryManager<OrcRPCTPCImplT> &Parent,
|
||||
HostAllocMap HostAllocs, TargetAllocMap TargetAllocs)
|
||||
: Parent(Parent), HostAllocs(std::move(HostAllocs)),
|
||||
TargetAllocs(std::move(TargetAllocs)) {
|
||||
assert(HostAllocs.size() == TargetAllocs.size() &&
|
||||
"HostAllocs size should match TargetAllocs");
|
||||
}
|
||||
|
||||
~OrcRPCAllocation() override {
|
||||
assert(TargetAllocs.empty() && "failed to deallocate");
|
||||
}
|
||||
|
||||
MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
|
||||
auto I = HostAllocs.find(Seg);
|
||||
assert(I != HostAllocs.end() && "No host allocation for segment");
|
||||
auto &HA = I->second;
|
||||
return {HA.Mem.get(), HA.Size};
|
||||
}
|
||||
|
||||
JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
|
||||
auto I = TargetAllocs.find(Seg);
|
||||
assert(I != TargetAllocs.end() && "No target allocation for segment");
|
||||
return I->second.Address;
|
||||
}
|
||||
|
||||
void finalizeAsync(FinalizeContinuation OnFinalize) override {
|
||||
|
||||
std::vector<tpctypes::BufferWrite> BufferWrites;
|
||||
orcrpctpc::ReleaseOrFinalizeMemRequest FMR;
|
||||
|
||||
for (auto &KV : HostAllocs) {
|
||||
assert(TargetAllocs.count(KV.first) &&
|
||||
"No target allocation for buffer");
|
||||
auto &HA = KV.second;
|
||||
auto &TA = TargetAllocs[KV.first];
|
||||
BufferWrites.push_back({TA.Address, StringRef(HA.Mem.get(), HA.Size)});
|
||||
FMR.push_back({orcrpctpc::toWireProtectionFlags(
|
||||
static_cast<sys::Memory::ProtectionFlags>(KV.first)),
|
||||
TA.Address, TA.AllocatedSize});
|
||||
}
|
||||
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << "finalizeAsync " << (void *)this << ":\n";
|
||||
auto FMRI = FMR.begin();
|
||||
for (auto &B : BufferWrites) {
|
||||
auto Prot = FMRI->Prot;
|
||||
++FMRI;
|
||||
dbgs() << " Writing " << formatv("{0:x16}", B.Buffer.size())
|
||||
<< " bytes to " << ((Prot & orcrpctpc::WPF_Read) ? 'R' : '-')
|
||||
<< ((Prot & orcrpctpc::WPF_Write) ? 'W' : '-')
|
||||
<< ((Prot & orcrpctpc::WPF_Exec) ? 'X' : '-')
|
||||
<< " segment: local " << (void *)B.Buffer.data()
|
||||
<< " -> target " << formatv("{0:x16}", B.Address) << "\n";
|
||||
}
|
||||
});
|
||||
if (auto Err =
|
||||
Parent.Parent.getMemoryAccess().writeBuffers(BufferWrites)) {
|
||||
OnFinalize(std::move(Err));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_WITH_TYPE("orc", dbgs() << " Applying permissions...\n");
|
||||
if (auto Err =
|
||||
Parent.getEndpoint().template callAsync<orcrpctpc::FinalizeMem>(
|
||||
[OF = std::move(OnFinalize)](Error Err2) {
|
||||
// FIXME: Dispatch to work queue.
|
||||
std::thread([OF = std::move(OF),
|
||||
Err3 = std::move(Err2)]() mutable {
|
||||
DEBUG_WITH_TYPE(
|
||||
"orc", { dbgs() << " finalizeAsync complete\n"; });
|
||||
OF(std::move(Err3));
|
||||
}).detach();
|
||||
return Error::success();
|
||||
},
|
||||
FMR)) {
|
||||
DEBUG_WITH_TYPE("orc", dbgs() << " failed.\n");
|
||||
Parent.getEndpoint().abandonPendingResponses();
|
||||
Parent.reportError(std::move(Err));
|
||||
}
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << "Leaving finalizeAsync (finalization may continue in "
|
||||
"background)\n";
|
||||
});
|
||||
}
|
||||
|
||||
Error deallocate() override {
|
||||
orcrpctpc::ReleaseOrFinalizeMemRequest RMR;
|
||||
for (auto &KV : TargetAllocs)
|
||||
RMR.push_back({orcrpctpc::toWireProtectionFlags(
|
||||
static_cast<sys::Memory::ProtectionFlags>(KV.first)),
|
||||
KV.second.Address, KV.second.AllocatedSize});
|
||||
TargetAllocs.clear();
|
||||
|
||||
return Parent.getEndpoint().template callB<orcrpctpc::ReleaseMem>(RMR);
|
||||
}
|
||||
|
||||
private:
|
||||
OrcRPCTPCJITLinkMemoryManager<OrcRPCTPCImplT> &Parent;
|
||||
HostAllocMap HostAllocs;
|
||||
TargetAllocMap TargetAllocs;
|
||||
};
|
||||
|
||||
OrcRPCTPCJITLinkMemoryManager(OrcRPCTPCImplT &Parent) : Parent(Parent) {}
|
||||
|
||||
Expected<std::unique_ptr<Allocation>>
|
||||
allocate(const SegmentsRequestMap &Request) override {
|
||||
orcrpctpc::ReserveMemRequest RMR;
|
||||
HostAllocMap HostAllocs;
|
||||
|
||||
for (auto &KV : Request) {
|
||||
RMR.push_back({orcrpctpc::toWireProtectionFlags(
|
||||
static_cast<sys::Memory::ProtectionFlags>(KV.first)),
|
||||
KV.second.getContentSize() + KV.second.getZeroFillSize(),
|
||||
KV.second.getAlignment()});
|
||||
HostAllocs[KV.first] = {
|
||||
std::make_unique<char[]>(KV.second.getContentSize()),
|
||||
KV.second.getContentSize()};
|
||||
}
|
||||
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << "Orc remote memmgr got request:\n";
|
||||
for (auto &KV : Request)
|
||||
dbgs() << " permissions: "
|
||||
<< ((KV.first & sys::Memory::MF_READ) ? 'R' : '-')
|
||||
<< ((KV.first & sys::Memory::MF_WRITE) ? 'W' : '-')
|
||||
<< ((KV.first & sys::Memory::MF_EXEC) ? 'X' : '-')
|
||||
<< ", content size: "
|
||||
<< formatv("{0:x16}", KV.second.getContentSize())
|
||||
<< " + zero-fill-size: "
|
||||
<< formatv("{0:x16}", KV.second.getZeroFillSize())
|
||||
<< ", align: " << KV.second.getAlignment() << "\n";
|
||||
});
|
||||
|
||||
// FIXME: LLVM RPC needs to be fixed to support alt
|
||||
// serialization/deserialization on return types. For now just
|
||||
// translate from std::map to DenseMap manually.
|
||||
auto TmpTargetAllocs =
|
||||
Parent.getEndpoint().template callB<orcrpctpc::ReserveMem>(RMR);
|
||||
if (!TmpTargetAllocs)
|
||||
return TmpTargetAllocs.takeError();
|
||||
|
||||
if (TmpTargetAllocs->size() != RMR.size())
|
||||
return make_error<StringError>(
|
||||
"Number of target allocations does not match request",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
TargetAllocMap TargetAllocs;
|
||||
for (auto &E : *TmpTargetAllocs)
|
||||
TargetAllocs[orcrpctpc::fromWireProtectionFlags(E.Prot)] = {
|
||||
E.Address, E.AllocatedSize};
|
||||
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
auto HAI = HostAllocs.begin();
|
||||
for (auto &KV : TargetAllocs)
|
||||
dbgs() << " permissions: "
|
||||
<< ((KV.first & sys::Memory::MF_READ) ? 'R' : '-')
|
||||
<< ((KV.first & sys::Memory::MF_WRITE) ? 'W' : '-')
|
||||
<< ((KV.first & sys::Memory::MF_EXEC) ? 'X' : '-')
|
||||
<< " assigned local " << (void *)HAI->second.Mem.get()
|
||||
<< ", target " << formatv("{0:x16}", KV.second.Address) << "\n";
|
||||
});
|
||||
|
||||
return std::make_unique<OrcRPCAllocation>(*this, std::move(HostAllocs),
|
||||
std::move(TargetAllocs));
|
||||
}
|
||||
|
||||
private:
|
||||
void reportError(Error Err) { Parent.reportError(std::move(Err)); }
|
||||
|
||||
decltype(std::declval<OrcRPCTPCImplT>().getEndpoint()) getEndpoint() {
|
||||
return Parent.getEndpoint();
|
||||
}
|
||||
|
||||
OrcRPCTPCImplT &Parent;
|
||||
};
|
||||
|
||||
/// TargetProcessControl::MemoryAccess implementation for a process connected
|
||||
/// via an ORC RPC endpoint.
|
||||
template <typename OrcRPCTPCImplT>
|
||||
class OrcRPCTPCMemoryAccess : public TargetProcessControl::MemoryAccess {
|
||||
public:
|
||||
OrcRPCTPCMemoryAccess(OrcRPCTPCImplT &Parent) : Parent(Parent) {}
|
||||
|
||||
void writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
writeViaRPC<orcrpctpc::WriteUInt8s>(Ws, std::move(OnWriteComplete));
|
||||
}
|
||||
|
||||
void writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
writeViaRPC<orcrpctpc::WriteUInt16s>(Ws, std::move(OnWriteComplete));
|
||||
}
|
||||
|
||||
void writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
writeViaRPC<orcrpctpc::WriteUInt32s>(Ws, std::move(OnWriteComplete));
|
||||
}
|
||||
|
||||
void writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
writeViaRPC<orcrpctpc::WriteUInt64s>(Ws, std::move(OnWriteComplete));
|
||||
}
|
||||
|
||||
void writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
|
||||
WriteResultFn OnWriteComplete) override {
|
||||
writeViaRPC<orcrpctpc::WriteBuffers>(Ws, std::move(OnWriteComplete));
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename WriteRPCFunction, typename WriteElementT>
|
||||
void writeViaRPC(ArrayRef<WriteElementT> Ws, WriteResultFn OnWriteComplete) {
|
||||
if (auto Err = Parent.getEndpoint().template callAsync<WriteRPCFunction>(
|
||||
[OWC = std::move(OnWriteComplete)](Error Err2) mutable -> Error {
|
||||
OWC(std::move(Err2));
|
||||
return Error::success();
|
||||
},
|
||||
Ws)) {
|
||||
Parent.reportError(std::move(Err));
|
||||
Parent.getEndpoint().abandonPendingResponses();
|
||||
}
|
||||
}
|
||||
|
||||
OrcRPCTPCImplT &Parent;
|
||||
};
|
||||
|
||||
// TargetProcessControl for a process connected via an ORC RPC Endpoint.
|
||||
template <typename RPCEndpointT>
|
||||
class OrcRPCTargetProcessControlBase : public TargetProcessControl {
|
||||
public:
|
||||
using ErrorReporter = unique_function<void(Error)>;
|
||||
|
||||
using OnCloseConnectionFunction = unique_function<Error(Error)>;
|
||||
|
||||
OrcRPCTargetProcessControlBase(std::shared_ptr<SymbolStringPool> SSP,
|
||||
RPCEndpointT &EP, ErrorReporter ReportError)
|
||||
: TargetProcessControl(std::move(SSP)),
|
||||
ReportError(std::move(ReportError)), EP(EP) {}
|
||||
|
||||
void reportError(Error Err) { ReportError(std::move(Err)); }
|
||||
|
||||
RPCEndpointT &getEndpoint() { return EP; }
|
||||
|
||||
Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override {
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << "Loading dylib \"" << (DylibPath ? DylibPath : "") << "\" ";
|
||||
if (!DylibPath)
|
||||
dbgs() << "(process symbols)";
|
||||
dbgs() << "\n";
|
||||
});
|
||||
if (!DylibPath)
|
||||
DylibPath = "";
|
||||
auto H = EP.template callB<orcrpctpc::LoadDylib>(DylibPath);
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
if (H)
|
||||
dbgs() << " got handle " << formatv("{0:x16}", *H) << "\n";
|
||||
else
|
||||
dbgs() << " error, unable to load\n";
|
||||
});
|
||||
return H;
|
||||
}
|
||||
|
||||
Expected<std::vector<tpctypes::LookupResult>>
|
||||
lookupSymbols(ArrayRef<tpctypes::LookupRequest> Request) override {
|
||||
std::vector<orcrpctpc::RemoteLookupRequest> RR;
|
||||
for (auto &E : Request) {
|
||||
RR.push_back({});
|
||||
RR.back().first = E.Handle;
|
||||
for (auto &KV : E.Symbols)
|
||||
RR.back().second.push_back(
|
||||
{(*KV.first).str(),
|
||||
KV.second == SymbolLookupFlags::WeaklyReferencedSymbol});
|
||||
}
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << "Compound lookup:\n";
|
||||
for (auto &R : Request) {
|
||||
dbgs() << " In " << formatv("{0:x16}", R.Handle) << ": {";
|
||||
bool First = true;
|
||||
for (auto &KV : R.Symbols) {
|
||||
dbgs() << (First ? "" : ",") << " " << *KV.first;
|
||||
First = false;
|
||||
}
|
||||
dbgs() << " }\n";
|
||||
}
|
||||
});
|
||||
return EP.template callB<orcrpctpc::LookupSymbols>(RR);
|
||||
}
|
||||
|
||||
Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
|
||||
ArrayRef<std::string> Args) override {
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << "Running as main: " << formatv("{0:x16}", MainFnAddr)
|
||||
<< ", args = [";
|
||||
for (unsigned I = 0; I != Args.size(); ++I)
|
||||
dbgs() << (I ? "," : "") << " \"" << Args[I] << "\"";
|
||||
dbgs() << "]\n";
|
||||
});
|
||||
auto Result = EP.template callB<orcrpctpc::RunMain>(MainFnAddr, Args);
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << " call to " << formatv("{0:x16}", MainFnAddr);
|
||||
if (Result)
|
||||
dbgs() << " returned result " << *Result << "\n";
|
||||
else
|
||||
dbgs() << " failed\n";
|
||||
});
|
||||
return Result;
|
||||
}
|
||||
|
||||
Expected<tpctypes::WrapperFunctionResult>
|
||||
runWrapper(JITTargetAddress WrapperFnAddr,
|
||||
ArrayRef<uint8_t> ArgBuffer) override {
|
||||
DEBUG_WITH_TYPE("orc", {
|
||||
dbgs() << "Running as wrapper function "
|
||||
<< formatv("{0:x16}", WrapperFnAddr) << " with "
|
||||
<< formatv("{0:x16}", ArgBuffer.size()) << " argument buffer\n";
|
||||
});
|
||||
auto Result =
|
||||
EP.template callB<orcrpctpc::RunWrapper>(WrapperFnAddr, ArgBuffer);
|
||||
// dbgs() << "Returned from runWrapper...\n";
|
||||
return Result;
|
||||
}
|
||||
|
||||
Error closeConnection(OnCloseConnectionFunction OnCloseConnection) {
|
||||
DEBUG_WITH_TYPE("orc", dbgs() << "Closing connection to remote\n");
|
||||
return EP.template callAsync<orcrpctpc::CloseConnection>(
|
||||
std::move(OnCloseConnection));
|
||||
}
|
||||
|
||||
Error closeConnectionAndWait() {
|
||||
std::promise<MSVCPError> P;
|
||||
auto F = P.get_future();
|
||||
if (auto Err = closeConnection([&](Error Err2) -> Error {
|
||||
P.set_value(std::move(Err2));
|
||||
return Error::success();
|
||||
})) {
|
||||
EP.abandonAllPendingResponses();
|
||||
return joinErrors(std::move(Err), F.get());
|
||||
}
|
||||
return F.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Subclasses must call this during construction to initialize the
|
||||
/// TargetTriple and PageSize members.
|
||||
Error initializeORCRPCTPCBase() {
|
||||
if (auto TripleOrErr = EP.template callB<orcrpctpc::GetTargetTriple>())
|
||||
TargetTriple = Triple(*TripleOrErr);
|
||||
else
|
||||
return TripleOrErr.takeError();
|
||||
|
||||
if (auto PageSizeOrErr = EP.template callB<orcrpctpc::GetPageSize>())
|
||||
PageSize = *PageSizeOrErr;
|
||||
else
|
||||
return PageSizeOrErr.takeError();
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
ErrorReporter ReportError;
|
||||
RPCEndpointT &EP;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
|
||||
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
||||
#include <unistd.h>
|
||||
#else
|
||||
|
@ -31,11 +34,13 @@ public:
|
|||
FDRawByteChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
|
||||
|
||||
llvm::Error readBytes(char *Dst, unsigned Size) override {
|
||||
// dbgs() << "Reading " << Size << " bytes: [";
|
||||
assert(Dst && "Attempt to read into null.");
|
||||
ssize_t Completed = 0;
|
||||
while (Completed < static_cast<ssize_t>(Size)) {
|
||||
ssize_t Read = ::read(InFD, Dst + Completed, Size - Completed);
|
||||
if (Read <= 0) {
|
||||
// dbgs() << " <<<\n";
|
||||
auto ErrNo = errno;
|
||||
if (ErrNo == EAGAIN || ErrNo == EINTR)
|
||||
continue;
|
||||
|
@ -43,17 +48,22 @@ public:
|
|||
return llvm::errorCodeToError(
|
||||
std::error_code(errno, std::generic_category()));
|
||||
}
|
||||
// for (size_t I = 0; I != Read; ++I)
|
||||
// dbgs() << " " << formatv("{0:x2}", Dst[Completed + I]);
|
||||
Completed += Read;
|
||||
}
|
||||
// dbgs() << " ]\n";
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Error appendBytes(const char *Src, unsigned Size) override {
|
||||
// dbgs() << "Appending " << Size << " bytes: [";
|
||||
assert(Src && "Attempt to append from null.");
|
||||
ssize_t Completed = 0;
|
||||
while (Completed < static_cast<ssize_t>(Size)) {
|
||||
ssize_t Written = ::write(OutFD, Src + Completed, Size - Completed);
|
||||
if (Written < 0) {
|
||||
// dbgs() << " <<<\n";
|
||||
auto ErrNo = errno;
|
||||
if (ErrNo == EAGAIN || ErrNo == EINTR)
|
||||
continue;
|
||||
|
@ -61,8 +71,11 @@ public:
|
|||
return llvm::errorCodeToError(
|
||||
std::error_code(errno, std::generic_category()));
|
||||
}
|
||||
// for (size_t I = 0; I != Written; ++I)
|
||||
// dbgs() << " " << formatv("{0:x2}", Src[Completed + I]);
|
||||
Completed += Written;
|
||||
}
|
||||
// dbgs() << " ]\n";
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#ifndef LLVM_EXECUTIONENGINE_ORC_RPC_RPCSERIALIZATION_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_RPC_RPCSERIALIZATION_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcError.h"
|
||||
#include "llvm/Support/thread.h"
|
||||
#include <map>
|
||||
|
@ -166,6 +168,19 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T> class RPCTypeName<Optional<T>> {
|
||||
public:
|
||||
static const char *getName() {
|
||||
static std::string Name = [] {
|
||||
std::string Name;
|
||||
raw_string_ostream(Name)
|
||||
<< "Optional<" << RPCTypeName<T>::getName() << ">";
|
||||
return Name;
|
||||
}();
|
||||
return Name.data();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class RPCTypeName<std::vector<T>> {
|
||||
public:
|
||||
|
@ -574,6 +589,31 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename T>
|
||||
class SerializationTraits<ChannelT, Optional<T>> {
|
||||
public:
|
||||
/// Serialize an Optional<T>.
|
||||
static Error serialize(ChannelT &C, const Optional<T> &O) {
|
||||
if (auto Err = serializeSeq(C, O != None))
|
||||
return Err;
|
||||
if (O)
|
||||
if (auto Err = serializeSeq(C, *O))
|
||||
return Err;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Deserialize an Optional<T>.
|
||||
static Error deserialize(ChannelT &C, Optional<T> &O) {
|
||||
bool HasValue = false;
|
||||
if (auto Err = deserializeSeq(C, HasValue))
|
||||
return Err;
|
||||
if (HasValue)
|
||||
if (auto Err = deserializeSeq(C, *O))
|
||||
return Err;
|
||||
return Error::success();
|
||||
};
|
||||
};
|
||||
|
||||
/// SerializationTraits default specialization for std::vector.
|
||||
template <typename ChannelT, typename T>
|
||||
class SerializationTraits<ChannelT, std::vector<T>> {
|
||||
|
@ -609,6 +649,22 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// Enable vector serialization from an ArrayRef.
|
||||
template <typename ChannelT, typename T>
|
||||
class SerializationTraits<ChannelT, std::vector<T>, ArrayRef<T>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, ArrayRef<T> V) {
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(V.size())))
|
||||
return Err;
|
||||
|
||||
for (const auto &E : V)
|
||||
if (auto Err = serializeSeq(C, E))
|
||||
return Err;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename T, typename T2>
|
||||
class SerializationTraits<ChannelT, std::set<T>, std::set<T2>> {
|
||||
public:
|
||||
|
@ -695,6 +751,55 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename K, typename V, typename K2, typename V2>
|
||||
class SerializationTraits<ChannelT, std::map<K, V>, DenseMap<K2, V2>> {
|
||||
public:
|
||||
/// Serialize a std::map<K, V> from DenseMap<K2, V2>.
|
||||
static Error serialize(ChannelT &C, const DenseMap<K2, V2> &M) {
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(M.size())))
|
||||
return Err;
|
||||
|
||||
for (auto &E : M) {
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, K, K2>::serialize(C, E.first))
|
||||
return Err;
|
||||
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, V, V2>::serialize(C, E.second))
|
||||
return Err;
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// Serialize a std::map<K, V> from DenseMap<K2, V2>.
|
||||
static Error deserialize(ChannelT &C, DenseMap<K2, V2> &M) {
|
||||
assert(M.empty() && "Expected default-constructed map to deserialize into");
|
||||
|
||||
uint64_t Count = 0;
|
||||
if (auto Err = deserializeSeq(C, Count))
|
||||
return Err;
|
||||
|
||||
while (Count-- != 0) {
|
||||
std::pair<K2, V2> Val;
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, K, K2>::deserialize(C, Val.first))
|
||||
return Err;
|
||||
|
||||
if (auto Err =
|
||||
SerializationTraits<ChannelT, V, V2>::deserialize(C, Val.second))
|
||||
return Err;
|
||||
|
||||
auto Added = M.insert(Val).second;
|
||||
if (!Added)
|
||||
return make_error<StringError>("Duplicate element in deserialized map",
|
||||
orcError(OrcErrorCode::UnknownORCError));
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace rpc
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
//===--- TargetProcessControlTypes.h -- Shared Core/TPC types ---*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// TargetProcessControl types that are used by both the Orc and
|
||||
// OrcTargetProcess libraries.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_TARGETPROCESSCONTROLTYPES_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_SHARED_TARGETPROCESSCONTROLTYPES_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace tpctypes {
|
||||
|
||||
template <typename T> struct UIntWrite {
|
||||
UIntWrite() = default;
|
||||
UIntWrite(JITTargetAddress Address, T Value)
|
||||
: Address(Address), Value(Value) {}
|
||||
|
||||
JITTargetAddress Address = 0;
|
||||
T Value = 0;
|
||||
};
|
||||
|
||||
/// Describes a write to a uint8_t.
|
||||
using UInt8Write = UIntWrite<uint8_t>;
|
||||
|
||||
/// Describes a write to a uint16_t.
|
||||
using UInt16Write = UIntWrite<uint16_t>;
|
||||
|
||||
/// Describes a write to a uint32_t.
|
||||
using UInt32Write = UIntWrite<uint32_t>;
|
||||
|
||||
/// Describes a write to a uint64_t.
|
||||
using UInt64Write = UIntWrite<uint64_t>;
|
||||
|
||||
/// Describes a write to a buffer.
|
||||
/// For use with TargetProcessControl::MemoryAccess objects.
|
||||
struct BufferWrite {
|
||||
BufferWrite() = default;
|
||||
BufferWrite(JITTargetAddress Address, StringRef Buffer)
|
||||
: Address(Address), Buffer(Buffer) {}
|
||||
|
||||
JITTargetAddress Address = 0;
|
||||
StringRef Buffer;
|
||||
};
|
||||
|
||||
/// A handle used to represent a loaded dylib in the target process.
|
||||
using DylibHandle = JITTargetAddress;
|
||||
|
||||
/// A pair of a dylib and a set of symbols to be looked up.
|
||||
struct LookupRequest {
|
||||
LookupRequest(DylibHandle Handle, const SymbolLookupSet &Symbols)
|
||||
: Handle(Handle), Symbols(Symbols) {}
|
||||
DylibHandle Handle;
|
||||
const SymbolLookupSet &Symbols;
|
||||
};
|
||||
|
||||
using LookupResult = std::vector<JITTargetAddress>;
|
||||
|
||||
/// Either a uint8_t array or a uint8_t*.
|
||||
union CWrapperFunctionResultData {
|
||||
uint8_t Value[8];
|
||||
uint8_t *ValuePtr;
|
||||
};
|
||||
|
||||
/// C ABI compatible wrapper function result.
|
||||
///
|
||||
/// This can be safely returned from extern "C" functions, but should be used
|
||||
/// to construct a WrapperFunctionResult for safety.
|
||||
struct CWrapperFunctionResult {
|
||||
uint64_t Size;
|
||||
CWrapperFunctionResultData Data;
|
||||
void (*Destroy)(CWrapperFunctionResultData Data, uint64_t Size);
|
||||
};
|
||||
|
||||
/// C++ wrapper function result: Same as CWrapperFunctionResult but
|
||||
/// auto-releases memory.
|
||||
class WrapperFunctionResult {
|
||||
public:
|
||||
/// Create a default WrapperFunctionResult.
|
||||
WrapperFunctionResult() { zeroInit(R); }
|
||||
|
||||
/// Create a WrapperFunctionResult from a CWrapperFunctionResult. This
|
||||
/// instance takes ownership of the result object and will automatically
|
||||
/// call the Destroy member upon destruction.
|
||||
WrapperFunctionResult(CWrapperFunctionResult R) : R(R) {}
|
||||
|
||||
WrapperFunctionResult(const WrapperFunctionResult &) = delete;
|
||||
WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
|
||||
|
||||
WrapperFunctionResult(WrapperFunctionResult &&Other) {
|
||||
zeroInit(R);
|
||||
std::swap(R, Other.R);
|
||||
}
|
||||
|
||||
WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
|
||||
CWrapperFunctionResult Tmp;
|
||||
zeroInit(Tmp);
|
||||
std::swap(Tmp, Other.R);
|
||||
std::swap(R, Tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~WrapperFunctionResult() {
|
||||
if (R.Destroy)
|
||||
R.Destroy(R.Data, R.Size);
|
||||
}
|
||||
|
||||
/// Relinquish ownership of and return the CWrapperFunctionResult.
|
||||
CWrapperFunctionResult release() {
|
||||
CWrapperFunctionResult Tmp;
|
||||
zeroInit(Tmp);
|
||||
std::swap(R, Tmp);
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
/// Get an ArrayRef covering the data in the result.
|
||||
ArrayRef<uint8_t> getData() const {
|
||||
if (R.Size <= 8)
|
||||
return ArrayRef<uint8_t>(R.Data.Value, R.Size);
|
||||
return ArrayRef<uint8_t>(R.Data.ValuePtr, R.Size);
|
||||
}
|
||||
|
||||
/// Create a WrapperFunctionResult from the given integer, provided its
|
||||
/// size is no greater than 64 bits.
|
||||
template <typename T,
|
||||
typename _ = std::enable_if_t<std::is_integral<T>::value &&
|
||||
sizeof(T) <= sizeof(uint64_t)>>
|
||||
static WrapperFunctionResult from(T Value) {
|
||||
CWrapperFunctionResult R;
|
||||
R.Size = sizeof(T);
|
||||
memcpy(&R.Data.Value, Value, R.Size);
|
||||
R.Destroy = nullptr;
|
||||
return R;
|
||||
}
|
||||
|
||||
/// Create a WrapperFunctionResult from the given string.
|
||||
static WrapperFunctionResult from(StringRef S);
|
||||
|
||||
/// Always free Data.ValuePtr by calling free on it.
|
||||
static void destroyWithFree(CWrapperFunctionResultData Data, uint64_t Size);
|
||||
|
||||
/// Always free Data.ValuePtr by calling delete[] on it.
|
||||
static void destroyWithDeleteArray(CWrapperFunctionResultData Data,
|
||||
uint64_t Size);
|
||||
|
||||
private:
|
||||
void zeroInit(CWrapperFunctionResult &R) {
|
||||
R.Size = 0;
|
||||
R.Data.ValuePtr = nullptr;
|
||||
R.Destroy = nullptr;
|
||||
}
|
||||
|
||||
CWrapperFunctionResult R;
|
||||
};
|
||||
|
||||
} // end namespace tpctypes
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_TARGETPROCESSCONTROLTYPES_H
|
|
@ -31,7 +31,7 @@ public:
|
|||
/// will be searched for. If the predicate is not given then all symbols will
|
||||
/// be searched for.
|
||||
TPCDynamicLibrarySearchGenerator(TargetProcessControl &TPC,
|
||||
TargetProcessControl::DylibHandle H,
|
||||
tpctypes::DylibHandle H,
|
||||
SymbolPredicate Allow = SymbolPredicate())
|
||||
: TPC(TPC), H(H), Allow(std::move(Allow)) {}
|
||||
|
||||
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
private:
|
||||
TargetProcessControl &TPC;
|
||||
TargetProcessControl::DylibHandle H;
|
||||
tpctypes::DylibHandle H;
|
||||
SymbolPredicate Allow;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
//===-- TPCEHFrameRegistrar.h - TPC based eh-frame registration -*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// TargetProcessControl based eh-frame registration.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_TPCEHFRAMEREGISTRAR_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_TPCEHFRAMEREGISTRAR_H
|
||||
|
||||
#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// Register/Deregisters EH frames in a remote process via a
|
||||
/// TargetProcessControl instance.
|
||||
class TPCEHFrameRegistrar : public jitlink::EHFrameRegistrar {
|
||||
public:
|
||||
/// Create from a TargetProcessControl instance alone. This will use
|
||||
/// the TPC's lookupSymbols method to find the registration/deregistration
|
||||
/// funciton addresses by name.
|
||||
static Expected<std::unique_ptr<TPCEHFrameRegistrar>>
|
||||
Create(TargetProcessControl &TPC);
|
||||
|
||||
/// Create a TPCEHFrameRegistrar with the given TargetProcessControl
|
||||
/// object and registration/deregistration function addresses.
|
||||
TPCEHFrameRegistrar(TargetProcessControl &TPC,
|
||||
JITTargetAddress RegisterEHFrameWrapperFnAddr,
|
||||
JITTargetAddress DeregisterEHFRameWrapperFnAddr)
|
||||
: TPC(TPC), RegisterEHFrameWrapperFnAddr(RegisterEHFrameWrapperFnAddr),
|
||||
DeregisterEHFrameWrapperFnAddr(DeregisterEHFRameWrapperFnAddr) {}
|
||||
|
||||
Error registerEHFrames(JITTargetAddress EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) override;
|
||||
Error deregisterEHFrames(JITTargetAddress EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) override;
|
||||
|
||||
private:
|
||||
TargetProcessControl &TPC;
|
||||
JITTargetAddress RegisterEHFrameWrapperFnAddr;
|
||||
JITTargetAddress DeregisterEHFrameWrapperFnAddr;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_TPCEHFRAMEREGISTRAR_H
|
|
@ -0,0 +1,614 @@
|
|||
//===-- OrcRPCTPCServer.h -- OrcRPCTargetProcessControl Server --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// OrcRPCTargetProcessControl server class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_ORCRPCTPCSERVER_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_ORCRPCTPCSERVER_H
|
||||
|
||||
#include "llvm/ADT/BitmaskEnum.h"
|
||||
#include "llvm/ExecutionEngine/Orc/RPC/RPCUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/RPC/RawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
namespace orcrpctpc {
|
||||
|
||||
enum WireProtectionFlags : uint8_t {
|
||||
WPF_None = 0,
|
||||
WPF_Read = 1U << 0,
|
||||
WPF_Write = 1U << 1,
|
||||
WPF_Exec = 1U << 2,
|
||||
LLVM_MARK_AS_BITMASK_ENUM(WPF_Exec)
|
||||
};
|
||||
|
||||
/// Convert from sys::Memory::ProtectionFlags
|
||||
inline WireProtectionFlags
|
||||
toWireProtectionFlags(sys::Memory::ProtectionFlags PF) {
|
||||
WireProtectionFlags WPF = WPF_None;
|
||||
if (PF & sys::Memory::MF_READ)
|
||||
WPF |= WPF_Read;
|
||||
if (PF & sys::Memory::MF_WRITE)
|
||||
WPF |= WPF_Write;
|
||||
if (PF & sys::Memory::MF_EXEC)
|
||||
WPF |= WPF_Exec;
|
||||
return WPF;
|
||||
}
|
||||
|
||||
inline sys::Memory::ProtectionFlags
|
||||
fromWireProtectionFlags(WireProtectionFlags WPF) {
|
||||
int PF = 0;
|
||||
if (WPF & WPF_Read)
|
||||
PF |= sys::Memory::MF_READ;
|
||||
if (WPF & WPF_Write)
|
||||
PF |= sys::Memory::MF_WRITE;
|
||||
if (WPF & WPF_Exec)
|
||||
PF |= sys::Memory::MF_EXEC;
|
||||
return static_cast<sys::Memory::ProtectionFlags>(PF);
|
||||
}
|
||||
|
||||
struct ReserveMemRequestElement {
|
||||
WireProtectionFlags Prot = WPF_None;
|
||||
uint64_t Size = 0;
|
||||
uint64_t Alignment = 0;
|
||||
};
|
||||
|
||||
using ReserveMemRequest = std::vector<ReserveMemRequestElement>;
|
||||
|
||||
struct ReserveMemResultElement {
|
||||
WireProtectionFlags Prot = WPF_None;
|
||||
JITTargetAddress Address = 0;
|
||||
uint64_t AllocatedSize = 0;
|
||||
};
|
||||
|
||||
using ReserveMemResult = std::vector<ReserveMemResultElement>;
|
||||
|
||||
struct ReleaseOrFinalizeMemRequestElement {
|
||||
WireProtectionFlags Prot = WPF_None;
|
||||
JITTargetAddress Address = 0;
|
||||
uint64_t Size = 0;
|
||||
};
|
||||
|
||||
using ReleaseOrFinalizeMemRequest =
|
||||
std::vector<ReleaseOrFinalizeMemRequestElement>;
|
||||
|
||||
} // end namespace orcrpctpc
|
||||
|
||||
namespace rpc {
|
||||
|
||||
template <> class RPCTypeName<tpctypes::UInt8Write> {
|
||||
public:
|
||||
static const char *getName() { return "UInt8Write"; }
|
||||
};
|
||||
|
||||
template <> class RPCTypeName<tpctypes::UInt16Write> {
|
||||
public:
|
||||
static const char *getName() { return "UInt16Write"; }
|
||||
};
|
||||
|
||||
template <> class RPCTypeName<tpctypes::UInt32Write> {
|
||||
public:
|
||||
static const char *getName() { return "UInt32Write"; }
|
||||
};
|
||||
|
||||
template <> class RPCTypeName<tpctypes::UInt64Write> {
|
||||
public:
|
||||
static const char *getName() { return "UInt64Write"; }
|
||||
};
|
||||
|
||||
template <> class RPCTypeName<tpctypes::BufferWrite> {
|
||||
public:
|
||||
static const char *getName() { return "BufferWrite"; }
|
||||
};
|
||||
|
||||
template <> class RPCTypeName<orcrpctpc::ReserveMemRequestElement> {
|
||||
public:
|
||||
static const char *getName() { return "ReserveMemRequestElement"; }
|
||||
};
|
||||
|
||||
template <> class RPCTypeName<orcrpctpc::ReserveMemResultElement> {
|
||||
public:
|
||||
static const char *getName() { return "ReserveMemResultElement"; }
|
||||
};
|
||||
|
||||
template <> class RPCTypeName<orcrpctpc::ReleaseOrFinalizeMemRequestElement> {
|
||||
public:
|
||||
static const char *getName() { return "ReleaseOrFinalizeMemRequestElement"; }
|
||||
};
|
||||
|
||||
template <> class RPCTypeName<tpctypes::WrapperFunctionResult> {
|
||||
public:
|
||||
static const char *getName() { return "WrapperFunctionResult"; }
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename WriteT>
|
||||
class SerializationTraits<
|
||||
ChannelT, WriteT, WriteT,
|
||||
std::enable_if_t<std::is_same<WriteT, tpctypes::UInt8Write>::value ||
|
||||
std::is_same<WriteT, tpctypes::UInt16Write>::value ||
|
||||
std::is_same<WriteT, tpctypes::UInt32Write>::value ||
|
||||
std::is_same<WriteT, tpctypes::UInt64Write>::value>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, const WriteT &W) {
|
||||
return serializeSeq(C, W.Address, W.Value);
|
||||
}
|
||||
static Error deserialize(ChannelT &C, WriteT &W) {
|
||||
return deserializeSeq(C, W.Address, W.Value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
class SerializationTraits<
|
||||
ChannelT, tpctypes::BufferWrite, tpctypes::BufferWrite,
|
||||
std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C, const tpctypes::BufferWrite &W) {
|
||||
uint64_t Size = W.Buffer.size();
|
||||
if (auto Err = serializeSeq(C, W.Address, Size))
|
||||
return Err;
|
||||
|
||||
return C.appendBytes(W.Buffer.data(), Size);
|
||||
}
|
||||
static Error deserialize(ChannelT &C, tpctypes::BufferWrite &W) {
|
||||
JITTargetAddress Address;
|
||||
uint64_t Size;
|
||||
|
||||
if (auto Err = deserializeSeq(C, Address, Size))
|
||||
return Err;
|
||||
|
||||
char *Buffer = jitTargetAddressToPointer<char *>(Address);
|
||||
|
||||
if (auto Err = C.readBytes(Buffer, Size))
|
||||
return Err;
|
||||
|
||||
W = {Address, StringRef(Buffer, Size)};
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
class SerializationTraits<ChannelT, orcrpctpc::ReserveMemRequestElement> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C,
|
||||
const orcrpctpc::ReserveMemRequestElement &E) {
|
||||
return serializeSeq(C, static_cast<uint8_t>(E.Prot), E.Size, E.Alignment);
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C,
|
||||
orcrpctpc::ReserveMemRequestElement &E) {
|
||||
return deserializeSeq(C, *reinterpret_cast<uint8_t *>(&E.Prot), E.Size,
|
||||
E.Alignment);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
class SerializationTraits<ChannelT, orcrpctpc::ReserveMemResultElement> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C,
|
||||
const orcrpctpc::ReserveMemResultElement &E) {
|
||||
return serializeSeq(C, static_cast<uint8_t>(E.Prot), E.Address,
|
||||
E.AllocatedSize);
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C, orcrpctpc::ReserveMemResultElement &E) {
|
||||
return deserializeSeq(C, *reinterpret_cast<uint8_t *>(&E.Prot), E.Address,
|
||||
E.AllocatedSize);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
class SerializationTraits<ChannelT,
|
||||
orcrpctpc::ReleaseOrFinalizeMemRequestElement> {
|
||||
public:
|
||||
static Error
|
||||
serialize(ChannelT &C,
|
||||
const orcrpctpc::ReleaseOrFinalizeMemRequestElement &E) {
|
||||
return serializeSeq(C, static_cast<uint8_t>(E.Prot), E.Address, E.Size);
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C,
|
||||
orcrpctpc::ReleaseOrFinalizeMemRequestElement &E) {
|
||||
return deserializeSeq(C, *reinterpret_cast<uint8_t *>(&E.Prot), E.Address,
|
||||
E.Size);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT>
|
||||
class SerializationTraits<
|
||||
ChannelT, tpctypes::WrapperFunctionResult, tpctypes::WrapperFunctionResult,
|
||||
std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
|
||||
public:
|
||||
static Error serialize(ChannelT &C,
|
||||
const tpctypes::WrapperFunctionResult &E) {
|
||||
auto Data = E.getData();
|
||||
if (auto Err = serializeSeq(C, static_cast<uint64_t>(Data.size())))
|
||||
return Err;
|
||||
if (Data.size() == 0)
|
||||
return Error::success();
|
||||
return C.appendBytes(reinterpret_cast<const char *>(Data.data()),
|
||||
Data.size());
|
||||
}
|
||||
|
||||
static Error deserialize(ChannelT &C, tpctypes::WrapperFunctionResult &E) {
|
||||
tpctypes::CWrapperFunctionResult R;
|
||||
|
||||
R.Size = 0;
|
||||
R.Data.ValuePtr = nullptr;
|
||||
R.Destroy = nullptr;
|
||||
|
||||
if (auto Err = deserializeSeq(C, R.Size))
|
||||
return Err;
|
||||
if (R.Size == 0)
|
||||
return Error::success();
|
||||
R.Data.ValuePtr = new uint8_t[R.Size];
|
||||
if (auto Err =
|
||||
C.readBytes(reinterpret_cast<char *>(R.Data.ValuePtr), R.Size)) {
|
||||
R.Destroy = tpctypes::WrapperFunctionResult::destroyWithDeleteArray;
|
||||
return Err;
|
||||
}
|
||||
|
||||
E = tpctypes::WrapperFunctionResult(R);
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace rpc
|
||||
|
||||
namespace orcrpctpc {
|
||||
|
||||
using RemoteSymbolLookupSet = std::vector<std::pair<std::string, bool>>;
|
||||
using RemoteLookupRequest =
|
||||
std::pair<tpctypes::DylibHandle, RemoteSymbolLookupSet>;
|
||||
|
||||
class GetTargetTriple : public rpc::Function<GetTargetTriple, std::string()> {
|
||||
public:
|
||||
static const char *getName() { return "GetTargetTriple"; }
|
||||
};
|
||||
|
||||
class GetPageSize : public rpc::Function<GetPageSize, uint64_t()> {
|
||||
public:
|
||||
static const char *getName() { return "GetPageSize"; }
|
||||
};
|
||||
|
||||
class ReserveMem : public rpc::Function<ReserveMem, Expected<ReserveMemResult>(
|
||||
ReserveMemRequest)> {
|
||||
public:
|
||||
static const char *getName() { return "ReserveMem"; }
|
||||
};
|
||||
|
||||
class FinalizeMem
|
||||
: public rpc::Function<FinalizeMem, Error(ReleaseOrFinalizeMemRequest)> {
|
||||
public:
|
||||
static const char *getName() { return "FinalizeMem"; }
|
||||
};
|
||||
|
||||
class ReleaseMem
|
||||
: public rpc::Function<ReleaseMem, Error(ReleaseOrFinalizeMemRequest)> {
|
||||
public:
|
||||
static const char *getName() { return "ReleaseMem"; }
|
||||
};
|
||||
|
||||
class WriteUInt8s
|
||||
: public rpc::Function<WriteUInt8s,
|
||||
Error(std::vector<tpctypes::UInt8Write>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteUInt8s"; }
|
||||
};
|
||||
|
||||
class WriteUInt16s
|
||||
: public rpc::Function<WriteUInt16s,
|
||||
Error(std::vector<tpctypes::UInt16Write>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteUInt16s"; }
|
||||
};
|
||||
|
||||
class WriteUInt32s
|
||||
: public rpc::Function<WriteUInt32s,
|
||||
Error(std::vector<tpctypes::UInt32Write>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteUInt32s"; }
|
||||
};
|
||||
|
||||
class WriteUInt64s
|
||||
: public rpc::Function<WriteUInt64s,
|
||||
Error(std::vector<tpctypes::UInt64Write>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteUInt64s"; }
|
||||
};
|
||||
|
||||
class WriteBuffers
|
||||
: public rpc::Function<WriteBuffers,
|
||||
Error(std::vector<tpctypes::BufferWrite>)> {
|
||||
public:
|
||||
static const char *getName() { return "WriteBuffers"; }
|
||||
};
|
||||
|
||||
class LoadDylib
|
||||
: public rpc::Function<LoadDylib, Expected<tpctypes::DylibHandle>(
|
||||
std::string DylibPath)> {
|
||||
public:
|
||||
static const char *getName() { return "LoadDylib"; }
|
||||
};
|
||||
|
||||
class LookupSymbols
|
||||
: public rpc::Function<LookupSymbols,
|
||||
Expected<std::vector<tpctypes::LookupResult>>(
|
||||
std::vector<RemoteLookupRequest>)> {
|
||||
public:
|
||||
static const char *getName() { return "LookupSymbols"; }
|
||||
};
|
||||
|
||||
class RunMain
|
||||
: public rpc::Function<RunMain, int32_t(JITTargetAddress MainAddr,
|
||||
std::vector<std::string> Args)> {
|
||||
public:
|
||||
static const char *getName() { return "RunMain"; }
|
||||
};
|
||||
|
||||
class RunWrapper
|
||||
: public rpc::Function<RunWrapper,
|
||||
tpctypes::WrapperFunctionResult(
|
||||
JITTargetAddress, std::vector<uint8_t>)> {
|
||||
public:
|
||||
static const char *getName() { return "RunWrapper"; }
|
||||
};
|
||||
|
||||
class CloseConnection : public rpc::Function<CloseConnection, void()> {
|
||||
public:
|
||||
static const char *getName() { return "CloseConnection"; }
|
||||
};
|
||||
|
||||
} // end namespace orcrpctpc
|
||||
|
||||
/// TargetProcessControl for a process connected via an ORC RPC Endpoint.
|
||||
template <typename RPCEndpointT> class OrcRPCTPCServer {
|
||||
public:
|
||||
/// Create an OrcRPCTPCServer from the given endpoint.
|
||||
OrcRPCTPCServer(RPCEndpointT &EP) : EP(EP) {
|
||||
using ThisT = OrcRPCTPCServer<RPCEndpointT>;
|
||||
|
||||
TripleStr = sys::getProcessTriple();
|
||||
PageSize = sys::Process::getPageSizeEstimate();
|
||||
|
||||
EP.template addHandler<orcrpctpc::GetTargetTriple>(*this,
|
||||
&ThisT::getTargetTriple);
|
||||
EP.template addHandler<orcrpctpc::GetPageSize>(*this, &ThisT::getPageSize);
|
||||
|
||||
EP.template addHandler<orcrpctpc::ReserveMem>(*this, &ThisT::reserveMemory);
|
||||
EP.template addHandler<orcrpctpc::FinalizeMem>(*this,
|
||||
&ThisT::finalizeMemory);
|
||||
EP.template addHandler<orcrpctpc::ReleaseMem>(*this, &ThisT::releaseMemory);
|
||||
|
||||
EP.template addHandler<orcrpctpc::WriteUInt8s>(
|
||||
handleWriteUInt<tpctypes::UInt8Write>);
|
||||
EP.template addHandler<orcrpctpc::WriteUInt16s>(
|
||||
handleWriteUInt<tpctypes::UInt16Write>);
|
||||
EP.template addHandler<orcrpctpc::WriteUInt32s>(
|
||||
handleWriteUInt<tpctypes::UInt32Write>);
|
||||
EP.template addHandler<orcrpctpc::WriteUInt64s>(
|
||||
handleWriteUInt<tpctypes::UInt64Write>);
|
||||
EP.template addHandler<orcrpctpc::WriteBuffers>(handleWriteBuffer);
|
||||
|
||||
EP.template addHandler<orcrpctpc::LoadDylib>(*this, &ThisT::loadDylib);
|
||||
EP.template addHandler<orcrpctpc::LookupSymbols>(*this,
|
||||
&ThisT::lookupSymbols);
|
||||
|
||||
EP.template addHandler<orcrpctpc::RunMain>(*this, &ThisT::runMain);
|
||||
EP.template addHandler<orcrpctpc::RunWrapper>(*this, &ThisT::runWrapper);
|
||||
|
||||
EP.template addHandler<orcrpctpc::CloseConnection>(*this,
|
||||
&ThisT::closeConnection);
|
||||
}
|
||||
|
||||
/// Set the ProgramName to be used as the first argv element when running
|
||||
/// functions via runAsMain.
|
||||
void setProgramName(Optional<std::string> ProgramName = None) {
|
||||
this->ProgramName = std::move(ProgramName);
|
||||
}
|
||||
|
||||
/// Get the RPC endpoint for this server.
|
||||
RPCEndpointT &getEndpoint() { return EP; }
|
||||
|
||||
/// Run the server loop.
|
||||
Error run() {
|
||||
while (!Finished) {
|
||||
if (auto Err = EP.handleOne())
|
||||
return Err;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string getTargetTriple() { return TripleStr; }
|
||||
uint64_t getPageSize() { return PageSize; }
|
||||
|
||||
template <typename WriteT>
|
||||
static void handleWriteUInt(const std::vector<WriteT> &Ws) {
|
||||
using ValueT = decltype(std::declval<WriteT>().Value);
|
||||
for (auto &W : Ws)
|
||||
*jitTargetAddressToPointer<ValueT *>(W.Address) = W.Value;
|
||||
}
|
||||
|
||||
std::string getProtStr(orcrpctpc::WireProtectionFlags WPF) {
|
||||
std::string Result;
|
||||
Result += (WPF & orcrpctpc::WPF_Read) ? 'R' : '-';
|
||||
Result += (WPF & orcrpctpc::WPF_Write) ? 'W' : '-';
|
||||
Result += (WPF & orcrpctpc::WPF_Exec) ? 'X' : '-';
|
||||
return Result;
|
||||
}
|
||||
|
||||
static void handleWriteBuffer(const std::vector<tpctypes::BufferWrite> &Ws) {
|
||||
for (auto &W : Ws) {
|
||||
memcpy(jitTargetAddressToPointer<char *>(W.Address), W.Buffer.data(),
|
||||
W.Buffer.size());
|
||||
}
|
||||
}
|
||||
|
||||
Expected<orcrpctpc::ReserveMemResult>
|
||||
reserveMemory(const orcrpctpc::ReserveMemRequest &Request) {
|
||||
orcrpctpc::ReserveMemResult Allocs;
|
||||
auto PF = sys::Memory::MF_READ | sys::Memory::MF_WRITE;
|
||||
|
||||
uint64_t TotalSize = 0;
|
||||
|
||||
for (const auto &E : Request) {
|
||||
uint64_t Size = alignTo(E.Size, PageSize);
|
||||
uint16_t Align = E.Alignment;
|
||||
|
||||
if ((Align > PageSize) || (PageSize % Align))
|
||||
return make_error<StringError>(
|
||||
"Page alignmen does not satisfy requested alignment",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
TotalSize += Size;
|
||||
}
|
||||
|
||||
// Allocate memory slab.
|
||||
std::error_code EC;
|
||||
auto MB = sys::Memory::allocateMappedMemory(TotalSize, nullptr, PF, EC);
|
||||
if (EC)
|
||||
return make_error<StringError>("Unable to allocate memory: " +
|
||||
EC.message(),
|
||||
inconvertibleErrorCode());
|
||||
|
||||
// Zero-fill the whole thing.
|
||||
memset(MB.base(), 0, MB.allocatedSize());
|
||||
|
||||
// Carve up sections to return.
|
||||
uint64_t SectionBase = 0;
|
||||
for (const auto &E : Request) {
|
||||
uint64_t SectionSize = alignTo(E.Size, PageSize);
|
||||
Allocs.push_back({E.Prot,
|
||||
pointerToJITTargetAddress(MB.base()) + SectionBase,
|
||||
SectionSize});
|
||||
SectionBase += SectionSize;
|
||||
}
|
||||
|
||||
return Allocs;
|
||||
}
|
||||
|
||||
Error finalizeMemory(const orcrpctpc::ReleaseOrFinalizeMemRequest &FMR) {
|
||||
for (const auto &E : FMR) {
|
||||
sys::MemoryBlock MB(jitTargetAddressToPointer<void *>(E.Address), E.Size);
|
||||
|
||||
auto PF = orcrpctpc::fromWireProtectionFlags(E.Prot);
|
||||
if (auto EC =
|
||||
sys::Memory::protectMappedMemory(MB, static_cast<unsigned>(PF)))
|
||||
return make_error<StringError>("error protecting memory: " +
|
||||
EC.message(),
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error releaseMemory(const orcrpctpc::ReleaseOrFinalizeMemRequest &RMR) {
|
||||
for (const auto &E : RMR) {
|
||||
sys::MemoryBlock MB(jitTargetAddressToPointer<void *>(E.Address), E.Size);
|
||||
|
||||
if (auto EC = sys::Memory::releaseMappedMemory(MB))
|
||||
return make_error<StringError>("error release memory: " + EC.message(),
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<tpctypes::DylibHandle> loadDylib(const std::string &Path) {
|
||||
std::string ErrMsg;
|
||||
const char *DLPath = !Path.empty() ? Path.c_str() : nullptr;
|
||||
auto DL = sys::DynamicLibrary::getPermanentLibrary(DLPath, &ErrMsg);
|
||||
if (!DL.isValid())
|
||||
return make_error<StringError>(std::move(ErrMsg),
|
||||
inconvertibleErrorCode());
|
||||
|
||||
tpctypes::DylibHandle H = Dylibs.size();
|
||||
Dylibs[H] = std::move(DL);
|
||||
return H;
|
||||
}
|
||||
|
||||
Expected<std::vector<tpctypes::LookupResult>>
|
||||
lookupSymbols(const std::vector<orcrpctpc::RemoteLookupRequest> &Request) {
|
||||
std::vector<tpctypes::LookupResult> Result;
|
||||
|
||||
for (const auto &E : Request) {
|
||||
auto I = Dylibs.find(E.first);
|
||||
if (I == Dylibs.end())
|
||||
return make_error<StringError>("Unrecognized handle",
|
||||
inconvertibleErrorCode());
|
||||
auto &DL = I->second;
|
||||
Result.push_back({});
|
||||
|
||||
for (const auto &KV : E.second) {
|
||||
auto &SymString = KV.first;
|
||||
bool WeakReference = KV.second;
|
||||
|
||||
const char *Sym = SymString.c_str();
|
||||
#ifdef __APPLE__
|
||||
if (*Sym == '_')
|
||||
++Sym;
|
||||
#endif
|
||||
|
||||
void *Addr = DL.getAddressOfSymbol(Sym);
|
||||
if (!Addr && !WeakReference)
|
||||
return make_error<StringError>(Twine("Missing definition for ") + Sym,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
Result.back().push_back(pointerToJITTargetAddress(Addr));
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
int32_t runMain(JITTargetAddress MainFnAddr,
|
||||
const std::vector<std::string> &Args) {
|
||||
Optional<StringRef> ProgramNameOverride;
|
||||
if (ProgramName)
|
||||
ProgramNameOverride = *ProgramName;
|
||||
|
||||
return runAsMain(
|
||||
jitTargetAddressToFunction<int (*)(int, char *[])>(MainFnAddr), Args,
|
||||
ProgramNameOverride);
|
||||
}
|
||||
|
||||
tpctypes::WrapperFunctionResult
|
||||
runWrapper(JITTargetAddress WrapperFnAddr,
|
||||
const std::vector<uint8_t> &ArgBuffer) {
|
||||
using WrapperFnTy = tpctypes::CWrapperFunctionResult (*)(
|
||||
const uint8_t *Data, uint64_t Size);
|
||||
auto *WrapperFn = jitTargetAddressToFunction<WrapperFnTy>(WrapperFnAddr);
|
||||
return WrapperFn(ArgBuffer.data(), ArgBuffer.size());
|
||||
}
|
||||
|
||||
void closeConnection() { Finished = true; }
|
||||
|
||||
std::string TripleStr;
|
||||
uint64_t PageSize = 0;
|
||||
Optional<std::string> ProgramName;
|
||||
RPCEndpointT &EP;
|
||||
std::atomic<bool> Finished{false};
|
||||
DenseMap<tpctypes::DylibHandle, sys::DynamicLibrary> Dylibs;
|
||||
};
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_ORCRPCTPCSERVER_H
|
|
@ -0,0 +1,41 @@
|
|||
//===----- RegisterEHFrames.h -- Register EH frame sections -----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Support for dynamically registering and deregistering eh-frame sections
|
||||
// in-process via libunwind.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_REGISTEREHFRAMES_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_REGISTEREHFRAMES_H
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// Register frames in the given eh-frame section with libunwind.
|
||||
Error registerEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize);
|
||||
|
||||
/// Unregister frames in the given eh-frame section with libunwind.
|
||||
Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize);
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
extern "C" llvm::orc::tpctypes::CWrapperFunctionResult
|
||||
llvm_orc_registerEHFrameSectionWrapper(uint8_t *Data, uint64_t Size);
|
||||
|
||||
extern "C" llvm::orc::tpctypes::CWrapperFunctionResult
|
||||
llvm_orc_deregisterEHFrameSectionWrapper(uint8_t *Data, uint64_t Size);
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_REGISTEREHFRAMES_H
|
|
@ -0,0 +1,38 @@
|
|||
//===-- TargetExecutionUtils.h - Utils for execution in target --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Utilities for execution in the target process.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_TARGETEXECUTIONUTILS_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_TARGETEXECUTIONUTILS_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// Run a main function, returning the result.
|
||||
///
|
||||
/// If the optional ProgramName argument is given then it will be inserted
|
||||
/// before the strings in Args as the first argument to the called function.
|
||||
///
|
||||
/// It is legal to have an empty argument list and no program name, however
|
||||
/// many main functions will expect a name argument at least, and will fail
|
||||
/// if none is provided.
|
||||
int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
|
||||
Optional<StringRef> ProgramName = None);
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_TARGETEXECUTIONUTILS_H
|
|
@ -18,6 +18,7 @@
|
|||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/MSVCErrorWorkarounds.h"
|
||||
|
||||
|
@ -33,76 +34,55 @@ public:
|
|||
/// APIs for manipulating memory in the target process.
|
||||
class MemoryAccess {
|
||||
public:
|
||||
template <typename T> struct UIntWrite {
|
||||
UIntWrite() = default;
|
||||
UIntWrite(JITTargetAddress Address, T Value)
|
||||
: Address(Address), Value(Value) {}
|
||||
|
||||
JITTargetAddress Address = 0;
|
||||
T Value = 0;
|
||||
};
|
||||
|
||||
using UInt8Write = UIntWrite<uint8_t>;
|
||||
using UInt16Write = UIntWrite<uint16_t>;
|
||||
using UInt32Write = UIntWrite<uint32_t>;
|
||||
using UInt64Write = UIntWrite<uint64_t>;
|
||||
|
||||
struct BufferWrite {
|
||||
BufferWrite(JITTargetAddress Address, StringRef Buffer)
|
||||
: Address(Address), Buffer(Buffer) {}
|
||||
|
||||
JITTargetAddress Address = 0;
|
||||
StringRef Buffer;
|
||||
};
|
||||
|
||||
/// Callback function for asynchronous writes.
|
||||
using WriteResultFn = unique_function<void(Error)>;
|
||||
|
||||
virtual ~MemoryAccess();
|
||||
|
||||
virtual void writeUInt8s(ArrayRef<UInt8Write> Ws,
|
||||
virtual void writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
|
||||
WriteResultFn OnWriteComplete) = 0;
|
||||
|
||||
virtual void writeUInt16s(ArrayRef<UInt16Write> Ws,
|
||||
virtual void writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
|
||||
WriteResultFn OnWriteComplete) = 0;
|
||||
|
||||
virtual void writeUInt32s(ArrayRef<UInt32Write> Ws,
|
||||
virtual void writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
|
||||
WriteResultFn OnWriteComplete) = 0;
|
||||
|
||||
virtual void writeUInt64s(ArrayRef<UInt64Write> Ws,
|
||||
virtual void writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
|
||||
WriteResultFn OnWriteComplete) = 0;
|
||||
|
||||
virtual void writeBuffers(ArrayRef<BufferWrite> Ws,
|
||||
virtual void writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
|
||||
WriteResultFn OnWriteComplete) = 0;
|
||||
|
||||
Error writeUInt8s(ArrayRef<UInt8Write> Ws) {
|
||||
Error writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws) {
|
||||
std::promise<MSVCPError> ResultP;
|
||||
auto ResultF = ResultP.get_future();
|
||||
writeUInt8s(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
|
||||
return ResultF.get();
|
||||
}
|
||||
|
||||
Error writeUInt16s(ArrayRef<UInt16Write> Ws) {
|
||||
Error writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws) {
|
||||
std::promise<MSVCPError> ResultP;
|
||||
auto ResultF = ResultP.get_future();
|
||||
writeUInt16s(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
|
||||
return ResultF.get();
|
||||
}
|
||||
|
||||
Error writeUInt32s(ArrayRef<UInt32Write> Ws) {
|
||||
Error writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws) {
|
||||
std::promise<MSVCPError> ResultP;
|
||||
auto ResultF = ResultP.get_future();
|
||||
writeUInt32s(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
|
||||
return ResultF.get();
|
||||
}
|
||||
|
||||
Error writeUInt64s(ArrayRef<UInt64Write> Ws) {
|
||||
Error writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws) {
|
||||
std::promise<MSVCPError> ResultP;
|
||||
auto ResultF = ResultP.get_future();
|
||||
writeUInt64s(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
|
||||
return ResultF.get();
|
||||
}
|
||||
|
||||
Error writeBuffers(ArrayRef<BufferWrite> Ws) {
|
||||
Error writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws) {
|
||||
std::promise<MSVCPError> ResultP;
|
||||
auto ResultF = ResultP.get_future();
|
||||
writeBuffers(Ws, [&](Error Err) { ResultP.set_value(std::move(Err)); });
|
||||
|
@ -110,43 +90,30 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// A handle for a library opened via loadDylib.
|
||||
///
|
||||
/// Note that this handle does not necessarily represent a JITDylib: it may
|
||||
/// be a regular dynamic library or shared object (e.g. one opened via a
|
||||
/// dlopen in the target process).
|
||||
using DylibHandle = JITTargetAddress;
|
||||
|
||||
/// Request lookup within the given DylibHandle.
|
||||
struct LookupRequestElement {
|
||||
LookupRequestElement(DylibHandle Handle, const SymbolLookupSet &Symbols)
|
||||
: Handle(Handle), Symbols(Symbols) {}
|
||||
DylibHandle Handle;
|
||||
const SymbolLookupSet &Symbols;
|
||||
};
|
||||
|
||||
using LookupRequest = ArrayRef<LookupRequestElement>;
|
||||
|
||||
using LookupResult = std::vector<std::vector<JITTargetAddress>>;
|
||||
|
||||
virtual ~TargetProcessControl();
|
||||
|
||||
/// Intern a symbol name in the SymbolStringPool.
|
||||
SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
|
||||
|
||||
/// Return a shared pointer to the SymbolStringPool for this instance.
|
||||
std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
|
||||
|
||||
/// Return the Triple for the target process.
|
||||
const Triple &getTargetTriple() const { return TT; }
|
||||
const Triple &getTargetTriple() const { return TargetTriple; }
|
||||
|
||||
/// Get the page size for the target process.
|
||||
unsigned getPageSize() const { return PageSize; }
|
||||
|
||||
/// Return a JITLinkMemoryManager for the target process.
|
||||
jitlink::JITLinkMemoryManager &getMemMgr() const { return *MemMgr; }
|
||||
|
||||
/// Return a MemoryAccess object for the target process.
|
||||
MemoryAccess &getMemoryAccess() const { return *MemAccess; }
|
||||
|
||||
/// Return a JITLinkMemoryManager for the target process.
|
||||
jitlink::JITLinkMemoryManager &getMemMgr() const { return *MemMgr; }
|
||||
|
||||
/// Load the dynamic library at the given path and return a handle to it.
|
||||
/// If LibraryPath is null this function will return the global handle for
|
||||
/// the target process.
|
||||
virtual Expected<DylibHandle> loadDylib(const char *DylibPath) = 0;
|
||||
virtual Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) = 0;
|
||||
|
||||
/// Search for symbols in the target process.
|
||||
///
|
||||
|
@ -154,14 +121,37 @@ public:
|
|||
/// that correspond to the lookup order. If a required symbol is not
|
||||
/// found then this method will return an error. If a weakly referenced
|
||||
/// symbol is not found then it be assigned a '0' value in the result.
|
||||
virtual Expected<LookupResult> lookupSymbols(LookupRequest Request) = 0;
|
||||
/// that correspond to the lookup order.
|
||||
virtual Expected<std::vector<tpctypes::LookupResult>>
|
||||
lookupSymbols(ArrayRef<tpctypes::LookupRequest> Request) = 0;
|
||||
|
||||
/// Run function with a main-like signature.
|
||||
virtual Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
|
||||
ArrayRef<std::string> Args) = 0;
|
||||
|
||||
/// Run a wrapper function with signature:
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// CWrapperFunctionResult fn(uint8_t *Data, uint64_t Size);
|
||||
/// \endcode{.cpp}
|
||||
///
|
||||
virtual Expected<tpctypes::WrapperFunctionResult>
|
||||
runWrapper(JITTargetAddress WrapperFnAddr, ArrayRef<uint8_t> ArgBuffer) = 0;
|
||||
|
||||
/// Disconnect from the target process.
|
||||
///
|
||||
/// This should be called after the JIT session is shut down.
|
||||
virtual Error disconnect() = 0;
|
||||
|
||||
protected:
|
||||
TargetProcessControl(std::shared_ptr<SymbolStringPool> SSP)
|
||||
: SSP(std::move(SSP)) {}
|
||||
|
||||
Triple TT;
|
||||
std::shared_ptr<SymbolStringPool> SSP;
|
||||
Triple TargetTriple;
|
||||
unsigned PageSize = 0;
|
||||
jitlink::JITLinkMemoryManager *MemMgr = nullptr;
|
||||
MemoryAccess *MemAccess = nullptr;
|
||||
jitlink::JITLinkMemoryManager *MemMgr = nullptr;
|
||||
};
|
||||
|
||||
/// A TargetProcessControl implementation targeting the current process.
|
||||
|
@ -169,33 +159,44 @@ class SelfTargetProcessControl : public TargetProcessControl,
|
|||
private TargetProcessControl::MemoryAccess {
|
||||
public:
|
||||
SelfTargetProcessControl(
|
||||
Triple TT, unsigned PageSize,
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
|
||||
std::shared_ptr<SymbolStringPool> SSP, Triple TargetTriple,
|
||||
unsigned PageSize, std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
|
||||
|
||||
/// Create a SelfTargetProcessControl with the given memory manager.
|
||||
/// If no memory manager is given a jitlink::InProcessMemoryManager will
|
||||
/// be used by default.
|
||||
static Expected<std::unique_ptr<SelfTargetProcessControl>>
|
||||
Create(std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
|
||||
Create(std::shared_ptr<SymbolStringPool> SSP,
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr = nullptr);
|
||||
|
||||
Expected<DylibHandle> loadDylib(const char *DylibPath) override;
|
||||
Expected<tpctypes::DylibHandle> loadDylib(const char *DylibPath) override;
|
||||
|
||||
Expected<LookupResult> lookupSymbols(LookupRequest Request) override;
|
||||
Expected<std::vector<tpctypes::LookupResult>>
|
||||
lookupSymbols(ArrayRef<tpctypes::LookupRequest> Request) override;
|
||||
|
||||
Expected<int32_t> runAsMain(JITTargetAddress MainFnAddr,
|
||||
ArrayRef<std::string> Args) override;
|
||||
|
||||
Expected<tpctypes::WrapperFunctionResult>
|
||||
runWrapper(JITTargetAddress WrapperFnAddr,
|
||||
ArrayRef<uint8_t> ArgBuffer) override;
|
||||
|
||||
Error disconnect() override;
|
||||
|
||||
private:
|
||||
void writeUInt8s(ArrayRef<UInt8Write> Ws,
|
||||
void writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override;
|
||||
|
||||
void writeUInt16s(ArrayRef<UInt16Write> Ws,
|
||||
void writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override;
|
||||
|
||||
void writeUInt32s(ArrayRef<UInt32Write> Ws,
|
||||
void writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override;
|
||||
|
||||
void writeUInt64s(ArrayRef<UInt64Write> Ws,
|
||||
void writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
|
||||
WriteResultFn OnWriteComplete) override;
|
||||
|
||||
void writeBuffers(ArrayRef<BufferWrite> Ws,
|
||||
void writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
|
||||
WriteResultFn OnWriteComplete) override;
|
||||
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
|
||||
|
|
|
@ -21,7 +21,6 @@ endif()
|
|||
add_subdirectory(Interpreter)
|
||||
add_subdirectory(JITLink)
|
||||
add_subdirectory(MCJIT)
|
||||
add_subdirectory(OrcError)
|
||||
add_subdirectory(Orc)
|
||||
add_subdirectory(RuntimeDyld)
|
||||
|
||||
|
|
|
@ -22,4 +22,6 @@ add_llvm_component_library(LLVMJITLink
|
|||
target_link_libraries(LLVMJITLink
|
||||
PRIVATE
|
||||
LLVMObject
|
||||
LLVMOrcTargetProcess
|
||||
LLVMSupport
|
||||
)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
|
||||
#define DEBUG_TYPE "jitlink"
|
||||
|
@ -630,142 +631,18 @@ Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC,
|
|||
return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false);
|
||||
}
|
||||
|
||||
#if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \
|
||||
!defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
extern "C" void __register_frame(const void *);
|
||||
extern "C" void __deregister_frame(const void *);
|
||||
|
||||
Error registerFrameWrapper(const void *P) {
|
||||
__register_frame(P);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error deregisterFrameWrapper(const void *P) {
|
||||
__deregister_frame(P);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// The building compiler does not have __(de)register_frame but
|
||||
// it may be found at runtime in a dynamically-loaded library.
|
||||
// For example, this happens when building LLVM with Visual C++
|
||||
// but using the MingW runtime.
|
||||
static Error registerFrameWrapper(const void *P) {
|
||||
static void((*RegisterFrame)(const void *)) = 0;
|
||||
|
||||
if (!RegisterFrame)
|
||||
*(void **)&RegisterFrame =
|
||||
llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
|
||||
|
||||
if (RegisterFrame) {
|
||||
RegisterFrame(P);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
return make_error<JITLinkError>("could not register eh-frame: "
|
||||
"__register_frame function not found");
|
||||
}
|
||||
|
||||
static Error deregisterFrameWrapper(const void *P) {
|
||||
static void((*DeregisterFrame)(const void *)) = 0;
|
||||
|
||||
if (!DeregisterFrame)
|
||||
*(void **)&DeregisterFrame =
|
||||
llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
|
||||
"__deregister_frame");
|
||||
|
||||
if (DeregisterFrame) {
|
||||
DeregisterFrame(P);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
return make_error<JITLinkError>("could not deregister eh-frame: "
|
||||
"__deregister_frame function not found");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
template <typename HandleFDEFn>
|
||||
Error walkAppleEHFrameSection(const char *const SectionStart,
|
||||
size_t SectionSize,
|
||||
HandleFDEFn HandleFDE) {
|
||||
const char *CurCFIRecord = SectionStart;
|
||||
const char *End = SectionStart + SectionSize;
|
||||
uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
|
||||
|
||||
while (CurCFIRecord != End && Size != 0) {
|
||||
const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
|
||||
if (Size == 0xffffffff)
|
||||
Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
|
||||
else
|
||||
Size += 4;
|
||||
uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
|
||||
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Registering eh-frame section:\n";
|
||||
dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
|
||||
<< (void *)CurCFIRecord << ": [";
|
||||
for (unsigned I = 0; I < Size; ++I)
|
||||
dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
|
||||
dbgs() << " ]\n";
|
||||
});
|
||||
|
||||
if (Offset != 0)
|
||||
if (auto Err = HandleFDE(CurCFIRecord))
|
||||
return Err;
|
||||
|
||||
CurCFIRecord += Size;
|
||||
|
||||
Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
Error registerEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) {
|
||||
#ifdef __APPLE__
|
||||
// On Darwin __register_frame has to be called for each FDE entry.
|
||||
return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize,
|
||||
registerFrameWrapper);
|
||||
#else
|
||||
// On Linux __register_frame takes a single argument:
|
||||
// a pointer to the start of the .eh_frame section.
|
||||
|
||||
// How can it find the end? Because crtendS.o is linked
|
||||
// in and it has an .eh_frame section with four zero chars.
|
||||
return registerFrameWrapper(EHFrameSectionAddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) {
|
||||
#ifdef __APPLE__
|
||||
return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize,
|
||||
deregisterFrameWrapper);
|
||||
#else
|
||||
return deregisterFrameWrapper(EHFrameSectionAddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
EHFrameRegistrar::~EHFrameRegistrar() {}
|
||||
|
||||
Error InProcessEHFrameRegistrar::registerEHFrames(
|
||||
JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
|
||||
return registerEHFrameSection(
|
||||
return orc::registerEHFrameSection(
|
||||
jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize);
|
||||
}
|
||||
|
||||
Error InProcessEHFrameRegistrar::deregisterEHFrames(
|
||||
JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
|
||||
return deregisterEHFrameSection(
|
||||
return orc::deregisterEHFrameSection(
|
||||
jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize);
|
||||
}
|
||||
|
|
|
@ -18,4 +18,4 @@
|
|||
type = Library
|
||||
name = JITLink
|
||||
parent = ExecutionEngine
|
||||
required_libraries = BinaryFormat Object Support
|
||||
required_libraries = BinaryFormat Object OrcTargetProcess Support
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
[common]
|
||||
subdirectories = Interpreter MCJIT JITLink RuntimeDyld IntelJITEvents
|
||||
OProfileJIT Orc OrcError PerfJITEvents
|
||||
OProfileJIT Orc PerfJITEvents
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
|
|
|
@ -23,6 +23,7 @@ add_llvm_component_library(LLVMOrcJIT
|
|||
TargetProcessControl.cpp
|
||||
ThreadSafeModule.cpp
|
||||
TPCDynamicLibrarySearchGenerator.cpp
|
||||
TPCEHFrameRegistrar.cpp
|
||||
TPCIndirectionUtils.cpp
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
|
||||
|
@ -31,6 +32,9 @@ add_llvm_component_library(LLVMOrcJIT
|
|||
intrinsics_gen
|
||||
)
|
||||
|
||||
add_subdirectory(Shared)
|
||||
add_subdirectory(TargetProcess)
|
||||
|
||||
target_link_libraries(LLVMOrcJIT
|
||||
PRIVATE
|
||||
LLVMAnalysis
|
||||
|
|
|
@ -21,32 +21,6 @@
|
|||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
|
||||
Optional<StringRef> ProgramName) {
|
||||
std::vector<std::unique_ptr<char[]>> ArgVStorage;
|
||||
std::vector<char *> ArgV;
|
||||
|
||||
ArgVStorage.reserve(Args.size() + (ProgramName ? 1 : 0));
|
||||
ArgV.reserve(Args.size() + 1 + (ProgramName ? 1 : 0));
|
||||
|
||||
if (ProgramName) {
|
||||
ArgVStorage.push_back(std::make_unique<char[]>(ProgramName->size() + 1));
|
||||
llvm::copy(*ProgramName, &ArgVStorage.back()[0]);
|
||||
ArgVStorage.back()[ProgramName->size()] = '\0';
|
||||
ArgV.push_back(ArgVStorage.back().get());
|
||||
}
|
||||
|
||||
for (auto &Arg : Args) {
|
||||
ArgVStorage.push_back(std::make_unique<char[]>(Arg.size() + 1));
|
||||
llvm::copy(Arg, &ArgVStorage.back()[0]);
|
||||
ArgVStorage.back()[Arg.size()] = '\0';
|
||||
ArgV.push_back(ArgVStorage.back().get());
|
||||
}
|
||||
ArgV.push_back(nullptr);
|
||||
|
||||
return Main(Args.size() + !!ProgramName, ArgV.data());
|
||||
}
|
||||
|
||||
CtorDtorIterator::CtorDtorIterator(const GlobalVariable *GV, bool End)
|
||||
: InitList(
|
||||
GV ? dyn_cast_or_null<ConstantArray>(GV->getInitializer()) : nullptr),
|
||||
|
|
|
@ -14,9 +14,12 @@
|
|||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[common]
|
||||
subdirectories = Shared TargetProcess
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = OrcJIT
|
||||
parent = ExecutionEngine
|
||||
required_libraries = Core ExecutionEngine JITLink Object OrcError MC Passes
|
||||
required_libraries = Core ExecutionEngine JITLink Object OrcShared MC Passes
|
||||
RuntimeDyld Support Target TransformUtils
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
add_llvm_component_library(LLVMOrcError
|
||||
add_llvm_component_library(LLVMOrcShared
|
||||
OrcError.cpp
|
||||
RPCError.cpp
|
||||
TargetProcessControlTypes.cpp
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
|
||||
)
|
|
@ -1,4 +1,4 @@
|
|||
;===- ./lib/ExecutionEngine/OrcError/LLVMBuild.txt -------------*- Conf -*--===;
|
||||
;===- ./lib/ExecutionEngine/Orc/Shared/LLVMBuild.txt ------------*- Conf -*--===;
|
||||
;
|
||||
; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
; See https://llvm.org/LICENSE.txt for license information.
|
||||
|
@ -16,6 +16,6 @@
|
|||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = OrcError
|
||||
parent = ExecutionEngine
|
||||
name = OrcShared
|
||||
parent = OrcJIT
|
||||
required_libraries = Support
|
|
@ -0,0 +1,27 @@
|
|||
***************
|
||||
*** 1,4 ****
|
||||
- ;===- ./lib/ExecutionEngine/OrcError/LLVMBuild.txt -------------*- Conf -*--===;
|
||||
;
|
||||
; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
; See https://llvm.org/LICENSE.txt for license information.
|
||||
--- 1,4 ----
|
||||
+ ;===- ./tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt -*- Conf -*--===;
|
||||
;
|
||||
; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
; See https://llvm.org/LICENSE.txt for license information.
|
||||
***************
|
||||
*** 15,21 ****
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
- type = Library
|
||||
- name = OrcError
|
||||
- parent = ExecutionEngine
|
||||
- required_libraries = Support
|
||||
--- 15,20 ----
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
+ type = Tool
|
||||
+ name = llvm-jitlink-executor
|
||||
+ parent = llvm-jitlink
|
|
@ -71,7 +71,7 @@ public:
|
|||
};
|
||||
|
||||
static ManagedStatic<OrcErrorCategory> OrcErrCat;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
@ -84,9 +84,8 @@ std::error_code orcError(OrcErrorCode ErrCode) {
|
|||
return std::error_code(static_cast<UT>(ErrCode), *OrcErrCat);
|
||||
}
|
||||
|
||||
|
||||
DuplicateDefinition::DuplicateDefinition(std::string SymbolName)
|
||||
: SymbolName(std::move(SymbolName)) {}
|
||||
: SymbolName(std::move(SymbolName)) {}
|
||||
|
||||
std::error_code DuplicateDefinition::convertToErrorCode() const {
|
||||
return orcError(OrcErrorCode::DuplicateDefinition);
|
||||
|
@ -101,7 +100,7 @@ const std::string &DuplicateDefinition::getSymbolName() const {
|
|||
}
|
||||
|
||||
JITSymbolNotFound::JITSymbolNotFound(std::string SymbolName)
|
||||
: SymbolName(std::move(SymbolName)) {}
|
||||
: SymbolName(std::move(SymbolName)) {}
|
||||
|
||||
std::error_code JITSymbolNotFound::convertToErrorCode() const {
|
||||
typedef std::underlying_type<OrcErrorCode>::type UT;
|
||||
|
@ -117,5 +116,5 @@ const std::string &JITSymbolNotFound::getSymbolName() const {
|
|||
return SymbolName;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace orc
|
||||
} // namespace llvm
|
|
@ -14,8 +14,8 @@
|
|||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
char llvm::orc::rpc::RPCFatalError::ID = 0;
|
||||
char llvm::orc::rpc::ConnectionClosed::ID = 0;
|
||||
|
@ -53,7 +53,6 @@ void CouldNotNegotiate::log(raw_ostream &OS) const {
|
|||
OS << "Could not negotiate RPC function " << Signature;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace rpc
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
|
@ -0,0 +1,43 @@
|
|||
//===---------- TargetProcessControlTypes.cpp - Shared TPC types ----------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// TargetProcessControl types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace tpctypes {
|
||||
|
||||
WrapperFunctionResult WrapperFunctionResult::from(StringRef S) {
|
||||
CWrapperFunctionResult R = {0, {.ValuePtr = nullptr}, nullptr};
|
||||
R.Size = S.size();
|
||||
if (R.Size > sizeof(uint64_t)) {
|
||||
R.Data.ValuePtr = new uint8_t[R.Size];
|
||||
memcpy(R.Data.ValuePtr, S.data(), R.Size);
|
||||
R.Destroy = destroyWithDeleteArray;
|
||||
} else
|
||||
memcpy(R.Data.Value, S.data(), R.Size);
|
||||
return R;
|
||||
}
|
||||
|
||||
void WrapperFunctionResult::destroyWithFree(CWrapperFunctionResultData Data,
|
||||
uint64_t Size) {
|
||||
free(Data.ValuePtr);
|
||||
}
|
||||
|
||||
void WrapperFunctionResult::destroyWithDeleteArray(
|
||||
CWrapperFunctionResultData Data, uint64_t Size) {
|
||||
delete[] Data.ValuePtr;
|
||||
}
|
||||
|
||||
} // end namespace tpctypes
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
|
@ -41,7 +41,7 @@ Error TPCDynamicLibrarySearchGenerator::tryToGenerate(
|
|||
|
||||
SymbolMap NewSymbols;
|
||||
|
||||
TargetProcessControl::LookupRequestElement Request(H, LookupSymbols);
|
||||
tpctypes::LookupRequest Request(H, LookupSymbols);
|
||||
auto Result = TPC.lookupSymbols(Request);
|
||||
if (!Result)
|
||||
return Result.takeError();
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
//===------ TPCEHFrameRegistrar.cpp - TPC-based eh-frame registration -----===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
Expected<std::unique_ptr<TPCEHFrameRegistrar>>
|
||||
TPCEHFrameRegistrar::Create(TargetProcessControl &TPC) {
|
||||
// FIXME: Proper mangling here -- we really need to decouple linker mangling
|
||||
// from DataLayout.
|
||||
|
||||
// Find the addresses of the registration/deregistration functions in the
|
||||
// target process.
|
||||
auto ProcessHandle = TPC.loadDylib(nullptr);
|
||||
if (!ProcessHandle)
|
||||
return ProcessHandle.takeError();
|
||||
|
||||
std::string RegisterWrapperName, DeregisterWrapperName;
|
||||
if (TPC.getTargetTriple().isOSBinFormatMachO()) {
|
||||
RegisterWrapperName += '_';
|
||||
DeregisterWrapperName += '_';
|
||||
}
|
||||
RegisterWrapperName += "llvm_orc_registerEHFrameSectionWrapper";
|
||||
DeregisterWrapperName += "llvm_orc_deregisterEHFrameSectionWrapper";
|
||||
|
||||
SymbolLookupSet RegistrationSymbols;
|
||||
RegistrationSymbols.add(TPC.intern(RegisterWrapperName));
|
||||
RegistrationSymbols.add(TPC.intern(DeregisterWrapperName));
|
||||
|
||||
auto Result = TPC.lookupSymbols({{*ProcessHandle, RegistrationSymbols}});
|
||||
if (!Result)
|
||||
return Result.takeError();
|
||||
|
||||
assert(Result->size() == 1 && "Unexpected number of dylibs in result");
|
||||
assert((*Result)[0].size() == 2 &&
|
||||
"Unexpected number of addresses in result");
|
||||
|
||||
auto RegisterEHFrameWrapperFnAddr = (*Result)[0][0];
|
||||
auto DeregisterEHFrameWrapperFnAddr = (*Result)[0][1];
|
||||
|
||||
return std::make_unique<TPCEHFrameRegistrar>(
|
||||
TPC, RegisterEHFrameWrapperFnAddr, DeregisterEHFrameWrapperFnAddr);
|
||||
}
|
||||
|
||||
Error TPCEHFrameRegistrar::registerEHFrames(JITTargetAddress EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) {
|
||||
constexpr size_t ArgBufferSize = sizeof(uint64_t) + sizeof(uint64_t);
|
||||
uint8_t ArgBuffer[ArgBufferSize];
|
||||
BinaryStreamWriter ArgWriter(
|
||||
MutableArrayRef<uint8_t>(ArgBuffer, ArgBufferSize),
|
||||
support::endianness::big);
|
||||
cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionAddr)));
|
||||
cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionSize)));
|
||||
|
||||
return TPC.runWrapper(RegisterEHFrameWrapperFnAddr, ArgBuffer).takeError();
|
||||
}
|
||||
|
||||
Error TPCEHFrameRegistrar::deregisterEHFrames(
|
||||
JITTargetAddress EHFrameSectionAddr, size_t EHFrameSectionSize) {
|
||||
constexpr size_t ArgBufferSize = sizeof(uint64_t) + sizeof(uint64_t);
|
||||
uint8_t ArgBuffer[ArgBufferSize];
|
||||
BinaryStreamWriter ArgWriter(
|
||||
MutableArrayRef<uint8_t>(ArgBuffer, ArgBufferSize),
|
||||
support::endianness::big);
|
||||
cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionAddr)));
|
||||
cantFail(ArgWriter.writeInteger(static_cast<uint64_t>(EHFrameSectionSize)));
|
||||
|
||||
return TPC.runWrapper(DeregisterEHFrameWrapperFnAddr, ArgBuffer).takeError();
|
||||
}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
|
@ -160,7 +160,7 @@ Error TPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
|
|||
switch (TPCIU.getABISupport().getPointerSize()) {
|
||||
case 4: {
|
||||
unsigned ASIdx = 0;
|
||||
std::vector<TargetProcessControl::MemoryAccess::UInt32Write> PtrUpdates;
|
||||
std::vector<tpctypes::UInt32Write> PtrUpdates;
|
||||
for (auto &SI : StubInits)
|
||||
PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
|
||||
static_cast<uint32_t>(SI.second.first)});
|
||||
|
@ -168,7 +168,7 @@ Error TPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
|
|||
}
|
||||
case 8: {
|
||||
unsigned ASIdx = 0;
|
||||
std::vector<TargetProcessControl::MemoryAccess::UInt64Write> PtrUpdates;
|
||||
std::vector<tpctypes::UInt64Write> PtrUpdates;
|
||||
for (auto &SI : StubInits)
|
||||
PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
|
||||
static_cast<uint64_t>(SI.second.first)});
|
||||
|
@ -213,11 +213,11 @@ Error TPCIndirectStubsManager::updatePointer(StringRef Name,
|
|||
auto &MemAccess = TPCIU.getTargetProcessControl().getMemoryAccess();
|
||||
switch (TPCIU.getABISupport().getPointerSize()) {
|
||||
case 4: {
|
||||
TargetProcessControl::MemoryAccess::UInt32Write PUpdate(PtrAddr, NewAddr);
|
||||
tpctypes::UInt32Write PUpdate(PtrAddr, NewAddr);
|
||||
return MemAccess.writeUInt32s(PUpdate);
|
||||
}
|
||||
case 8: {
|
||||
TargetProcessControl::MemoryAccess::UInt64Write PUpdate(PtrAddr, NewAddr);
|
||||
tpctypes::UInt64Write PUpdate(PtrAddr, NewAddr);
|
||||
return MemAccess.writeUInt64s(PUpdate);
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
add_llvm_component_library(LLVMOrcTargetProcess
|
||||
RegisterEHFrames.cpp
|
||||
TargetExecutionUtils.cpp
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
;===- ./lib/ExecutionEngine/OrcTargetProcess/LLVMBuild.txt -----*- Conf -*--===;
|
||||
;
|
||||
; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
; See https://llvm.org/LICENSE.txt for license information.
|
||||
; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = OrcTargetProcess
|
||||
parent = OrcJIT
|
||||
required_libraries = OrcShared Support
|
|
@ -0,0 +1,207 @@
|
|||
//===--------- RegisterEHFrames.cpp - Register EH frame sections ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
|
||||
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
#define DEBUG_TYPE "orc"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::orc;
|
||||
using namespace llvm::orc::tpctypes;
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
#if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \
|
||||
!defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
|
||||
extern "C" void __register_frame(const void *);
|
||||
extern "C" void __deregister_frame(const void *);
|
||||
|
||||
Error registerFrameWrapper(const void *P) {
|
||||
__register_frame(P);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error deregisterFrameWrapper(const void *P) {
|
||||
__deregister_frame(P);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// The building compiler does not have __(de)register_frame but
|
||||
// it may be found at runtime in a dynamically-loaded library.
|
||||
// For example, this happens when building LLVM with Visual C++
|
||||
// but using the MingW runtime.
|
||||
static Error registerFrameWrapper(const void *P) {
|
||||
static void((*RegisterFrame)(const void *)) = 0;
|
||||
|
||||
if (!RegisterFrame)
|
||||
*(void **)&RegisterFrame =
|
||||
llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
|
||||
|
||||
if (RegisterFrame) {
|
||||
RegisterFrame(P);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
return make_error<StringError>("could not register eh-frame: "
|
||||
"__register_frame function not found",
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
static Error deregisterFrameWrapper(const void *P) {
|
||||
static void((*DeregisterFrame)(const void *)) = 0;
|
||||
|
||||
if (!DeregisterFrame)
|
||||
*(void **)&DeregisterFrame =
|
||||
llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
|
||||
"__deregister_frame");
|
||||
|
||||
if (DeregisterFrame) {
|
||||
DeregisterFrame(P);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
return make_error<StringError>("could not deregister eh-frame: "
|
||||
"__deregister_frame function not found",
|
||||
inconvertibleErrorCode());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
template <typename HandleFDEFn>
|
||||
Error walkAppleEHFrameSection(const char *const SectionStart,
|
||||
size_t SectionSize, HandleFDEFn HandleFDE) {
|
||||
const char *CurCFIRecord = SectionStart;
|
||||
const char *End = SectionStart + SectionSize;
|
||||
uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
|
||||
|
||||
while (CurCFIRecord != End && Size != 0) {
|
||||
const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
|
||||
if (Size == 0xffffffff)
|
||||
Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
|
||||
else
|
||||
Size += 4;
|
||||
uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
|
||||
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Registering eh-frame section:\n";
|
||||
dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
|
||||
<< (void *)CurCFIRecord << ": [";
|
||||
for (unsigned I = 0; I < Size; ++I)
|
||||
dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
|
||||
dbgs() << " ]\n";
|
||||
});
|
||||
|
||||
if (Offset != 0)
|
||||
if (auto Err = HandleFDE(CurCFIRecord))
|
||||
return Err;
|
||||
|
||||
CurCFIRecord += Size;
|
||||
|
||||
Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
Error registerEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) {
|
||||
#ifdef __APPLE__
|
||||
// On Darwin __register_frame has to be called for each FDE entry.
|
||||
return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize, registerFrameWrapper);
|
||||
#else
|
||||
// On Linux __register_frame takes a single argument:
|
||||
// a pointer to the start of the .eh_frame section.
|
||||
|
||||
// How can it find the end? Because crtendS.o is linked
|
||||
// in and it has an .eh_frame section with four zero chars.
|
||||
return registerFrameWrapper(EHFrameSectionAddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
Error deregisterEHFrameSection(const void *EHFrameSectionAddr,
|
||||
size_t EHFrameSectionSize) {
|
||||
#ifdef __APPLE__
|
||||
return walkAppleEHFrameSection(static_cast<const char *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize, deregisterFrameWrapper);
|
||||
#else
|
||||
return deregisterFrameWrapper(EHFrameSectionAddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
extern "C" CWrapperFunctionResult
|
||||
llvm_orc_registerEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) {
|
||||
if (Size != sizeof(uint64_t) + sizeof(uint64_t))
|
||||
return WrapperFunctionResult::from(
|
||||
"Invalid arguments to llvm_orc_registerEHFrameSectionWrapper")
|
||||
.release();
|
||||
|
||||
uint64_t EHFrameSectionAddr;
|
||||
uint64_t EHFrameSectionSize;
|
||||
|
||||
{
|
||||
BinaryStreamReader ArgReader(ArrayRef<uint8_t>(Data, Size),
|
||||
support::endianness::big);
|
||||
cantFail(ArgReader.readInteger(EHFrameSectionAddr));
|
||||
cantFail(ArgReader.readInteger(EHFrameSectionSize));
|
||||
}
|
||||
|
||||
if (auto Err = registerEHFrameSection(
|
||||
jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize)) {
|
||||
auto ErrMsg = toString(std::move(Err));
|
||||
return WrapperFunctionResult::from(ErrMsg).release();
|
||||
}
|
||||
return WrapperFunctionResult().release();
|
||||
}
|
||||
|
||||
extern "C" CWrapperFunctionResult
|
||||
llvm_orc_deregisterEHFrameSectionWrapper(uint8_t *Data, uint64_t Size) {
|
||||
if (Size != sizeof(uint64_t) + sizeof(uint64_t))
|
||||
return WrapperFunctionResult::from(
|
||||
"Invalid arguments to llvm_orc_registerEHFrameSectionWrapper")
|
||||
.release();
|
||||
|
||||
uint64_t EHFrameSectionAddr;
|
||||
uint64_t EHFrameSectionSize;
|
||||
|
||||
{
|
||||
BinaryStreamReader ArgReader(ArrayRef<uint8_t>(Data, Size),
|
||||
support::endianness::big);
|
||||
cantFail(ArgReader.readInteger(EHFrameSectionAddr));
|
||||
cantFail(ArgReader.readInteger(EHFrameSectionSize));
|
||||
}
|
||||
|
||||
if (auto Err = deregisterEHFrameSection(
|
||||
jitTargetAddressToPointer<void *>(EHFrameSectionAddr),
|
||||
EHFrameSectionSize)) {
|
||||
auto ErrMsg = toString(std::move(Err));
|
||||
return WrapperFunctionResult::from(ErrMsg).release();
|
||||
}
|
||||
return WrapperFunctionResult().release();
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
//===--- TargetExecutionUtils.cpp - Execution utils for target processes --===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
int runAsMain(int (*Main)(int, char *[]), ArrayRef<std::string> Args,
|
||||
Optional<StringRef> ProgramName) {
|
||||
std::vector<std::unique_ptr<char[]>> ArgVStorage;
|
||||
std::vector<char *> ArgV;
|
||||
|
||||
ArgVStorage.reserve(Args.size() + (ProgramName ? 1 : 0));
|
||||
ArgV.reserve(Args.size() + 1 + (ProgramName ? 1 : 0));
|
||||
|
||||
if (ProgramName) {
|
||||
ArgVStorage.push_back(std::make_unique<char[]>(ProgramName->size() + 1));
|
||||
llvm::copy(*ProgramName, &ArgVStorage.back()[0]);
|
||||
ArgVStorage.back()[ProgramName->size()] = '\0';
|
||||
ArgV.push_back(ArgVStorage.back().get());
|
||||
}
|
||||
|
||||
for (const auto &Arg : Args) {
|
||||
ArgVStorage.push_back(std::make_unique<char[]>(Arg.size() + 1));
|
||||
llvm::copy(Arg, &ArgVStorage.back()[0]);
|
||||
ArgVStorage.back()[Arg.size()] = '\0';
|
||||
ArgV.push_back(ArgVStorage.back().get());
|
||||
}
|
||||
ArgV.push_back(nullptr);
|
||||
|
||||
return Main(Args.size() + !!ProgramName, ArgV.data());
|
||||
}
|
||||
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
|
@ -9,6 +9,7 @@
|
|||
#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
|
||||
|
@ -22,23 +23,25 @@ TargetProcessControl::MemoryAccess::~MemoryAccess() {}
|
|||
TargetProcessControl::~TargetProcessControl() {}
|
||||
|
||||
SelfTargetProcessControl::SelfTargetProcessControl(
|
||||
Triple TT, unsigned PageSize,
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
|
||||
std::shared_ptr<SymbolStringPool> SSP, Triple TargetTriple,
|
||||
unsigned PageSize, std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr)
|
||||
: TargetProcessControl(std::move(SSP)) {
|
||||
|
||||
OwnedMemMgr = std::move(MemMgr);
|
||||
if (!OwnedMemMgr)
|
||||
OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>();
|
||||
|
||||
this->TT = std::move(TT);
|
||||
this->TargetTriple = std::move(TargetTriple);
|
||||
this->PageSize = PageSize;
|
||||
this->MemMgr = OwnedMemMgr.get();
|
||||
this->MemAccess = this;
|
||||
if (this->TT.isOSBinFormatMachO())
|
||||
if (this->TargetTriple.isOSBinFormatMachO())
|
||||
GlobalManglingPrefix = '_';
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<SelfTargetProcessControl>>
|
||||
SelfTargetProcessControl::Create(
|
||||
std::shared_ptr<SymbolStringPool> SSP,
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
|
||||
auto PageSize = sys::Process::getPageSize();
|
||||
if (!PageSize)
|
||||
|
@ -46,11 +49,11 @@ SelfTargetProcessControl::Create(
|
|||
|
||||
Triple TT(sys::getProcessTriple());
|
||||
|
||||
return std::make_unique<SelfTargetProcessControl>(std::move(TT), *PageSize,
|
||||
std::move(MemMgr));
|
||||
return std::make_unique<SelfTargetProcessControl>(
|
||||
std::move(SSP), std::move(TT), *PageSize, std::move(MemMgr));
|
||||
}
|
||||
|
||||
Expected<TargetProcessControl::DylibHandle>
|
||||
Expected<tpctypes::DylibHandle>
|
||||
SelfTargetProcessControl::loadDylib(const char *DylibPath) {
|
||||
std::string ErrMsg;
|
||||
auto Dylib = std::make_unique<sys::DynamicLibrary>(
|
||||
|
@ -61,9 +64,10 @@ SelfTargetProcessControl::loadDylib(const char *DylibPath) {
|
|||
return pointerToJITTargetAddress(DynamicLibraries.back().get());
|
||||
}
|
||||
|
||||
Expected<TargetProcessControl::LookupResult>
|
||||
SelfTargetProcessControl::lookupSymbols(LookupRequest Request) {
|
||||
LookupResult R;
|
||||
Expected<std::vector<tpctypes::LookupResult>>
|
||||
SelfTargetProcessControl::lookupSymbols(
|
||||
ArrayRef<tpctypes::LookupRequest> Request) {
|
||||
std::vector<tpctypes::LookupResult> R;
|
||||
|
||||
for (auto &Elem : Request) {
|
||||
auto *Dylib = jitTargetAddressToPointer<sys::DynamicLibrary *>(Elem.Handle);
|
||||
|
@ -92,35 +96,53 @@ SelfTargetProcessControl::lookupSymbols(LookupRequest Request) {
|
|||
return R;
|
||||
}
|
||||
|
||||
void SelfTargetProcessControl::writeUInt8s(ArrayRef<UInt8Write> Ws,
|
||||
Expected<int32_t>
|
||||
SelfTargetProcessControl::runAsMain(JITTargetAddress MainFnAddr,
|
||||
ArrayRef<std::string> Args) {
|
||||
using MainTy = int (*)(int, char *[]);
|
||||
return orc::runAsMain(jitTargetAddressToFunction<MainTy>(MainFnAddr), Args);
|
||||
}
|
||||
|
||||
Expected<tpctypes::WrapperFunctionResult>
|
||||
SelfTargetProcessControl::runWrapper(JITTargetAddress WrapperFnAddr,
|
||||
ArrayRef<uint8_t> ArgBuffer) {
|
||||
using WrapperFnTy =
|
||||
tpctypes::CWrapperFunctionResult (*)(const uint8_t *Data, uint64_t Size);
|
||||
auto *WrapperFn = jitTargetAddressToFunction<WrapperFnTy>(WrapperFnAddr);
|
||||
return WrapperFn(ArgBuffer.data(), ArgBuffer.size());
|
||||
};
|
||||
|
||||
Error SelfTargetProcessControl::disconnect() { return Error::success(); }
|
||||
|
||||
void SelfTargetProcessControl::writeUInt8s(ArrayRef<tpctypes::UInt8Write> Ws,
|
||||
WriteResultFn OnWriteComplete) {
|
||||
for (auto &W : Ws)
|
||||
*jitTargetAddressToPointer<uint8_t *>(W.Address) = W.Value;
|
||||
OnWriteComplete(Error::success());
|
||||
}
|
||||
|
||||
void SelfTargetProcessControl::writeUInt16s(ArrayRef<UInt16Write> Ws,
|
||||
void SelfTargetProcessControl::writeUInt16s(ArrayRef<tpctypes::UInt16Write> Ws,
|
||||
WriteResultFn OnWriteComplete) {
|
||||
for (auto &W : Ws)
|
||||
*jitTargetAddressToPointer<uint16_t *>(W.Address) = W.Value;
|
||||
OnWriteComplete(Error::success());
|
||||
}
|
||||
|
||||
void SelfTargetProcessControl::writeUInt32s(ArrayRef<UInt32Write> Ws,
|
||||
void SelfTargetProcessControl::writeUInt32s(ArrayRef<tpctypes::UInt32Write> Ws,
|
||||
WriteResultFn OnWriteComplete) {
|
||||
for (auto &W : Ws)
|
||||
*jitTargetAddressToPointer<uint32_t *>(W.Address) = W.Value;
|
||||
OnWriteComplete(Error::success());
|
||||
}
|
||||
|
||||
void SelfTargetProcessControl::writeUInt64s(ArrayRef<UInt64Write> Ws,
|
||||
void SelfTargetProcessControl::writeUInt64s(ArrayRef<tpctypes::UInt64Write> Ws,
|
||||
WriteResultFn OnWriteComplete) {
|
||||
for (auto &W : Ws)
|
||||
*jitTargetAddressToPointer<uint64_t *>(W.Address) = W.Value;
|
||||
OnWriteComplete(Error::success());
|
||||
}
|
||||
|
||||
void SelfTargetProcessControl::writeBuffers(ArrayRef<BufferWrite> Ws,
|
||||
void SelfTargetProcessControl::writeBuffers(ArrayRef<tpctypes::BufferWrite> Ws,
|
||||
WriteResultFn OnWriteComplete) {
|
||||
for (auto &W : Ws)
|
||||
memcpy(jitTargetAddressToPointer<char *>(W.Address), W.Buffer.data(),
|
||||
|
|
|
@ -11,8 +11,9 @@ set(LLVM_LINK_COMPONENTS
|
|||
MC
|
||||
MCJIT
|
||||
Object
|
||||
OrcError
|
||||
OrcShared
|
||||
OrcJIT
|
||||
OrcTargetProcess
|
||||
Passes
|
||||
RuntimeDyld
|
||||
SelectionDAG
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
OrcError
|
||||
OrcShared
|
||||
OrcJIT
|
||||
RuntimeDyld
|
||||
Support
|
||||
|
|
|
@ -28,6 +28,9 @@ required_libraries =
|
|||
Instrumentation
|
||||
Interpreter
|
||||
MCJIT
|
||||
OrcJIT
|
||||
OrcShared
|
||||
OrcTargetProcess
|
||||
Native
|
||||
NativeCodeGen
|
||||
SelectionDAG
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h"
|
||||
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
|
||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if ( LLVM_INCLUDE_UTILS )
|
||||
add_subdirectory(llvm-jitlink-executor)
|
||||
endif()
|
||||
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
AllTargetsDescs
|
||||
AllTargetsDisassemblers
|
||||
|
@ -8,6 +12,8 @@ set(LLVM_LINK_COMPONENTS
|
|||
MC
|
||||
Object
|
||||
OrcJIT
|
||||
OrcShared
|
||||
OrcTargetProcess
|
||||
RuntimeDyld
|
||||
Support
|
||||
)
|
||||
|
|
|
@ -18,5 +18,5 @@
|
|||
type = Tool
|
||||
name = llvm-jitlink
|
||||
parent = Tools
|
||||
required_libraries = JITLink BinaryFormat MC Object RuntimeDyld Support
|
||||
all-targets
|
||||
required_libraries = JITLink BinaryFormat MC Object OrcJIT OrcTargetProcess
|
||||
Support all-targets
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
OrcShared
|
||||
OrcTargetProcess
|
||||
Support
|
||||
)
|
||||
|
||||
add_llvm_utility(llvm-jitlink-executor
|
||||
llvm-jitlink-executor.cpp
|
||||
|
||||
DEPENDS
|
||||
intrinsics_gen
|
||||
)
|
||||
|
||||
export_executable_symbols(llvm-jitlink-executor)
|
|
@ -0,0 +1,21 @@
|
|||
;===- ./tools/llvm-jitlink/llvm-jitlink-executor/LLVMBuild.txt -*- Conf -*--===;
|
||||
;
|
||||
; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
; See https://llvm.org/LICENSE.txt for license information.
|
||||
; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Tool
|
||||
name = llvm-jitlink-executor
|
||||
parent = llvm-jitlink
|
||||
required_libraries = OrcTargetProcess Support
|
|
@ -0,0 +1,127 @@
|
|||
//===- llvm-jitlink-executor.cpp - Out-of-proc executor for llvm-jitlink -===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Simple out-of-process executor for llvm-jitlink.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <sstream>
|
||||
|
||||
#ifdef LLVM_ON_UNIX
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::orc;
|
||||
|
||||
ExitOnError ExitOnErr;
|
||||
|
||||
LLVM_ATTRIBUTE_USED void linkComponents() {
|
||||
errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
|
||||
<< (void *)&llvm_orc_deregisterEHFrameSectionWrapper;
|
||||
}
|
||||
|
||||
void printErrorAndExit(Twine ErrMsg) {
|
||||
errs() << "error: " << ErrMsg.str() << "\n\n"
|
||||
<< "Usage:\n"
|
||||
<< " llvm-jitlink-executor filedescs=<infd>,<outfd> [args...]\n"
|
||||
<< " llvm-jitlink-executor listen=<host>:<port> [args...]\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int openListener(std::string Host, int Port) {
|
||||
#ifndef LLVM_ON_UNIX
|
||||
// FIXME: Add TCP support for Windows.
|
||||
printErrorAndExit("listen option not supported");
|
||||
#else
|
||||
int SockFD = socket(PF_INET, SOCK_STREAM, 0);
|
||||
struct sockaddr_in ServerAddr, ClientAddr;
|
||||
socklen_t ClientAddrLen = sizeof(ClientAddr);
|
||||
memset(&ServerAddr, 0, sizeof(ServerAddr));
|
||||
ServerAddr.sin_family = PF_INET;
|
||||
ServerAddr.sin_family = INADDR_ANY;
|
||||
ServerAddr.sin_port = htons(Port);
|
||||
|
||||
{
|
||||
// lose the "Address already in use" error message
|
||||
int Yes = 1;
|
||||
if (setsockopt(SockFD, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1) {
|
||||
errs() << "Error calling setsockopt.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(SockFD, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr)) < 0) {
|
||||
errs() << "Error on binding.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
listen(SockFD, 1);
|
||||
return accept(SockFD, (struct sockaddr *)&ClientAddr, &ClientAddrLen);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
|
||||
|
||||
int InFD = 0;
|
||||
int OutFD = 0;
|
||||
|
||||
if (argc < 2)
|
||||
printErrorAndExit("insufficient arguments");
|
||||
else {
|
||||
StringRef Arg1 = argv[1];
|
||||
StringRef SpecifierType, Specifier;
|
||||
std::tie(SpecifierType, Specifier) = Arg1.split('=');
|
||||
if (SpecifierType == "filedescs") {
|
||||
StringRef FD1Str, FD2Str;
|
||||
std::tie(FD1Str, FD2Str) = Specifier.split(',');
|
||||
if (FD1Str.getAsInteger(10, InFD))
|
||||
printErrorAndExit(FD1Str + " is not a valid file descriptor");
|
||||
if (FD2Str.getAsInteger(10, OutFD))
|
||||
printErrorAndExit(FD2Str + " is not a valid file descriptor");
|
||||
} else if (SpecifierType == "listen") {
|
||||
StringRef Host, PortStr;
|
||||
std::tie(Host, PortStr) = Specifier.split(':');
|
||||
|
||||
int Port = 0;
|
||||
if (PortStr.getAsInteger(10, Port))
|
||||
printErrorAndExit("port" + PortStr + " is not a valid integer");
|
||||
|
||||
InFD = OutFD = openListener(Host.str(), Port);
|
||||
} else
|
||||
printErrorAndExit("invalid specifier type \"" + SpecifierType + "\"");
|
||||
}
|
||||
|
||||
ExitOnErr.setBanner(std::string(argv[0]) + ":");
|
||||
|
||||
using JITLinkExecutorEndpoint =
|
||||
rpc::MultiThreadedRPCEndpoint<rpc::FDRawByteChannel>;
|
||||
|
||||
rpc::registerStringError<rpc::FDRawByteChannel>();
|
||||
|
||||
rpc::FDRawByteChannel C(InFD, OutFD);
|
||||
JITLinkExecutorEndpoint EP(C, true);
|
||||
OrcRPCTPCServer<JITLinkExecutorEndpoint> Server(EP);
|
||||
Server.setProgramName(std::string("llvm-jitlink-executor"));
|
||||
|
||||
ExitOnErr(Server.run());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -15,9 +15,9 @@
|
|||
#include "llvm-jitlink.h"
|
||||
|
||||
#include "llvm/BinaryFormat/Magic.h"
|
||||
#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
|
||||
|
@ -41,6 +41,13 @@
|
|||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#ifdef LLVM_ON_UNIX
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#endif // LLVM_ON_UNIX
|
||||
|
||||
#define DEBUG_TYPE "llvm_jitlink"
|
||||
|
||||
using namespace llvm;
|
||||
|
@ -138,6 +145,14 @@ static cl::opt<bool> PhonyExternals(
|
|||
cl::desc("resolve all otherwise unresolved externals to null"),
|
||||
cl::init(false));
|
||||
|
||||
static cl::opt<std::string> OutOfProcessExecutor(
|
||||
"oop-executor", cl::desc("Launch an out-of-process executor to run code"),
|
||||
cl::ValueOptional);
|
||||
|
||||
static cl::opt<std::string> OutOfProcessExecutorConnect(
|
||||
"oop-executor-connect",
|
||||
cl::desc("Connect to an out-of-process executor via TCP"));
|
||||
|
||||
ExitOnError ExitOnErr;
|
||||
|
||||
namespace llvm {
|
||||
|
@ -561,6 +576,165 @@ Error LLVMJITLinkObjectLinkingLayer::add(ResourceTrackerSP RT,
|
|||
return JD.define(std::move(MU), std::move(RT));
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<TargetProcessControl>>
|
||||
LLVMJITLinkRemoteTargetProcessControl::LaunchExecutor() {
|
||||
#ifndef LLVM_ON_UNIX
|
||||
// FIXME: Add support for Windows.
|
||||
return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr +
|
||||
" not supported on non-unix platforms",
|
||||
inconvertibleErrorCode());
|
||||
#else
|
||||
|
||||
rpc::registerStringError<LLVMJITLinkChannel>();
|
||||
|
||||
constexpr int ReadEnd = 0;
|
||||
constexpr int WriteEnd = 1;
|
||||
|
||||
// Pipe FDs.
|
||||
int ToExecutor[2];
|
||||
int FromExecutor[2];
|
||||
|
||||
pid_t ChildPID;
|
||||
|
||||
// Create pipes to/from the executor..
|
||||
if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
|
||||
return make_error<StringError>("Unable to create pipe for executor",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
ChildPID = fork();
|
||||
|
||||
if (ChildPID == 0) {
|
||||
// In the child...
|
||||
|
||||
// Close the parent ends of the pipes
|
||||
close(ToExecutor[WriteEnd]);
|
||||
close(FromExecutor[ReadEnd]);
|
||||
|
||||
// Execute the child process.
|
||||
std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
|
||||
{
|
||||
ExecutorPath = std::make_unique<char[]>(OutOfProcessExecutor.size() + 1);
|
||||
strcpy(ExecutorPath.get(), OutOfProcessExecutor.data());
|
||||
|
||||
std::string FDSpecifierStr("filedescs=");
|
||||
FDSpecifierStr += utostr(ToExecutor[ReadEnd]);
|
||||
FDSpecifierStr += ',';
|
||||
FDSpecifierStr += utostr(FromExecutor[WriteEnd]);
|
||||
FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
|
||||
strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
|
||||
}
|
||||
|
||||
char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};
|
||||
int RC = execvp(ExecutorPath.get(), Args);
|
||||
if (RC != 0) {
|
||||
errs() << "unable to launch out-of-process executor \""
|
||||
<< ExecutorPath.get() << "\"\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
// else we're the parent...
|
||||
|
||||
// Close the child ends of the pipes
|
||||
close(ToExecutor[ReadEnd]);
|
||||
close(FromExecutor[WriteEnd]);
|
||||
|
||||
// Return an RPC channel connected to our end of the pipes.
|
||||
auto SSP = std::make_shared<SymbolStringPool>();
|
||||
auto Channel = std::make_unique<rpc::FDRawByteChannel>(FromExecutor[ReadEnd],
|
||||
ToExecutor[WriteEnd]);
|
||||
auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel, true);
|
||||
|
||||
auto ReportError = [](Error Err) {
|
||||
logAllUnhandledErrors(std::move(Err), errs(), "");
|
||||
};
|
||||
|
||||
Error Err = Error::success();
|
||||
std::unique_ptr<LLVMJITLinkRemoteTargetProcessControl> RTPC(
|
||||
new LLVMJITLinkRemoteTargetProcessControl(
|
||||
std::move(SSP), std::move(Channel), std::move(Endpoint),
|
||||
std::move(ReportError), Err));
|
||||
if (Err)
|
||||
return std::move(Err);
|
||||
return std::move(RTPC);
|
||||
#endif
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<TargetProcessControl>>
|
||||
LLVMJITLinkRemoteTargetProcessControl::ConnectToExecutor() {
|
||||
#ifndef LLVM_ON_UNIX
|
||||
// FIXME: Add TCP support for Windows.
|
||||
return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr +
|
||||
" not supported on non-unix platforms",
|
||||
inconvertibleErrorCode());
|
||||
#else
|
||||
|
||||
rpc::registerStringError<LLVMJITLinkChannel>();
|
||||
|
||||
StringRef HostNameStr, PortStr;
|
||||
std::tie(HostNameStr, PortStr) =
|
||||
StringRef(OutOfProcessExecutorConnect).split(':');
|
||||
|
||||
if (HostNameStr.empty())
|
||||
return make_error<StringError>("host name for -" +
|
||||
OutOfProcessExecutorConnect.ArgStr +
|
||||
" can not be empty",
|
||||
inconvertibleErrorCode());
|
||||
if (PortStr.empty())
|
||||
return make_error<StringError>(
|
||||
"port for -" + OutOfProcessExecutorConnect.ArgStr + " can not be empty",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
std::string HostName = HostNameStr.str();
|
||||
int Port = 0;
|
||||
if (PortStr.getAsInteger(10, Port))
|
||||
return make_error<StringError>("port number " + PortStr +
|
||||
" is not a valid integer",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
int SockFD = socket(PF_INET, SOCK_STREAM, 0);
|
||||
hostent *Server = gethostbyname(HostName.c_str());
|
||||
sockaddr_in ServAddr;
|
||||
memset(&ServAddr, 0, sizeof(ServAddr));
|
||||
ServAddr.sin_family = PF_INET;
|
||||
memmove(&Server->h_addr, &ServAddr.sin_addr.s_addr, Server->h_length);
|
||||
ServAddr.sin_port = htons(Port);
|
||||
if (connect(SockFD, reinterpret_cast<sockaddr *>(&ServAddr),
|
||||
sizeof(ServAddr)) < 0)
|
||||
return make_error<StringError>("Failed to connect to " + HostName + ":" +
|
||||
Twine(Port),
|
||||
inconvertibleErrorCode());
|
||||
|
||||
auto SSP = std::make_shared<SymbolStringPool>();
|
||||
auto Channel = std::make_unique<rpc::FDRawByteChannel>(SockFD, SockFD);
|
||||
auto Endpoint = std::make_unique<LLVMJITLinkRPCEndpoint>(*Channel, true);
|
||||
|
||||
auto ReportError = [](Error Err) {
|
||||
logAllUnhandledErrors(std::move(Err), errs(), "");
|
||||
};
|
||||
|
||||
Error Err = Error::success();
|
||||
std::unique_ptr<LLVMJITLinkRemoteTargetProcessControl> RTPC(
|
||||
new LLVMJITLinkRemoteTargetProcessControl(
|
||||
std::move(SSP), std::move(Channel), std::move(Endpoint),
|
||||
std::move(ReportError), Err));
|
||||
if (Err)
|
||||
return std::move(Err);
|
||||
return std::move(RTPC);
|
||||
#endif
|
||||
}
|
||||
|
||||
Error LLVMJITLinkRemoteTargetProcessControl::disconnect() {
|
||||
std::promise<MSVCPError> P;
|
||||
auto F = P.get_future();
|
||||
auto Err = closeConnection([&](Error Err) -> Error {
|
||||
P.set_value(std::move(Err));
|
||||
Finished = true;
|
||||
return Error::success();
|
||||
});
|
||||
ListenerThread.join();
|
||||
return joinErrors(std::move(Err), F.get());
|
||||
};
|
||||
|
||||
class PhonyExternalsGenerator : public DefinitionGenerator {
|
||||
public:
|
||||
Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
|
||||
|
@ -574,13 +748,30 @@ public:
|
|||
};
|
||||
|
||||
Expected<std::unique_ptr<Session>> Session::Create(Triple TT) {
|
||||
Error Err = Error::success();
|
||||
|
||||
auto PageSize = sys::Process::getPageSize();
|
||||
if (!PageSize)
|
||||
return PageSize.takeError();
|
||||
|
||||
std::unique_ptr<Session> S(new Session(std::move(TT), *PageSize, Err));
|
||||
/// If -oop-executor is passed then launch the executor.
|
||||
std::unique_ptr<TargetProcessControl> TPC;
|
||||
if (OutOfProcessExecutor.getNumOccurrences()) {
|
||||
if (auto RTPC = LLVMJITLinkRemoteTargetProcessControl::LaunchExecutor())
|
||||
TPC = std::move(*RTPC);
|
||||
else
|
||||
return RTPC.takeError();
|
||||
} else if (OutOfProcessExecutorConnect.getNumOccurrences()) {
|
||||
if (auto RTPC = LLVMJITLinkRemoteTargetProcessControl::ConnectToExecutor())
|
||||
TPC = std::move(*RTPC);
|
||||
else
|
||||
return RTPC.takeError();
|
||||
} else
|
||||
TPC = std::make_unique<SelfTargetProcessControl>(
|
||||
std::make_shared<SymbolStringPool>(), std::move(TT), *PageSize,
|
||||
createMemoryManager());
|
||||
|
||||
Error Err = Error::success();
|
||||
std::unique_ptr<Session> S(new Session(std::move(TPC), Err));
|
||||
if (Err)
|
||||
return std::move(Err);
|
||||
return std::move(S);
|
||||
|
@ -593,10 +784,8 @@ Session::~Session() {
|
|||
|
||||
// FIXME: Move to createJITDylib if/when we start using Platform support in
|
||||
// llvm-jitlink.
|
||||
Session::Session(Triple TT, uint64_t PageSize, Error &Err)
|
||||
: TPC(std::make_unique<SelfTargetProcessControl>(std::move(TT), PageSize,
|
||||
createMemoryManager())),
|
||||
ObjLayer(*this, TPC->getMemMgr()) {
|
||||
Session::Session(std::unique_ptr<TargetProcessControl> TPC, Error &Err)
|
||||
: TPC(std::move(TPC)), ObjLayer(*this, this->TPC->getMemMgr()) {
|
||||
|
||||
/// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
|
||||
/// Session.
|
||||
|
@ -630,9 +819,9 @@ Session::Session(Triple TT, uint64_t PageSize, Error &Err)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!NoExec && !TT.isOSWindows())
|
||||
if (!NoExec && !this->TPC->getTargetTriple().isOSWindows())
|
||||
ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
|
||||
ES, std::make_unique<InProcessEHFrameRegistrar>()));
|
||||
ES, ExitOnErr(TPCEHFrameRegistrar::Create(*this->TPC))));
|
||||
|
||||
ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
|
||||
|
||||
|
@ -785,22 +974,28 @@ Session::findSymbolInfo(StringRef SymbolName, Twine ErrorMsgStem) {
|
|||
} // end namespace llvm
|
||||
|
||||
static Triple getFirstFileTriple() {
|
||||
assert(!InputFiles.empty() && "InputFiles can not be empty");
|
||||
auto ObjBuffer =
|
||||
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
|
||||
auto Obj = ExitOnErr(
|
||||
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
|
||||
return Obj->makeTriple();
|
||||
static Triple FirstTT = []() {
|
||||
assert(!InputFiles.empty() && "InputFiles can not be empty");
|
||||
auto ObjBuffer =
|
||||
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputFiles.front())));
|
||||
auto Obj = ExitOnErr(
|
||||
object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()));
|
||||
return Obj->makeTriple();
|
||||
}();
|
||||
|
||||
return FirstTT;
|
||||
}
|
||||
|
||||
static Error sanitizeArguments(const Session &S) {
|
||||
static Error sanitizeArguments(const Triple &TT, const char *ArgV0) {
|
||||
// Set the entry point name if not specified.
|
||||
if (EntryPointName.empty()) {
|
||||
if (S.TPC->getTargetTriple().getObjectFormat() == Triple::MachO)
|
||||
if (TT.getObjectFormat() == Triple::MachO)
|
||||
EntryPointName = "_main";
|
||||
else
|
||||
EntryPointName = "main";
|
||||
}
|
||||
|
||||
// -noexec and --args should not be used together.
|
||||
if (NoExec && !InputArgv.empty())
|
||||
outs() << "Warning: --args passed to -noexec run will be ignored.\n";
|
||||
|
||||
|
@ -812,14 +1007,35 @@ static Error sanitizeArguments(const Session &S) {
|
|||
inconvertibleErrorCode());
|
||||
}
|
||||
|
||||
// Only one of -oop-executor and -oop-executor-connect can be used.
|
||||
if (!!OutOfProcessExecutor.getNumOccurrences() &&
|
||||
!!OutOfProcessExecutorConnect.getNumOccurrences())
|
||||
return make_error<StringError>(
|
||||
"Only one of -" + OutOfProcessExecutor.ArgStr + " and -" +
|
||||
OutOfProcessExecutorConnect.ArgStr + " can be specified",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
// If -oop-executor was used but no value was specified then use a sensible
|
||||
// default.
|
||||
if (!!OutOfProcessExecutor.getNumOccurrences() &&
|
||||
OutOfProcessExecutor.empty()) {
|
||||
SmallString<256> OOPExecutorPath(sys::fs::getMainExecutable(
|
||||
ArgV0, reinterpret_cast<void *>(&sanitizeArguments)));
|
||||
sys::path::remove_filename(OOPExecutorPath);
|
||||
if (OOPExecutorPath.back() != '/')
|
||||
OOPExecutorPath += '/';
|
||||
OOPExecutorPath += "llvm-jitlink-executor";
|
||||
OutOfProcessExecutor = OOPExecutorPath.str().str();
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Error loadProcessSymbols(Session &S) {
|
||||
auto InternedEntryPointName = S.ES.intern(EntryPointName);
|
||||
auto FilterMainEntryPoint = [InternedEntryPointName](SymbolStringPtr Name) {
|
||||
return Name != InternedEntryPointName;
|
||||
};
|
||||
auto FilterMainEntryPoint =
|
||||
[EPName = S.ES.intern(EntryPointName)](SymbolStringPtr Name) {
|
||||
return Name != EPName;
|
||||
};
|
||||
S.MainJD->addGenerator(
|
||||
ExitOnErr(orc::TPCDynamicLibrarySearchGenerator::GetForTargetProcess(
|
||||
*S.TPC, std::move(FilterMainEntryPoint))));
|
||||
|
@ -827,15 +1043,12 @@ static Error loadProcessSymbols(Session &S) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
static Error loadDylibs() {
|
||||
// FIXME: This should all be handled inside DynamicLibrary.
|
||||
static Error loadDylibs(Session &S) {
|
||||
for (const auto &Dylib : Dylibs) {
|
||||
if (!sys::fs::is_regular_file(Dylib))
|
||||
return make_error<StringError>("\"" + Dylib + "\" is not a regular file",
|
||||
inconvertibleErrorCode());
|
||||
std::string ErrMsg;
|
||||
if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
|
||||
return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
|
||||
auto G = orc::TPCDynamicLibrarySearchGenerator::Load(*S.TPC, Dylib.c_str());
|
||||
if (!G)
|
||||
return G.takeError();
|
||||
S.MainJD->addGenerator(std::move(*G));
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
|
@ -1072,9 +1285,9 @@ int main(int argc, char *argv[]) {
|
|||
std::unique_ptr<JITLinkTimers> Timers =
|
||||
ShowTimes ? std::make_unique<JITLinkTimers>() : nullptr;
|
||||
|
||||
auto S = ExitOnErr(Session::Create(getFirstFileTriple()));
|
||||
ExitOnErr(sanitizeArguments(getFirstFileTriple(), argv[0]));
|
||||
|
||||
ExitOnErr(sanitizeArguments(*S));
|
||||
auto S = ExitOnErr(Session::Create(getFirstFileTriple()));
|
||||
|
||||
{
|
||||
TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
|
||||
|
@ -1083,7 +1296,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
if (!NoProcessSymbols)
|
||||
ExitOnErr(loadProcessSymbols(*S));
|
||||
ExitOnErr(loadDylibs());
|
||||
ExitOnErr(loadDylibs(*S));
|
||||
|
||||
if (PhonyExternals)
|
||||
addPhonyExternalsGenerator(*S);
|
||||
|
@ -1110,11 +1323,12 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
int Result = 0;
|
||||
{
|
||||
using MainTy = int (*)(int, char *[]);
|
||||
auto EntryFn = jitTargetAddressToFunction<MainTy>(EntryPoint.getAddress());
|
||||
TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);
|
||||
Result = runAsMain(EntryFn, InputArgv, StringRef(InputFiles.front()));
|
||||
Result = ExitOnErr(S->TPC->runAsMain(EntryPoint.getAddress(), InputArgv));
|
||||
}
|
||||
|
||||
ExitOnErr(S->ES.endSession());
|
||||
ExitOnErr(S->TPC->disconnect());
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ExecutionEngine/Orc/Core.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h"
|
||||
#include "llvm/ExecutionEngine/Orc/RPC/FDRawByteChannel.h"
|
||||
#include "llvm/ExecutionEngine/Orc/RPC/RPCUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
@ -45,9 +48,71 @@ private:
|
|||
Session &S;
|
||||
};
|
||||
|
||||
using LLVMJITLinkChannel = orc::rpc::FDRawByteChannel;
|
||||
using LLVMJITLinkRPCEndpoint =
|
||||
orc::rpc::MultiThreadedRPCEndpoint<LLVMJITLinkChannel>;
|
||||
using LLVMJITLinkRemoteMemoryManager =
|
||||
orc::OrcRPCTPCJITLinkMemoryManager<LLVMJITLinkRPCEndpoint>;
|
||||
using LLVMJITLinkRemoteMemoryAccess =
|
||||
orc::OrcRPCTPCMemoryAccess<LLVMJITLinkRPCEndpoint>;
|
||||
|
||||
class LLVMJITLinkRemoteTargetProcessControl
|
||||
: public orc::OrcRPCTargetProcessControlBase<LLVMJITLinkRPCEndpoint> {
|
||||
public:
|
||||
using BaseT = orc::OrcRPCTargetProcessControlBase<LLVMJITLinkRPCEndpoint>;
|
||||
static Expected<std::unique_ptr<TargetProcessControl>> LaunchExecutor();
|
||||
|
||||
static Expected<std::unique_ptr<TargetProcessControl>> ConnectToExecutor();
|
||||
|
||||
Error disconnect() override;
|
||||
|
||||
private:
|
||||
using LLVMJITLinkRemoteMemoryAccess =
|
||||
orc::OrcRPCTPCMemoryAccess<LLVMJITLinkRemoteTargetProcessControl>;
|
||||
|
||||
using LLVMJITLinkRemoteMemoryManager =
|
||||
orc::OrcRPCTPCJITLinkMemoryManager<LLVMJITLinkRemoteTargetProcessControl>;
|
||||
|
||||
LLVMJITLinkRemoteTargetProcessControl(
|
||||
std::shared_ptr<orc::SymbolStringPool> SSP,
|
||||
std::unique_ptr<LLVMJITLinkChannel> Channel,
|
||||
std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint,
|
||||
ErrorReporter ReportError, Error &Err)
|
||||
: BaseT(std::move(SSP), *Endpoint, std::move(ReportError)),
|
||||
Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) {
|
||||
ErrorAsOutParameter _(&Err);
|
||||
|
||||
ListenerThread = std::thread([&]() {
|
||||
while (!Finished) {
|
||||
if (auto Err = this->Endpoint->handleOne()) {
|
||||
reportError(std::move(Err));
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (auto Err2 = initializeORCRPCTPCBase()) {
|
||||
Err = joinErrors(std::move(Err2), disconnect());
|
||||
return;
|
||||
}
|
||||
|
||||
OwnedMemAccess = std::make_unique<LLVMJITLinkRemoteMemoryAccess>(*this);
|
||||
MemAccess = OwnedMemAccess.get();
|
||||
OwnedMemMgr = std::make_unique<LLVMJITLinkRemoteMemoryManager>(*this);
|
||||
MemMgr = OwnedMemMgr.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<LLVMJITLinkChannel> Channel;
|
||||
std::unique_ptr<LLVMJITLinkRPCEndpoint> Endpoint;
|
||||
std::unique_ptr<TargetProcessControl::MemoryAccess> OwnedMemAccess;
|
||||
std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
|
||||
std::atomic<bool> Finished{false};
|
||||
std::thread ListenerThread;
|
||||
};
|
||||
|
||||
struct Session {
|
||||
orc::ExecutionSession ES;
|
||||
std::unique_ptr<orc::TargetProcessControl> TPC;
|
||||
orc::ExecutionSession ES;
|
||||
orc::JITDylib *MainJD;
|
||||
LLVMJITLinkObjectLinkingLayer ObjLayer;
|
||||
std::vector<orc::JITDylib *> JDSearchOrder;
|
||||
|
@ -93,7 +158,7 @@ struct Session {
|
|||
DenseMap<StringRef, StringRef> CanonicalWeakDefs;
|
||||
|
||||
private:
|
||||
Session(Triple TT, uint64_t PageSize, Error &Err);
|
||||
Session(std::unique_ptr<orc::TargetProcessControl> TPC, Error &Err);
|
||||
};
|
||||
|
||||
/// Record symbols, GOT entries, stubs, and sections for ELF file.
|
||||
|
|
|
@ -2,6 +2,8 @@ set(LLVM_LINK_COMPONENTS
|
|||
${LLVM_TARGETS_TO_BUILD}
|
||||
JITLink
|
||||
Object
|
||||
OrcShared
|
||||
OrcTargetProcess
|
||||
RuntimeDyld
|
||||
Support
|
||||
)
|
||||
|
|
|
@ -3,8 +3,8 @@ set(LLVM_LINK_COMPONENTS
|
|||
Core
|
||||
ExecutionEngine
|
||||
Object
|
||||
OrcError
|
||||
OrcJIT
|
||||
OrcShared
|
||||
Passes
|
||||
RuntimeDyld
|
||||
Support
|
||||
|
|
Loading…
Reference in New Issue