18#define DEBUG_TYPE "orc"
25Expected<std::unique_ptr<EPCGenericRTDyldMemoryManager>>
30 EPC.getExecutionSession().getBootstrapJITDylib(),
31 {recordAddr(rt::sps_ci::SimpleNativeMemoryMapInstanceName,
32 &SAs.MemMgr.Instance),
33 recordProxy<sps::MemMgrReserveProxySpec>(&SAs.MemMgr.Reserve),
34 recordProxy<sps::MemMgrInitializeProxySpec>(&SAs.MemMgr.Initialize),
35 recordProxy<sps::MemMgrReleaseProxySpec>(&SAs.MemMgr.Release),
36 recordAddr(rt::RegisterEHFrameSectionAllocActionName,
37 &SAs.RegisterEHFrame),
38 recordAddr(rt::DeregisterEHFrameSectionAllocActionName,
39 &SAs.DeregisterEHFrame)}))
40 return std::move(Err);
41 return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC, std::move(SAs));
46 : EPC(EPC), SAs(
std::
move(SAs)) {
47 LLVM_DEBUG(
dbgs() <<
"Created remote allocator " << (
void *)
this <<
"\n");
51 LLVM_DEBUG(
dbgs() <<
"Destroyed remote allocator " << (
void *)
this <<
"\n");
53 errs() <<
"Destroying with existing errors:\n" << ErrMsg <<
"\n";
56 if (
auto Err = SAs.MemMgr.Release(EPC.getExecutionSession(),
57 SAs.MemMgr.Instance, FinalizedAllocs))
64 std::lock_guard<std::mutex> Lock(M);
66 dbgs() <<
"Allocator " << (
void *)
this <<
" allocating code section "
68 <<
" bytes, alignment = " << Alignment <<
"\n";
70 auto &Seg = Unmapped.back().CodeAllocs;
71 Seg.emplace_back(
Size, Alignment);
72 return reinterpret_cast<uint8_t *
>(
79 std::lock_guard<std::mutex> Lock(M);
81 dbgs() <<
"Allocator " << (
void *)
this <<
" allocating "
82 << (IsReadOnly ?
"ro" :
"rw") <<
"-data section " <<
SectionName
83 <<
": size = " <<
formatv(
"{0:x}",
Size) <<
" bytes, alignment "
84 << Alignment <<
")\n";
88 IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs;
90 Seg.emplace_back(
Size, Alignment);
91 return reinterpret_cast<uint8_t *
>(
100 std::lock_guard<std::mutex> Lock(M);
105 if (CodeAlign > EPC.getPageSize()) {
106 ErrMsg =
"Invalid code alignment in reserveAllocationSpace";
109 if (RODataAlign > EPC.getPageSize()) {
110 ErrMsg =
"Invalid ro-data alignment in reserveAllocationSpace";
113 if (RWDataAlign > EPC.getPageSize()) {
114 ErrMsg =
"Invalid rw-data alignment in reserveAllocationSpace";
119 uint64_t TotalSize = 0;
121 TotalSize +=
alignTo(RODataSize, EPC.getPageSize());
122 TotalSize +=
alignTo(RWDataSize, EPC.getPageSize());
125 dbgs() <<
"Allocator " << (
void *)
this <<
" reserving "
126 <<
formatv(
"{0:x}", TotalSize) <<
" bytes.\n";
130 EPC.getExecutionSession(), SAs.MemMgr.Instance, TotalSize);
131 if (!TargetAllocAddr) {
132 std::lock_guard<std::mutex> Lock(M);
133 ErrMsg =
toString(TargetAllocAddr.takeError());
137 std::lock_guard<std::mutex> Lock(M);
138 Unmapped.push_back(SectionAllocGroup());
139 Unmapped.back().RemoteCode = {
141 Unmapped.back().RemoteROData = {
142 Unmapped.back().RemoteCode.End,
144 Unmapped.back().RemoteRWData = {
145 Unmapped.back().RemoteROData.End,
157 dbgs() <<
"Allocator " << (
void *)
this <<
" added unfinalized eh-frame "
158 <<
formatv(
"[ {0:x} {1:x} ]", LoadAddr, LoadAddr +
Size) <<
"\n";
160 std::lock_guard<std::mutex> Lock(M);
167 if (SecAllocGroup.RemoteCode.contains(LA) ||
168 SecAllocGroup.RemoteROData.contains(LA) ||
169 SecAllocGroup.RemoteRWData.contains(LA)) {
170 SecAllocGroup.UnfinalizedEHFrames.push_back({LA,
Size});
174 ErrMsg =
"eh-frame does not lie inside unfinalized alloc";
183 std::lock_guard<std::mutex> Lock(M);
184 LLVM_DEBUG(
dbgs() <<
"Allocator " << (
void *)
this <<
" applied mappings:\n");
185 for (
auto &ObjAllocs : Unmapped) {
186 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
187 ObjAllocs.RemoteCode.Start);
188 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
189 ObjAllocs.RemoteROData.Start);
190 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
191 ObjAllocs.RemoteRWData.Start);
192 Unfinalized.push_back(std::move(ObjAllocs));
198 LLVM_DEBUG(
dbgs() <<
"Allocator " << (
void *)
this <<
" finalizing:\n");
201 std::vector<SectionAllocGroup> SecAllocGroups;
203 std::lock_guard<std::mutex> Lock(M);
204 if (ErrMsg && !this->ErrMsg.empty()) {
205 *ErrMsg = std::move(this->ErrMsg);
212 for (
auto &SecAllocGroup : SecAllocGroups) {
218 &SecAllocGroup.RemoteROData,
219 &SecAllocGroup.RemoteRWData};
221 std::vector<SectionAlloc> *SegSections[3] = {&SecAllocGroup.CodeAllocs,
222 &SecAllocGroup.RODataAllocs,
223 &SecAllocGroup.RWDataAllocs};
226 std::unique_ptr<char[]> AggregateContents[3];
228 for (
unsigned I = 0;
I != 3; ++
I) {
231 Seg.RAG = SegMemProts[
I];
232 Seg.Addr = RemoteAddrs[
I]->
Start;
233 for (
auto &SecAlloc : *SegSections[
I]) {
234 Seg.Size =
alignTo(Seg.Size, SecAlloc.Align);
235 Seg.Size += SecAlloc.Size;
237 AggregateContents[
I] = std::make_unique<char[]>(Seg.Size);
238 size_t SecOffset = 0;
239 for (
auto &SecAlloc : *SegSections[
I]) {
240 SecOffset =
alignTo(SecOffset, SecAlloc.Align);
241 memcpy(&AggregateContents[
I][SecOffset],
242 reinterpret_cast<const char *
>(
245 SecOffset += SecAlloc.Size;
249 Seg.Content = {AggregateContents[
I].get(), SecOffset};
252 for (
auto &Frame : SecAllocGroup.UnfinalizedEHFrames)
256 SAs.RegisterEHFrame, Frame)),
259 SAs.DeregisterEHFrame, Frame))});
264 EPC.getExecutionSession(), SAs.MemMgr.Instance, std::move(FR));
265 if (!InitializeKey) {
266 std::lock_guard<std::mutex> Lock(M);
268 dbgs() <<
"Finalization error: " << this->ErrMsg <<
"\n";
270 *ErrMsg = this->ErrMsg;
278void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs(
279 RuntimeDyld &Dyld, std::vector<SectionAlloc> &Allocs,
281 for (
auto &
Alloc : Allocs) {
284 dbgs() <<
" " <<
static_cast<void *
>(
Alloc.Contents.get()) <<
" -> "
290 Alloc.RemoteAddr = NextAddr;
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.
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.
MemProt
Describes Read/Write/Exec permissions for memory.
LLVM_ABI void lookupAndApply(unique_function< void(Error)> OnApplied, LookupKind K, const JITDylibSearchOrder &SearchOrder, ArrayRef< LookupPrepareFn > PrepareFns)
Resolve the symbols contributed by every prepare function with a single lookup, then let each of thei...
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.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
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.
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.
Bindings to the executor-side memory manager, plus the EH-frame registration alloc-action wrappers.
Represents an address range in the exceutor process.
std::vector< SegFinalizeRequest > Segments
shared::AllocActions Actions