OrcRemoteTargetServer.h 18 KB

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