1 //===- OrcRemoteTargetClient.h - Orc Remote-target Client -------*- 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 OrcRemoteTargetClient class and helpers. This class 11 // can be used to communicate over an RawByteChannel with an 12 // OrcRemoteTargetServer instance to support remote-JITing. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H 17 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H 18 19 #include "llvm/ADT/Optional.h" 20 #include "llvm/ADT/STLExtras.h" 21 #include "llvm/ADT/StringMap.h" 22 #include "llvm/ADT/StringRef.h" 23 #include "llvm/ExecutionEngine/JITSymbol.h" 24 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" 25 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h" 26 #include "llvm/ExecutionEngine/RuntimeDyld.h" 27 #include "llvm/Support/Debug.h" 28 #include "llvm/Support/Error.h" 29 #include "llvm/Support/ErrorHandling.h" 30 #include "llvm/Support/Format.h" 31 #include "llvm/Support/MathExtras.h" 32 #include "llvm/Support/Memory.h" 33 #include "llvm/Support/raw_ostream.h" 34 #include <algorithm> 35 #include <cassert> 36 #include <cstdint> 37 #include <memory> 38 #include <string> 39 #include <tuple> 40 #include <utility> 41 #include <vector> 42 43 #define DEBUG_TYPE "orc-remote" 44 45 namespace llvm { 46 namespace orc { 47 namespace remote { 48 49 /// This class provides utilities (including memory manager, indirect stubs 50 /// manager, and compile callback manager types) that support remote JITing 51 /// in ORC. 52 /// 53 /// Each of the utility classes talks to a JIT server (an instance of the 54 /// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out 55 /// its actions. 56 class OrcRemoteTargetClient 57 : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> { 58 public: 59 /// Remote-mapped RuntimeDyld-compatible memory manager. 60 class RemoteRTDyldMemoryManager : public RuntimeDyld::MemoryManager { 61 friend class OrcRemoteTargetClient; 62 63 public: ~RemoteRTDyldMemoryManager()64 ~RemoteRTDyldMemoryManager() { 65 Client.destroyRemoteAllocator(Id); 66 LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n"); 67 } 68 69 RemoteRTDyldMemoryManager(const RemoteRTDyldMemoryManager &) = delete; 70 RemoteRTDyldMemoryManager & 71 operator=(const RemoteRTDyldMemoryManager &) = delete; 72 RemoteRTDyldMemoryManager(RemoteRTDyldMemoryManager &&) = default; 73 RemoteRTDyldMemoryManager &operator=(RemoteRTDyldMemoryManager &&) = delete; 74 allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)75 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, 76 unsigned SectionID, 77 StringRef SectionName) override { 78 Unmapped.back().CodeAllocs.emplace_back(Size, Alignment); 79 uint8_t *Alloc = reinterpret_cast<uint8_t *>( 80 Unmapped.back().CodeAllocs.back().getLocalAddress()); 81 LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated code for " 82 << SectionName << ": " << Alloc << " (" << Size 83 << " bytes, alignment " << Alignment << ")\n"); 84 return Alloc; 85 } 86 allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool IsReadOnly)87 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, 88 unsigned SectionID, StringRef SectionName, 89 bool IsReadOnly) override { 90 if (IsReadOnly) { 91 Unmapped.back().RODataAllocs.emplace_back(Size, Alignment); 92 uint8_t *Alloc = reinterpret_cast<uint8_t *>( 93 Unmapped.back().RODataAllocs.back().getLocalAddress()); 94 LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for " 95 << SectionName << ": " << Alloc << " (" << Size 96 << " bytes, alignment " << Alignment << ")\n"); 97 return Alloc; 98 } // else... 99 100 Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment); 101 uint8_t *Alloc = reinterpret_cast<uint8_t *>( 102 Unmapped.back().RWDataAllocs.back().getLocalAddress()); 103 LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for " 104 << SectionName << ": " << Alloc << " (" << Size 105 << " bytes, alignment " << Alignment << ")\n"); 106 return Alloc; 107 } 108 reserveAllocationSpace(uintptr_t CodeSize,uint32_t CodeAlign,uintptr_t RODataSize,uint32_t RODataAlign,uintptr_t RWDataSize,uint32_t RWDataAlign)109 void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, 110 uintptr_t RODataSize, uint32_t RODataAlign, 111 uintptr_t RWDataSize, 112 uint32_t RWDataAlign) override { 113 Unmapped.push_back(ObjectAllocs()); 114 115 LLVM_DEBUG(dbgs() << "Allocator " << Id << " reserved:\n"); 116 117 if (CodeSize != 0) { 118 Unmapped.back().RemoteCodeAddr = 119 Client.reserveMem(Id, CodeSize, CodeAlign); 120 121 LLVM_DEBUG( 122 dbgs() << " code: " 123 << format("0x%016" PRIx64, Unmapped.back().RemoteCodeAddr) 124 << " (" << CodeSize << " bytes, alignment " << CodeAlign 125 << ")\n"); 126 } 127 128 if (RODataSize != 0) { 129 Unmapped.back().RemoteRODataAddr = 130 Client.reserveMem(Id, RODataSize, RODataAlign); 131 132 LLVM_DEBUG( 133 dbgs() << " ro-data: " 134 << format("0x%016" PRIx64, Unmapped.back().RemoteRODataAddr) 135 << " (" << RODataSize << " bytes, alignment " << RODataAlign 136 << ")\n"); 137 } 138 139 if (RWDataSize != 0) { 140 Unmapped.back().RemoteRWDataAddr = 141 Client.reserveMem(Id, RWDataSize, RWDataAlign); 142 143 LLVM_DEBUG( 144 dbgs() << " rw-data: " 145 << format("0x%016" PRIx64, Unmapped.back().RemoteRWDataAddr) 146 << " (" << RWDataSize << " bytes, alignment " << RWDataAlign 147 << ")\n"); 148 } 149 } 150 needsToReserveAllocationSpace()151 bool needsToReserveAllocationSpace() override { return true; } 152 registerEHFrames(uint8_t * Addr,uint64_t LoadAddr,size_t Size)153 void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, 154 size_t Size) override { 155 UnfinalizedEHFrames.push_back({LoadAddr, Size}); 156 } 157 deregisterEHFrames()158 void deregisterEHFrames() override { 159 for (auto &Frame : RegisteredEHFrames) { 160 // FIXME: Add error poll. 161 Client.deregisterEHFrames(Frame.Addr, Frame.Size); 162 } 163 } 164 notifyObjectLoaded(RuntimeDyld & Dyld,const object::ObjectFile & Obj)165 void notifyObjectLoaded(RuntimeDyld &Dyld, 166 const object::ObjectFile &Obj) override { 167 LLVM_DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n"); 168 for (auto &ObjAllocs : Unmapped) { 169 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs, 170 ObjAllocs.RemoteCodeAddr); 171 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs, 172 ObjAllocs.RemoteRODataAddr); 173 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs, 174 ObjAllocs.RemoteRWDataAddr); 175 Unfinalized.push_back(std::move(ObjAllocs)); 176 } 177 Unmapped.clear(); 178 } 179 180 bool finalizeMemory(std::string *ErrMsg = nullptr) override { 181 LLVM_DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n"); 182 183 for (auto &ObjAllocs : Unfinalized) { 184 if (copyAndProtect(ObjAllocs.CodeAllocs, ObjAllocs.RemoteCodeAddr, 185 sys::Memory::MF_READ | sys::Memory::MF_EXEC)) 186 return true; 187 188 if (copyAndProtect(ObjAllocs.RODataAllocs, ObjAllocs.RemoteRODataAddr, 189 sys::Memory::MF_READ)) 190 return true; 191 192 if (copyAndProtect(ObjAllocs.RWDataAllocs, ObjAllocs.RemoteRWDataAddr, 193 sys::Memory::MF_READ | sys::Memory::MF_WRITE)) 194 return true; 195 } 196 Unfinalized.clear(); 197 198 for (auto &EHFrame : UnfinalizedEHFrames) { 199 if (auto Err = Client.registerEHFrames(EHFrame.Addr, EHFrame.Size)) { 200 // FIXME: Replace this once finalizeMemory can return an Error. 201 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 202 if (ErrMsg) { 203 raw_string_ostream ErrOut(*ErrMsg); 204 EIB.log(ErrOut); 205 } 206 }); 207 return false; 208 } 209 } 210 RegisteredEHFrames = std::move(UnfinalizedEHFrames); 211 UnfinalizedEHFrames = {}; 212 213 return false; 214 } 215 216 private: 217 class Alloc { 218 public: Alloc(uint64_t Size,unsigned Align)219 Alloc(uint64_t Size, unsigned Align) 220 : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {} 221 222 Alloc(const Alloc &) = delete; 223 Alloc &operator=(const Alloc &) = delete; 224 Alloc(Alloc &&) = default; 225 Alloc &operator=(Alloc &&) = default; 226 getSize()227 uint64_t getSize() const { return Size; } 228 getAlign()229 unsigned getAlign() const { return Align; } 230 getLocalAddress()231 char *getLocalAddress() const { 232 uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get()); 233 LocalAddr = alignTo(LocalAddr, Align); 234 return reinterpret_cast<char *>(LocalAddr); 235 } 236 setRemoteAddress(JITTargetAddress RemoteAddr)237 void setRemoteAddress(JITTargetAddress RemoteAddr) { 238 this->RemoteAddr = RemoteAddr; 239 } 240 getRemoteAddress()241 JITTargetAddress getRemoteAddress() const { return RemoteAddr; } 242 243 private: 244 uint64_t Size; 245 unsigned Align; 246 std::unique_ptr<char[]> Contents; 247 JITTargetAddress RemoteAddr = 0; 248 }; 249 250 struct ObjectAllocs { 251 ObjectAllocs() = default; 252 ObjectAllocs(const ObjectAllocs &) = delete; 253 ObjectAllocs &operator=(const ObjectAllocs &) = delete; 254 ObjectAllocs(ObjectAllocs &&) = default; 255 ObjectAllocs &operator=(ObjectAllocs &&) = default; 256 257 JITTargetAddress RemoteCodeAddr = 0; 258 JITTargetAddress RemoteRODataAddr = 0; 259 JITTargetAddress RemoteRWDataAddr = 0; 260 std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs; 261 }; 262 RemoteRTDyldMemoryManager(OrcRemoteTargetClient & Client,ResourceIdMgr::ResourceId Id)263 RemoteRTDyldMemoryManager(OrcRemoteTargetClient &Client, 264 ResourceIdMgr::ResourceId Id) 265 : Client(Client), Id(Id) { 266 LLVM_DEBUG(dbgs() << "Created remote allocator " << Id << "\n"); 267 } 268 269 // Maps all allocations in Allocs to aligned blocks mapAllocsToRemoteAddrs(RuntimeDyld & Dyld,std::vector<Alloc> & Allocs,JITTargetAddress NextAddr)270 void mapAllocsToRemoteAddrs(RuntimeDyld &Dyld, std::vector<Alloc> &Allocs, 271 JITTargetAddress NextAddr) { 272 for (auto &Alloc : Allocs) { 273 NextAddr = alignTo(NextAddr, Alloc.getAlign()); 274 Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextAddr); 275 LLVM_DEBUG( 276 dbgs() << " " << static_cast<void *>(Alloc.getLocalAddress()) 277 << " -> " << format("0x%016" PRIx64, NextAddr) << "\n"); 278 Alloc.setRemoteAddress(NextAddr); 279 280 // Only advance NextAddr if it was non-null to begin with, 281 // otherwise leave it as null. 282 if (NextAddr) 283 NextAddr += Alloc.getSize(); 284 } 285 } 286 287 // Copies data for each alloc in the list, then set permissions on the 288 // segment. copyAndProtect(const std::vector<Alloc> & Allocs,JITTargetAddress RemoteSegmentAddr,unsigned Permissions)289 bool copyAndProtect(const std::vector<Alloc> &Allocs, 290 JITTargetAddress RemoteSegmentAddr, 291 unsigned Permissions) { 292 if (RemoteSegmentAddr) { 293 assert(!Allocs.empty() && "No sections in allocated segment"); 294 295 for (auto &Alloc : Allocs) { 296 LLVM_DEBUG(dbgs() << " copying section: " 297 << static_cast<void *>(Alloc.getLocalAddress()) 298 << " -> " 299 << format("0x%016" PRIx64, Alloc.getRemoteAddress()) 300 << " (" << Alloc.getSize() << " bytes)\n";); 301 302 if (Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(), 303 Alloc.getSize())) 304 return true; 305 } 306 307 LLVM_DEBUG(dbgs() << " setting " 308 << (Permissions & sys::Memory::MF_READ ? 'R' : '-') 309 << (Permissions & sys::Memory::MF_WRITE ? 'W' : '-') 310 << (Permissions & sys::Memory::MF_EXEC ? 'X' : '-') 311 << " permissions on block: " 312 << format("0x%016" PRIx64, RemoteSegmentAddr) 313 << "\n"); 314 if (Client.setProtections(Id, RemoteSegmentAddr, Permissions)) 315 return true; 316 } 317 return false; 318 } 319 320 OrcRemoteTargetClient &Client; 321 ResourceIdMgr::ResourceId Id; 322 std::vector<ObjectAllocs> Unmapped; 323 std::vector<ObjectAllocs> Unfinalized; 324 325 struct EHFrame { 326 JITTargetAddress Addr; 327 uint64_t Size; 328 }; 329 std::vector<EHFrame> UnfinalizedEHFrames; 330 std::vector<EHFrame> RegisteredEHFrames; 331 }; 332 333 /// Remote indirect stubs manager. 334 class RemoteIndirectStubsManager : public IndirectStubsManager { 335 public: RemoteIndirectStubsManager(OrcRemoteTargetClient & Client,ResourceIdMgr::ResourceId Id)336 RemoteIndirectStubsManager(OrcRemoteTargetClient &Client, 337 ResourceIdMgr::ResourceId Id) 338 : Client(Client), Id(Id) {} 339 ~RemoteIndirectStubsManager()340 ~RemoteIndirectStubsManager() override { 341 Client.destroyIndirectStubsManager(Id); 342 } 343 createStub(StringRef StubName,JITTargetAddress StubAddr,JITSymbolFlags StubFlags)344 Error createStub(StringRef StubName, JITTargetAddress StubAddr, 345 JITSymbolFlags StubFlags) override { 346 if (auto Err = reserveStubs(1)) 347 return Err; 348 349 return createStubInternal(StubName, StubAddr, StubFlags); 350 } 351 createStubs(const StubInitsMap & StubInits)352 Error createStubs(const StubInitsMap &StubInits) override { 353 if (auto Err = reserveStubs(StubInits.size())) 354 return Err; 355 356 for (auto &Entry : StubInits) 357 if (auto Err = createStubInternal(Entry.first(), Entry.second.first, 358 Entry.second.second)) 359 return Err; 360 361 return Error::success(); 362 } 363 findStub(StringRef Name,bool ExportedStubsOnly)364 JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { 365 auto I = StubIndexes.find(Name); 366 if (I == StubIndexes.end()) 367 return nullptr; 368 auto Key = I->second.first; 369 auto Flags = I->second.second; 370 auto StubSymbol = JITEvaluatedSymbol(getStubAddr(Key), Flags); 371 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported()) 372 return nullptr; 373 return StubSymbol; 374 } 375 findPointer(StringRef Name)376 JITEvaluatedSymbol findPointer(StringRef Name) override { 377 auto I = StubIndexes.find(Name); 378 if (I == StubIndexes.end()) 379 return nullptr; 380 auto Key = I->second.first; 381 auto Flags = I->second.second; 382 return JITEvaluatedSymbol(getPtrAddr(Key), Flags); 383 } 384 updatePointer(StringRef Name,JITTargetAddress NewAddr)385 Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override { 386 auto I = StubIndexes.find(Name); 387 assert(I != StubIndexes.end() && "No stub pointer for symbol"); 388 auto Key = I->second.first; 389 return Client.writePointer(getPtrAddr(Key), NewAddr); 390 } 391 392 private: 393 struct RemoteIndirectStubsInfo { 394 JITTargetAddress StubBase; 395 JITTargetAddress PtrBase; 396 unsigned NumStubs; 397 }; 398 399 using StubKey = std::pair<uint16_t, uint16_t>; 400 reserveStubs(unsigned NumStubs)401 Error reserveStubs(unsigned NumStubs) { 402 if (NumStubs <= FreeStubs.size()) 403 return Error::success(); 404 405 unsigned NewStubsRequired = NumStubs - FreeStubs.size(); 406 JITTargetAddress StubBase; 407 JITTargetAddress PtrBase; 408 unsigned NumStubsEmitted; 409 410 if (auto StubInfoOrErr = Client.emitIndirectStubs(Id, NewStubsRequired)) 411 std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr; 412 else 413 return StubInfoOrErr.takeError(); 414 415 unsigned NewBlockId = RemoteIndirectStubsInfos.size(); 416 RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted}); 417 418 for (unsigned I = 0; I < NumStubsEmitted; ++I) 419 FreeStubs.push_back(std::make_pair(NewBlockId, I)); 420 421 return Error::success(); 422 } 423 createStubInternal(StringRef StubName,JITTargetAddress InitAddr,JITSymbolFlags StubFlags)424 Error createStubInternal(StringRef StubName, JITTargetAddress InitAddr, 425 JITSymbolFlags StubFlags) { 426 auto Key = FreeStubs.back(); 427 FreeStubs.pop_back(); 428 StubIndexes[StubName] = std::make_pair(Key, StubFlags); 429 return Client.writePointer(getPtrAddr(Key), InitAddr); 430 } 431 getStubAddr(StubKey K)432 JITTargetAddress getStubAddr(StubKey K) { 433 assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 && 434 "Missing stub address"); 435 return RemoteIndirectStubsInfos[K.first].StubBase + 436 K.second * Client.getIndirectStubSize(); 437 } 438 getPtrAddr(StubKey K)439 JITTargetAddress getPtrAddr(StubKey K) { 440 assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 && 441 "Missing pointer address"); 442 return RemoteIndirectStubsInfos[K.first].PtrBase + 443 K.second * Client.getPointerSize(); 444 } 445 446 OrcRemoteTargetClient &Client; 447 ResourceIdMgr::ResourceId Id; 448 std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos; 449 std::vector<StubKey> FreeStubs; 450 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; 451 }; 452 453 class RemoteTrampolinePool : public TrampolinePool { 454 public: RemoteTrampolinePool(OrcRemoteTargetClient & Client)455 RemoteTrampolinePool(OrcRemoteTargetClient &Client) : Client(Client) {} 456 getTrampoline()457 Expected<JITTargetAddress> getTrampoline() override { 458 std::lock_guard<std::mutex> Lock(RTPMutex); 459 if (AvailableTrampolines.empty()) { 460 if (auto Err = grow()) 461 return std::move(Err); 462 } 463 assert(!AvailableTrampolines.empty() && "Failed to grow trampoline pool"); 464 auto TrampolineAddr = AvailableTrampolines.back(); 465 AvailableTrampolines.pop_back(); 466 return TrampolineAddr; 467 } 468 469 private: grow()470 Error grow() { 471 JITTargetAddress BlockAddr = 0; 472 uint32_t NumTrampolines = 0; 473 if (auto TrampolineInfoOrErr = Client.emitTrampolineBlock()) 474 std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr; 475 else 476 return TrampolineInfoOrErr.takeError(); 477 478 uint32_t TrampolineSize = Client.getTrampolineSize(); 479 for (unsigned I = 0; I < NumTrampolines; ++I) 480 this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize)); 481 482 return Error::success(); 483 } 484 485 std::mutex RTPMutex; 486 OrcRemoteTargetClient &Client; 487 std::vector<JITTargetAddress> AvailableTrampolines; 488 }; 489 490 /// Remote compile callback manager. 491 class RemoteCompileCallbackManager : public JITCompileCallbackManager { 492 public: RemoteCompileCallbackManager(OrcRemoteTargetClient & Client,ExecutionSession & ES,JITTargetAddress ErrorHandlerAddress)493 RemoteCompileCallbackManager(OrcRemoteTargetClient &Client, 494 ExecutionSession &ES, 495 JITTargetAddress ErrorHandlerAddress) 496 : JITCompileCallbackManager( 497 llvm::make_unique<RemoteTrampolinePool>(Client), ES, 498 ErrorHandlerAddress) {} 499 }; 500 501 /// Create an OrcRemoteTargetClient. 502 /// Channel is the ChannelT instance to communicate on. It is assumed that 503 /// the channel is ready to be read from and written to. 504 static Expected<std::unique_ptr<OrcRemoteTargetClient>> Create(rpc::RawByteChannel & Channel,ExecutionSession & ES)505 Create(rpc::RawByteChannel &Channel, ExecutionSession &ES) { 506 Error Err = Error::success(); 507 auto Client = std::unique_ptr<OrcRemoteTargetClient>( 508 new OrcRemoteTargetClient(Channel, ES, Err)); 509 if (Err) 510 return std::move(Err); 511 return std::move(Client); 512 } 513 514 /// Call the int(void) function at the given address in the target and return 515 /// its result. callIntVoid(JITTargetAddress Addr)516 Expected<int> callIntVoid(JITTargetAddress Addr) { 517 LLVM_DEBUG(dbgs() << "Calling int(*)(void) " 518 << format("0x%016" PRIx64, Addr) << "\n"); 519 return callB<exec::CallIntVoid>(Addr); 520 } 521 522 /// Call the int(int, char*[]) function at the given address in the target and 523 /// return its result. callMain(JITTargetAddress Addr,const std::vector<std::string> & Args)524 Expected<int> callMain(JITTargetAddress Addr, 525 const std::vector<std::string> &Args) { 526 LLVM_DEBUG(dbgs() << "Calling int(*)(int, char*[]) " 527 << format("0x%016" PRIx64, Addr) << "\n"); 528 return callB<exec::CallMain>(Addr, Args); 529 } 530 531 /// Call the void() function at the given address in the target and wait for 532 /// it to finish. callVoidVoid(JITTargetAddress Addr)533 Error callVoidVoid(JITTargetAddress Addr) { 534 LLVM_DEBUG(dbgs() << "Calling void(*)(void) " 535 << format("0x%016" PRIx64, Addr) << "\n"); 536 return callB<exec::CallVoidVoid>(Addr); 537 } 538 539 /// Create an RCMemoryManager which will allocate its memory on the remote 540 /// target. 541 Expected<std::unique_ptr<RemoteRTDyldMemoryManager>> createRemoteMemoryManager()542 createRemoteMemoryManager() { 543 auto Id = AllocatorIds.getNext(); 544 if (auto Err = callB<mem::CreateRemoteAllocator>(Id)) 545 return std::move(Err); 546 return std::unique_ptr<RemoteRTDyldMemoryManager>( 547 new RemoteRTDyldMemoryManager(*this, Id)); 548 } 549 550 /// Create an RCIndirectStubsManager that will allocate stubs on the remote 551 /// target. 552 Expected<std::unique_ptr<RemoteIndirectStubsManager>> createIndirectStubsManager()553 createIndirectStubsManager() { 554 auto Id = IndirectStubOwnerIds.getNext(); 555 if (auto Err = callB<stubs::CreateIndirectStubsOwner>(Id)) 556 return std::move(Err); 557 return llvm::make_unique<RemoteIndirectStubsManager>(*this, Id); 558 } 559 560 Expected<RemoteCompileCallbackManager &> enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress)561 enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress) { 562 assert(!CallbackManager && "CallbackManager already obtained"); 563 564 // Emit the resolver block on the JIT server. 565 if (auto Err = callB<stubs::EmitResolverBlock>()) 566 return std::move(Err); 567 568 // Create the callback manager. 569 CallbackManager.emplace(*this, ES, ErrorHandlerAddress); 570 RemoteCompileCallbackManager &Mgr = *CallbackManager; 571 return Mgr; 572 } 573 574 /// Search for symbols in the remote process. Note: This should be used by 575 /// symbol resolvers *after* they've searched the local symbol table in the 576 /// JIT stack. getSymbolAddress(StringRef Name)577 Expected<JITTargetAddress> getSymbolAddress(StringRef Name) { 578 return callB<utils::GetSymbolAddress>(Name); 579 } 580 581 /// Get the triple for the remote target. getTargetTriple()582 const std::string &getTargetTriple() const { return RemoteTargetTriple; } 583 terminateSession()584 Error terminateSession() { return callB<utils::TerminateSession>(); } 585 586 private: OrcRemoteTargetClient(rpc::RawByteChannel & Channel,ExecutionSession & ES,Error & Err)587 OrcRemoteTargetClient(rpc::RawByteChannel &Channel, ExecutionSession &ES, 588 Error &Err) 589 : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(Channel, true), 590 ES(ES) { 591 ErrorAsOutParameter EAO(&Err); 592 593 addHandler<utils::RequestCompile>( 594 [this](JITTargetAddress Addr) -> JITTargetAddress { 595 if (CallbackManager) 596 return CallbackManager->executeCompileCallback(Addr); 597 return 0; 598 }); 599 600 if (auto RIOrErr = callB<utils::GetRemoteInfo>()) { 601 std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize, 602 RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr; 603 Err = Error::success(); 604 } else 605 Err = RIOrErr.takeError(); 606 } 607 deregisterEHFrames(JITTargetAddress Addr,uint32_t Size)608 void deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) { 609 if (auto Err = callB<eh::RegisterEHFrames>(Addr, Size)) 610 ES.reportError(std::move(Err)); 611 } 612 destroyRemoteAllocator(ResourceIdMgr::ResourceId Id)613 void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) { 614 if (auto Err = callB<mem::DestroyRemoteAllocator>(Id)) { 615 // FIXME: This will be triggered by a removeModuleSet call: Propagate 616 // error return up through that. 617 llvm_unreachable("Failed to destroy remote allocator."); 618 AllocatorIds.release(Id); 619 } 620 } 621 destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id)622 void destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) { 623 IndirectStubOwnerIds.release(Id); 624 if (auto Err = callB<stubs::DestroyIndirectStubsOwner>(Id)) 625 ES.reportError(std::move(Err)); 626 } 627 628 Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>> emitIndirectStubs(ResourceIdMgr::ResourceId Id,uint32_t NumStubsRequired)629 emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) { 630 return callB<stubs::EmitIndirectStubs>(Id, NumStubsRequired); 631 } 632 emitTrampolineBlock()633 Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() { 634 return callB<stubs::EmitTrampolineBlock>(); 635 } 636 getIndirectStubSize()637 uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; } getPageSize()638 uint32_t getPageSize() const { return RemotePageSize; } getPointerSize()639 uint32_t getPointerSize() const { return RemotePointerSize; } 640 getTrampolineSize()641 uint32_t getTrampolineSize() const { return RemoteTrampolineSize; } 642 readMem(char * Dst,JITTargetAddress Src,uint64_t Size)643 Expected<std::vector<uint8_t>> readMem(char *Dst, JITTargetAddress Src, 644 uint64_t Size) { 645 return callB<mem::ReadMem>(Src, Size); 646 } 647 registerEHFrames(JITTargetAddress & RAddr,uint32_t Size)648 Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) { 649 // FIXME: Duplicate error and report it via ReportError too? 650 return callB<eh::RegisterEHFrames>(RAddr, Size); 651 } 652 reserveMem(ResourceIdMgr::ResourceId Id,uint64_t Size,uint32_t Align)653 JITTargetAddress reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size, 654 uint32_t Align) { 655 if (auto AddrOrErr = callB<mem::ReserveMem>(Id, Size, Align)) 656 return *AddrOrErr; 657 else { 658 ES.reportError(AddrOrErr.takeError()); 659 return 0; 660 } 661 } 662 setProtections(ResourceIdMgr::ResourceId Id,JITTargetAddress RemoteSegAddr,unsigned ProtFlags)663 bool setProtections(ResourceIdMgr::ResourceId Id, 664 JITTargetAddress RemoteSegAddr, unsigned ProtFlags) { 665 if (auto Err = callB<mem::SetProtections>(Id, RemoteSegAddr, ProtFlags)) { 666 ES.reportError(std::move(Err)); 667 return true; 668 } else 669 return false; 670 } 671 writeMem(JITTargetAddress Addr,const char * Src,uint64_t Size)672 bool writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) { 673 if (auto Err = callB<mem::WriteMem>(DirectBufferWriter(Src, Addr, Size))) { 674 ES.reportError(std::move(Err)); 675 return true; 676 } else 677 return false; 678 } 679 writePointer(JITTargetAddress Addr,JITTargetAddress PtrVal)680 Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) { 681 return callB<mem::WritePtr>(Addr, PtrVal); 682 } 683 doNothing()684 static Error doNothing() { return Error::success(); } 685 686 ExecutionSession &ES; 687 std::function<void(Error)> ReportError; 688 std::string RemoteTargetTriple; 689 uint32_t RemotePointerSize = 0; 690 uint32_t RemotePageSize = 0; 691 uint32_t RemoteTrampolineSize = 0; 692 uint32_t RemoteIndirectStubSize = 0; 693 ResourceIdMgr AllocatorIds, IndirectStubOwnerIds; 694 Optional<RemoteCompileCallbackManager> CallbackManager; 695 }; 696 697 } // end namespace remote 698 } // end namespace orc 699 } // end namespace llvm 700 701 #undef DEBUG_TYPE 702 703 #endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H 704