Home | History | Annotate | Download | only in Orc
      1 //===---- OrcRemoteTargetServer.h - Orc Remote-target Server ----*- 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 OrcRemoteTargetServer class. It can be used to build a
     11 // JIT server that can execute code sent from an OrcRemoteTargetClient.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
     16 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
     17 
     18 #include "OrcRemoteTargetRPCAPI.h"
     19 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
     20 #include "llvm/Support/Debug.h"
     21 #include "llvm/Support/Format.h"
     22 #include "llvm/Support/Process.h"
     23 #include "llvm/Support/raw_ostream.h"
     24 #include <map>
     25 
     26 #define DEBUG_TYPE "orc-remote"
     27 
     28 namespace llvm {
     29 namespace orc {
     30 namespace remote {
     31 
     32 template <typename ChannelT, typename TargetT>
     33 class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
     34 public:
     35   typedef std::function<TargetAddress(const std::string &Name)>
     36       SymbolLookupFtor;
     37 
     38   typedef std::function<void(uint8_t *Addr, uint32_t Size)>
     39       EHFrameRegistrationFtor;
     40 
     41   OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup,
     42                         EHFrameRegistrationFtor EHFramesRegister,
     43                         EHFrameRegistrationFtor EHFramesDeregister)
     44       : Channel(Channel), SymbolLookup(std::move(SymbolLookup)),
     45         EHFramesRegister(std::move(EHFramesRegister)),
     46         EHFramesDeregister(std::move(EHFramesDeregister)) {}
     47 
     48   // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
     49   OrcRemoteTargetServer(const OrcRemoteTargetServer &) = delete;
     50   OrcRemoteTargetServer &operator=(const OrcRemoteTargetServer &) = delete;
     51 
     52   OrcRemoteTargetServer(OrcRemoteTargetServer &&Other)
     53       : Channel(Other.Channel), SymbolLookup(std::move(Other.SymbolLookup)),
     54         EHFramesRegister(std::move(Other.EHFramesRegister)),
     55         EHFramesDeregister(std::move(Other.EHFramesDeregister)) {}
     56 
     57   OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete;
     58 
     59   Error handleKnownFunction(JITFuncId Id) {
     60     typedef OrcRemoteTargetServer ThisT;
     61 
     62     DEBUG(dbgs() << "Handling known proc: " << getJITFuncIdName(Id) << "\n");
     63 
     64     switch (Id) {
     65     case CallIntVoidId:
     66       return handle<CallIntVoid>(Channel, *this, &ThisT::handleCallIntVoid);
     67     case CallMainId:
     68       return handle<CallMain>(Channel, *this, &ThisT::handleCallMain);
     69     case CallVoidVoidId:
     70       return handle<CallVoidVoid>(Channel, *this, &ThisT::handleCallVoidVoid);
     71     case CreateRemoteAllocatorId:
     72       return handle<CreateRemoteAllocator>(Channel, *this,
     73                                            &ThisT::handleCreateRemoteAllocator);
     74     case CreateIndirectStubsOwnerId:
     75       return handle<CreateIndirectStubsOwner>(
     76           Channel, *this, &ThisT::handleCreateIndirectStubsOwner);
     77     case DeregisterEHFramesId:
     78       return handle<DeregisterEHFrames>(Channel, *this,
     79                                         &ThisT::handleDeregisterEHFrames);
     80     case DestroyRemoteAllocatorId:
     81       return handle<DestroyRemoteAllocator>(
     82           Channel, *this, &ThisT::handleDestroyRemoteAllocator);
     83     case DestroyIndirectStubsOwnerId:
     84       return handle<DestroyIndirectStubsOwner>(
     85           Channel, *this, &ThisT::handleDestroyIndirectStubsOwner);
     86     case EmitIndirectStubsId:
     87       return handle<EmitIndirectStubs>(Channel, *this,
     88                                        &ThisT::handleEmitIndirectStubs);
     89     case EmitResolverBlockId:
     90       return handle<EmitResolverBlock>(Channel, *this,
     91                                        &ThisT::handleEmitResolverBlock);
     92     case EmitTrampolineBlockId:
     93       return handle<EmitTrampolineBlock>(Channel, *this,
     94                                          &ThisT::handleEmitTrampolineBlock);
     95     case GetSymbolAddressId:
     96       return handle<GetSymbolAddress>(Channel, *this,
     97                                       &ThisT::handleGetSymbolAddress);
     98     case GetRemoteInfoId:
     99       return handle<GetRemoteInfo>(Channel, *this, &ThisT::handleGetRemoteInfo);
    100     case ReadMemId:
    101       return handle<ReadMem>(Channel, *this, &ThisT::handleReadMem);
    102     case RegisterEHFramesId:
    103       return handle<RegisterEHFrames>(Channel, *this,
    104                                       &ThisT::handleRegisterEHFrames);
    105     case ReserveMemId:
    106       return handle<ReserveMem>(Channel, *this, &ThisT::handleReserveMem);
    107     case SetProtectionsId:
    108       return handle<SetProtections>(Channel, *this,
    109                                     &ThisT::handleSetProtections);
    110     case WriteMemId:
    111       return handle<WriteMem>(Channel, *this, &ThisT::handleWriteMem);
    112     case WritePtrId:
    113       return handle<WritePtr>(Channel, *this, &ThisT::handleWritePtr);
    114     default:
    115       return orcError(OrcErrorCode::UnexpectedRPCCall);
    116     }
    117 
    118     llvm_unreachable("Unhandled JIT RPC procedure Id.");
    119   }
    120 
    121   Expected<TargetAddress> requestCompile(TargetAddress TrampolineAddr) {
    122     auto Listen = [&](RPCChannel &C, uint32_t Id) {
    123       return handleKnownFunction(static_cast<JITFuncId>(Id));
    124     };
    125 
    126     return callSTHandling<RequestCompile>(Channel, Listen, TrampolineAddr);
    127   }
    128 
    129   Error handleTerminateSession() {
    130     return handle<TerminateSession>(Channel, []() { return Error::success(); });
    131   }
    132 
    133 private:
    134   struct Allocator {
    135     Allocator() = default;
    136     Allocator(Allocator &&Other) : Allocs(std::move(Other.Allocs)) {}
    137     Allocator &operator=(Allocator &&Other) {
    138       Allocs = std::move(Other.Allocs);
    139       return *this;
    140     }
    141 
    142     ~Allocator() {
    143       for (auto &Alloc : Allocs)
    144         sys::Memory::releaseMappedMemory(Alloc.second);
    145     }
    146 
    147     Error allocate(void *&Addr, size_t Size, uint32_t Align) {
    148       std::error_code EC;
    149       sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(
    150           Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
    151       if (EC)
    152         return errorCodeToError(EC);
    153 
    154       Addr = MB.base();
    155       assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc");
    156       Allocs[MB.base()] = std::move(MB);
    157       return Error::success();
    158     }
    159 
    160     Error setProtections(void *block, unsigned Flags) {
    161       auto I = Allocs.find(block);
    162       if (I == Allocs.end())
    163         return orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized);
    164       return errorCodeToError(
    165           sys::Memory::protectMappedMemory(I->second, Flags));
    166     }
    167 
    168   private:
    169     std::map<void *, sys::MemoryBlock> Allocs;
    170   };
    171 
    172   static Error doNothing() { return Error::success(); }
    173 
    174   static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
    175     auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr);
    176     auto AddrOrErr = T->requestCompile(static_cast<TargetAddress>(
    177         reinterpret_cast<uintptr_t>(TrampolineAddr)));
    178     // FIXME: Allow customizable failure substitution functions.
    179     assert(AddrOrErr && "Compile request failed");
    180     return *AddrOrErr;
    181   }
    182 
    183   Expected<int32_t> handleCallIntVoid(TargetAddress Addr) {
    184     typedef int (*IntVoidFnTy)();
    185     IntVoidFnTy Fn =
    186         reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr));
    187 
    188     DEBUG(dbgs() << "  Calling " << format("0x%016x", Addr) << "\n");
    189     int Result = Fn();
    190     DEBUG(dbgs() << "  Result = " << Result << "\n");
    191 
    192     return Result;
    193   }
    194 
    195   Expected<int32_t> handleCallMain(TargetAddress Addr,
    196                                    std::vector<std::string> Args) {
    197     typedef int (*MainFnTy)(int, const char *[]);
    198 
    199     MainFnTy Fn = reinterpret_cast<MainFnTy>(static_cast<uintptr_t>(Addr));
    200     int ArgC = Args.size() + 1;
    201     int Idx = 1;
    202     std::unique_ptr<const char *[]> ArgV(new const char *[ArgC + 1]);
    203     ArgV[0] = "<jit process>";
    204     for (auto &Arg : Args)
    205       ArgV[Idx++] = Arg.c_str();
    206 
    207     DEBUG(dbgs() << "  Calling " << format("0x%016x", Addr) << "\n");
    208     int Result = Fn(ArgC, ArgV.get());
    209     DEBUG(dbgs() << "  Result = " << Result << "\n");
    210 
    211     return Result;
    212   }
    213 
    214   Error handleCallVoidVoid(TargetAddress Addr) {
    215     typedef void (*VoidVoidFnTy)();
    216     VoidVoidFnTy Fn =
    217         reinterpret_cast<VoidVoidFnTy>(static_cast<uintptr_t>(Addr));
    218 
    219     DEBUG(dbgs() << "  Calling " << format("0x%016x", Addr) << "\n");
    220     Fn();
    221     DEBUG(dbgs() << "  Complete.\n");
    222 
    223     return Error::success();
    224   }
    225 
    226   Error handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
    227     auto I = Allocators.find(Id);
    228     if (I != Allocators.end())
    229       return orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse);
    230     DEBUG(dbgs() << "  Created allocator " << Id << "\n");
    231     Allocators[Id] = Allocator();
    232     return Error::success();
    233   }
    234 
    235   Error handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
    236     auto I = IndirectStubsOwners.find(Id);
    237     if (I != IndirectStubsOwners.end())
    238       return orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse);
    239     DEBUG(dbgs() << "  Create indirect stubs owner " << Id << "\n");
    240     IndirectStubsOwners[Id] = ISBlockOwnerList();
    241     return Error::success();
    242   }
    243 
    244   Error handleDeregisterEHFrames(TargetAddress TAddr, uint32_t Size) {
    245     uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr));
    246     DEBUG(dbgs() << "  Registering EH frames at " << format("0x%016x", TAddr)
    247                  << ", Size = " << Size << " bytes\n");
    248     EHFramesDeregister(Addr, Size);
    249     return Error::success();
    250   }
    251 
    252   Error handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
    253     auto I = Allocators.find(Id);
    254     if (I == Allocators.end())
    255       return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
    256     Allocators.erase(I);
    257     DEBUG(dbgs() << "  Destroyed allocator " << Id << "\n");
    258     return Error::success();
    259   }
    260 
    261   Error handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
    262     auto I = IndirectStubsOwners.find(Id);
    263     if (I == IndirectStubsOwners.end())
    264       return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
    265     IndirectStubsOwners.erase(I);
    266     return Error::success();
    267   }
    268 
    269   Expected<std::tuple<TargetAddress, TargetAddress, uint32_t>>
    270   handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
    271                           uint32_t NumStubsRequired) {
    272     DEBUG(dbgs() << "  ISMgr " << Id << " request " << NumStubsRequired
    273                  << " stubs.\n");
    274 
    275     auto StubOwnerItr = IndirectStubsOwners.find(Id);
    276     if (StubOwnerItr == IndirectStubsOwners.end())
    277       return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
    278 
    279     typename TargetT::IndirectStubsInfo IS;
    280     if (auto Err =
    281             TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr))
    282       return std::move(Err);
    283 
    284     TargetAddress StubsBase =
    285         static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getStub(0)));
    286     TargetAddress PtrsBase =
    287         static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getPtr(0)));
    288     uint32_t NumStubsEmitted = IS.getNumStubs();
    289 
    290     auto &BlockList = StubOwnerItr->second;
    291     BlockList.push_back(std::move(IS));
    292 
    293     return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted);
    294   }
    295 
    296   Error handleEmitResolverBlock() {
    297     std::error_code EC;
    298     ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
    299         TargetT::ResolverCodeSize, nullptr,
    300         sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
    301     if (EC)
    302       return errorCodeToError(EC);
    303 
    304     TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
    305                                &reenter, this);
    306 
    307     return errorCodeToError(sys::Memory::protectMappedMemory(
    308         ResolverBlock.getMemoryBlock(),
    309         sys::Memory::MF_READ | sys::Memory::MF_EXEC));
    310   }
    311 
    312   Expected<std::tuple<TargetAddress, uint32_t>> handleEmitTrampolineBlock() {
    313     std::error_code EC;
    314     auto TrampolineBlock =
    315         sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
    316             sys::Process::getPageSize(), nullptr,
    317             sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
    318     if (EC)
    319       return errorCodeToError(EC);
    320 
    321     uint32_t NumTrampolines =
    322         (sys::Process::getPageSize() - TargetT::PointerSize) /
    323         TargetT::TrampolineSize;
    324 
    325     uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
    326     TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
    327                               NumTrampolines);
    328 
    329     EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
    330                                           sys::Memory::MF_READ |
    331                                               sys::Memory::MF_EXEC);
    332 
    333     TrampolineBlocks.push_back(std::move(TrampolineBlock));
    334 
    335     auto TrampolineBaseAddr =
    336         static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem));
    337 
    338     return std::make_tuple(TrampolineBaseAddr, NumTrampolines);
    339   }
    340 
    341   Expected<TargetAddress> handleGetSymbolAddress(const std::string &Name) {
    342     TargetAddress Addr = SymbolLookup(Name);
    343     DEBUG(dbgs() << "  Symbol '" << Name << "' =  " << format("0x%016x", Addr)
    344                  << "\n");
    345     return Addr;
    346   }
    347 
    348   Expected<std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>>
    349   handleGetRemoteInfo() {
    350     std::string ProcessTriple = sys::getProcessTriple();
    351     uint32_t PointerSize = TargetT::PointerSize;
    352     uint32_t PageSize = sys::Process::getPageSize();
    353     uint32_t TrampolineSize = TargetT::TrampolineSize;
    354     uint32_t IndirectStubSize = TargetT::IndirectStubsInfo::StubSize;
    355     DEBUG(dbgs() << "  Remote info:\n"
    356                  << "    triple             = '" << ProcessTriple << "'\n"
    357                  << "    pointer size       = " << PointerSize << "\n"
    358                  << "    page size          = " << PageSize << "\n"
    359                  << "    trampoline size    = " << TrampolineSize << "\n"
    360                  << "    indirect stub size = " << IndirectStubSize << "\n");
    361     return std::make_tuple(ProcessTriple, PointerSize, PageSize, TrampolineSize,
    362                            IndirectStubSize);
    363   }
    364 
    365   Expected<std::vector<char>> handleReadMem(TargetAddress RSrc, uint64_t Size) {
    366     char *Src = reinterpret_cast<char *>(static_cast<uintptr_t>(RSrc));
    367 
    368     DEBUG(dbgs() << "  Reading " << Size << " bytes from "
    369                  << format("0x%016x", RSrc) << "\n");
    370 
    371     std::vector<char> Buffer;
    372     Buffer.resize(Size);
    373     for (char *P = Src; Size != 0; --Size)
    374       Buffer.push_back(*P++);
    375 
    376     return Buffer;
    377   }
    378 
    379   Error handleRegisterEHFrames(TargetAddress TAddr, uint32_t Size) {
    380     uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr));
    381     DEBUG(dbgs() << "  Registering EH frames at " << format("0x%016x", TAddr)
    382                  << ", Size = " << Size << " bytes\n");
    383     EHFramesRegister(Addr, Size);
    384     return Error::success();
    385   }
    386 
    387   Expected<TargetAddress> handleReserveMem(ResourceIdMgr::ResourceId Id,
    388                                            uint64_t Size, uint32_t Align) {
    389     auto I = Allocators.find(Id);
    390     if (I == Allocators.end())
    391       return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
    392     auto &Allocator = I->second;
    393     void *LocalAllocAddr = nullptr;
    394     if (auto Err = Allocator.allocate(LocalAllocAddr, Size, Align))
    395       return std::move(Err);
    396 
    397     DEBUG(dbgs() << "  Allocator " << Id << " reserved " << LocalAllocAddr
    398                  << " (" << Size << " bytes, alignment " << Align << ")\n");
    399 
    400     TargetAddress AllocAddr =
    401         static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(LocalAllocAddr));
    402 
    403     return AllocAddr;
    404   }
    405 
    406   Error handleSetProtections(ResourceIdMgr::ResourceId Id, TargetAddress Addr,
    407                              uint32_t Flags) {
    408     auto I = Allocators.find(Id);
    409     if (I == Allocators.end())
    410       return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
    411     auto &Allocator = I->second;
    412     void *LocalAddr = reinterpret_cast<void *>(static_cast<uintptr_t>(Addr));
    413     DEBUG(dbgs() << "  Allocator " << Id << " set permissions on " << LocalAddr
    414                  << " to " << (Flags & sys::Memory::MF_READ ? 'R' : '-')
    415                  << (Flags & sys::Memory::MF_WRITE ? 'W' : '-')
    416                  << (Flags & sys::Memory::MF_EXEC ? 'X' : '-') << "\n");
    417     return Allocator.setProtections(LocalAddr, Flags);
    418   }
    419 
    420   Error handleWriteMem(DirectBufferWriter DBW) {
    421     DEBUG(dbgs() << "  Writing " << DBW.getSize() << " bytes to "
    422                  << format("0x%016x", DBW.getDst()) << "\n");
    423     return Error::success();
    424   }
    425 
    426   Error handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) {
    427     DEBUG(dbgs() << "  Writing pointer *" << format("0x%016x", Addr) << " = "
    428                  << format("0x%016x", PtrVal) << "\n");
    429     uintptr_t *Ptr =
    430         reinterpret_cast<uintptr_t *>(static_cast<uintptr_t>(Addr));
    431     *Ptr = static_cast<uintptr_t>(PtrVal);
    432     return Error::success();
    433   }
    434 
    435   ChannelT &Channel;
    436   SymbolLookupFtor SymbolLookup;
    437   EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister;
    438   std::map<ResourceIdMgr::ResourceId, Allocator> Allocators;
    439   typedef std::vector<typename TargetT::IndirectStubsInfo> ISBlockOwnerList;
    440   std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList> IndirectStubsOwners;
    441   sys::OwningMemoryBlock ResolverBlock;
    442   std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
    443 };
    444 
    445 } // end namespace remote
    446 } // end namespace orc
    447 } // end namespace llvm
    448 
    449 #undef DEBUG_TYPE
    450 
    451 #endif
    452