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