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