LLVM  9.0.0svn
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 
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"
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>
48  : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
49 public:
50  using SymbolLookupFtor =
51  std::function<JITTargetAddress(const std::string &Name)>;
52 
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.
96 
99 
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 
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;
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())
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(
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(
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(
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(
250  IndirectStubsOwners.erase(I);
251  return Error::success();
252  }
253 
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(
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;
285  TargetT::ResolverCodeSize, nullptr,
287  if (EC)
288  return errorCodeToError(EC);
289 
290  TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
291  &reenter, this);
292 
294  ResolverBlock.getMemoryBlock(),
296  }
297 
298  Expected<std::tuple<JITTargetAddress, uint32_t>> handleEmitTrampolineBlock() {
299  std::error_code EC;
300  auto TrampolineBlock =
302  sys::Process::getPageSize(), nullptr,
304  if (EC)
305  return errorCodeToError(EC);
306 
307  uint32_t NumTrampolines =
308  (sys::Process::getPageSize() - 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(),
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 
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::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 
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<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
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
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:123
static std::error_code releaseMappedMemory(MemoryBlock &Block)
This method releases a block of memory that was allocated with the allocateMappedMemory method...
block Block Frequency true
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:32
Definition: BitVector.h:937
std::error_code orcError(OrcErrorCode ErrCode)
Definition: OrcError.cpp:76
Tagged union holding either a T or a Error.
Definition: CachePruning.h:22
ELFYAML::ELF_STO Other
Definition: ELFYAML.cpp:849
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:40
#define P(N)
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:1464
static unsigned getPageSize()
Basic Register Allocator
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
This class encapsulates the notion of a memory block which has an address and a size.
Definition: Memory.h:28
Owning version of MemoryBlock.
Definition: Memory.h:121
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
Provides a library for accessing information about this process and other processes on the operating ...
#define I(x, y, z)
Definition: MD5.cpp:58
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:1476
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...