15#define DEBUG_TYPE "orc"
27 {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName},
28 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
29 {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
31 rt::SimpleExecutorMemoryManagerDeallocateWrapperName},
32 {SAs.RegisterEHFrame, rt::RegisterEHFrameSectionWrapperName},
33 {SAs.DeregisterEHFrame, rt::DeregisterEHFrameSectionWrapperName}}))
34 return std::move(Err);
35 return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC, std::move(SAs));
38EPCGenericRTDyldMemoryManager::EPCGenericRTDyldMemoryManager(
40 : EPC(EPC), SAs(
std::
move(SAs)) {
41 LLVM_DEBUG(
dbgs() <<
"Created remote allocator " << (
void *)
this <<
"\n");
45 LLVM_DEBUG(
dbgs() <<
"Destroyed remote allocator " << (
void *)
this <<
"\n");
47 errs() <<
"Destroying with existing errors:\n" << ErrMsg <<
"\n";
63 uintptr_t
Size,
unsigned Alignment,
unsigned SectionID,
65 std::lock_guard<std::mutex> Lock(M);
67 dbgs() <<
"Allocator " << (
void *)
this <<
" allocating code section "
69 <<
" bytes, alignment = " << Alignment <<
"\n";
71 auto &Seg = Unmapped.back().CodeAllocs;
72 Seg.emplace_back(
Size, Alignment);
73 return reinterpret_cast<uint8_t *
>(
78 uintptr_t
Size,
unsigned Alignment,
unsigned SectionID,
80 std::lock_guard<std::mutex> Lock(M);
82 dbgs() <<
"Allocator " << (
void *)
this <<
" allocating "
83 << (IsReadOnly ?
"ro" :
"rw") <<
"-data section " <<
SectionName
84 <<
": size = " <<
formatv(
"{0:x}",
Size) <<
" bytes, alignment "
85 << Alignment <<
")\n";
89 IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs;
91 Seg.emplace_back(
Size, Alignment);
92 return reinterpret_cast<uint8_t *
>(
97 uintptr_t CodeSize,
Align CodeAlign, uintptr_t RODataSize,
98 Align RODataAlign, uintptr_t RWDataSize,
Align RWDataAlign) {
101 std::lock_guard<std::mutex> Lock(M);
107 ErrMsg =
"Invalid code alignment in reserveAllocationSpace";
111 ErrMsg =
"Invalid ro-data alignment in reserveAllocationSpace";
115 ErrMsg =
"Invalid rw-data alignment in reserveAllocationSpace";
126 dbgs() <<
"Allocator " << (
void *)
this <<
" reserving "
127 <<
formatv(
"{0:x}", TotalSize) <<
" bytes.\n";
134 std::lock_guard<std::mutex> Lock(M);
138 if (!TargetAllocAddr) {
139 std::lock_guard<std::mutex> Lock(M);
140 ErrMsg =
toString(TargetAllocAddr.takeError());
144 std::lock_guard<std::mutex> Lock(M);
145 Unmapped.push_back(SectionAllocGroup());
146 Unmapped.back().RemoteCode = {
148 Unmapped.back().RemoteROData = {
149 Unmapped.back().RemoteCode.End,
151 Unmapped.back().RemoteRWData = {
152 Unmapped.back().RemoteROData.End,
164 dbgs() <<
"Allocator " << (
void *)
this <<
" added unfinalized eh-frame "
165 <<
formatv(
"[ {0:x} {1:x} ]", LoadAddr, LoadAddr +
Size) <<
"\n";
167 std::lock_guard<std::mutex> Lock(M);
174 if (SecAllocGroup.RemoteCode.contains(LA) ||
175 SecAllocGroup.RemoteROData.contains(LA) ||
176 SecAllocGroup.RemoteRWData.contains(LA)) {
177 SecAllocGroup.UnfinalizedEHFrames.push_back({LA,
Size});
181 ErrMsg =
"eh-frame does not lie inside unfinalized alloc";
190 std::lock_guard<std::mutex> Lock(M);
191 LLVM_DEBUG(
dbgs() <<
"Allocator " << (
void *)
this <<
" applied mappings:\n");
192 for (
auto &ObjAllocs : Unmapped) {
193 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
194 ObjAllocs.RemoteCode.Start);
195 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
196 ObjAllocs.RemoteROData.Start);
197 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
198 ObjAllocs.RemoteRWData.Start);
199 Unfinalized.push_back(std::move(ObjAllocs));
205 LLVM_DEBUG(
dbgs() <<
"Allocator " << (
void *)
this <<
" finalizing:\n");
208 std::vector<SectionAllocGroup> SecAllocGroups;
210 std::lock_guard<std::mutex> Lock(M);
211 if (ErrMsg && !this->ErrMsg.empty()) {
212 *ErrMsg = std::move(this->ErrMsg);
219 for (
auto &SecAllocGroup : SecAllocGroups) {
225 &SecAllocGroup.RemoteROData,
226 &SecAllocGroup.RemoteRWData};
228 std::vector<SectionAlloc> *SegSections[3] = {&SecAllocGroup.CodeAllocs,
229 &SecAllocGroup.RODataAllocs,
230 &SecAllocGroup.RWDataAllocs};
233 std::unique_ptr<char[]> AggregateContents[3];
235 for (
unsigned I = 0;
I != 3; ++
I) {
238 Seg.RAG = SegMemProts[
I];
239 Seg.Addr = RemoteAddrs[
I]->
Start;
240 for (
auto &SecAlloc : *SegSections[
I]) {
241 Seg.Size =
alignTo(Seg.Size, SecAlloc.Align);
242 Seg.Size += SecAlloc.Size;
244 AggregateContents[
I] = std::make_unique<char[]>(Seg.Size);
245 size_t SecOffset = 0;
246 for (
auto &SecAlloc : *SegSections[
I]) {
247 SecOffset =
alignTo(SecOffset, SecAlloc.Align);
248 memcpy(&AggregateContents[
I][SecOffset],
249 reinterpret_cast<const char *
>(
252 SecOffset += SecAlloc.Size;
256 Seg.Content = {AggregateContents[
I].get(), SecOffset};
259 for (
auto &Frame : SecAllocGroup.UnfinalizedEHFrames)
274 std::lock_guard<std::mutex> Lock(M);
275 this->ErrMsg =
toString(std::move(Err));
276 dbgs() <<
"Serialization error: " << this->ErrMsg <<
"\n";
278 *ErrMsg = this->ErrMsg;
282 std::lock_guard<std::mutex> Lock(M);
283 this->ErrMsg =
toString(std::move(FinalizeErr));
284 dbgs() <<
"Finalization error: " << this->ErrMsg <<
"\n";
286 *ErrMsg = this->ErrMsg;
294void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs(
295 RuntimeDyld &Dyld, std::vector<SectionAlloc> &Allocs,
297 for (
auto &
Alloc : Allocs) {
300 dbgs() <<
" " <<
static_cast<void *
>(
Alloc.Contents.get()) <<
" -> "
306 Alloc.RemoteAddr = NextAddr;
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress)
Map a section to its target address space value.
StringRef - Represent a constant reference to a string, i.e.
This class is the base class for all object file types.
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.
bool finalizeMemory(std::string *ErrMsg=nullptr) override
This method is called when object loading is complete and section page permissions can be applied.
bool needsToReserveAllocationSpace() override
Override to return true to enable the reserveAllocationSpace callback.
~EPCGenericRTDyldMemoryManager()
static Expected< std::unique_ptr< EPCGenericRTDyldMemoryManager > > CreateWithDefaultBootstrapSymbols(ExecutorProcessControl &EPC)
Create an EPCGenericRTDyldMemoryManager using the given EPC, looking up the default symbol names in t...
void reserveAllocationSpace(uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize, Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) override
Inform the memory manager about the total amount of memory required to allocate all sections to be lo...
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override
Register the EH frames with the runtime so that c++ exceptions work.
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 ...
void deregisterEHFrames() override
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.
Represents an address in the executor process.
uint64_t getValue() const
void setValue(uint64_t Addr)
ExecutorProcessControl supports interaction with a JIT target process.
unsigned getPageSize() const
Get the page size for the target process.
Error callSPSWrapper(ExecutorAddr WrapperFnAddr, WrapperCallArgTs &&...WrapperCallArgs)
Run a wrapper function using SPS to serialize the arguments and deserialize the results.
Error getBootstrapSymbols(ArrayRef< std::pair< ExecutorAddr &, StringRef > > Pairs) const
For each (ExecutorAddr&, StringRef) pair, looks up the string in the bootstrap symbols map and writes...
A utility class for serializing to a blob from a variadic list.
static Expected< WrapperFunctionCall > Create(ExecutorAddr FnAddr, const ArgTs &...Args)
Create a WrapperFunctionCall using the given SPS serializer to serialize the arguments.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, uint64_t) SPSSimpleExecutorMemoryManagerReserveSignature
shared::SPSError(shared::SPSExecutorAddr, shared::SPSFinalizeRequest) SPSSimpleExecutorMemoryManagerFinalizeSignature
shared::SPSError(shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSSimpleExecutorMemoryManagerDeallocateSignature
MemProt
Describes Read/Write/Exec permissions for memory.
uint64_t ExecutorAddrDiff
This is an optimization pass for GlobalISel generic memory operations.
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
auto formatv(const char *Fmt, Ts &&...Vals) -> formatv_object< decltype(std::make_tuple(support::detail::build_format_adapter(std::forward< Ts >(Vals))...))>
auto reverse(ContainerTy &&C)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
uintptr_t alignAddr(const void *Addr, Align Alignment)
Aligns Addr to Alignment bytes, rounding up.
Implement std::hash so that hash_code can be used in STL containers.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Symbol addresses for memory access.
ExecutorAddr DeregisterEHFrame
ExecutorAddr RegisterEHFrame
Represents an address range in the exceutor process.
std::vector< SegFinalizeRequest > Segments
shared::AllocActions Actions