//===---- OrcRemoteTargetClient.h - Orc Remote-target Client ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the OrcRemoteTargetClient class and helpers. This class // can be used to communicate over an RPCChannel with an OrcRemoteTargetServer // instance to support remote-JITing. // //===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H #include "IndirectionUtils.h" #include "OrcRemoteTargetRPCAPI.h" #include #define DEBUG_TYPE "orc-remote" namespace llvm { namespace orc { namespace remote { /// This class provides utilities (including memory manager, indirect stubs /// manager, and compile callback manager types) that support remote JITing /// in ORC. /// /// Each of the utility classes talks to a JIT server (an instance of the /// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out /// its actions. template class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI { public: /// Remote memory manager. class RCMemoryManager : public RuntimeDyld::MemoryManager { public: RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id) : Client(Client), Id(Id) { DEBUG(dbgs() << "Created remote allocator " << Id << "\n"); } RCMemoryManager(RCMemoryManager &&Other) : Client(std::move(Other.Client)), Id(std::move(Other.Id)), Unmapped(std::move(Other.Unmapped)), Unfinalized(std::move(Other.Unfinalized)) {} RCMemoryManager operator=(RCMemoryManager &&Other) { Client = std::move(Other.Client); Id = std::move(Other.Id); Unmapped = std::move(Other.Unmapped); Unfinalized = std::move(Other.Unfinalized); return *this; } ~RCMemoryManager() { Client.destroyRemoteAllocator(Id); DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n"); } uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) override { Unmapped.back().CodeAllocs.emplace_back(Size, Alignment); uint8_t *Alloc = reinterpret_cast( Unmapped.back().CodeAllocs.back().getLocalAddress()); DEBUG(dbgs() << "Allocator " << Id << " allocated code for " << SectionName << ": " << Alloc << " (" << Size << " bytes, alignment " << Alignment << ")\n"); return Alloc; } uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, bool IsReadOnly) override { if (IsReadOnly) { Unmapped.back().RODataAllocs.emplace_back(Size, Alignment); uint8_t *Alloc = reinterpret_cast( Unmapped.back().RODataAllocs.back().getLocalAddress()); DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for " << SectionName << ": " << Alloc << " (" << Size << " bytes, alignment " << Alignment << ")\n"); return Alloc; } // else... Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment); uint8_t *Alloc = reinterpret_cast( Unmapped.back().RWDataAllocs.back().getLocalAddress()); DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for " << SectionName << ": " << Alloc << " (" << Size << " bytes, alignment " << Alignment << ")\n"); return Alloc; } void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize, uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) override { Unmapped.push_back(ObjectAllocs()); DEBUG(dbgs() << "Allocator " << Id << " reserved:\n"); if (CodeSize != 0) { std::error_code EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr, Id, CodeSize, CodeAlign); // FIXME; Add error to poll. assert(!EC && "Failed reserving remote memory."); (void)EC; DEBUG(dbgs() << " code: " << format("0x%016x", Unmapped.back().RemoteCodeAddr) << " (" << CodeSize << " bytes, alignment " << CodeAlign << ")\n"); } if (RODataSize != 0) { std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr, Id, RODataSize, RODataAlign); // FIXME; Add error to poll. assert(!EC && "Failed reserving remote memory."); (void)EC; DEBUG(dbgs() << " ro-data: " << format("0x%016x", Unmapped.back().RemoteRODataAddr) << " (" << RODataSize << " bytes, alignment " << RODataAlign << ")\n"); } if (RWDataSize != 0) { std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr, Id, RWDataSize, RWDataAlign); // FIXME; Add error to poll. assert(!EC && "Failed reserving remote memory."); (void)EC; DEBUG(dbgs() << " rw-data: " << format("0x%016x", Unmapped.back().RemoteRWDataAddr) << " (" << RWDataSize << " bytes, alignment " << RWDataAlign << ")\n"); } } bool needsToReserveAllocationSpace() override { return true; } void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override {} void deregisterEHFrames(uint8_t *addr, uint64_t LoadAddr, size_t Size) override {} void notifyObjectLoaded(RuntimeDyld &Dyld, const object::ObjectFile &Obj) override { DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n"); for (auto &ObjAllocs : Unmapped) { { TargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr; for (auto &Alloc : ObjAllocs.CodeAllocs) { NextCodeAddr = RoundUpToAlignment(NextCodeAddr, Alloc.getAlign()); Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr); DEBUG(dbgs() << " code: " << static_cast(Alloc.getLocalAddress()) << " -> " << format("0x%016x", NextCodeAddr) << "\n"); Alloc.setRemoteAddress(NextCodeAddr); NextCodeAddr += Alloc.getSize(); } } { TargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr; for (auto &Alloc : ObjAllocs.RODataAllocs) { NextRODataAddr = RoundUpToAlignment(NextRODataAddr, Alloc.getAlign()); Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr); DEBUG(dbgs() << " ro-data: " << static_cast(Alloc.getLocalAddress()) << " -> " << format("0x%016x", NextRODataAddr) << "\n"); Alloc.setRemoteAddress(NextRODataAddr); NextRODataAddr += Alloc.getSize(); } } { TargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr; for (auto &Alloc : ObjAllocs.RWDataAllocs) { NextRWDataAddr = RoundUpToAlignment(NextRWDataAddr, Alloc.getAlign()); Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr); DEBUG(dbgs() << " rw-data: " << static_cast(Alloc.getLocalAddress()) << " -> " << format("0x%016x", NextRWDataAddr) << "\n"); Alloc.setRemoteAddress(NextRWDataAddr); NextRWDataAddr += Alloc.getSize(); } } Unfinalized.push_back(std::move(ObjAllocs)); } Unmapped.clear(); } bool finalizeMemory(std::string *ErrMsg = nullptr) override { DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n"); for (auto &ObjAllocs : Unfinalized) { for (auto &Alloc : ObjAllocs.CodeAllocs) { DEBUG(dbgs() << " copying code: " << static_cast(Alloc.getLocalAddress()) << " -> " << format("0x%016x", Alloc.getRemoteAddress()) << " (" << Alloc.getSize() << " bytes)\n"); Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), Alloc.getSize()); } if (ObjAllocs.RemoteCodeAddr) { DEBUG(dbgs() << " setting R-X permissions on code block: " << format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n"); Client.setProtections(Id, ObjAllocs.RemoteCodeAddr, sys::Memory::MF_READ | sys::Memory::MF_EXEC); } for (auto &Alloc : ObjAllocs.RODataAllocs) { DEBUG(dbgs() << " copying ro-data: " << static_cast(Alloc.getLocalAddress()) << " -> " << format("0x%016x", Alloc.getRemoteAddress()) << " (" << Alloc.getSize() << " bytes)\n"); Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), Alloc.getSize()); } if (ObjAllocs.RemoteRODataAddr) { DEBUG(dbgs() << " setting R-- permissions on ro-data block: " << format("0x%016x", ObjAllocs.RemoteRODataAddr) << "\n"); Client.setProtections(Id, ObjAllocs.RemoteRODataAddr, sys::Memory::MF_READ); } for (auto &Alloc : ObjAllocs.RWDataAllocs) { DEBUG(dbgs() << " copying rw-data: " << static_cast(Alloc.getLocalAddress()) << " -> " << format("0x%016x", Alloc.getRemoteAddress()) << " (" << Alloc.getSize() << " bytes)\n"); Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), Alloc.getSize()); } if (ObjAllocs.RemoteRWDataAddr) { DEBUG(dbgs() << " setting RW- permissions on rw-data block: " << format("0x%016x", ObjAllocs.RemoteRWDataAddr) << "\n"); Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr, sys::Memory::MF_READ | sys::Memory::MF_WRITE); } } Unfinalized.clear(); return false; } private: class Alloc { public: Alloc(uint64_t Size, unsigned Align) : Size(Size), Align(Align), Contents(new char[Size + Align - 1]), RemoteAddr(0) {} Alloc(Alloc &&Other) : Size(std::move(Other.Size)), Align(std::move(Other.Align)), Contents(std::move(Other.Contents)), RemoteAddr(std::move(Other.RemoteAddr)) {} Alloc &operator=(Alloc &&Other) { Size = std::move(Other.Size); Align = std::move(Other.Align); Contents = std::move(Other.Contents); RemoteAddr = std::move(Other.RemoteAddr); return *this; } uint64_t getSize() const { return Size; } unsigned getAlign() const { return Align; } char *getLocalAddress() const { uintptr_t LocalAddr = reinterpret_cast(Contents.get()); LocalAddr = RoundUpToAlignment(LocalAddr, Align); return reinterpret_cast(LocalAddr); } void setRemoteAddress(TargetAddress RemoteAddr) { this->RemoteAddr = RemoteAddr; } TargetAddress getRemoteAddress() const { return RemoteAddr; } private: uint64_t Size; unsigned Align; std::unique_ptr Contents; TargetAddress RemoteAddr; }; struct ObjectAllocs { ObjectAllocs() : RemoteCodeAddr(0), RemoteRODataAddr(0), RemoteRWDataAddr(0) {} ObjectAllocs(ObjectAllocs &&Other) : RemoteCodeAddr(std::move(Other.RemoteCodeAddr)), RemoteRODataAddr(std::move(Other.RemoteRODataAddr)), RemoteRWDataAddr(std::move(Other.RemoteRWDataAddr)), CodeAllocs(std::move(Other.CodeAllocs)), RODataAllocs(std::move(Other.RODataAllocs)), RWDataAllocs(std::move(Other.RWDataAllocs)) {} ObjectAllocs &operator=(ObjectAllocs &&Other) { RemoteCodeAddr = std::move(Other.RemoteCodeAddr); RemoteRODataAddr = std::move(Other.RemoteRODataAddr); RemoteRWDataAddr = std::move(Other.RemoteRWDataAddr); CodeAllocs = std::move(Other.CodeAllocs); RODataAllocs = std::move(Other.RODataAllocs); RWDataAllocs = std::move(Other.RWDataAllocs); return *this; } TargetAddress RemoteCodeAddr; TargetAddress RemoteRODataAddr; TargetAddress RemoteRWDataAddr; std::vector CodeAllocs, RODataAllocs, RWDataAllocs; }; OrcRemoteTargetClient &Client; ResourceIdMgr::ResourceId Id; std::vector Unmapped; std::vector Unfinalized; }; /// Remote indirect stubs manager. class RCIndirectStubsManager : public IndirectStubsManager { public: RCIndirectStubsManager(OrcRemoteTargetClient &Remote, ResourceIdMgr::ResourceId Id) : Remote(Remote), Id(Id) {} ~RCIndirectStubsManager() { Remote.destroyIndirectStubsManager(Id); } std::error_code createStub(StringRef StubName, TargetAddress StubAddr, JITSymbolFlags StubFlags) override { if (auto EC = reserveStubs(1)) return EC; return createStubInternal(StubName, StubAddr, StubFlags); } std::error_code createStubs(const StubInitsMap &StubInits) override { if (auto EC = reserveStubs(StubInits.size())) return EC; for (auto &Entry : StubInits) if (auto EC = createStubInternal(Entry.first(), Entry.second.first, Entry.second.second)) return EC; return std::error_code(); } JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { auto I = StubIndexes.find(Name); if (I == StubIndexes.end()) return nullptr; auto Key = I->second.first; auto Flags = I->second.second; auto StubSymbol = JITSymbol(getStubAddr(Key), Flags); if (ExportedStubsOnly && !StubSymbol.isExported()) return nullptr; return StubSymbol; } JITSymbol findPointer(StringRef Name) override { auto I = StubIndexes.find(Name); if (I == StubIndexes.end()) return nullptr; auto Key = I->second.first; auto Flags = I->second.second; return JITSymbol(getPtrAddr(Key), Flags); } std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) override { auto I = StubIndexes.find(Name); assert(I != StubIndexes.end() && "No stub pointer for symbol"); auto Key = I->second.first; return Remote.writePointer(getPtrAddr(Key), NewAddr); } private: struct RemoteIndirectStubsInfo { RemoteIndirectStubsInfo(TargetAddress StubBase, TargetAddress PtrBase, unsigned NumStubs) : StubBase(StubBase), PtrBase(PtrBase), NumStubs(NumStubs) {} TargetAddress StubBase; TargetAddress PtrBase; unsigned NumStubs; }; OrcRemoteTargetClient &Remote; ResourceIdMgr::ResourceId Id; std::vector RemoteIndirectStubsInfos; typedef std::pair StubKey; std::vector FreeStubs; StringMap> StubIndexes; std::error_code reserveStubs(unsigned NumStubs) { if (NumStubs <= FreeStubs.size()) return std::error_code(); unsigned NewStubsRequired = NumStubs - FreeStubs.size(); TargetAddress StubBase; TargetAddress PtrBase; unsigned NumStubsEmitted; Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id, NewStubsRequired); unsigned NewBlockId = RemoteIndirectStubsInfos.size(); RemoteIndirectStubsInfos.push_back( RemoteIndirectStubsInfo(StubBase, PtrBase, NumStubsEmitted)); for (unsigned I = 0; I < NumStubsEmitted; ++I) FreeStubs.push_back(std::make_pair(NewBlockId, I)); return std::error_code(); } std::error_code createStubInternal(StringRef StubName, TargetAddress InitAddr, JITSymbolFlags StubFlags) { auto Key = FreeStubs.back(); FreeStubs.pop_back(); StubIndexes[StubName] = std::make_pair(Key, StubFlags); return Remote.writePointer(getPtrAddr(Key), InitAddr); } TargetAddress getStubAddr(StubKey K) { assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 && "Missing stub address"); return RemoteIndirectStubsInfos[K.first].StubBase + K.second * Remote.getIndirectStubSize(); } TargetAddress getPtrAddr(StubKey K) { assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 && "Missing pointer address"); return RemoteIndirectStubsInfos[K.first].PtrBase + K.second * Remote.getPointerSize(); } }; /// Remote compile callback manager. class RCCompileCallbackManager : public JITCompileCallbackManager { public: RCCompileCallbackManager(TargetAddress ErrorHandlerAddress, OrcRemoteTargetClient &Remote) : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) { assert(!Remote.CompileCallback && "Compile callback already set"); Remote.CompileCallback = [this](TargetAddress TrampolineAddr) { return executeCompileCallback(TrampolineAddr); }; Remote.emitResolverBlock(); } private: void grow() { TargetAddress BlockAddr = 0; uint32_t NumTrampolines = 0; auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines); assert(!EC && "Failed to create trampolines"); uint32_t TrampolineSize = Remote.getTrampolineSize(); for (unsigned I = 0; I < NumTrampolines; ++I) this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize)); } OrcRemoteTargetClient &Remote; }; /// Create an OrcRemoteTargetClient. /// Channel is the ChannelT instance to communicate on. It is assumed that /// the channel is ready to be read from and written to. static ErrorOr Create(ChannelT &Channel) { std::error_code EC; OrcRemoteTargetClient H(Channel, EC); if (EC) return EC; return H; } /// Call the int(void) function at the given address in the target and return /// its result. std::error_code callIntVoid(int &Result, TargetAddress Addr) { DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n"); if (auto EC = call(Channel, Addr)) return EC; unsigned NextProcId; if (auto EC = listenForCompileRequests(NextProcId)) return EC; if (NextProcId != CallIntVoidResponseId) return orcError(OrcErrorCode::UnexpectedRPCCall); return handle(Channel, [&](int R) { Result = R; DEBUG(dbgs() << "Result: " << R << "\n"); return std::error_code(); }); } /// Call the int(int, char*[]) function at the given address in the target and /// return its result. std::error_code callMain(int &Result, TargetAddress Addr, const std::vector &Args) { DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr) << "\n"); if (auto EC = call(Channel, Addr, Args)) return EC; unsigned NextProcId; if (auto EC = listenForCompileRequests(NextProcId)) return EC; if (NextProcId != CallMainResponseId) return orcError(OrcErrorCode::UnexpectedRPCCall); return handle(Channel, [&](int R) { Result = R; DEBUG(dbgs() << "Result: " << R << "\n"); return std::error_code(); }); } /// Call the void() function at the given address in the target and wait for /// it to finish. std::error_code callVoidVoid(TargetAddress Addr) { DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr) << "\n"); if (auto EC = call(Channel, Addr)) return EC; unsigned NextProcId; if (auto EC = listenForCompileRequests(NextProcId)) return EC; if (NextProcId != CallVoidVoidResponseId) return orcError(OrcErrorCode::UnexpectedRPCCall); return handle(Channel, doNothing); } /// Create an RCMemoryManager which will allocate its memory on the remote /// target. std::error_code createRemoteMemoryManager(std::unique_ptr &MM) { assert(!MM && "MemoryManager should be null before creation."); auto Id = AllocatorIds.getNext(); if (auto EC = call(Channel, Id)) return EC; MM = llvm::make_unique(*this, Id); return std::error_code(); } /// Create an RCIndirectStubsManager that will allocate stubs on the remote /// target. std::error_code createIndirectStubsManager(std::unique_ptr &I) { assert(!I && "Indirect stubs manager should be null before creation."); auto Id = IndirectStubOwnerIds.getNext(); if (auto EC = call(Channel, Id)) return EC; I = llvm::make_unique(*this, Id); return std::error_code(); } /// Search for symbols in the remote process. Note: This should be used by /// symbol resolvers *after* they've searched the local symbol table in the /// JIT stack. std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) return ExistingError; // Request remote symbol address. if (auto EC = call(Channel, Name)) return EC; return expect(Channel, [&](TargetAddress &A) { Addr = A; DEBUG(dbgs() << "Remote address lookup " << Name << " = " << format("0x%016x", Addr) << "\n"); return std::error_code(); }); } /// Get the triple for the remote target. const std::string &getTargetTriple() const { return RemoteTargetTriple; } std::error_code terminateSession() { return call(Channel); } private: OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC) : Channel(Channel), RemotePointerSize(0), RemotePageSize(0), RemoteTrampolineSize(0), RemoteIndirectStubSize(0) { if ((EC = call(Channel))) return; EC = expect( Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize, RemoteTrampolineSize, RemoteIndirectStubSize)); } void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { if (auto EC = call(Channel, Id)) { // FIXME: This will be triggered by a removeModuleSet call: Propagate // error return up through that. llvm_unreachable("Failed to destroy remote allocator."); AllocatorIds.release(Id); } } std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) { IndirectStubOwnerIds.release(Id); return call(Channel, Id); } std::error_code emitIndirectStubs(TargetAddress &StubBase, TargetAddress &PtrBase, uint32_t &NumStubsEmitted, ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) { if (auto EC = call(Channel, Id, NumStubsRequired)) return EC; return expect( Channel, readArgs(StubBase, PtrBase, NumStubsEmitted)); } std::error_code emitResolverBlock() { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) return ExistingError; return call(Channel); } std::error_code emitTrampolineBlock(TargetAddress &BlockAddr, uint32_t &NumTrampolines) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) return ExistingError; if (auto EC = call(Channel)) return EC; return expect( Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) { BlockAddr = BAddr; NumTrampolines = NTrampolines; return std::error_code(); }); } uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; } uint32_t getPageSize() const { return RemotePageSize; } uint32_t getPointerSize() const { return RemotePointerSize; } uint32_t getTrampolineSize() const { return RemoteTrampolineSize; } std::error_code listenForCompileRequests(uint32_t &NextId) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) return ExistingError; if (auto EC = getNextProcId(Channel, NextId)) return EC; while (NextId == RequestCompileId) { TargetAddress TrampolineAddr = 0; if (auto EC = handle(Channel, readArgs(TrampolineAddr))) return EC; TargetAddress ImplAddr = CompileCallback(TrampolineAddr); if (auto EC = call(Channel, ImplAddr)) return EC; if (auto EC = getNextProcId(Channel, NextId)) return EC; } return std::error_code(); } std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) return ExistingError; if (auto EC = call(Channel, Src, Size)) return EC; if (auto EC = expect( Channel, [&]() { return Channel.readBytes(Dst, Size); })) return EC; return std::error_code(); } std::error_code reserveMem(TargetAddress &RemoteAddr, ResourceIdMgr::ResourceId Id, uint64_t Size, uint32_t Align) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) return ExistingError; if (std::error_code EC = call(Channel, Id, Size, Align)) return EC; return expect(Channel, readArgs(RemoteAddr)); } std::error_code setProtections(ResourceIdMgr::ResourceId Id, TargetAddress RemoteSegAddr, unsigned ProtFlags) { return call(Channel, Id, RemoteSegAddr, ProtFlags); } std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) return ExistingError; // Make the send call. if (auto EC = call(Channel, Addr, Size)) return EC; // Follow this up with the section contents. if (auto EC = Channel.appendBytes(Src, Size)) return EC; return Channel.send(); } std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) { // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) return ExistingError; return call(Channel, Addr, PtrVal); } static std::error_code doNothing() { return std::error_code(); } ChannelT &Channel; std::error_code ExistingError; std::string RemoteTargetTriple; uint32_t RemotePointerSize; uint32_t RemotePageSize; uint32_t RemoteTrampolineSize; uint32_t RemoteIndirectStubSize; ResourceIdMgr AllocatorIds, IndirectStubOwnerIds; std::function CompileCallback; }; } // end namespace remote } // end namespace orc } // end namespace llvm #undef DEBUG_TYPE #endif