16 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
17 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
21 #include <system_error>
23 #define DEBUG_TYPE "orc-remote"
36 template <
typename ChannelT>
43 : Client(Client), Id(Id) {
44 DEBUG(
dbgs() <<
"Created remote allocator " << Id <<
"\n");
53 Client.destroyRemoteAllocator(Id);
54 DEBUG(
dbgs() <<
"Destroyed remote allocator " << Id <<
"\n");
60 Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
61 uint8_t *Alloc =
reinterpret_cast<uint8_t *
>(
62 Unmapped.back().CodeAllocs.back().getLocalAddress());
63 DEBUG(
dbgs() <<
"Allocator " << Id <<
" allocated code for "
64 << SectionName <<
": " << Alloc <<
" (" << Size
65 <<
" bytes, alignment " << Alignment <<
")\n");
71 bool IsReadOnly)
override {
73 Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
74 uint8_t *Alloc =
reinterpret_cast<uint8_t *
>(
75 Unmapped.back().RODataAllocs.back().getLocalAddress());
76 DEBUG(
dbgs() <<
"Allocator " << Id <<
" allocated ro-data for "
77 << SectionName <<
": " << Alloc <<
" (" << Size
78 <<
" bytes, alignment " << Alignment <<
")\n");
82 Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
83 uint8_t *Alloc =
reinterpret_cast<uint8_t *
>(
84 Unmapped.back().RWDataAllocs.back().getLocalAddress());
85 DEBUG(
dbgs() <<
"Allocator " << Id <<
" allocated rw-data for "
86 << SectionName <<
": " << Alloc <<
" (" << Size
87 <<
" bytes, alignment " << Alignment <<
")\n");
92 uintptr_t RODataSize,
uint32_t RODataAlign,
95 Unmapped.push_back(ObjectAllocs());
97 DEBUG(
dbgs() <<
"Allocator " << Id <<
" reserved:\n");
100 if (
auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign))
101 Unmapped.back().RemoteCodeAddr = *AddrOrErr;
104 assert(!AddrOrErr.takeError() &&
"Failed reserving remote memory.");
108 <<
format(
"0x%016x", Unmapped.back().RemoteCodeAddr)
109 <<
" (" << CodeSize <<
" bytes, alignment " << CodeAlign
113 if (RODataSize != 0) {
114 if (
auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign))
115 Unmapped.back().RemoteRODataAddr = *AddrOrErr;
118 assert(!AddrOrErr.takeError() &&
"Failed reserving remote memory.");
122 <<
format(
"0x%016x", Unmapped.back().RemoteRODataAddr)
123 <<
" (" << RODataSize <<
" bytes, alignment "
124 << RODataAlign <<
")\n");
127 if (RWDataSize != 0) {
128 if (
auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign))
129 Unmapped.back().RemoteRWDataAddr = *AddrOrErr;
132 assert(!AddrOrErr.takeError() &&
"Failed reserving remote memory.");
136 <<
format(
"0x%016x", Unmapped.back().RemoteRWDataAddr)
137 <<
" (" << RWDataSize <<
" bytes, alignment "
138 << RWDataAlign <<
")\n");
145 size_t Size)
override {
146 UnfinalizedEHFrames.push_back(
147 std::make_pair(LoadAddr, static_cast<uint32_t>(Size)));
151 size_t Size)
override {
152 auto Err = Client.deregisterEHFrames(LoadAddr, Size);
154 assert(!Err &&
"Failed to register remote EH frames.");
160 DEBUG(
dbgs() <<
"Allocator " << Id <<
" applied mappings:\n");
161 for (
auto &ObjAllocs : Unmapped) {
164 for (
auto &Alloc : ObjAllocs.CodeAllocs) {
165 NextCodeAddr =
alignTo(NextCodeAddr, Alloc.getAlign());
168 << static_cast<void *>(Alloc.getLocalAddress())
169 <<
" -> " <<
format(
"0x%016x", NextCodeAddr) <<
"\n");
170 Alloc.setRemoteAddress(NextCodeAddr);
171 NextCodeAddr += Alloc.getSize();
176 for (
auto &Alloc : ObjAllocs.RODataAllocs) {
177 NextRODataAddr =
alignTo(NextRODataAddr, Alloc.getAlign());
180 << static_cast<void *>(Alloc.getLocalAddress())
181 <<
" -> " <<
format(
"0x%016x", NextRODataAddr)
183 Alloc.setRemoteAddress(NextRODataAddr);
184 NextRODataAddr += Alloc.getSize();
189 for (
auto &Alloc : ObjAllocs.RWDataAllocs) {
190 NextRWDataAddr =
alignTo(NextRWDataAddr, Alloc.getAlign());
193 << static_cast<void *>(Alloc.getLocalAddress())
194 <<
" -> " <<
format(
"0x%016x", NextRWDataAddr)
196 Alloc.setRemoteAddress(NextRWDataAddr);
197 NextRWDataAddr += Alloc.getSize();
200 Unfinalized.push_back(std::move(ObjAllocs));
206 DEBUG(
dbgs() <<
"Allocator " << Id <<
" finalizing:\n");
208 for (
auto &ObjAllocs : Unfinalized) {
210 for (
auto &Alloc : ObjAllocs.CodeAllocs) {
212 << static_cast<void *>(Alloc.getLocalAddress()) <<
" -> "
213 <<
format(
"0x%016x", Alloc.getRemoteAddress()) <<
" ("
214 << Alloc.getSize() <<
" bytes)\n");
216 Client.writeMem(Alloc.getRemoteAddress(),
217 Alloc.getLocalAddress(), Alloc.getSize())) {
229 if (ObjAllocs.RemoteCodeAddr) {
230 DEBUG(
dbgs() <<
" setting R-X permissions on code block: "
231 <<
format(
"0x%016x", ObjAllocs.RemoteCodeAddr) <<
"\n");
232 if (
auto Err = Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
246 for (
auto &Alloc : ObjAllocs.RODataAllocs) {
248 << static_cast<void *>(Alloc.getLocalAddress()) <<
" -> "
249 <<
format(
"0x%016x", Alloc.getRemoteAddress()) <<
" ("
250 << Alloc.getSize() <<
" bytes)\n");
252 Client.writeMem(Alloc.getRemoteAddress(),
253 Alloc.getLocalAddress(), Alloc.getSize())) {
265 if (ObjAllocs.RemoteRODataAddr) {
266 DEBUG(
dbgs() <<
" setting R-- permissions on ro-data block: "
267 <<
format(
"0x%016x", ObjAllocs.RemoteRODataAddr)
269 if (
auto Err = Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
282 for (
auto &Alloc : ObjAllocs.RWDataAllocs) {
284 << static_cast<void *>(Alloc.getLocalAddress()) <<
" -> "
285 <<
format(
"0x%016x", Alloc.getRemoteAddress()) <<
" ("
286 << Alloc.getSize() <<
" bytes)\n");
288 Client.writeMem(Alloc.getRemoteAddress(),
289 Alloc.getLocalAddress(), Alloc.getSize())) {
301 if (ObjAllocs.RemoteRWDataAddr) {
302 DEBUG(
dbgs() <<
" setting RW- permissions on rw-data block: "
303 <<
format(
"0x%016x", ObjAllocs.RemoteRWDataAddr)
305 if (
auto Err = Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
321 for (
auto &EHFrame : UnfinalizedEHFrames) {
322 if (
auto Err = Client.registerEHFrames(EHFrame.first, EHFrame.second)) {
333 UnfinalizedEHFrames.clear();
341 Alloc(uint64_t Size,
unsigned Align)
342 : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
344 Alloc(
const Alloc &) =
delete;
345 Alloc &
operator=(
const Alloc &) =
delete;
346 Alloc(Alloc &&) =
default;
349 uint64_t getSize()
const {
return Size; }
351 unsigned getAlign()
const {
return Align; }
353 char *getLocalAddress()
const {
354 uintptr_t LocalAddr =
reinterpret_cast<uintptr_t
>(Contents.get());
355 LocalAddr =
alignTo(LocalAddr, Align);
356 return reinterpret_cast<char *
>(LocalAddr);
360 this->RemoteAddr = RemoteAddr;
368 std::unique_ptr<char[]> Contents;
372 struct ObjectAllocs {
373 ObjectAllocs() =
default;
374 ObjectAllocs(
const ObjectAllocs &) =
delete;
375 ObjectAllocs &
operator=(
const ObjectAllocs &) =
delete;
376 ObjectAllocs(ObjectAllocs &&) =
default;
377 ObjectAllocs &
operator=(ObjectAllocs &&) =
default;
382 std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
385 OrcRemoteTargetClient &Client;
387 std::vector<ObjectAllocs> Unmapped;
388 std::vector<ObjectAllocs> Unfinalized;
389 std::vector<std::pair<uint64_t, uint32_t>> UnfinalizedEHFrames;
397 : Remote(Remote), Id(Id) {}
400 if (
auto Err = Remote.destroyIndirectStubsManager(Id)) {
408 if (
auto Err = reserveStubs(1))
411 return createStubInternal(StubName, StubAddr, StubFlags);
415 if (
auto Err = reserveStubs(StubInits.
size()))
418 for (
auto &Entry : StubInits)
419 if (
auto Err = createStubInternal(Entry.first(), Entry.second.first,
420 Entry.second.second))
427 auto I = StubIndexes.find(Name);
428 if (
I == StubIndexes.end())
430 auto Key =
I->second.first;
431 auto Flags =
I->second.second;
433 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
439 auto I = StubIndexes.find(Name);
440 if (
I == StubIndexes.end())
442 auto Key =
I->second.first;
443 auto Flags =
I->second.second;
448 auto I = StubIndexes.find(Name);
449 assert(
I != StubIndexes.end() &&
"No stub pointer for symbol");
450 auto Key =
I->second.first;
451 return Remote.writePointer(getPtrAddr(Key), NewAddr);
455 struct RemoteIndirectStubsInfo {
463 std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
464 typedef std::pair<uint16_t, uint16_t> StubKey;
465 std::vector<StubKey> FreeStubs;
468 Error reserveStubs(
unsigned NumStubs) {
469 if (NumStubs <= FreeStubs.size())
472 unsigned NewStubsRequired = NumStubs - FreeStubs.size();
475 unsigned NumStubsEmitted;
477 if (
auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired))
478 std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
480 return StubInfoOrErr.takeError();
482 unsigned NewBlockId = RemoteIndirectStubsInfos.size();
483 RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
485 for (
unsigned I = 0;
I < NumStubsEmitted; ++
I)
486 FreeStubs.push_back(std::make_pair(NewBlockId,
I));
493 auto Key = FreeStubs.back();
494 FreeStubs.pop_back();
495 StubIndexes[StubName] = std::make_pair(Key, StubFlags);
496 return Remote.writePointer(getPtrAddr(Key), InitAddr);
500 assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
501 "Missing stub address");
502 return RemoteIndirectStubsInfos[K.first].StubBase +
503 K.second * Remote.getIndirectStubSize();
507 assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
508 "Missing pointer address");
509 return RemoteIndirectStubsInfos[K.first].PtrBase +
510 K.second * Remote.getPointerSize();
522 void grow()
override {
525 if (
auto TrampolineInfoOrErr = Remote.emitTrampolineBlock())
526 std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
532 uint32_t TrampolineSize = Remote.getTrampolineSize();
533 for (
unsigned I = 0;
I < NumTrampolines; ++
I)
537 OrcRemoteTargetClient &Remote;
546 std::unique_ptr<OrcRemoteTargetClient> Client(
549 return std::move(Err);
550 return std::move(Client);
556 DEBUG(
dbgs() <<
"Calling int(*)(void) " <<
format(
"0x%016x", Addr) <<
"\n");
557 return callB<CallIntVoid>(Addr);
563 const std::vector<std::string> &
Args) {
564 DEBUG(
dbgs() <<
"Calling int(*)(int, char*[]) " <<
format(
"0x%016x", Addr)
566 return callB<CallMain>(Addr,
Args);
574 return callB<CallVoidVoid>(Addr);
580 assert(!MM &&
"MemoryManager should be null before creation.");
583 if (
auto Err = callB<CreateRemoteAllocator>(
Id))
585 MM = llvm::make_unique<RCMemoryManager>(*
this,
Id);
592 assert(!I &&
"Indirect stubs manager should be null before creation.");
593 auto Id = IndirectStubOwnerIds.
getNext();
594 if (
auto Err = callB<CreateIndirectStubsOwner>(
Id))
596 I = llvm::make_unique<RCIndirectStubsManager>(*
this,
Id);
604 return std::move(ExistingError);
607 if (
auto Err = callB<EmitResolverBlock>())
608 return std::move(Err);
611 CallbackManager.emplace(ErrorHandlerAddress, *
this);
622 return std::move(ExistingError);
624 return callB<GetSymbolAddress>(
Name);
637 addHandler<RequestCompile>(
640 return CallbackManager->executeCompileCallback(Addr);
644 if (
auto RIOrErr = callB<GetRemoteInfo>()) {
645 std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
646 RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
649 Err =
joinErrors(RIOrErr.takeError(), std::move(ExistingError));
654 return callB<RegisterEHFrames>(Addr, Size);
658 if (
auto Err = callB<DestroyRemoteAllocator>(Id)) {
667 IndirectStubOwnerIds.
release(Id);
668 return callB<DestroyIndirectStubsOwner>(
Id);
671 Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
673 return callB<EmitIndirectStubs>(
Id, NumStubsRequired);
676 Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() {
679 return std::move(ExistingError);
681 return callB<EmitTrampolineBlock>();
684 uint32_t getIndirectStubSize()
const {
return RemoteIndirectStubSize; }
685 uint32_t getPageSize()
const {
return RemotePageSize; }
686 uint32_t getPointerSize()
const {
return RemotePointerSize; }
688 uint32_t getTrampolineSize()
const {
return RemoteTrampolineSize; }
694 return std::move(ExistingError);
696 return callB<ReadMem>(Src, Size);
700 return callB<RegisterEHFrames>(RAddr, Size);
708 return std::move(ExistingError);
710 return callB<ReserveMem>(
Id, Size, Align);
715 return callB<SetProtections>(
Id, RemoteSegAddr, ProtFlags);
721 return std::move(ExistingError);
723 return callB<WriteMem>(DirectBufferWriter(Src, Addr, Size));
729 return std::move(ExistingError);
731 return callB<WritePtr>(Addr, PtrVal);
737 std::string RemoteTargetTriple;
741 uint32_t RemoteIndirectStubSize = 0;
742 ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
743 Optional<RCCompileCallbackManager> CallbackManager;
752 #endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
bool finalizeMemory(std::string *ErrMsg=nullptr) override
This method is called when object loading is complete and section page permissions can be applied...
Base class for managing collections of named indirect stubs.
Represents a symbol in the JIT.
bool getAlign(const Function &F, unsigned index, unsigned &align)
This class is the base class for all object file types.
Expected< RCCompileCallbackManager & > enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress)
Error callVoidVoid(JITTargetAddress Addr)
Call the void() function at the given address in the target and wait for it to finish.
uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew=0)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
RCIndirectStubsManager(OrcRemoteTargetClient &Remote, ResourceIdMgr::ResourceId Id)
void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize, uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) override
Inform the memory manager about the total amount of memory required to allocate all sections to be lo...
void notifyObjectLoaded(RuntimeDyld &Dyld, const object::ObjectFile &Obj) override
This method is called after an object has been loaded into memory but before relocations are applied ...
Base class for error info classes.
Expected< int > callIntVoid(JITTargetAddress Addr)
Call the int(void) function at the given address in the target and return its result.
Target-independent base class for compile callback management.
RCMemoryManager & operator=(const RCMemoryManager &)=delete
struct fuzzer::@269 Flags
Expected< JITTargetAddress > getSymbolAddress(StringRef Name)
Search for symbols in the remote process.
virtual void log(raw_ostream &OS) const =0
Print an error message to an output stream.
JITSymbol findPointer(StringRef Name) override
Find the implementation-pointer for the stub.
void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override
Tagged union holding either a T or a Error.
JITTargetAddress ErrorHandlerAddress
JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override
Find the stub with the given name.
RCCompileCallbackManager(JITTargetAddress ErrorHandlerAddress, OrcRemoteTargetClient &Remote)
~RCMemoryManager() override
Expected< int > callMain(JITTargetAddress Addr, const std::vector< std::string > &Args)
Call the int(int, char*[]) function at the given address in the target and return its result...
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override
Register the EH frames with the runtime so that c++ exceptions work.
std::vector< JITTargetAddress > AvailableTrampolines
Remote indirect stubs manager.
format_object< Ts...> format(const char *Fmt, const Ts &...Vals)
These are helper functions used to produce formatted output.
Error createStubs(const StubInitsMap &StubInits) override
Create StubInits.size() stubs with the given names, target addresses, and flags.
Error createStub(StringRef StubName, JITTargetAddress StubAddr, JITSymbolFlags StubFlags) override
Create a single stub with the given name, target address and flags.
RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id)
uint8_t * allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, bool IsReadOnly) override
Allocate a memory block of (at least) the given size suitable for data.
Error createRemoteMemoryManager(std::unique_ptr< RCMemoryManager > &MM)
Create an RCMemoryManager which will allocate its memory on the remote target.
This class provides utilities (including memory manager, indirect stubs manager, and compile callback...
Flags for symbols in the JIT.
uint64_t JITTargetAddress
Represents an address in the target process's address space.
void handleAllErrors(Error E, HandlerTs &&...Handlers)
Behaves the same as handleErrors, except that it requires that all errors be handled by the given han...
void consumeError(Error Err)
Consume a Error without doing anything.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static ErrorSuccess success()
Create a success value.
void release(ResourceId I)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Error createIndirectStubsManager(std::unique_ptr< RCIndirectStubsManager > &I)
Create an RCIndirectStubsManager that will allocate stubs on the remote target.
Helper for Errors used as out-parameters.
Error joinErrors(Error E1, Error E2)
Concatenate errors.
~RCIndirectStubsManager() override
static Expected< std::unique_ptr< OrcRemoteTargetClient > > Create(ChannelT &Channel)
Create an OrcRemoteTargetClient.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
uint8_t * allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) override
Allocate a memory block of (at least) the given size suitable for executable code.
A raw_ostream that writes to an std::string.
Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override
Change the value of the implementation pointer for the stub.
bool needsToReserveAllocationSpace() override
Override to return true to enable the reserveAllocationSpace callback.
Lightweight error class with error context and mandatory checking.
Remote compile callback manager.
StringRef - Represent a constant reference to a string, i.e.
void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress)
Map a section to its target address space value.
const std::string & getTargetTriple() const
Get the triple for the remote target.