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