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