16498b0e9SLang Hames //===----- EPCGenericRTDyldMemoryManager.cpp - EPC-bbasde MemMgr -----===//
26498b0e9SLang Hames //
36498b0e9SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46498b0e9SLang Hames // See https://llvm.org/LICENSE.txt for license information.
56498b0e9SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66498b0e9SLang Hames //
76498b0e9SLang Hames //===----------------------------------------------------------------------===//
86498b0e9SLang Hames
96498b0e9SLang Hames #include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h"
106498b0e9SLang Hames #include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
116498b0e9SLang Hames #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
126498b0e9SLang Hames #include "llvm/Support/Alignment.h"
136498b0e9SLang Hames #include "llvm/Support/FormatVariadic.h"
146498b0e9SLang Hames
156498b0e9SLang Hames #define DEBUG_TYPE "orc"
166498b0e9SLang Hames
17*089acf25SLang Hames using namespace llvm::orc::shared;
18*089acf25SLang Hames
196498b0e9SLang Hames namespace llvm {
206498b0e9SLang Hames namespace orc {
216498b0e9SLang Hames
226498b0e9SLang Hames Expected<std::unique_ptr<EPCGenericRTDyldMemoryManager>>
CreateWithDefaultBootstrapSymbols(ExecutorProcessControl & EPC)236498b0e9SLang Hames EPCGenericRTDyldMemoryManager::CreateWithDefaultBootstrapSymbols(
246498b0e9SLang Hames ExecutorProcessControl &EPC) {
256498b0e9SLang Hames SymbolAddrs SAs;
266498b0e9SLang Hames if (auto Err = EPC.getBootstrapSymbols(
276498b0e9SLang Hames {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName},
286498b0e9SLang Hames {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
296498b0e9SLang Hames {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
306498b0e9SLang Hames {SAs.Deallocate,
316498b0e9SLang Hames rt::SimpleExecutorMemoryManagerDeallocateWrapperName},
32*089acf25SLang Hames {SAs.RegisterEHFrame, rt::RegisterEHFrameSectionWrapperName},
33*089acf25SLang Hames {SAs.DeregisterEHFrame, rt::DeregisterEHFrameSectionWrapperName}}))
346498b0e9SLang Hames return std::move(Err);
356498b0e9SLang Hames return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC, std::move(SAs));
366498b0e9SLang Hames }
376498b0e9SLang Hames
EPCGenericRTDyldMemoryManager(ExecutorProcessControl & EPC,SymbolAddrs SAs)386498b0e9SLang Hames EPCGenericRTDyldMemoryManager::EPCGenericRTDyldMemoryManager(
396498b0e9SLang Hames ExecutorProcessControl &EPC, SymbolAddrs SAs)
406498b0e9SLang Hames : EPC(EPC), SAs(std::move(SAs)) {
416498b0e9SLang Hames LLVM_DEBUG(dbgs() << "Created remote allocator " << (void *)this << "\n");
426498b0e9SLang Hames }
436498b0e9SLang Hames
~EPCGenericRTDyldMemoryManager()446498b0e9SLang Hames EPCGenericRTDyldMemoryManager::~EPCGenericRTDyldMemoryManager() {
456498b0e9SLang Hames LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << (void *)this << "\n");
466498b0e9SLang Hames if (!ErrMsg.empty())
476498b0e9SLang Hames errs() << "Destroying with existing errors:\n" << ErrMsg << "\n";
486498b0e9SLang Hames
496498b0e9SLang Hames Error Err = Error::success();
506498b0e9SLang Hames if (auto Err2 = EPC.callSPSWrapper<
516498b0e9SLang Hames rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>(
5221a06254SLang Hames SAs.Reserve, Err, SAs.Instance, FinalizedAllocs)) {
536498b0e9SLang Hames // FIXME: Report errors through EPC once that functionality is available.
546498b0e9SLang Hames logAllUnhandledErrors(std::move(Err2), errs(), "");
556498b0e9SLang Hames return;
566498b0e9SLang Hames }
576498b0e9SLang Hames
586498b0e9SLang Hames if (Err)
596498b0e9SLang Hames logAllUnhandledErrors(std::move(Err), errs(), "");
606498b0e9SLang Hames }
616498b0e9SLang Hames
allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)626498b0e9SLang Hames uint8_t *EPCGenericRTDyldMemoryManager::allocateCodeSection(
636498b0e9SLang Hames uintptr_t Size, unsigned Alignment, unsigned SectionID,
646498b0e9SLang Hames StringRef SectionName) {
656498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
666498b0e9SLang Hames LLVM_DEBUG({
676498b0e9SLang Hames dbgs() << "Allocator " << (void *)this << " allocating code section "
686498b0e9SLang Hames << SectionName << ": size = " << formatv("{0:x}", Size)
696498b0e9SLang Hames << " bytes, alignment = " << Alignment << "\n";
706498b0e9SLang Hames });
716498b0e9SLang Hames auto &Seg = Unmapped.back().CodeAllocs;
726498b0e9SLang Hames Seg.emplace_back(Size, Alignment);
736498b0e9SLang Hames return reinterpret_cast<uint8_t *>(
746498b0e9SLang Hames alignAddr(Seg.back().Contents.get(), Align(Alignment)));
756498b0e9SLang Hames }
766498b0e9SLang Hames
allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool IsReadOnly)776498b0e9SLang Hames uint8_t *EPCGenericRTDyldMemoryManager::allocateDataSection(
786498b0e9SLang Hames uintptr_t Size, unsigned Alignment, unsigned SectionID,
796498b0e9SLang Hames StringRef SectionName, bool IsReadOnly) {
806498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
816498b0e9SLang Hames LLVM_DEBUG({
826498b0e9SLang Hames dbgs() << "Allocator " << (void *)this << " allocating "
836498b0e9SLang Hames << (IsReadOnly ? "ro" : "rw") << "-data section " << SectionName
846498b0e9SLang Hames << ": size = " << formatv("{0:x}", Size) << " bytes, alignment "
856498b0e9SLang Hames << Alignment << ")\n";
866498b0e9SLang Hames });
876498b0e9SLang Hames
886498b0e9SLang Hames auto &Seg =
896498b0e9SLang Hames IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs;
906498b0e9SLang Hames
916498b0e9SLang Hames Seg.emplace_back(Size, Alignment);
926498b0e9SLang Hames return reinterpret_cast<uint8_t *>(
936498b0e9SLang Hames alignAddr(Seg.back().Contents.get(), Align(Alignment)));
946498b0e9SLang Hames }
956498b0e9SLang Hames
reserveAllocationSpace(uintptr_t CodeSize,uint32_t CodeAlign,uintptr_t RODataSize,uint32_t RODataAlign,uintptr_t RWDataSize,uint32_t RWDataAlign)966498b0e9SLang Hames void EPCGenericRTDyldMemoryManager::reserveAllocationSpace(
976498b0e9SLang Hames uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize,
986498b0e9SLang Hames uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) {
996498b0e9SLang Hames
1006498b0e9SLang Hames {
1016498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
1026498b0e9SLang Hames // If there's already an error then bail out.
1036498b0e9SLang Hames if (!ErrMsg.empty())
1046498b0e9SLang Hames return;
1056498b0e9SLang Hames
1066498b0e9SLang Hames if (!isPowerOf2_32(CodeAlign) || CodeAlign > EPC.getPageSize()) {
1076498b0e9SLang Hames ErrMsg = "Invalid code alignment in reserveAllocationSpace";
1086498b0e9SLang Hames return;
1096498b0e9SLang Hames }
1106498b0e9SLang Hames if (!isPowerOf2_32(RODataAlign) || RODataAlign > EPC.getPageSize()) {
1116498b0e9SLang Hames ErrMsg = "Invalid ro-data alignment in reserveAllocationSpace";
1126498b0e9SLang Hames return;
1136498b0e9SLang Hames }
1146498b0e9SLang Hames if (!isPowerOf2_32(RWDataAlign) || RWDataAlign > EPC.getPageSize()) {
1156498b0e9SLang Hames ErrMsg = "Invalid rw-data alignment in reserveAllocationSpace";
1166498b0e9SLang Hames return;
1176498b0e9SLang Hames }
1186498b0e9SLang Hames }
1196498b0e9SLang Hames
1206498b0e9SLang Hames uint64_t TotalSize = 0;
1216498b0e9SLang Hames TotalSize += alignTo(CodeSize, EPC.getPageSize());
1226498b0e9SLang Hames TotalSize += alignTo(RODataSize, EPC.getPageSize());
1236498b0e9SLang Hames TotalSize += alignTo(RWDataSize, EPC.getPageSize());
1246498b0e9SLang Hames
1256498b0e9SLang Hames LLVM_DEBUG({
1266498b0e9SLang Hames dbgs() << "Allocator " << (void *)this << " reserving "
1276498b0e9SLang Hames << formatv("{0:x}", TotalSize) << " bytes.\n";
1286498b0e9SLang Hames });
1296498b0e9SLang Hames
1306498b0e9SLang Hames Expected<ExecutorAddr> TargetAllocAddr((ExecutorAddr()));
1316498b0e9SLang Hames if (auto Err = EPC.callSPSWrapper<
1326498b0e9SLang Hames rt::SPSSimpleExecutorMemoryManagerReserveSignature>(
13321a06254SLang Hames SAs.Reserve, TargetAllocAddr, SAs.Instance, TotalSize)) {
1346498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
1356498b0e9SLang Hames ErrMsg = toString(std::move(Err));
1366498b0e9SLang Hames return;
1376498b0e9SLang Hames }
1386498b0e9SLang Hames if (!TargetAllocAddr) {
1396498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
1406498b0e9SLang Hames ErrMsg = toString(TargetAllocAddr.takeError());
1416498b0e9SLang Hames return;
1426498b0e9SLang Hames }
1436498b0e9SLang Hames
1446498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
1456498b0e9SLang Hames Unmapped.push_back(AllocGroup());
1466498b0e9SLang Hames Unmapped.back().RemoteCode = {
1476498b0e9SLang Hames *TargetAllocAddr, ExecutorAddrDiff(alignTo(CodeSize, EPC.getPageSize()))};
1486498b0e9SLang Hames Unmapped.back().RemoteROData = {
1496498b0e9SLang Hames Unmapped.back().RemoteCode.End,
1506498b0e9SLang Hames ExecutorAddrDiff(alignTo(RODataSize, EPC.getPageSize()))};
1516498b0e9SLang Hames Unmapped.back().RemoteRWData = {
1526498b0e9SLang Hames Unmapped.back().RemoteROData.End,
1536498b0e9SLang Hames ExecutorAddrDiff(alignTo(RWDataSize, EPC.getPageSize()))};
1546498b0e9SLang Hames }
1556498b0e9SLang Hames
needsToReserveAllocationSpace()1566498b0e9SLang Hames bool EPCGenericRTDyldMemoryManager::needsToReserveAllocationSpace() {
1576498b0e9SLang Hames return true;
1586498b0e9SLang Hames }
1596498b0e9SLang Hames
registerEHFrames(uint8_t * Addr,uint64_t LoadAddr,size_t Size)1606498b0e9SLang Hames void EPCGenericRTDyldMemoryManager::registerEHFrames(uint8_t *Addr,
1616498b0e9SLang Hames uint64_t LoadAddr,
1626498b0e9SLang Hames size_t Size) {
1636498b0e9SLang Hames LLVM_DEBUG({
1646498b0e9SLang Hames dbgs() << "Allocator " << (void *)this << " added unfinalized eh-frame "
1656498b0e9SLang Hames << formatv("[ {0:x} {1:x} ]", LoadAddr, LoadAddr + Size) << "\n";
1666498b0e9SLang Hames });
1676498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
1686498b0e9SLang Hames // Bail out early if there's already an error.
1696498b0e9SLang Hames if (!ErrMsg.empty())
1706498b0e9SLang Hames return;
1716498b0e9SLang Hames
1726498b0e9SLang Hames ExecutorAddr LA(LoadAddr);
1736498b0e9SLang Hames for (auto &Alloc : llvm::reverse(Unfinalized)) {
1746498b0e9SLang Hames if (Alloc.RemoteCode.contains(LA) || Alloc.RemoteROData.contains(LA) ||
1756498b0e9SLang Hames Alloc.RemoteRWData.contains(LA)) {
1766498b0e9SLang Hames Alloc.UnfinalizedEHFrames.push_back({LA, Size});
1776498b0e9SLang Hames return;
1786498b0e9SLang Hames }
1796498b0e9SLang Hames }
1806498b0e9SLang Hames ErrMsg = "eh-frame does not lie inside unfinalized alloc";
1816498b0e9SLang Hames }
1826498b0e9SLang Hames
deregisterEHFrames()1836498b0e9SLang Hames void EPCGenericRTDyldMemoryManager::deregisterEHFrames() {
1846498b0e9SLang Hames // This is a no-op for us: We've registered a deallocation action for it.
1856498b0e9SLang Hames }
1866498b0e9SLang Hames
notifyObjectLoaded(RuntimeDyld & Dyld,const object::ObjectFile & Obj)1876498b0e9SLang Hames void EPCGenericRTDyldMemoryManager::notifyObjectLoaded(
1886498b0e9SLang Hames RuntimeDyld &Dyld, const object::ObjectFile &Obj) {
1896498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
1906498b0e9SLang Hames LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " applied mappings:\n");
1916498b0e9SLang Hames for (auto &ObjAllocs : Unmapped) {
1926498b0e9SLang Hames mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
1936498b0e9SLang Hames ObjAllocs.RemoteCode.Start);
1946498b0e9SLang Hames mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
1956498b0e9SLang Hames ObjAllocs.RemoteROData.Start);
1966498b0e9SLang Hames mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
1976498b0e9SLang Hames ObjAllocs.RemoteRWData.Start);
1986498b0e9SLang Hames Unfinalized.push_back(std::move(ObjAllocs));
1996498b0e9SLang Hames }
2006498b0e9SLang Hames Unmapped.clear();
2016498b0e9SLang Hames }
2026498b0e9SLang Hames
finalizeMemory(std::string * ErrMsg)2036498b0e9SLang Hames bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) {
2046498b0e9SLang Hames LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " finalizing:\n");
2056498b0e9SLang Hames
2066498b0e9SLang Hames // If there's an error then bail out here.
2076498b0e9SLang Hames std::vector<AllocGroup> Allocs;
2086498b0e9SLang Hames {
2096498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
2106498b0e9SLang Hames if (ErrMsg && !this->ErrMsg.empty()) {
2116498b0e9SLang Hames *ErrMsg = std::move(this->ErrMsg);
2126498b0e9SLang Hames return true;
2136498b0e9SLang Hames }
2146498b0e9SLang Hames std::swap(Allocs, Unfinalized);
2156498b0e9SLang Hames }
2166498b0e9SLang Hames
2176498b0e9SLang Hames // Loop over unfinalized objects to make finalization requests.
2186498b0e9SLang Hames for (auto &ObjAllocs : Allocs) {
2196498b0e9SLang Hames
2206498b0e9SLang Hames tpctypes::WireProtectionFlags SegProts[3] = {
2216498b0e9SLang Hames tpctypes::toWireProtectionFlags(
2226498b0e9SLang Hames static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
2236498b0e9SLang Hames sys::Memory::MF_EXEC)),
2246498b0e9SLang Hames tpctypes::toWireProtectionFlags(sys::Memory::MF_READ),
2256498b0e9SLang Hames tpctypes::toWireProtectionFlags(
2266498b0e9SLang Hames static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
2276498b0e9SLang Hames sys::Memory::MF_WRITE))};
2286498b0e9SLang Hames
2296498b0e9SLang Hames ExecutorAddrRange *RemoteAddrs[3] = {&ObjAllocs.RemoteCode,
2306498b0e9SLang Hames &ObjAllocs.RemoteROData,
2316498b0e9SLang Hames &ObjAllocs.RemoteRWData};
2326498b0e9SLang Hames
2336498b0e9SLang Hames std::vector<Alloc> *SegSections[3] = {&ObjAllocs.CodeAllocs,
2346498b0e9SLang Hames &ObjAllocs.RODataAllocs,
2356498b0e9SLang Hames &ObjAllocs.RWDataAllocs};
2366498b0e9SLang Hames
2376498b0e9SLang Hames tpctypes::FinalizeRequest FR;
2386498b0e9SLang Hames std::unique_ptr<char[]> AggregateContents[3];
2396498b0e9SLang Hames
2406498b0e9SLang Hames for (unsigned I = 0; I != 3; ++I) {
2416498b0e9SLang Hames FR.Segments.push_back({});
2426498b0e9SLang Hames auto &Seg = FR.Segments.back();
2436498b0e9SLang Hames Seg.Prot = SegProts[I];
2446498b0e9SLang Hames Seg.Addr = RemoteAddrs[I]->Start;
2456498b0e9SLang Hames for (auto &SecAlloc : *SegSections[I]) {
2466498b0e9SLang Hames Seg.Size = alignTo(Seg.Size, SecAlloc.Align);
2476498b0e9SLang Hames Seg.Size += SecAlloc.Size;
2486498b0e9SLang Hames }
2496498b0e9SLang Hames AggregateContents[I] = std::make_unique<char[]>(Seg.Size);
2506498b0e9SLang Hames size_t SecOffset = 0;
2516498b0e9SLang Hames for (auto &SecAlloc : *SegSections[I]) {
2526498b0e9SLang Hames SecOffset = alignTo(SecOffset, SecAlloc.Align);
2536498b0e9SLang Hames memcpy(&AggregateContents[I][SecOffset],
2546498b0e9SLang Hames reinterpret_cast<const char *>(
2556498b0e9SLang Hames alignAddr(SecAlloc.Contents.get(), Align(SecAlloc.Align))),
2566498b0e9SLang Hames SecAlloc.Size);
2576498b0e9SLang Hames SecOffset += SecAlloc.Size;
2586498b0e9SLang Hames // FIXME: Can we reset SecAlloc.Content here, now that it's copied into
2596498b0e9SLang Hames // the aggregated content?
2606498b0e9SLang Hames }
2616498b0e9SLang Hames Seg.Content = {AggregateContents[I].get(), SecOffset};
2626498b0e9SLang Hames }
2636498b0e9SLang Hames
2646498b0e9SLang Hames for (auto &Frame : ObjAllocs.UnfinalizedEHFrames)
265999c6a23SLang Hames FR.Actions.push_back(
266*089acf25SLang Hames {cantFail(
267*089acf25SLang Hames WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
268*089acf25SLang Hames SAs.RegisterEHFrame, Frame)),
269*089acf25SLang Hames cantFail(
270*089acf25SLang Hames WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
271*089acf25SLang Hames SAs.DeregisterEHFrame, Frame))});
2726498b0e9SLang Hames
2736498b0e9SLang Hames // We'll also need to make an extra allocation for the eh-frame wrapper call
2746498b0e9SLang Hames // arguments.
2756498b0e9SLang Hames Error FinalizeErr = Error::success();
2766498b0e9SLang Hames if (auto Err = EPC.callSPSWrapper<
2776498b0e9SLang Hames rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>(
27821a06254SLang Hames SAs.Finalize, FinalizeErr, SAs.Instance, std::move(FR))) {
2796498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
2806498b0e9SLang Hames this->ErrMsg = toString(std::move(Err));
2816498b0e9SLang Hames dbgs() << "Serialization error: " << this->ErrMsg << "\n";
2826498b0e9SLang Hames if (ErrMsg)
2836498b0e9SLang Hames *ErrMsg = this->ErrMsg;
2846498b0e9SLang Hames return true;
2856498b0e9SLang Hames }
2866498b0e9SLang Hames if (FinalizeErr) {
2876498b0e9SLang Hames std::lock_guard<std::mutex> Lock(M);
2886498b0e9SLang Hames this->ErrMsg = toString(std::move(FinalizeErr));
2896498b0e9SLang Hames dbgs() << "Finalization error: " << this->ErrMsg << "\n";
2906498b0e9SLang Hames if (ErrMsg)
2916498b0e9SLang Hames *ErrMsg = this->ErrMsg;
2926498b0e9SLang Hames return true;
2936498b0e9SLang Hames }
2946498b0e9SLang Hames }
2956498b0e9SLang Hames
2966498b0e9SLang Hames return false;
2976498b0e9SLang Hames }
2986498b0e9SLang Hames
mapAllocsToRemoteAddrs(RuntimeDyld & Dyld,std::vector<Alloc> & Allocs,ExecutorAddr NextAddr)2996498b0e9SLang Hames void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs(
3006498b0e9SLang Hames RuntimeDyld &Dyld, std::vector<Alloc> &Allocs, ExecutorAddr NextAddr) {
3016498b0e9SLang Hames for (auto &Alloc : Allocs) {
3026498b0e9SLang Hames NextAddr.setValue(alignTo(NextAddr.getValue(), Alloc.Align));
3036498b0e9SLang Hames LLVM_DEBUG({
3046498b0e9SLang Hames dbgs() << " " << static_cast<void *>(Alloc.Contents.get()) << " -> "
3056498b0e9SLang Hames << format("0x%016" PRIx64, NextAddr.getValue()) << "\n";
3066498b0e9SLang Hames });
3076498b0e9SLang Hames Dyld.mapSectionAddress(reinterpret_cast<const void *>(alignAddr(
3086498b0e9SLang Hames Alloc.Contents.get(), Align(Alloc.Align))),
3096498b0e9SLang Hames NextAddr.getValue());
3106498b0e9SLang Hames Alloc.RemoteAddr = NextAddr;
3116498b0e9SLang Hames // Only advance NextAddr if it was non-null to begin with,
3126498b0e9SLang Hames // otherwise leave it as null.
3136498b0e9SLang Hames if (NextAddr)
3146498b0e9SLang Hames NextAddr += ExecutorAddrDiff(Alloc.Size);
3156498b0e9SLang Hames }
3166498b0e9SLang Hames }
3176498b0e9SLang Hames
3186498b0e9SLang Hames } // end namespace orc
3196498b0e9SLang Hames } // end namespace llvm
320