blob: acbc1682fa5d06772b1c8e86e8d25efd563c451e [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- 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
43namespace llvm {
44namespace orc {
45namespace remote {
46
47template <typename ChannelT, typename TargetT>
48class OrcRemoteTargetServer
49 : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
50public:
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
107private:
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
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100164 LLVM_DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100165 int Result = Fn();
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100166 LLVM_DEBUG(dbgs() << " Result = " << Result << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100167
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;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100183 LLVM_DEBUG(for (int Idx = 0; Idx < ArgC; ++Idx) {
184 llvm::dbgs() << "Arg " << Idx << ": " << ArgV[Idx] << "\n";
185 });
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100186
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100187 LLVM_DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100188 int Result = Fn(ArgC, ArgV.get());
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100189 LLVM_DEBUG(dbgs() << " Result = " << Result << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100190
191 return Result;
192 }
193
194 Error handleCallVoidVoid(JITTargetAddress Addr) {
195 using VoidVoidFnTy = void (*)();
196
197 VoidVoidFnTy Fn =
198 reinterpret_cast<VoidVoidFnTy>(static_cast<uintptr_t>(Addr));
199
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100200 LLVM_DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100201 Fn();
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100202 LLVM_DEBUG(dbgs() << " Complete.\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100203
204 return Error::success();
205 }
206
207 Error handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
208 auto I = Allocators.find(Id);
209 if (I != Allocators.end())
210 return errorCodeToError(
211 orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse));
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100212 LLVM_DEBUG(dbgs() << " Created allocator " << Id << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100213 Allocators[Id] = Allocator();
214 return Error::success();
215 }
216
217 Error handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
218 auto I = IndirectStubsOwners.find(Id);
219 if (I != IndirectStubsOwners.end())
220 return errorCodeToError(
221 orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse));
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100222 LLVM_DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100223 IndirectStubsOwners[Id] = ISBlockOwnerList();
224 return Error::success();
225 }
226
227 Error handleDeregisterEHFrames(JITTargetAddress TAddr, uint32_t Size) {
228 uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr));
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100229 LLVM_DEBUG(dbgs() << " Registering EH frames at "
230 << format("0x%016x", TAddr) << ", Size = " << Size
231 << " bytes\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100232 EHFramesDeregister(Addr, Size);
233 return Error::success();
234 }
235
236 Error handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
237 auto I = Allocators.find(Id);
238 if (I == Allocators.end())
239 return errorCodeToError(
240 orcError(OrcErrorCode::RemoteAllocatorDoesNotExist));
241 Allocators.erase(I);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100242 LLVM_DEBUG(dbgs() << " Destroyed allocator " << Id << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100243 return Error::success();
244 }
245
246 Error handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
247 auto I = IndirectStubsOwners.find(Id);
248 if (I == IndirectStubsOwners.end())
249 return errorCodeToError(
250 orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist));
251 IndirectStubsOwners.erase(I);
252 return Error::success();
253 }
254
255 Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
256 handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
257 uint32_t NumStubsRequired) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100258 LLVM_DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
259 << " stubs.\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100260
261 auto StubOwnerItr = IndirectStubsOwners.find(Id);
262 if (StubOwnerItr == IndirectStubsOwners.end())
263 return errorCodeToError(
264 orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist));
265
266 typename TargetT::IndirectStubsInfo IS;
267 if (auto Err =
268 TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr))
269 return std::move(Err);
270
271 JITTargetAddress StubsBase = static_cast<JITTargetAddress>(
272 reinterpret_cast<uintptr_t>(IS.getStub(0)));
273 JITTargetAddress PtrsBase = static_cast<JITTargetAddress>(
274 reinterpret_cast<uintptr_t>(IS.getPtr(0)));
275 uint32_t NumStubsEmitted = IS.getNumStubs();
276
277 auto &BlockList = StubOwnerItr->second;
278 BlockList.push_back(std::move(IS));
279
280 return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted);
281 }
282
283 Error handleEmitResolverBlock() {
284 std::error_code EC;
285 ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
286 TargetT::ResolverCodeSize, nullptr,
287 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
288 if (EC)
289 return errorCodeToError(EC);
290
291 TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
292 &reenter, this);
293
294 return errorCodeToError(sys::Memory::protectMappedMemory(
295 ResolverBlock.getMemoryBlock(),
296 sys::Memory::MF_READ | sys::Memory::MF_EXEC));
297 }
298
299 Expected<std::tuple<JITTargetAddress, uint32_t>> handleEmitTrampolineBlock() {
300 std::error_code EC;
301 auto TrampolineBlock =
302 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
303 sys::Process::getPageSize(), nullptr,
304 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
305 if (EC)
306 return errorCodeToError(EC);
307
308 uint32_t NumTrampolines =
309 (sys::Process::getPageSize() - TargetT::PointerSize) /
310 TargetT::TrampolineSize;
311
312 uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
313 TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
314 NumTrampolines);
315
316 EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
317 sys::Memory::MF_READ |
318 sys::Memory::MF_EXEC);
319
320 TrampolineBlocks.push_back(std::move(TrampolineBlock));
321
322 auto TrampolineBaseAddr = static_cast<JITTargetAddress>(
323 reinterpret_cast<uintptr_t>(TrampolineMem));
324
325 return std::make_tuple(TrampolineBaseAddr, NumTrampolines);
326 }
327
328 Expected<JITTargetAddress> handleGetSymbolAddress(const std::string &Name) {
329 JITTargetAddress Addr = SymbolLookup(Name);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100330 LLVM_DEBUG(dbgs() << " Symbol '" << Name
331 << "' = " << format("0x%016x", Addr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100332 return Addr;
333 }
334
335 Expected<std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>>
336 handleGetRemoteInfo() {
337 std::string ProcessTriple = sys::getProcessTriple();
338 uint32_t PointerSize = TargetT::PointerSize;
339 uint32_t PageSize = sys::Process::getPageSize();
340 uint32_t TrampolineSize = TargetT::TrampolineSize;
341 uint32_t IndirectStubSize = TargetT::IndirectStubsInfo::StubSize;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100342 LLVM_DEBUG(dbgs() << " Remote info:\n"
343 << " triple = '" << ProcessTriple << "'\n"
344 << " pointer size = " << PointerSize << "\n"
345 << " page size = " << PageSize << "\n"
346 << " trampoline size = " << TrampolineSize << "\n"
347 << " indirect stub size = " << IndirectStubSize
348 << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100349 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
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100357 LLVM_DEBUG(dbgs() << " Reading " << Size << " bytes from "
358 << format("0x%016x", RSrc) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100359
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));
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100370 LLVM_DEBUG(dbgs() << " Registering EH frames at "
371 << format("0x%016x", TAddr) << ", Size = " << Size
372 << " bytes\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100373 EHFramesRegister(Addr, Size);
374 return Error::success();
375 }
376
377 Expected<JITTargetAddress> handleReserveMem(ResourceIdMgr::ResourceId Id,
378 uint64_t Size, uint32_t Align) {
379 auto I = Allocators.find(Id);
380 if (I == Allocators.end())
381 return errorCodeToError(
382 orcError(OrcErrorCode::RemoteAllocatorDoesNotExist));
383 auto &Allocator = I->second;
384 void *LocalAllocAddr = nullptr;
385 if (auto Err = Allocator.allocate(LocalAllocAddr, Size, Align))
386 return std::move(Err);
387
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100388 LLVM_DEBUG(dbgs() << " Allocator " << Id << " reserved " << LocalAllocAddr
389 << " (" << Size << " bytes, alignment " << Align
390 << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100391
392 JITTargetAddress AllocAddr = static_cast<JITTargetAddress>(
393 reinterpret_cast<uintptr_t>(LocalAllocAddr));
394
395 return AllocAddr;
396 }
397
398 Error handleSetProtections(ResourceIdMgr::ResourceId Id,
399 JITTargetAddress Addr, uint32_t Flags) {
400 auto I = Allocators.find(Id);
401 if (I == Allocators.end())
402 return errorCodeToError(
403 orcError(OrcErrorCode::RemoteAllocatorDoesNotExist));
404 auto &Allocator = I->second;
405 void *LocalAddr = reinterpret_cast<void *>(static_cast<uintptr_t>(Addr));
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100406 LLVM_DEBUG(dbgs() << " Allocator " << Id << " set permissions on "
407 << LocalAddr << " to "
408 << (Flags & sys::Memory::MF_READ ? 'R' : '-')
409 << (Flags & sys::Memory::MF_WRITE ? 'W' : '-')
410 << (Flags & sys::Memory::MF_EXEC ? 'X' : '-') << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100411 return Allocator.setProtections(LocalAddr, Flags);
412 }
413
414 Error handleTerminateSession() {
415 TerminateFlag = true;
416 return Error::success();
417 }
418
419 Error handleWriteMem(DirectBufferWriter DBW) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100420 LLVM_DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to "
421 << format("0x%016x", DBW.getDst()) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100422 return Error::success();
423 }
424
425 Error handleWritePtr(JITTargetAddress Addr, JITTargetAddress PtrVal) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100426 LLVM_DEBUG(dbgs() << " Writing pointer *" << format("0x%016x", Addr)
427 << " = " << format("0x%016x", PtrVal) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100428 uintptr_t *Ptr =
429 reinterpret_cast<uintptr_t *>(static_cast<uintptr_t>(Addr));
430 *Ptr = static_cast<uintptr_t>(PtrVal);
431 return Error::success();
432 }
433
434 SymbolLookupFtor SymbolLookup;
435 EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister;
436 std::map<ResourceIdMgr::ResourceId, Allocator> Allocators;
437 using ISBlockOwnerList = std::vector<typename TargetT::IndirectStubsInfo>;
438 std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList> IndirectStubsOwners;
439 sys::OwningMemoryBlock ResolverBlock;
440 std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
441 bool TerminateFlag = false;
442};
443
444} // end namespace remote
445} // end namespace orc
446} // end namespace llvm
447
448#undef DEBUG_TYPE
449
450#endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H