LLVM  4.0.0
OrcRemoteTargetServer.h
Go to the documentation of this file.
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"
22 #include "llvm/Support/Debug.h"
23 #include "llvm/Support/Error.h"
24 #include "llvm/Support/Format.h"
25 #include "llvm/Support/Host.h"
26 #include "llvm/Support/Memory.h"
27 #include "llvm/Support/Process.h"
29 #include <algorithm>
30 #include <cassert>
31 #include <cstddef>
32 #include <cstdint>
33 #include <functional>
34 #include <map>
35 #include <memory>
36 #include <string>
37 #include <system_error>
38 #include <tuple>
39 #include <type_traits>
40 #include <vector>
41 
42 #define DEBUG_TYPE "orc-remote"
43 
44 namespace llvm {
45 namespace orc {
46 namespace remote {
47 
48 template <typename ChannelT, typename TargetT>
50 public:
51  typedef std::function<JITTargetAddress(const std::string &Name)>
53 
54  typedef std::function<void(uint8_t *Addr, uint32_t Size)>
56 
57  OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup,
58  EHFrameRegistrationFtor EHFramesRegister,
59  EHFrameRegistrationFtor EHFramesDeregister)
60  : OrcRemoteTargetRPCAPI(Channel), SymbolLookup(std::move(SymbolLookup)),
61  EHFramesRegister(std::move(EHFramesRegister)),
62  EHFramesDeregister(std::move(EHFramesDeregister)),
63  TerminateFlag(false) {
64 
65  using ThisT = typename std::remove_reference<decltype(*this)>::type;
66  addHandler<CallIntVoid>(*this, &ThisT::handleCallIntVoid);
67  addHandler<CallMain>(*this, &ThisT::handleCallMain);
68  addHandler<CallVoidVoid>(*this, &ThisT::handleCallVoidVoid);
69  addHandler<CreateRemoteAllocator>(*this,
70  &ThisT::handleCreateRemoteAllocator);
71  addHandler<CreateIndirectStubsOwner>(
72  *this, &ThisT::handleCreateIndirectStubsOwner);
73  addHandler<DeregisterEHFrames>(*this, &ThisT::handleDeregisterEHFrames);
74  addHandler<DestroyRemoteAllocator>(*this,
75  &ThisT::handleDestroyRemoteAllocator);
76  addHandler<DestroyIndirectStubsOwner>(
77  *this, &ThisT::handleDestroyIndirectStubsOwner);
78  addHandler<EmitIndirectStubs>(*this, &ThisT::handleEmitIndirectStubs);
79  addHandler<EmitResolverBlock>(*this, &ThisT::handleEmitResolverBlock);
80  addHandler<EmitTrampolineBlock>(*this, &ThisT::handleEmitTrampolineBlock);
81  addHandler<GetSymbolAddress>(*this, &ThisT::handleGetSymbolAddress);
82  addHandler<GetRemoteInfo>(*this, &ThisT::handleGetRemoteInfo);
83  addHandler<ReadMem>(*this, &ThisT::handleReadMem);
84  addHandler<RegisterEHFrames>(*this, &ThisT::handleRegisterEHFrames);
85  addHandler<ReserveMem>(*this, &ThisT::handleReserveMem);
86  addHandler<SetProtections>(*this, &ThisT::handleSetProtections);
87  addHandler<TerminateSession>(*this, &ThisT::handleTerminateSession);
88  addHandler<WriteMem>(*this, &ThisT::handleWriteMem);
89  addHandler<WritePtr>(*this, &ThisT::handleWritePtr);
90  }
91 
92  // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
95 
98 
100  return callB<RequestCompile>(TrampolineAddr);
101  }
102 
103  bool receivedTerminate() const { return TerminateFlag; }
104 
105 private:
106  struct Allocator {
107  Allocator() = default;
108  Allocator(Allocator &&Other) : Allocs(std::move(Other.Allocs)) {}
109  Allocator &operator=(Allocator &&Other) {
110  Allocs = std::move(Other.Allocs);
111  return *this;
112  }
113 
114  ~Allocator() {
115  for (auto &Alloc : Allocs)
116  sys::Memory::releaseMappedMemory(Alloc.second);
117  }
118 
119  Error allocate(void *&Addr, size_t Size, uint32_t Align) {
120  std::error_code EC;
121  sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(
122  Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
123  if (EC)
124  return errorCodeToError(EC);
125 
126  Addr = MB.base();
127  assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc");
128  Allocs[MB.base()] = std::move(MB);
129  return Error::success();
130  }
131 
132  Error setProtections(void *block, unsigned Flags) {
133  auto I = Allocs.find(block);
134  if (I == Allocs.end())
136  return errorCodeToError(
137  sys::Memory::protectMappedMemory(I->second, Flags));
138  }
139 
140  private:
141  std::map<void *, sys::MemoryBlock> Allocs;
142  };
143 
144  static Error doNothing() { return Error::success(); }
145 
146  static JITTargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
147  auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr);
148  auto AddrOrErr = T->requestCompile(static_cast<JITTargetAddress>(
149  reinterpret_cast<uintptr_t>(TrampolineAddr)));
150  // FIXME: Allow customizable failure substitution functions.
151  assert(AddrOrErr && "Compile request failed");
152  return *AddrOrErr;
153  }
154 
155  Expected<int32_t> handleCallIntVoid(JITTargetAddress Addr) {
156  typedef int (*IntVoidFnTy)();
157  IntVoidFnTy Fn =
158  reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr));
159 
160  DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
161  int Result = Fn();
162  DEBUG(dbgs() << " Result = " << Result << "\n");
163 
164  return Result;
165  }
166 
167  Expected<int32_t> handleCallMain(JITTargetAddress Addr,
168  std::vector<std::string> Args) {
169  typedef int (*MainFnTy)(int, const char *[]);
170 
171  MainFnTy Fn = reinterpret_cast<MainFnTy>(static_cast<uintptr_t>(Addr));
172  int ArgC = Args.size() + 1;
173  int Idx = 1;
174  std::unique_ptr<const char *[]> ArgV(new const char *[ArgC + 1]);
175  ArgV[0] = "<jit process>";
176  for (auto &Arg : Args)
177  ArgV[Idx++] = Arg.c_str();
178 
179  DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
180  int Result = Fn(ArgC, ArgV.get());
181  DEBUG(dbgs() << " Result = " << Result << "\n");
182 
183  return Result;
184  }
185 
186  Error handleCallVoidVoid(JITTargetAddress Addr) {
187  typedef void (*VoidVoidFnTy)();
188  VoidVoidFnTy Fn =
189  reinterpret_cast<VoidVoidFnTy>(static_cast<uintptr_t>(Addr));
190 
191  DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
192  Fn();
193  DEBUG(dbgs() << " Complete.\n");
194 
195  return Error::success();
196  }
197 
198  Error handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
199  auto I = Allocators.find(Id);
200  if (I != Allocators.end())
202  DEBUG(dbgs() << " Created allocator " << Id << "\n");
203  Allocators[Id] = Allocator();
204  return Error::success();
205  }
206 
207  Error handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
208  auto I = IndirectStubsOwners.find(Id);
209  if (I != IndirectStubsOwners.end())
211  DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n");
212  IndirectStubsOwners[Id] = ISBlockOwnerList();
213  return Error::success();
214  }
215 
216  Error handleDeregisterEHFrames(JITTargetAddress TAddr, uint32_t Size) {
217  uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr));
218  DEBUG(dbgs() << " Registering EH frames at " << format("0x%016x", TAddr)
219  << ", Size = " << Size << " bytes\n");
220  EHFramesDeregister(Addr, Size);
221  return Error::success();
222  }
223 
224  Error handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
225  auto I = Allocators.find(Id);
226  if (I == Allocators.end())
228  Allocators.erase(I);
229  DEBUG(dbgs() << " Destroyed allocator " << Id << "\n");
230  return Error::success();
231  }
232 
233  Error handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
234  auto I = IndirectStubsOwners.find(Id);
235  if (I == IndirectStubsOwners.end())
237  IndirectStubsOwners.erase(I);
238  return Error::success();
239  }
240 
241  Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
242  handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
243  uint32_t NumStubsRequired) {
244  DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
245  << " stubs.\n");
246 
247  auto StubOwnerItr = IndirectStubsOwners.find(Id);
248  if (StubOwnerItr == IndirectStubsOwners.end())
250 
251  typename TargetT::IndirectStubsInfo IS;
252  if (auto Err =
253  TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr))
254  return std::move(Err);
255 
256  JITTargetAddress StubsBase = static_cast<JITTargetAddress>(
257  reinterpret_cast<uintptr_t>(IS.getStub(0)));
258  JITTargetAddress PtrsBase = static_cast<JITTargetAddress>(
259  reinterpret_cast<uintptr_t>(IS.getPtr(0)));
260  uint32_t NumStubsEmitted = IS.getNumStubs();
261 
262  auto &BlockList = StubOwnerItr->second;
263  BlockList.push_back(std::move(IS));
264 
265  return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted);
266  }
267 
268  Error handleEmitResolverBlock() {
269  std::error_code EC;
270  ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
271  TargetT::ResolverCodeSize, nullptr,
273  if (EC)
274  return errorCodeToError(EC);
275 
276  TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
277  &reenter, this);
278 
280  ResolverBlock.getMemoryBlock(),
282  }
283 
284  Expected<std::tuple<JITTargetAddress, uint32_t>> handleEmitTrampolineBlock() {
285  std::error_code EC;
286  auto TrampolineBlock =
287  sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
288  sys::Process::getPageSize(), nullptr,
290  if (EC)
291  return errorCodeToError(EC);
292 
293  uint32_t NumTrampolines =
294  (sys::Process::getPageSize() - TargetT::PointerSize) /
295  TargetT::TrampolineSize;
296 
297  uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
298  TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
299  NumTrampolines);
300 
301  EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
304 
305  TrampolineBlocks.push_back(std::move(TrampolineBlock));
306 
307  auto TrampolineBaseAddr = static_cast<JITTargetAddress>(
308  reinterpret_cast<uintptr_t>(TrampolineMem));
309 
310  return std::make_tuple(TrampolineBaseAddr, NumTrampolines);
311  }
312 
313  Expected<JITTargetAddress> handleGetSymbolAddress(const std::string &Name) {
314  JITTargetAddress Addr = SymbolLookup(Name);
315  DEBUG(dbgs() << " Symbol '" << Name << "' = " << format("0x%016x", Addr)
316  << "\n");
317  return Addr;
318  }
319 
320  Expected<std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>>
321  handleGetRemoteInfo() {
322  std::string ProcessTriple = sys::getProcessTriple();
323  uint32_t PointerSize = TargetT::PointerSize;
325  uint32_t TrampolineSize = TargetT::TrampolineSize;
326  uint32_t IndirectStubSize = TargetT::IndirectStubsInfo::StubSize;
327  DEBUG(dbgs() << " Remote info:\n"
328  << " triple = '" << ProcessTriple << "'\n"
329  << " pointer size = " << PointerSize << "\n"
330  << " page size = " << PageSize << "\n"
331  << " trampoline size = " << TrampolineSize << "\n"
332  << " indirect stub size = " << IndirectStubSize << "\n");
333  return std::make_tuple(ProcessTriple, PointerSize, PageSize, TrampolineSize,
334  IndirectStubSize);
335  }
336 
337  Expected<std::vector<uint8_t>> handleReadMem(JITTargetAddress RSrc,
338  uint64_t Size) {
339  uint8_t *Src = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(RSrc));
340 
341  DEBUG(dbgs() << " Reading " << Size << " bytes from "
342  << format("0x%016x", RSrc) << "\n");
343 
344  std::vector<uint8_t> Buffer;
345  Buffer.resize(Size);
346  for (uint8_t *P = Src; Size != 0; --Size)
347  Buffer.push_back(*P++);
348 
349  return Buffer;
350  }
351 
352  Error handleRegisterEHFrames(JITTargetAddress TAddr, uint32_t Size) {
353  uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr));
354  DEBUG(dbgs() << " Registering EH frames at " << format("0x%016x", TAddr)
355  << ", Size = " << Size << " bytes\n");
356  EHFramesRegister(Addr, Size);
357  return Error::success();
358  }
359 
360  Expected<JITTargetAddress> handleReserveMem(ResourceIdMgr::ResourceId Id,
361  uint64_t Size, uint32_t Align) {
362  auto I = Allocators.find(Id);
363  if (I == Allocators.end())
365  auto &Allocator = I->second;
366  void *LocalAllocAddr = nullptr;
367  if (auto Err = Allocator.allocate(LocalAllocAddr, Size, Align))
368  return std::move(Err);
369 
370  DEBUG(dbgs() << " Allocator " << Id << " reserved " << LocalAllocAddr
371  << " (" << Size << " bytes, alignment " << Align << ")\n");
372 
373  JITTargetAddress AllocAddr = static_cast<JITTargetAddress>(
374  reinterpret_cast<uintptr_t>(LocalAllocAddr));
375 
376  return AllocAddr;
377  }
378 
379  Error handleSetProtections(ResourceIdMgr::ResourceId Id,
380  JITTargetAddress Addr, uint32_t Flags) {
381  auto I = Allocators.find(Id);
382  if (I == Allocators.end())
384  auto &Allocator = I->second;
385  void *LocalAddr = reinterpret_cast<void *>(static_cast<uintptr_t>(Addr));
386  DEBUG(dbgs() << " Allocator " << Id << " set permissions on " << LocalAddr
387  << " to " << (Flags & sys::Memory::MF_READ ? 'R' : '-')
388  << (Flags & sys::Memory::MF_WRITE ? 'W' : '-')
389  << (Flags & sys::Memory::MF_EXEC ? 'X' : '-') << "\n");
390  return Allocator.setProtections(LocalAddr, Flags);
391  }
392 
393  Error handleTerminateSession() {
394  TerminateFlag = true;
395  return Error::success();
396  }
397 
398  Error handleWriteMem(DirectBufferWriter DBW) {
399  DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to "
400  << format("0x%016x", DBW.getDst()) << "\n");
401  return Error::success();
402  }
403 
404  Error handleWritePtr(JITTargetAddress Addr, JITTargetAddress PtrVal) {
405  DEBUG(dbgs() << " Writing pointer *" << format("0x%016x", Addr) << " = "
406  << format("0x%016x", PtrVal) << "\n");
407  uintptr_t *Ptr =
408  reinterpret_cast<uintptr_t *>(static_cast<uintptr_t>(Addr));
409  *Ptr = static_cast<uintptr_t>(PtrVal);
410  return Error::success();
411  }
412 
413  SymbolLookupFtor SymbolLookup;
414  EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister;
415  std::map<ResourceIdMgr::ResourceId, Allocator> Allocators;
416  typedef std::vector<typename TargetT::IndirectStubsInfo> ISBlockOwnerList;
417  std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList> IndirectStubsOwners;
418  sys::OwningMemoryBlock ResolverBlock;
419  std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
420  bool TerminateFlag;
421 };
422 
423 } // end namespace remote
424 } // end namespace orc
425 } // end namespace llvm
426 
427 #undef DEBUG_TYPE
428 
429 #endif
std::function< JITTargetAddress(const std::string &Name)> SymbolLookupFtor
OrcRemoteTargetServer & operator=(const OrcRemoteTargetServer &)=delete
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...
struct fuzzer::@269 Flags
Tagged union holding either a T or a Error.
ELFYAML::ELF_STO Other
Definition: ELFYAML.cpp:662
Function Alias Analysis false
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096))
MemoryBlock getMemoryBlock() const
Definition: Memory.h:178
format_object< Ts...> format(const char *Fmt, const Ts &...Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:124
#define P(N)
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Greedy Register Allocator
uint64_t JITTargetAddress
Represents an address in the target process's address space.
Definition: JITSymbol.h:33
OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup, EHFrameRegistrationFtor EHFramesRegister, EHFrameRegistrationFtor EHFramesDeregister)
std::function< void(uint8_t *Addr, uint32_t Size)> EHFrameRegistrationFtor
std::string getProcessTriple()
getProcessTriple() - Return an appropriate target triple for generating code to be loaded into the cu...
Definition: Host.cpp:1477
static unsigned getPageSize()
static ErrorSuccess success()
Create a success value.
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 ...
void * base() const
Definition: Memory.h:176
#define I(x, y, z)
Definition: MD5.cpp:54
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Error orcError(OrcErrorCode ErrCode)
Definition: OrcError.cpp:61
#define DEBUG(X)
Definition: Debug.h:100
int * Ptr
Expected< JITTargetAddress > requestCompile(JITTargetAddress TrampolineAddr)
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...