• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
OrcRemoteTargetServer(ChannelT & Channel,SymbolLookupFtor SymbolLookup,EHFrameRegistrationFtor EHFramesRegister,EHFrameRegistrationFtor EHFramesDeregister)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 
OrcRemoteTargetServer(OrcRemoteTargetServer && Other)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 
handleKnownFunction(JITFuncId Id)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 
requestCompile(TargetAddress TrampolineAddr)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 
handleTerminateSession()129   Error handleTerminateSession() {
130     return handle<TerminateSession>(Channel, []() { return Error::success(); });
131   }
132 
133 private:
134   struct Allocator {
135     Allocator() = default;
AllocatorAllocator136     Allocator(Allocator &&Other) : Allocs(std::move(Other.Allocs)) {}
137     Allocator &operator=(Allocator &&Other) {
138       Allocs = std::move(Other.Allocs);
139       return *this;
140     }
141 
~AllocatorAllocator142     ~Allocator() {
143       for (auto &Alloc : Allocs)
144         sys::Memory::releaseMappedMemory(Alloc.second);
145     }
146 
allocateAllocator147     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 
setProtectionsAllocator160     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 
doNothing()172   static Error doNothing() { return Error::success(); }
173 
reenter(void * JITTargetAddr,void * TrampolineAddr)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 
handleCallIntVoid(TargetAddress Addr)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 
handleCallMain(TargetAddress Addr,std::vector<std::string> Args)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 
handleCallVoidVoid(TargetAddress Addr)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 
handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id)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 
handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id)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 
handleDeregisterEHFrames(TargetAddress TAddr,uint32_t Size)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 
handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id)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 
handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id)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>>
handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,uint32_t NumStubsRequired)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 
handleEmitResolverBlock()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 
handleEmitTrampolineBlock()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 
handleGetSymbolAddress(const std::string & Name)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>>
handleGetRemoteInfo()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 
handleReadMem(TargetAddress RSrc,uint64_t Size)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 
handleRegisterEHFrames(TargetAddress TAddr,uint32_t Size)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 
handleReserveMem(ResourceIdMgr::ResourceId Id,uint64_t Size,uint32_t Align)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 
handleSetProtections(ResourceIdMgr::ResourceId Id,TargetAddress Addr,uint32_t Flags)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 
handleWriteMem(DirectBufferWriter DBW)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 
handleWritePtr(TargetAddress Addr,TargetAddress PtrVal)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