123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- //===----- EPCGenericRTDyldMemoryManager.cpp - EPC-bbasde MemMgr -----===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h"
- #include "llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h"
- #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
- #include "llvm/Support/Alignment.h"
- #include "llvm/Support/FormatVariadic.h"
- #define DEBUG_TYPE "orc"
- using namespace llvm::orc::shared;
- namespace llvm {
- namespace orc {
- Expected<std::unique_ptr<EPCGenericRTDyldMemoryManager>>
- EPCGenericRTDyldMemoryManager::CreateWithDefaultBootstrapSymbols(
- ExecutorProcessControl &EPC) {
- SymbolAddrs SAs;
- if (auto Err = EPC.getBootstrapSymbols(
- {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName},
- {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
- {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
- {SAs.Deallocate,
- rt::SimpleExecutorMemoryManagerDeallocateWrapperName},
- {SAs.RegisterEHFrame, rt::RegisterEHFrameSectionWrapperName},
- {SAs.DeregisterEHFrame, rt::DeregisterEHFrameSectionWrapperName}}))
- return std::move(Err);
- return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC, std::move(SAs));
- }
- EPCGenericRTDyldMemoryManager::EPCGenericRTDyldMemoryManager(
- ExecutorProcessControl &EPC, SymbolAddrs SAs)
- : EPC(EPC), SAs(std::move(SAs)) {
- LLVM_DEBUG(dbgs() << "Created remote allocator " << (void *)this << "\n");
- }
- EPCGenericRTDyldMemoryManager::~EPCGenericRTDyldMemoryManager() {
- LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << (void *)this << "\n");
- if (!ErrMsg.empty())
- errs() << "Destroying with existing errors:\n" << ErrMsg << "\n";
- Error Err = Error::success();
- if (auto Err2 = EPC.callSPSWrapper<
- rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>(
- SAs.Reserve, Err, SAs.Instance, FinalizedAllocs)) {
- // FIXME: Report errors through EPC once that functionality is available.
- logAllUnhandledErrors(std::move(Err2), errs(), "");
- return;
- }
- if (Err)
- logAllUnhandledErrors(std::move(Err), errs(), "");
- }
- uint8_t *EPCGenericRTDyldMemoryManager::allocateCodeSection(
- uintptr_t Size, unsigned Alignment, unsigned SectionID,
- StringRef SectionName) {
- std::lock_guard<std::mutex> Lock(M);
- LLVM_DEBUG({
- dbgs() << "Allocator " << (void *)this << " allocating code section "
- << SectionName << ": size = " << formatv("{0:x}", Size)
- << " bytes, alignment = " << Alignment << "\n";
- });
- auto &Seg = Unmapped.back().CodeAllocs;
- Seg.emplace_back(Size, Alignment);
- return reinterpret_cast<uint8_t *>(
- alignAddr(Seg.back().Contents.get(), Align(Alignment)));
- }
- uint8_t *EPCGenericRTDyldMemoryManager::allocateDataSection(
- uintptr_t Size, unsigned Alignment, unsigned SectionID,
- StringRef SectionName, bool IsReadOnly) {
- std::lock_guard<std::mutex> Lock(M);
- LLVM_DEBUG({
- dbgs() << "Allocator " << (void *)this << " allocating "
- << (IsReadOnly ? "ro" : "rw") << "-data section " << SectionName
- << ": size = " << formatv("{0:x}", Size) << " bytes, alignment "
- << Alignment << ")\n";
- });
- auto &Seg =
- IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs;
- Seg.emplace_back(Size, Alignment);
- return reinterpret_cast<uint8_t *>(
- alignAddr(Seg.back().Contents.get(), Align(Alignment)));
- }
- void EPCGenericRTDyldMemoryManager::reserveAllocationSpace(
- uintptr_t CodeSize, uint32_t CodeAlign, uintptr_t RODataSize,
- uint32_t RODataAlign, uintptr_t RWDataSize, uint32_t RWDataAlign) {
- {
- std::lock_guard<std::mutex> Lock(M);
- // If there's already an error then bail out.
- if (!ErrMsg.empty())
- return;
- if (!isPowerOf2_32(CodeAlign) || CodeAlign > EPC.getPageSize()) {
- ErrMsg = "Invalid code alignment in reserveAllocationSpace";
- return;
- }
- if (!isPowerOf2_32(RODataAlign) || RODataAlign > EPC.getPageSize()) {
- ErrMsg = "Invalid ro-data alignment in reserveAllocationSpace";
- return;
- }
- if (!isPowerOf2_32(RWDataAlign) || RWDataAlign > EPC.getPageSize()) {
- ErrMsg = "Invalid rw-data alignment in reserveAllocationSpace";
- return;
- }
- }
- uint64_t TotalSize = 0;
- TotalSize += alignTo(CodeSize, EPC.getPageSize());
- TotalSize += alignTo(RODataSize, EPC.getPageSize());
- TotalSize += alignTo(RWDataSize, EPC.getPageSize());
- LLVM_DEBUG({
- dbgs() << "Allocator " << (void *)this << " reserving "
- << formatv("{0:x}", TotalSize) << " bytes.\n";
- });
- Expected<ExecutorAddr> TargetAllocAddr((ExecutorAddr()));
- if (auto Err = EPC.callSPSWrapper<
- rt::SPSSimpleExecutorMemoryManagerReserveSignature>(
- SAs.Reserve, TargetAllocAddr, SAs.Instance, TotalSize)) {
- std::lock_guard<std::mutex> Lock(M);
- ErrMsg = toString(std::move(Err));
- return;
- }
- if (!TargetAllocAddr) {
- std::lock_guard<std::mutex> Lock(M);
- ErrMsg = toString(TargetAllocAddr.takeError());
- return;
- }
- std::lock_guard<std::mutex> Lock(M);
- Unmapped.push_back(AllocGroup());
- Unmapped.back().RemoteCode = {
- *TargetAllocAddr, ExecutorAddrDiff(alignTo(CodeSize, EPC.getPageSize()))};
- Unmapped.back().RemoteROData = {
- Unmapped.back().RemoteCode.End,
- ExecutorAddrDiff(alignTo(RODataSize, EPC.getPageSize()))};
- Unmapped.back().RemoteRWData = {
- Unmapped.back().RemoteROData.End,
- ExecutorAddrDiff(alignTo(RWDataSize, EPC.getPageSize()))};
- }
- bool EPCGenericRTDyldMemoryManager::needsToReserveAllocationSpace() {
- return true;
- }
- void EPCGenericRTDyldMemoryManager::registerEHFrames(uint8_t *Addr,
- uint64_t LoadAddr,
- size_t Size) {
- LLVM_DEBUG({
- dbgs() << "Allocator " << (void *)this << " added unfinalized eh-frame "
- << formatv("[ {0:x} {1:x} ]", LoadAddr, LoadAddr + Size) << "\n";
- });
- std::lock_guard<std::mutex> Lock(M);
- // Bail out early if there's already an error.
- if (!ErrMsg.empty())
- return;
- ExecutorAddr LA(LoadAddr);
- for (auto &Alloc : llvm::reverse(Unfinalized)) {
- if (Alloc.RemoteCode.contains(LA) || Alloc.RemoteROData.contains(LA) ||
- Alloc.RemoteRWData.contains(LA)) {
- Alloc.UnfinalizedEHFrames.push_back({LA, Size});
- return;
- }
- }
- ErrMsg = "eh-frame does not lie inside unfinalized alloc";
- }
- void EPCGenericRTDyldMemoryManager::deregisterEHFrames() {
- // This is a no-op for us: We've registered a deallocation action for it.
- }
- void EPCGenericRTDyldMemoryManager::notifyObjectLoaded(
- RuntimeDyld &Dyld, const object::ObjectFile &Obj) {
- std::lock_guard<std::mutex> Lock(M);
- LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " applied mappings:\n");
- for (auto &ObjAllocs : Unmapped) {
- mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
- ObjAllocs.RemoteCode.Start);
- mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
- ObjAllocs.RemoteROData.Start);
- mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
- ObjAllocs.RemoteRWData.Start);
- Unfinalized.push_back(std::move(ObjAllocs));
- }
- Unmapped.clear();
- }
- bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) {
- LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " finalizing:\n");
- // If there's an error then bail out here.
- std::vector<AllocGroup> Allocs;
- {
- std::lock_guard<std::mutex> Lock(M);
- if (ErrMsg && !this->ErrMsg.empty()) {
- *ErrMsg = std::move(this->ErrMsg);
- return true;
- }
- std::swap(Allocs, Unfinalized);
- }
- // Loop over unfinalized objects to make finalization requests.
- for (auto &ObjAllocs : Allocs) {
- tpctypes::WireProtectionFlags SegProts[3] = {
- tpctypes::toWireProtectionFlags(
- static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
- sys::Memory::MF_EXEC)),
- tpctypes::toWireProtectionFlags(sys::Memory::MF_READ),
- tpctypes::toWireProtectionFlags(
- static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
- sys::Memory::MF_WRITE))};
- ExecutorAddrRange *RemoteAddrs[3] = {&ObjAllocs.RemoteCode,
- &ObjAllocs.RemoteROData,
- &ObjAllocs.RemoteRWData};
- std::vector<Alloc> *SegSections[3] = {&ObjAllocs.CodeAllocs,
- &ObjAllocs.RODataAllocs,
- &ObjAllocs.RWDataAllocs};
- tpctypes::FinalizeRequest FR;
- std::unique_ptr<char[]> AggregateContents[3];
- for (unsigned I = 0; I != 3; ++I) {
- FR.Segments.push_back({});
- auto &Seg = FR.Segments.back();
- Seg.Prot = SegProts[I];
- Seg.Addr = RemoteAddrs[I]->Start;
- for (auto &SecAlloc : *SegSections[I]) {
- Seg.Size = alignTo(Seg.Size, SecAlloc.Align);
- Seg.Size += SecAlloc.Size;
- }
- AggregateContents[I] = std::make_unique<char[]>(Seg.Size);
- size_t SecOffset = 0;
- for (auto &SecAlloc : *SegSections[I]) {
- SecOffset = alignTo(SecOffset, SecAlloc.Align);
- memcpy(&AggregateContents[I][SecOffset],
- reinterpret_cast<const char *>(
- alignAddr(SecAlloc.Contents.get(), Align(SecAlloc.Align))),
- SecAlloc.Size);
- SecOffset += SecAlloc.Size;
- // FIXME: Can we reset SecAlloc.Content here, now that it's copied into
- // the aggregated content?
- }
- Seg.Content = {AggregateContents[I].get(), SecOffset};
- }
- for (auto &Frame : ObjAllocs.UnfinalizedEHFrames)
- FR.Actions.push_back(
- {cantFail(
- WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
- SAs.RegisterEHFrame, Frame)),
- cantFail(
- WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
- SAs.DeregisterEHFrame, Frame))});
- // We'll also need to make an extra allocation for the eh-frame wrapper call
- // arguments.
- Error FinalizeErr = Error::success();
- if (auto Err = EPC.callSPSWrapper<
- rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>(
- SAs.Finalize, FinalizeErr, SAs.Instance, std::move(FR))) {
- std::lock_guard<std::mutex> Lock(M);
- this->ErrMsg = toString(std::move(Err));
- dbgs() << "Serialization error: " << this->ErrMsg << "\n";
- if (ErrMsg)
- *ErrMsg = this->ErrMsg;
- return true;
- }
- if (FinalizeErr) {
- std::lock_guard<std::mutex> Lock(M);
- this->ErrMsg = toString(std::move(FinalizeErr));
- dbgs() << "Finalization error: " << this->ErrMsg << "\n";
- if (ErrMsg)
- *ErrMsg = this->ErrMsg;
- return true;
- }
- }
- return false;
- }
- void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs(
- RuntimeDyld &Dyld, std::vector<Alloc> &Allocs, ExecutorAddr NextAddr) {
- for (auto &Alloc : Allocs) {
- NextAddr.setValue(alignTo(NextAddr.getValue(), Alloc.Align));
- LLVM_DEBUG({
- dbgs() << " " << static_cast<void *>(Alloc.Contents.get()) << " -> "
- << format("0x%016" PRIx64, NextAddr.getValue()) << "\n";
- });
- Dyld.mapSectionAddress(reinterpret_cast<const void *>(alignAddr(
- Alloc.Contents.get(), Align(Alloc.Align))),
- NextAddr.getValue());
- Alloc.RemoteAddr = NextAddr;
- // Only advance NextAddr if it was non-null to begin with,
- // otherwise leave it as null.
- if (NextAddr)
- NextAddr += ExecutorAddrDiff(Alloc.Size);
- }
- }
- } // end namespace orc
- } // end namespace llvm
|