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