OrcRemoteTargetServer.h 18 KB

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