xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.cpp (revision 1f4d91ecb8529678a3d3919d7523743bd21942ca)
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/Shared/OrcRTBridge.h"
116498b0e9SLang Hames #include "llvm/Support/Alignment.h"
126498b0e9SLang Hames #include "llvm/Support/FormatVariadic.h"
136498b0e9SLang Hames 
146498b0e9SLang Hames #define DEBUG_TYPE "orc"
156498b0e9SLang Hames 
16089acf25SLang Hames using namespace llvm::orc::shared;
17089acf25SLang Hames 
186498b0e9SLang Hames namespace llvm {
196498b0e9SLang Hames namespace orc {
206498b0e9SLang Hames 
216498b0e9SLang Hames Expected<std::unique_ptr<EPCGenericRTDyldMemoryManager>>
226498b0e9SLang Hames EPCGenericRTDyldMemoryManager::CreateWithDefaultBootstrapSymbols(
236498b0e9SLang Hames     ExecutorProcessControl &EPC) {
246498b0e9SLang Hames   SymbolAddrs SAs;
256498b0e9SLang Hames   if (auto Err = EPC.getBootstrapSymbols(
266498b0e9SLang Hames           {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName},
276498b0e9SLang Hames            {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
286498b0e9SLang Hames            {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
296498b0e9SLang Hames            {SAs.Deallocate,
306498b0e9SLang Hames             rt::SimpleExecutorMemoryManagerDeallocateWrapperName},
31089acf25SLang Hames            {SAs.RegisterEHFrame, rt::RegisterEHFrameSectionWrapperName},
32089acf25SLang Hames            {SAs.DeregisterEHFrame, rt::DeregisterEHFrameSectionWrapperName}}))
336498b0e9SLang Hames     return std::move(Err);
346498b0e9SLang Hames   return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC, std::move(SAs));
356498b0e9SLang Hames }
366498b0e9SLang Hames 
376498b0e9SLang Hames EPCGenericRTDyldMemoryManager::EPCGenericRTDyldMemoryManager(
386498b0e9SLang Hames     ExecutorProcessControl &EPC, SymbolAddrs SAs)
396498b0e9SLang Hames     : EPC(EPC), SAs(std::move(SAs)) {
406498b0e9SLang Hames   LLVM_DEBUG(dbgs() << "Created remote allocator " << (void *)this << "\n");
416498b0e9SLang Hames }
426498b0e9SLang Hames 
436498b0e9SLang Hames EPCGenericRTDyldMemoryManager::~EPCGenericRTDyldMemoryManager() {
446498b0e9SLang Hames   LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << (void *)this << "\n");
456498b0e9SLang Hames   if (!ErrMsg.empty())
466498b0e9SLang Hames     errs() << "Destroying with existing errors:\n" << ErrMsg << "\n";
476498b0e9SLang Hames 
486498b0e9SLang Hames   Error Err = Error::success();
496498b0e9SLang Hames   if (auto Err2 = EPC.callSPSWrapper<
506498b0e9SLang Hames                   rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>(
5121a06254SLang Hames           SAs.Reserve, Err, SAs.Instance, FinalizedAllocs)) {
526498b0e9SLang Hames     // FIXME: Report errors through EPC once that functionality is available.
536498b0e9SLang Hames     logAllUnhandledErrors(std::move(Err2), errs(), "");
546498b0e9SLang Hames     return;
556498b0e9SLang Hames   }
566498b0e9SLang Hames 
576498b0e9SLang Hames   if (Err)
586498b0e9SLang Hames     logAllUnhandledErrors(std::move(Err), errs(), "");
596498b0e9SLang Hames }
606498b0e9SLang Hames 
616498b0e9SLang Hames uint8_t *EPCGenericRTDyldMemoryManager::allocateCodeSection(
626498b0e9SLang Hames     uintptr_t Size, unsigned Alignment, unsigned SectionID,
636498b0e9SLang Hames     StringRef SectionName) {
646498b0e9SLang Hames   std::lock_guard<std::mutex> Lock(M);
656498b0e9SLang Hames   LLVM_DEBUG({
666498b0e9SLang Hames     dbgs() << "Allocator " << (void *)this << " allocating code section "
676498b0e9SLang Hames            << SectionName << ": size = " << formatv("{0:x}", Size)
686498b0e9SLang Hames            << " bytes, alignment = " << Alignment << "\n";
696498b0e9SLang Hames   });
706498b0e9SLang Hames   auto &Seg = Unmapped.back().CodeAllocs;
716498b0e9SLang Hames   Seg.emplace_back(Size, Alignment);
726498b0e9SLang Hames   return reinterpret_cast<uint8_t *>(
736498b0e9SLang Hames       alignAddr(Seg.back().Contents.get(), Align(Alignment)));
746498b0e9SLang Hames }
756498b0e9SLang Hames 
766498b0e9SLang Hames uint8_t *EPCGenericRTDyldMemoryManager::allocateDataSection(
776498b0e9SLang Hames     uintptr_t Size, unsigned Alignment, unsigned SectionID,
786498b0e9SLang Hames     StringRef SectionName, bool IsReadOnly) {
796498b0e9SLang Hames   std::lock_guard<std::mutex> Lock(M);
806498b0e9SLang Hames   LLVM_DEBUG({
816498b0e9SLang Hames     dbgs() << "Allocator " << (void *)this << " allocating "
826498b0e9SLang Hames            << (IsReadOnly ? "ro" : "rw") << "-data section " << SectionName
836498b0e9SLang Hames            << ": size = " << formatv("{0:x}", Size) << " bytes, alignment "
846498b0e9SLang Hames            << Alignment << ")\n";
856498b0e9SLang Hames   });
866498b0e9SLang Hames 
876498b0e9SLang Hames   auto &Seg =
886498b0e9SLang Hames       IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs;
896498b0e9SLang Hames 
906498b0e9SLang Hames   Seg.emplace_back(Size, Alignment);
916498b0e9SLang Hames   return reinterpret_cast<uint8_t *>(
926498b0e9SLang Hames       alignAddr(Seg.back().Contents.get(), Align(Alignment)));
936498b0e9SLang Hames }
946498b0e9SLang Hames 
956498b0e9SLang Hames void EPCGenericRTDyldMemoryManager::reserveAllocationSpace(
96828ce42aSGuillaume Chatelet     uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize,
97828ce42aSGuillaume Chatelet     Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) {
986498b0e9SLang Hames 
996498b0e9SLang Hames   {
1006498b0e9SLang Hames     std::lock_guard<std::mutex> Lock(M);
1016498b0e9SLang Hames     // If there's already an error then bail out.
1026498b0e9SLang Hames     if (!ErrMsg.empty())
1036498b0e9SLang Hames       return;
1046498b0e9SLang Hames 
105828ce42aSGuillaume Chatelet     if (CodeAlign > EPC.getPageSize()) {
1066498b0e9SLang Hames       ErrMsg = "Invalid code alignment in reserveAllocationSpace";
1076498b0e9SLang Hames       return;
1086498b0e9SLang Hames     }
109828ce42aSGuillaume Chatelet     if (RODataAlign > EPC.getPageSize()) {
1106498b0e9SLang Hames       ErrMsg = "Invalid ro-data alignment in reserveAllocationSpace";
1116498b0e9SLang Hames       return;
1126498b0e9SLang Hames     }
113828ce42aSGuillaume Chatelet     if (RWDataAlign > EPC.getPageSize()) {
1146498b0e9SLang Hames       ErrMsg = "Invalid rw-data alignment in reserveAllocationSpace";
1156498b0e9SLang Hames       return;
1166498b0e9SLang Hames     }
1176498b0e9SLang Hames   }
1186498b0e9SLang Hames 
1196498b0e9SLang Hames   uint64_t TotalSize = 0;
1206498b0e9SLang Hames   TotalSize += alignTo(CodeSize, EPC.getPageSize());
1216498b0e9SLang Hames   TotalSize += alignTo(RODataSize, EPC.getPageSize());
1226498b0e9SLang Hames   TotalSize += alignTo(RWDataSize, EPC.getPageSize());
1236498b0e9SLang Hames 
1246498b0e9SLang Hames   LLVM_DEBUG({
1256498b0e9SLang Hames     dbgs() << "Allocator " << (void *)this << " reserving "
1266498b0e9SLang Hames            << formatv("{0:x}", TotalSize) << " bytes.\n";
1276498b0e9SLang Hames   });
1286498b0e9SLang Hames 
1296498b0e9SLang Hames   Expected<ExecutorAddr> TargetAllocAddr((ExecutorAddr()));
1306498b0e9SLang Hames   if (auto Err = EPC.callSPSWrapper<
1316498b0e9SLang Hames                  rt::SPSSimpleExecutorMemoryManagerReserveSignature>(
13221a06254SLang Hames           SAs.Reserve, TargetAllocAddr, SAs.Instance, TotalSize)) {
1336498b0e9SLang Hames     std::lock_guard<std::mutex> Lock(M);
1346498b0e9SLang Hames     ErrMsg = toString(std::move(Err));
1356498b0e9SLang Hames     return;
1366498b0e9SLang Hames   }
1376498b0e9SLang Hames   if (!TargetAllocAddr) {
1386498b0e9SLang Hames     std::lock_guard<std::mutex> Lock(M);
1396498b0e9SLang Hames     ErrMsg = toString(TargetAllocAddr.takeError());
1406498b0e9SLang Hames     return;
1416498b0e9SLang Hames   }
1426498b0e9SLang Hames 
1436498b0e9SLang Hames   std::lock_guard<std::mutex> Lock(M);
144d3d9f7caSLang Hames   Unmapped.push_back(SectionAllocGroup());
1456498b0e9SLang Hames   Unmapped.back().RemoteCode = {
1466498b0e9SLang Hames       *TargetAllocAddr, ExecutorAddrDiff(alignTo(CodeSize, EPC.getPageSize()))};
1476498b0e9SLang Hames   Unmapped.back().RemoteROData = {
1486498b0e9SLang Hames       Unmapped.back().RemoteCode.End,
1496498b0e9SLang Hames       ExecutorAddrDiff(alignTo(RODataSize, EPC.getPageSize()))};
1506498b0e9SLang Hames   Unmapped.back().RemoteRWData = {
1516498b0e9SLang Hames       Unmapped.back().RemoteROData.End,
1526498b0e9SLang Hames       ExecutorAddrDiff(alignTo(RWDataSize, EPC.getPageSize()))};
1536498b0e9SLang Hames }
1546498b0e9SLang Hames 
1556498b0e9SLang Hames bool EPCGenericRTDyldMemoryManager::needsToReserveAllocationSpace() {
1566498b0e9SLang Hames   return true;
1576498b0e9SLang Hames }
1586498b0e9SLang Hames 
1596498b0e9SLang Hames void EPCGenericRTDyldMemoryManager::registerEHFrames(uint8_t *Addr,
1606498b0e9SLang Hames                                                      uint64_t LoadAddr,
1616498b0e9SLang Hames                                                      size_t Size) {
1626498b0e9SLang Hames   LLVM_DEBUG({
1636498b0e9SLang Hames     dbgs() << "Allocator " << (void *)this << " added unfinalized eh-frame "
1646498b0e9SLang Hames            << formatv("[ {0:x} {1:x} ]", LoadAddr, LoadAddr + Size) << "\n";
1656498b0e9SLang Hames   });
1666498b0e9SLang Hames   std::lock_guard<std::mutex> Lock(M);
1676498b0e9SLang Hames   // Bail out early if there's already an error.
1686498b0e9SLang Hames   if (!ErrMsg.empty())
1696498b0e9SLang Hames     return;
1706498b0e9SLang Hames 
1716498b0e9SLang Hames   ExecutorAddr LA(LoadAddr);
172d3d9f7caSLang Hames   for (auto &SecAllocGroup : llvm::reverse(Unfinalized)) {
173d3d9f7caSLang Hames     if (SecAllocGroup.RemoteCode.contains(LA) ||
174d3d9f7caSLang Hames         SecAllocGroup.RemoteROData.contains(LA) ||
175d3d9f7caSLang Hames         SecAllocGroup.RemoteRWData.contains(LA)) {
176d3d9f7caSLang Hames       SecAllocGroup.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 
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 
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 
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.
207d3d9f7caSLang Hames   std::vector<SectionAllocGroup> SecAllocGroups;
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     }
214d3d9f7caSLang Hames     std::swap(SecAllocGroups, Unfinalized);
2156498b0e9SLang Hames   }
2166498b0e9SLang Hames 
2176498b0e9SLang Hames   // Loop over unfinalized objects to make finalization requests.
218d3d9f7caSLang Hames   for (auto &SecAllocGroup : SecAllocGroups) {
2196498b0e9SLang Hames 
220d3d9f7caSLang Hames     MemProt SegMemProts[3] = {MemProt::Read | MemProt::Exec, MemProt::Read,
221d3d9f7caSLang Hames                               MemProt::Read | MemProt::Write};
2226498b0e9SLang Hames 
223d3d9f7caSLang Hames     ExecutorAddrRange *RemoteAddrs[3] = {&SecAllocGroup.RemoteCode,
224d3d9f7caSLang Hames                                          &SecAllocGroup.RemoteROData,
225d3d9f7caSLang Hames                                          &SecAllocGroup.RemoteRWData};
2266498b0e9SLang Hames 
227d3d9f7caSLang Hames     std::vector<SectionAlloc> *SegSections[3] = {&SecAllocGroup.CodeAllocs,
228d3d9f7caSLang Hames                                                  &SecAllocGroup.RODataAllocs,
229d3d9f7caSLang Hames                                                  &SecAllocGroup.RWDataAllocs};
2306498b0e9SLang Hames 
2316498b0e9SLang Hames     tpctypes::FinalizeRequest FR;
2326498b0e9SLang Hames     std::unique_ptr<char[]> AggregateContents[3];
2336498b0e9SLang Hames 
2346498b0e9SLang Hames     for (unsigned I = 0; I != 3; ++I) {
2356498b0e9SLang Hames       FR.Segments.push_back({});
2366498b0e9SLang Hames       auto &Seg = FR.Segments.back();
237*0b7e16afSLang Hames       Seg.RAG = SegMemProts[I];
2386498b0e9SLang Hames       Seg.Addr = RemoteAddrs[I]->Start;
2396498b0e9SLang Hames       for (auto &SecAlloc : *SegSections[I]) {
2406498b0e9SLang Hames         Seg.Size = alignTo(Seg.Size, SecAlloc.Align);
2416498b0e9SLang Hames         Seg.Size += SecAlloc.Size;
2426498b0e9SLang Hames       }
2436498b0e9SLang Hames       AggregateContents[I] = std::make_unique<char[]>(Seg.Size);
2446498b0e9SLang Hames       size_t SecOffset = 0;
2456498b0e9SLang Hames       for (auto &SecAlloc : *SegSections[I]) {
2466498b0e9SLang Hames         SecOffset = alignTo(SecOffset, SecAlloc.Align);
2476498b0e9SLang Hames         memcpy(&AggregateContents[I][SecOffset],
2486498b0e9SLang Hames                reinterpret_cast<const char *>(
2496498b0e9SLang Hames                    alignAddr(SecAlloc.Contents.get(), Align(SecAlloc.Align))),
2506498b0e9SLang Hames                SecAlloc.Size);
2516498b0e9SLang Hames         SecOffset += SecAlloc.Size;
2526498b0e9SLang Hames         // FIXME: Can we reset SecAlloc.Content here, now that it's copied into
2536498b0e9SLang Hames         // the aggregated content?
2546498b0e9SLang Hames       }
2556498b0e9SLang Hames       Seg.Content = {AggregateContents[I].get(), SecOffset};
2566498b0e9SLang Hames     }
2576498b0e9SLang Hames 
258d3d9f7caSLang Hames     for (auto &Frame : SecAllocGroup.UnfinalizedEHFrames)
259999c6a23SLang Hames       FR.Actions.push_back(
260089acf25SLang Hames           {cantFail(
261089acf25SLang Hames                WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
262089acf25SLang Hames                    SAs.RegisterEHFrame, Frame)),
263089acf25SLang Hames            cantFail(
264089acf25SLang Hames                WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
265089acf25SLang Hames                    SAs.DeregisterEHFrame, Frame))});
2666498b0e9SLang Hames 
2676498b0e9SLang Hames     // We'll also need to make an extra allocation for the eh-frame wrapper call
2686498b0e9SLang Hames     // arguments.
2696498b0e9SLang Hames     Error FinalizeErr = Error::success();
2706498b0e9SLang Hames     if (auto Err = EPC.callSPSWrapper<
2716498b0e9SLang Hames                    rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>(
27221a06254SLang Hames             SAs.Finalize, FinalizeErr, SAs.Instance, std::move(FR))) {
2736498b0e9SLang Hames       std::lock_guard<std::mutex> Lock(M);
2746498b0e9SLang Hames       this->ErrMsg = toString(std::move(Err));
2756498b0e9SLang Hames       dbgs() << "Serialization error: " << this->ErrMsg << "\n";
2766498b0e9SLang Hames       if (ErrMsg)
2776498b0e9SLang Hames         *ErrMsg = this->ErrMsg;
2786498b0e9SLang Hames       return true;
2796498b0e9SLang Hames     }
2806498b0e9SLang Hames     if (FinalizeErr) {
2816498b0e9SLang Hames       std::lock_guard<std::mutex> Lock(M);
2826498b0e9SLang Hames       this->ErrMsg = toString(std::move(FinalizeErr));
2836498b0e9SLang Hames       dbgs() << "Finalization error: " << this->ErrMsg << "\n";
2846498b0e9SLang Hames       if (ErrMsg)
2856498b0e9SLang Hames         *ErrMsg = this->ErrMsg;
2866498b0e9SLang Hames       return true;
2876498b0e9SLang Hames     }
2886498b0e9SLang Hames   }
2896498b0e9SLang Hames 
2906498b0e9SLang Hames   return false;
2916498b0e9SLang Hames }
2926498b0e9SLang Hames 
2936498b0e9SLang Hames void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs(
294d3d9f7caSLang Hames     RuntimeDyld &Dyld, std::vector<SectionAlloc> &Allocs,
295d3d9f7caSLang Hames     ExecutorAddr NextAddr) {
2966498b0e9SLang Hames   for (auto &Alloc : Allocs) {
2976498b0e9SLang Hames     NextAddr.setValue(alignTo(NextAddr.getValue(), Alloc.Align));
2986498b0e9SLang Hames     LLVM_DEBUG({
2996498b0e9SLang Hames       dbgs() << "     " << static_cast<void *>(Alloc.Contents.get()) << " -> "
3006498b0e9SLang Hames              << format("0x%016" PRIx64, NextAddr.getValue()) << "\n";
3016498b0e9SLang Hames     });
3026498b0e9SLang Hames     Dyld.mapSectionAddress(reinterpret_cast<const void *>(alignAddr(
3036498b0e9SLang Hames                                Alloc.Contents.get(), Align(Alloc.Align))),
3046498b0e9SLang Hames                            NextAddr.getValue());
3056498b0e9SLang Hames     Alloc.RemoteAddr = NextAddr;
3066498b0e9SLang Hames     // Only advance NextAddr if it was non-null to begin with,
3076498b0e9SLang Hames     // otherwise leave it as null.
3086498b0e9SLang Hames     if (NextAddr)
3096498b0e9SLang Hames       NextAddr += ExecutorAddrDiff(Alloc.Size);
3106498b0e9SLang Hames   }
3116498b0e9SLang Hames }
3126498b0e9SLang Hames 
3136498b0e9SLang Hames } // end namespace orc
3146498b0e9SLang Hames } // end namespace llvm
315