14#define DEBUG_TYPE "orc"
21Expected<std::unique_ptr<EPCGenericRTDyldMemoryManager>>
25 if (
auto Err = EPC.getBootstrapSymbols(
26 {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName},
27 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
29 rt::SimpleExecutorMemoryManagerInitializeWrapperName},
30 {SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName},
31 {SAs.RegisterEHFrame, rt::RegisterEHFrameSectionAllocActionName},
32 {SAs.DeregisterEHFrame,
33 rt::DeregisterEHFrameSectionAllocActionName}}))
34 return std::move(Err);
35 return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC, std::move(SAs));
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";
50 if (
auto Err2 = EPC.callSPSWrapper<
52 SAs.Reserve, Err, SAs.Instance, FinalizedAllocs)) {
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 *
>(
98 Align RODataAlign, uintptr_t RWDataSize,
Align RWDataAlign) {
101 std::lock_guard<std::mutex> Lock(M);
106 if (CodeAlign > EPC.getPageSize()) {
107 ErrMsg =
"Invalid code alignment in reserveAllocationSpace";
110 if (RODataAlign > EPC.getPageSize()) {
111 ErrMsg =
"Invalid ro-data alignment in reserveAllocationSpace";
114 if (RWDataAlign > EPC.getPageSize()) {
115 ErrMsg =
"Invalid rw-data alignment in reserveAllocationSpace";
122 TotalSize +=
alignTo(RODataSize, EPC.getPageSize());
123 TotalSize +=
alignTo(RWDataSize, EPC.getPageSize());
126 dbgs() <<
"Allocator " << (
void *)
this <<
" reserving "
127 <<
formatv(
"{0:x}", TotalSize) <<
" bytes.\n";
131 if (
auto Err = EPC.callSPSWrapper<
133 SAs.Reserve, TargetAllocAddr, SAs.Instance, TotalSize)) {
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)
263 SAs.RegisterEHFrame, Frame)),
266 SAs.DeregisterEHFrame, Frame))});
271 if (
auto Err = EPC.callSPSWrapper<
273 SAs.Initialize, InitializeKey, SAs.Instance, std::move(FR))) {
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;
281 if (!InitializeKey) {
282 std::lock_guard<std::mutex> Lock(M);
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.
Error takeError()
Take ownership of the stored error.
LLVM_ABI 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.
static Expected< std::unique_ptr< EPCGenericRTDyldMemoryManager > > CreateWithDefaultBootstrapSymbols(ExecutorProcessControl &EPC)
Create an EPCGenericRTDyldMemoryManager using the given EPC, looking up the default symbol names in t...
EPCGenericRTDyldMemoryManager(ExecutorProcessControl &EPC, SymbolAddrs SAs)
Create an EPCGenericRTDyldMemoryManager using the given EPC and symbol addrs.
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.
~EPCGenericRTDyldMemoryManager() override
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.
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.
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, uint64_t) SPSSimpleExecutorMemoryManagerReserveSignature
shared::SPSExpected< shared::SPSExecutorAddr >(shared::SPSExecutorAddr, shared::SPSFinalizeRequest) SPSSimpleExecutorMemoryManagerInitializeSignature
shared::SPSError( shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSSimpleExecutorMemoryManagerReleaseSignature
MemProt
Describes Read/Write/Exec permissions for memory.
uint64_t ExecutorAddrDiff
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
auto reverse(ContainerTy &&C)
LLVM_ABI 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.
LLVM_ABI 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.
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
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.
Represents an address range in the exceutor process.
std::vector< SegFinalizeRequest > Segments
shared::AllocActions Actions