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
28namespace llvm {
29namespace orc {
30namespace remote {
31
32template <typename ChannelT, typename TargetT>
33class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
34public:
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
133private:
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