Home | History | Annotate | Download | only in Orc
      1 //===- OrcRemoteTargetClient.h - Orc Remote-target Client -------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines the OrcRemoteTargetClient class and helpers. This class
     11 // can be used to communicate over an RawByteChannel with an
     12 // OrcRemoteTargetServer instance to support remote-JITing.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
     17 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
     18 
     19 #include "llvm/ADT/Optional.h"
     20 #include "llvm/ADT/STLExtras.h"
     21 #include "llvm/ADT/StringMap.h"
     22 #include "llvm/ADT/StringRef.h"
     23 #include "llvm/ExecutionEngine/JITSymbol.h"
     24 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
     25 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
     26 #include "llvm/ExecutionEngine/RuntimeDyld.h"
     27 #include "llvm/Support/Debug.h"
     28 #include "llvm/Support/Error.h"
     29 #include "llvm/Support/ErrorHandling.h"
     30 #include "llvm/Support/Format.h"
     31 #include "llvm/Support/MathExtras.h"
     32 #include "llvm/Support/Memory.h"
     33 #include "llvm/Support/raw_ostream.h"
     34 #include <algorithm>
     35 #include <cassert>
     36 #include <cstdint>
     37 #include <memory>
     38 #include <string>
     39 #include <tuple>
     40 #include <utility>
     41 #include <vector>
     42 
     43 #define DEBUG_TYPE "orc-remote"
     44 
     45 namespace llvm {
     46 namespace orc {
     47 namespace remote {
     48 
     49 /// This class provides utilities (including memory manager, indirect stubs
     50 /// manager, and compile callback manager types) that support remote JITing
     51 /// in ORC.
     52 ///
     53 /// Each of the utility classes talks to a JIT server (an instance of the
     54 /// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
     55 /// its actions.
     56 class OrcRemoteTargetClient
     57     : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
     58 public:
     59   /// Remote-mapped RuntimeDyld-compatible memory manager.
     60   class RemoteRTDyldMemoryManager : public RuntimeDyld::MemoryManager {
     61     friend class OrcRemoteTargetClient;
     62 
     63   public:
     64     ~RemoteRTDyldMemoryManager() {
     65       Client.destroyRemoteAllocator(Id);
     66       DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
     67     }
     68 
     69     RemoteRTDyldMemoryManager(const RemoteRTDyldMemoryManager &) = delete;
     70     RemoteRTDyldMemoryManager &
     71     operator=(const RemoteRTDyldMemoryManager &) = delete;
     72     RemoteRTDyldMemoryManager(RemoteRTDyldMemoryManager &&) = default;
     73     RemoteRTDyldMemoryManager &
     74     operator=(RemoteRTDyldMemoryManager &&) = default;
     75 
     76     uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
     77                                  unsigned SectionID,
     78                                  StringRef SectionName) override {
     79       Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
     80       uint8_t *Alloc = reinterpret_cast<uint8_t *>(
     81           Unmapped.back().CodeAllocs.back().getLocalAddress());
     82       DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
     83                    << SectionName << ": " << Alloc << " (" << Size
     84                    << " bytes, alignment " << Alignment << ")\n");
     85       return Alloc;
     86     }
     87 
     88     uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
     89                                  unsigned SectionID, StringRef SectionName,
     90                                  bool IsReadOnly) override {
     91       if (IsReadOnly) {
     92         Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
     93         uint8_t *Alloc = reinterpret_cast<uint8_t *>(
     94             Unmapped.back().RODataAllocs.back().getLocalAddress());
     95         DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
     96                      << SectionName << ": " << Alloc << " (" << Size
     97                      << " bytes, alignment " << Alignment << ")\n");
     98         return Alloc;
     99       } // else...
    100 
    101       Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
    102       uint8_t *Alloc = reinterpret_cast<uint8_t *>(
    103           Unmapped.back().RWDataAllocs.back().getLocalAddress());
    104       DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
    105                    << SectionName << ": " << Alloc << " (" << Size
    106                    << " bytes, alignment " << Alignment << ")\n");
    107       return Alloc;
    108     }
    109 
    110     void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
    111                                 uintptr_t RODataSize, uint32_t RODataAlign,
    112                                 uintptr_t RWDataSize,
    113                                 uint32_t RWDataAlign) override {
    114       Unmapped.push_back(ObjectAllocs());
    115 
    116       DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
    117 
    118       if (CodeSize != 0) {
    119         Unmapped.back().RemoteCodeAddr =
    120             Client.reserveMem(Id, CodeSize, CodeAlign);
    121 
    122         DEBUG(dbgs() << "  code: "
    123                      << format("0x%016x", Unmapped.back().RemoteCodeAddr)
    124                      << " (" << CodeSize << " bytes, alignment " << CodeAlign
    125                      << ")\n");
    126       }
    127 
    128       if (RODataSize != 0) {
    129         Unmapped.back().RemoteRODataAddr =
    130             Client.reserveMem(Id, RODataSize, RODataAlign);
    131 
    132         DEBUG(dbgs() << "  ro-data: "
    133                      << format("0x%016x", Unmapped.back().RemoteRODataAddr)
    134                      << " (" << RODataSize << " bytes, alignment "
    135                      << RODataAlign << ")\n");
    136       }
    137 
    138       if (RWDataSize != 0) {
    139         Unmapped.back().RemoteRWDataAddr =
    140             Client.reserveMem(Id, RWDataSize, RWDataAlign);
    141 
    142         DEBUG(dbgs() << "  rw-data: "
    143                      << format("0x%016x", Unmapped.back().RemoteRWDataAddr)
    144                      << " (" << RWDataSize << " bytes, alignment "
    145                      << RWDataAlign << ")\n");
    146       }
    147     }
    148 
    149     bool needsToReserveAllocationSpace() override { return true; }
    150 
    151     void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
    152                           size_t Size) override {
    153       UnfinalizedEHFrames.push_back({LoadAddr, Size});
    154     }
    155 
    156     void deregisterEHFrames() override {
    157       for (auto &Frame : RegisteredEHFrames) {
    158         // FIXME: Add error poll.
    159         Client.deregisterEHFrames(Frame.Addr, Frame.Size);
    160       }
    161     }
    162 
    163     void notifyObjectLoaded(RuntimeDyld &Dyld,
    164                             const object::ObjectFile &Obj) override {
    165       DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
    166       for (auto &ObjAllocs : Unmapped) {
    167         mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
    168                                ObjAllocs.RemoteCodeAddr);
    169         mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
    170                                ObjAllocs.RemoteRODataAddr);
    171         mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
    172                                ObjAllocs.RemoteRWDataAddr);
    173         Unfinalized.push_back(std::move(ObjAllocs));
    174       }
    175       Unmapped.clear();
    176     }
    177 
    178     bool finalizeMemory(std::string *ErrMsg = nullptr) override {
    179       DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
    180 
    181       for (auto &ObjAllocs : Unfinalized) {
    182         if (copyAndProtect(ObjAllocs.CodeAllocs, ObjAllocs.RemoteCodeAddr,
    183                            sys::Memory::MF_READ | sys::Memory::MF_EXEC))
    184           return true;
    185 
    186         if (copyAndProtect(ObjAllocs.RODataAllocs, ObjAllocs.RemoteRODataAddr,
    187                            sys::Memory::MF_READ))
    188           return true;
    189 
    190         if (copyAndProtect(ObjAllocs.RWDataAllocs, ObjAllocs.RemoteRWDataAddr,
    191                            sys::Memory::MF_READ | sys::Memory::MF_WRITE))
    192           return true;
    193       }
    194       Unfinalized.clear();
    195 
    196       for (auto &EHFrame : UnfinalizedEHFrames) {
    197         if (auto Err = Client.registerEHFrames(EHFrame.Addr, EHFrame.Size)) {
    198           // FIXME: Replace this once finalizeMemory can return an Error.
    199           handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
    200             if (ErrMsg) {
    201               raw_string_ostream ErrOut(*ErrMsg);
    202               EIB.log(ErrOut);
    203             }
    204           });
    205           return false;
    206         }
    207       }
    208       RegisteredEHFrames = std::move(UnfinalizedEHFrames);
    209       UnfinalizedEHFrames = {};
    210 
    211       return false;
    212     }
    213 
    214   private:
    215     class Alloc {
    216     public:
    217       Alloc(uint64_t Size, unsigned Align)
    218           : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
    219 
    220       Alloc(const Alloc &) = delete;
    221       Alloc &operator=(const Alloc &) = delete;
    222       Alloc(Alloc &&) = default;
    223       Alloc &operator=(Alloc &&) = default;
    224 
    225       uint64_t getSize() const { return Size; }
    226 
    227       unsigned getAlign() const { return Align; }
    228 
    229       char *getLocalAddress() const {
    230         uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
    231         LocalAddr = alignTo(LocalAddr, Align);
    232         return reinterpret_cast<char *>(LocalAddr);
    233       }
    234 
    235       void setRemoteAddress(JITTargetAddress RemoteAddr) {
    236         this->RemoteAddr = RemoteAddr;
    237       }
    238 
    239       JITTargetAddress getRemoteAddress() const { return RemoteAddr; }
    240 
    241     private:
    242       uint64_t Size;
    243       unsigned Align;
    244       std::unique_ptr<char[]> Contents;
    245       JITTargetAddress RemoteAddr = 0;
    246     };
    247 
    248     struct ObjectAllocs {
    249       ObjectAllocs() = default;
    250       ObjectAllocs(const ObjectAllocs &) = delete;
    251       ObjectAllocs &operator=(const ObjectAllocs &) = delete;
    252       ObjectAllocs(ObjectAllocs &&) = default;
    253       ObjectAllocs &operator=(ObjectAllocs &&) = default;
    254 
    255       JITTargetAddress RemoteCodeAddr = 0;
    256       JITTargetAddress RemoteRODataAddr = 0;
    257       JITTargetAddress RemoteRWDataAddr = 0;
    258       std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
    259     };
    260 
    261     RemoteRTDyldMemoryManager(OrcRemoteTargetClient &Client,
    262                               ResourceIdMgr::ResourceId Id)
    263         : Client(Client), Id(Id) {
    264       DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
    265     }
    266 
    267     // Maps all allocations in Allocs to aligned blocks
    268     void mapAllocsToRemoteAddrs(RuntimeDyld &Dyld, std::vector<Alloc> &Allocs,
    269                                 JITTargetAddress NextAddr) {
    270       for (auto &Alloc : Allocs) {
    271         NextAddr = alignTo(NextAddr, Alloc.getAlign());
    272         Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextAddr);
    273         DEBUG(dbgs() << "     " << static_cast<void *>(Alloc.getLocalAddress())
    274                      << " -> " << format("0x%016x", NextAddr) << "\n");
    275         Alloc.setRemoteAddress(NextAddr);
    276 
    277         // Only advance NextAddr if it was non-null to begin with,
    278         // otherwise leave it as null.
    279         if (NextAddr)
    280           NextAddr += Alloc.getSize();
    281       }
    282     }
    283 
    284     // Copies data for each alloc in the list, then set permissions on the
    285     // segment.
    286     bool copyAndProtect(const std::vector<Alloc> &Allocs,
    287                         JITTargetAddress RemoteSegmentAddr,
    288                         unsigned Permissions) {
    289       if (RemoteSegmentAddr) {
    290         assert(!Allocs.empty() && "No sections in allocated segment");
    291 
    292         for (auto &Alloc : Allocs) {
    293           DEBUG(dbgs() << "  copying section: "
    294                        << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
    295                        << format("0x%016x", Alloc.getRemoteAddress()) << " ("
    296                        << Alloc.getSize() << " bytes)\n";);
    297 
    298           if (Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
    299                               Alloc.getSize()))
    300             return true;
    301         }
    302 
    303         DEBUG(dbgs() << "  setting "
    304                      << (Permissions & sys::Memory::MF_READ ? 'R' : '-')
    305                      << (Permissions & sys::Memory::MF_WRITE ? 'W' : '-')
    306                      << (Permissions & sys::Memory::MF_EXEC ? 'X' : '-')
    307                      << " permissions on block: "
    308                      << format("0x%016x", RemoteSegmentAddr) << "\n");
    309         if (Client.setProtections(Id, RemoteSegmentAddr, Permissions))
    310           return true;
    311       }
    312       return false;
    313     }
    314 
    315     OrcRemoteTargetClient &Client;
    316     ResourceIdMgr::ResourceId Id;
    317     std::vector<ObjectAllocs> Unmapped;
    318     std::vector<ObjectAllocs> Unfinalized;
    319 
    320     struct EHFrame {
    321       JITTargetAddress Addr;
    322       uint64_t Size;
    323     };
    324     std::vector<EHFrame> UnfinalizedEHFrames;
    325     std::vector<EHFrame> RegisteredEHFrames;
    326   };
    327 
    328   /// Remote indirect stubs manager.
    329   class RemoteIndirectStubsManager : public IndirectStubsManager {
    330   public:
    331     RemoteIndirectStubsManager(OrcRemoteTargetClient &Client,
    332                                ResourceIdMgr::ResourceId Id)
    333         : Client(Client), Id(Id) {}
    334 
    335     ~RemoteIndirectStubsManager() override {
    336       Client.destroyIndirectStubsManager(Id);
    337     }
    338 
    339     Error createStub(StringRef StubName, JITTargetAddress StubAddr,
    340                      JITSymbolFlags StubFlags) override {
    341       if (auto Err = reserveStubs(1))
    342         return Err;
    343 
    344       return createStubInternal(StubName, StubAddr, StubFlags);
    345     }
    346 
    347     Error createStubs(const StubInitsMap &StubInits) override {
    348       if (auto Err = reserveStubs(StubInits.size()))
    349         return Err;
    350 
    351       for (auto &Entry : StubInits)
    352         if (auto Err = createStubInternal(Entry.first(), Entry.second.first,
    353                                           Entry.second.second))
    354           return Err;
    355 
    356       return Error::success();
    357     }
    358 
    359     JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
    360       auto I = StubIndexes.find(Name);
    361       if (I == StubIndexes.end())
    362         return nullptr;
    363       auto Key = I->second.first;
    364       auto Flags = I->second.second;
    365       auto StubSymbol = JITSymbol(getStubAddr(Key), Flags);
    366       if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
    367         return nullptr;
    368       return StubSymbol;
    369     }
    370 
    371     JITSymbol findPointer(StringRef Name) override {
    372       auto I = StubIndexes.find(Name);
    373       if (I == StubIndexes.end())
    374         return nullptr;
    375       auto Key = I->second.first;
    376       auto Flags = I->second.second;
    377       return JITSymbol(getPtrAddr(Key), Flags);
    378     }
    379 
    380     Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
    381       auto I = StubIndexes.find(Name);
    382       assert(I != StubIndexes.end() && "No stub pointer for symbol");
    383       auto Key = I->second.first;
    384       return Client.writePointer(getPtrAddr(Key), NewAddr);
    385     }
    386 
    387   private:
    388     struct RemoteIndirectStubsInfo {
    389       JITTargetAddress StubBase;
    390       JITTargetAddress PtrBase;
    391       unsigned NumStubs;
    392     };
    393 
    394     using StubKey = std::pair<uint16_t, uint16_t>;
    395 
    396     Error reserveStubs(unsigned NumStubs) {
    397       if (NumStubs <= FreeStubs.size())
    398         return Error::success();
    399 
    400       unsigned NewStubsRequired = NumStubs - FreeStubs.size();
    401       JITTargetAddress StubBase;
    402       JITTargetAddress PtrBase;
    403       unsigned NumStubsEmitted;
    404 
    405       if (auto StubInfoOrErr = Client.emitIndirectStubs(Id, NewStubsRequired))
    406         std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
    407       else
    408         return StubInfoOrErr.takeError();
    409 
    410       unsigned NewBlockId = RemoteIndirectStubsInfos.size();
    411       RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
    412 
    413       for (unsigned I = 0; I < NumStubsEmitted; ++I)
    414         FreeStubs.push_back(std::make_pair(NewBlockId, I));
    415 
    416       return Error::success();
    417     }
    418 
    419     Error createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
    420                              JITSymbolFlags StubFlags) {
    421       auto Key = FreeStubs.back();
    422       FreeStubs.pop_back();
    423       StubIndexes[StubName] = std::make_pair(Key, StubFlags);
    424       return Client.writePointer(getPtrAddr(Key), InitAddr);
    425     }
    426 
    427     JITTargetAddress getStubAddr(StubKey K) {
    428       assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
    429              "Missing stub address");
    430       return RemoteIndirectStubsInfos[K.first].StubBase +
    431              K.second * Client.getIndirectStubSize();
    432     }
    433 
    434     JITTargetAddress getPtrAddr(StubKey K) {
    435       assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
    436              "Missing pointer address");
    437       return RemoteIndirectStubsInfos[K.first].PtrBase +
    438              K.second * Client.getPointerSize();
    439     }
    440 
    441     OrcRemoteTargetClient &Client;
    442     ResourceIdMgr::ResourceId Id;
    443     std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
    444     std::vector<StubKey> FreeStubs;
    445     StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
    446   };
    447 
    448   /// Remote compile callback manager.
    449   class RemoteCompileCallbackManager : public JITCompileCallbackManager {
    450   public:
    451     RemoteCompileCallbackManager(OrcRemoteTargetClient &Client,
    452                                  JITTargetAddress ErrorHandlerAddress)
    453         : JITCompileCallbackManager(ErrorHandlerAddress), Client(Client) {}
    454 
    455   private:
    456     Error grow() override {
    457       JITTargetAddress BlockAddr = 0;
    458       uint32_t NumTrampolines = 0;
    459       if (auto TrampolineInfoOrErr = Client.emitTrampolineBlock())
    460         std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
    461       else
    462         return TrampolineInfoOrErr.takeError();
    463 
    464       uint32_t TrampolineSize = Client.getTrampolineSize();
    465       for (unsigned I = 0; I < NumTrampolines; ++I)
    466         this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
    467 
    468       return Error::success();
    469     }
    470 
    471     OrcRemoteTargetClient &Client;
    472   };
    473 
    474   /// Create an OrcRemoteTargetClient.
    475   /// Channel is the ChannelT instance to communicate on. It is assumed that
    476   /// the channel is ready to be read from and written to.
    477   static Expected<std::unique_ptr<OrcRemoteTargetClient>>
    478   Create(rpc::RawByteChannel &Channel, std::function<void(Error)> ReportError) {
    479     Error Err = Error::success();
    480     auto Client = std::unique_ptr<OrcRemoteTargetClient>(
    481         new OrcRemoteTargetClient(Channel, std::move(ReportError), Err));
    482     if (Err)
    483       return std::move(Err);
    484     return std::move(Client);
    485   }
    486 
    487   /// Call the int(void) function at the given address in the target and return
    488   /// its result.
    489   Expected<int> callIntVoid(JITTargetAddress Addr) {
    490     DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
    491     return callB<exec::CallIntVoid>(Addr);
    492   }
    493 
    494   /// Call the int(int, char*[]) function at the given address in the target and
    495   /// return its result.
    496   Expected<int> callMain(JITTargetAddress Addr,
    497                          const std::vector<std::string> &Args) {
    498     DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
    499                  << "\n");
    500     return callB<exec::CallMain>(Addr, Args);
    501   }
    502 
    503   /// Call the void() function at the given address in the target and wait for
    504   /// it to finish.
    505   Error callVoidVoid(JITTargetAddress Addr) {
    506     DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
    507                  << "\n");
    508     return callB<exec::CallVoidVoid>(Addr);
    509   }
    510 
    511   /// Create an RCMemoryManager which will allocate its memory on the remote
    512   /// target.
    513   Expected<std::unique_ptr<RemoteRTDyldMemoryManager>>
    514   createRemoteMemoryManager() {
    515     auto Id = AllocatorIds.getNext();
    516     if (auto Err = callB<mem::CreateRemoteAllocator>(Id))
    517       return std::move(Err);
    518     return std::unique_ptr<RemoteRTDyldMemoryManager>(
    519         new RemoteRTDyldMemoryManager(*this, Id));
    520   }
    521 
    522   /// Create an RCIndirectStubsManager that will allocate stubs on the remote
    523   /// target.
    524   Expected<std::unique_ptr<RemoteIndirectStubsManager>>
    525   createIndirectStubsManager() {
    526     auto Id = IndirectStubOwnerIds.getNext();
    527     if (auto Err = callB<stubs::CreateIndirectStubsOwner>(Id))
    528       return std::move(Err);
    529     return llvm::make_unique<RemoteIndirectStubsManager>(*this, Id);
    530   }
    531 
    532   Expected<RemoteCompileCallbackManager &>
    533   enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress) {
    534     // Emit the resolver block on the JIT server.
    535     if (auto Err = callB<stubs::EmitResolverBlock>())
    536       return std::move(Err);
    537 
    538     // Create the callback manager.
    539     CallbackManager.emplace(*this, ErrorHandlerAddress);
    540     RemoteCompileCallbackManager &Mgr = *CallbackManager;
    541     return Mgr;
    542   }
    543 
    544   /// Search for symbols in the remote process. Note: This should be used by
    545   /// symbol resolvers *after* they've searched the local symbol table in the
    546   /// JIT stack.
    547   Expected<JITTargetAddress> getSymbolAddress(StringRef Name) {
    548     return callB<utils::GetSymbolAddress>(Name);
    549   }
    550 
    551   /// Get the triple for the remote target.
    552   const std::string &getTargetTriple() const { return RemoteTargetTriple; }
    553 
    554   Error terminateSession() { return callB<utils::TerminateSession>(); }
    555 
    556 private:
    557   OrcRemoteTargetClient(rpc::RawByteChannel &Channel,
    558                         std::function<void(Error)> ReportError, Error &Err)
    559       : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(Channel, true),
    560         ReportError(std::move(ReportError)) {
    561     ErrorAsOutParameter EAO(&Err);
    562 
    563     addHandler<utils::RequestCompile>(
    564         [this](JITTargetAddress Addr) -> JITTargetAddress {
    565           if (CallbackManager)
    566             return CallbackManager->executeCompileCallback(Addr);
    567           return 0;
    568         });
    569 
    570     if (auto RIOrErr = callB<utils::GetRemoteInfo>()) {
    571       std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
    572                RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
    573       Err = Error::success();
    574     } else
    575       Err = RIOrErr.takeError();
    576   }
    577 
    578   void deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
    579     if (auto Err = callB<eh::RegisterEHFrames>(Addr, Size))
    580       ReportError(std::move(Err));
    581   }
    582 
    583   void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
    584     if (auto Err = callB<mem::DestroyRemoteAllocator>(Id)) {
    585       // FIXME: This will be triggered by a removeModuleSet call: Propagate
    586       //        error return up through that.
    587       llvm_unreachable("Failed to destroy remote allocator.");
    588       AllocatorIds.release(Id);
    589     }
    590   }
    591 
    592   void destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
    593     IndirectStubOwnerIds.release(Id);
    594     if (auto Err = callB<stubs::DestroyIndirectStubsOwner>(Id))
    595       ReportError(std::move(Err));
    596   }
    597 
    598   Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
    599   emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
    600     return callB<stubs::EmitIndirectStubs>(Id, NumStubsRequired);
    601   }
    602 
    603   Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() {
    604     return callB<stubs::EmitTrampolineBlock>();
    605   }
    606 
    607   uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
    608   uint32_t getPageSize() const { return RemotePageSize; }
    609   uint32_t getPointerSize() const { return RemotePointerSize; }
    610 
    611   uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
    612 
    613   Expected<std::vector<uint8_t>> readMem(char *Dst, JITTargetAddress Src,
    614                                          uint64_t Size) {
    615     return callB<mem::ReadMem>(Src, Size);
    616   }
    617 
    618   Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) {
    619     // FIXME: Duplicate error and report it via ReportError too?
    620     return callB<eh::RegisterEHFrames>(RAddr, Size);
    621   }
    622 
    623   JITTargetAddress reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
    624                               uint32_t Align) {
    625     if (auto AddrOrErr = callB<mem::ReserveMem>(Id, Size, Align))
    626       return *AddrOrErr;
    627     else {
    628       ReportError(AddrOrErr.takeError());
    629       return 0;
    630     }
    631   }
    632 
    633   bool setProtections(ResourceIdMgr::ResourceId Id,
    634                       JITTargetAddress RemoteSegAddr, unsigned ProtFlags) {
    635     if (auto Err = callB<mem::SetProtections>(Id, RemoteSegAddr, ProtFlags)) {
    636       ReportError(std::move(Err));
    637       return true;
    638     } else
    639       return false;
    640   }
    641 
    642   bool writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) {
    643     if (auto Err = callB<mem::WriteMem>(DirectBufferWriter(Src, Addr, Size))) {
    644       ReportError(std::move(Err));
    645       return true;
    646     } else
    647       return false;
    648   }
    649 
    650   Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
    651     return callB<mem::WritePtr>(Addr, PtrVal);
    652   }
    653 
    654   static Error doNothing() { return Error::success(); }
    655 
    656   std::function<void(Error)> ReportError;
    657   std::string RemoteTargetTriple;
    658   uint32_t RemotePointerSize = 0;
    659   uint32_t RemotePageSize = 0;
    660   uint32_t RemoteTrampolineSize = 0;
    661   uint32_t RemoteIndirectStubSize = 0;
    662   ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
    663   Optional<RemoteCompileCallbackManager> CallbackManager;
    664 };
    665 
    666 } // end namespace remote
    667 } // end namespace orc
    668 } // end namespace llvm
    669 
    670 #undef DEBUG_TYPE
    671 
    672 #endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
    673