LLVM  12.0.0git
OrcRemoteTargetServer.h
Go to the documentation of this file.
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 
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"
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>
49  : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
50 public:
51  using SymbolLookupFtor =
52  std::function<JITTargetAddress(const std::string &Name)>;
53 
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 = std::remove_reference_t<decltype(*this)>;
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.
97 
100 
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 
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;
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())
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  LLVM_DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
165  int Result = Fn();
166  LLVM_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  LLVM_DEBUG(for (int Idx = 0; Idx < ArgC; ++Idx) {
184  llvm::dbgs() << "Arg " << Idx << ": " << ArgV[Idx] << "\n";
185  });
186 
187  LLVM_DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
188  int Result = Fn(ArgC, ArgV.get());
189  LLVM_DEBUG(dbgs() << " Result = " << Result << "\n");
190 
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 
200  LLVM_DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
201  Fn();
202  LLVM_DEBUG(dbgs() << " Complete.\n");
203 
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(
212  LLVM_DEBUG(dbgs() << " Created allocator " << Id << "\n");
213  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(
222  LLVM_DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n");
223  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));
229  LLVM_DEBUG(dbgs() << " Registering EH frames at "
230  << format("0x%016x", TAddr) << ", Size = " << Size
231  << " bytes\n");
232  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(
241  Allocators.erase(I);
242  LLVM_DEBUG(dbgs() << " Destroyed allocator " << Id << "\n");
243  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(
251  IndirectStubsOwners.erase(I);
252  return Error::success();
253  }
254 
256  handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
257  uint32_t NumStubsRequired) {
258  LLVM_DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
259  << " stubs.\n");
260 
261  auto StubOwnerItr = IndirectStubsOwners.find(Id);
262  if (StubOwnerItr == IndirectStubsOwners.end())
263  return errorCodeToError(
265 
267  NumStubsRequired, sys::Process::getPageSizeEstimate());
268  if (!IS)
269  return IS.takeError();
270 
271  JITTargetAddress StubsBase = pointerToJITTargetAddress(IS->getStub(0));
272  JITTargetAddress PtrsBase = pointerToJITTargetAddress(IS->getPtr(0));
273  uint32_t NumStubsEmitted = IS->getNumStubs();
274 
275  auto &BlockList = StubOwnerItr->second;
276  BlockList.push_back(std::move(*IS));
277 
278  return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted);
279  }
280 
281  Error handleEmitResolverBlock() {
282  std::error_code EC;
284  TargetT::ResolverCodeSize, nullptr,
286  if (EC)
287  return errorCodeToError(EC);
288 
289  TargetT::writeResolverCode(static_cast<char *>(ResolverBlock.base()),
290  pointerToJITTargetAddress(ResolverBlock.base()),
291  pointerToJITTargetAddress(&reenter),
293 
295  ResolverBlock.getMemoryBlock(),
297  }
298 
299  Expected<std::tuple<JITTargetAddress, uint32_t>> handleEmitTrampolineBlock() {
300  std::error_code EC;
301  auto TrampolineBlock =
305  if (EC)
306  return errorCodeToError(EC);
307 
308  uint32_t NumTrampolines =
309  (sys::Process::getPageSizeEstimate() - TargetT::PointerSize) /
310  TargetT::TrampolineSize;
311 
312  char *TrampolineMem = static_cast<char *>(TrampolineBlock.base());
313  TargetT::writeTrampolines(
314  TrampolineMem, pointerToJITTargetAddress(TrampolineMem),
315  pointerToJITTargetAddress(ResolverBlock.base()), NumTrampolines);
316 
317  EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
320 
321  TrampolineBlocks.push_back(std::move(TrampolineBlock));
322 
323  return std::make_tuple(pointerToJITTargetAddress(TrampolineMem),
324  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 
335  handleGetRemoteInfo() {
336  std::string ProcessTriple = sys::getProcessTriple();
337  uint32_t PointerSize = TargetT::PointerSize;
339  uint32_t TrampolineSize = TargetT::TrampolineSize;
340  uint32_t IndirectStubSize = TargetT::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 
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 
377  uint64_t Size, uint32_t Align) {
378  auto I = Allocators.find(Id);
379  if (I == Allocators.end())
380  return errorCodeToError(
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(
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<LocalIndirectStubsInfo<TargetT>>;
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
std::function< JITTargetAddress(const std::string &Name)> SymbolLookupFtor
This class represents lattice values for constants.
Definition: AllocatorList.h:23
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
OrcRemoteTargetServer & operator=(const OrcRemoteTargetServer &)=delete
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:124
Optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1015
static std::error_code releaseMappedMemory(MemoryBlock &Block)
This method releases a block of memory that was allocated with the allocateMappedMemory method...
static MemoryBlock allocateMappedMemory(size_t NumBytes, const MemoryBlock *const NearBlock, unsigned Flags, std::error_code &EC)
This method allocates a block of memory that is suitable for loading dynamically generated code (e...
void * base() const
Definition: Memory.h:37
Definition: BitVector.h:959
std::error_code orcError(OrcErrorCode ErrCode)
Definition: OrcError.cpp:82
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
unify loop Fixup each natural loop to have a single exit block
static unsigned getPageSizeEstimate()
Get the process&#39;s estimated page size.
Definition: Process.h:61
std::function< void(uint8_t *Addr, uint32_t Size)> EHFrameRegistrationFtor
uint64_t JITTargetAddress
Represents an address in the target process&#39;s address space.
Definition: JITSymbol.h:42
#define P(N)
JITTargetAddress pointerToJITTargetAddress(T *Ptr)
Convert a pointer to a JITTargetAddress.
Definition: JITSymbol.h:69
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:87
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup, EHFrameRegistrationFtor EHFramesRegister, EHFrameRegistrationFtor EHFramesDeregister)
std::string getProcessTriple()
getProcessTriple() - Return an appropriate target triple for generating code to be loaded into the cu...
Definition: Host.cpp:1545
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
Basic Register Allocator
static ErrorSuccess success()
Create a success value.
Definition: Error.h:332
static Expected< LocalIndirectStubsInfo > create(unsigned MinStubs, unsigned PageSize)
This class encapsulates the notion of a memory block which has an address and a size.
Definition: Memory.h:32
Owning version of MemoryBlock.
Definition: Memory.h:139
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
basic Basic Alias true
Provides a library for accessing information about this process and other processes on the operating ...
#define I(x, y, z)
Definition: MD5.cpp:59
uint32_t Size
Definition: Profile.cpp:46
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
Expected< JITTargetAddress > requestCompile(JITTargetAddress TrampolineAddr)
#define LLVM_DEBUG(X)
Definition: Debug.h:122
SingleThreadedRPCEndpoint(rpc::RawByteChannel &C, bool LazyAutoNegotiation)
Definition: RPCUtils.h:1481
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
static std::error_code protectMappedMemory(const MemoryBlock &Block, unsigned Flags)
This method sets the protection flags for a block of memory to the state specified by /p Flags...