1ef238923SStefan Gränitz //===---- DebugObjectManagerPlugin.h - JITLink debug objects ---*- C++ -*-===// 2ef238923SStefan Gränitz // 3ef238923SStefan Gränitz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ef238923SStefan Gränitz // See https://llvm.org/LICENSE.txt for license information. 5ef238923SStefan Gränitz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ef238923SStefan Gränitz // 7ef238923SStefan Gränitz //===----------------------------------------------------------------------===// 8ef238923SStefan Gränitz 9ef238923SStefan Gränitz #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" 10ef238923SStefan Gränitz 11ef238923SStefan Gränitz #include "llvm/ADT/ArrayRef.h" 12ef238923SStefan Gränitz #include "llvm/ADT/StringMap.h" 13ef238923SStefan Gränitz #include "llvm/ADT/StringRef.h" 14ef238923SStefan Gränitz #include "llvm/BinaryFormat/ELF.h" 15ef238923SStefan Gränitz #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h" 16ef238923SStefan Gränitz #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" 17ef238923SStefan Gränitz #include "llvm/ExecutionEngine/JITSymbol.h" 18ef238923SStefan Gränitz #include "llvm/Object/ELFObjectFile.h" 19ef238923SStefan Gränitz #include "llvm/Object/ObjectFile.h" 20ef238923SStefan Gränitz #include "llvm/Support/Errc.h" 21ff52121bSStefan Gränitz #include "llvm/Support/MSVCErrorWorkarounds.h" 22ef238923SStefan Gränitz #include "llvm/Support/MemoryBuffer.h" 23ef238923SStefan Gränitz #include "llvm/Support/Process.h" 24ef238923SStefan Gränitz #include "llvm/Support/raw_ostream.h" 25ef238923SStefan Gränitz 26ef238923SStefan Gränitz #include <set> 27ef238923SStefan Gränitz 28ef238923SStefan Gränitz #define DEBUG_TYPE "orc" 29ef238923SStefan Gränitz 30ef238923SStefan Gränitz using namespace llvm::jitlink; 31ef238923SStefan Gränitz using namespace llvm::object; 32ef238923SStefan Gränitz 33ef238923SStefan Gränitz namespace llvm { 34ef238923SStefan Gränitz namespace orc { 35ef238923SStefan Gränitz 36ef238923SStefan Gränitz class DebugObjectSection { 37ef238923SStefan Gränitz public: 38ef238923SStefan Gränitz virtual void setTargetMemoryRange(SectionRange Range) = 0; 39ef238923SStefan Gränitz virtual void dump(raw_ostream &OS, StringRef Name) {} 40ef238923SStefan Gränitz virtual ~DebugObjectSection() {} 41ef238923SStefan Gränitz }; 42ef238923SStefan Gränitz 43ef238923SStefan Gränitz template <typename ELFT> 44ef238923SStefan Gränitz class ELFDebugObjectSection : public DebugObjectSection { 45ef238923SStefan Gränitz public: 46ef238923SStefan Gränitz // BinaryFormat ELF is not meant as a mutable format. We can only make changes 47ef238923SStefan Gränitz // that don't invalidate the file structure. 48ef238923SStefan Gränitz ELFDebugObjectSection(const typename ELFT::Shdr *Header) 49ef238923SStefan Gränitz : Header(const_cast<typename ELFT::Shdr *>(Header)) {} 50ef238923SStefan Gränitz 51ef238923SStefan Gränitz void setTargetMemoryRange(SectionRange Range) override; 52ef238923SStefan Gränitz void dump(raw_ostream &OS, StringRef Name) override; 53ef238923SStefan Gränitz 54265bc5afSStefan Gränitz Error validateInBounds(StringRef Buffer, const char *Name) const; 55265bc5afSStefan Gränitz 56ef238923SStefan Gränitz private: 57ef238923SStefan Gränitz typename ELFT::Shdr *Header; 58ef238923SStefan Gränitz 59ef238923SStefan Gränitz bool isTextOrDataSection() const; 60ef238923SStefan Gränitz }; 61ef238923SStefan Gränitz 62ef238923SStefan Gränitz template <typename ELFT> 63ef238923SStefan Gränitz void ELFDebugObjectSection<ELFT>::setTargetMemoryRange(SectionRange Range) { 64ef238923SStefan Gränitz // Only patch load-addresses for executable and data sections. 65ef238923SStefan Gränitz if (isTextOrDataSection()) { 66ef238923SStefan Gränitz Header->sh_addr = static_cast<typename ELFT::uint>(Range.getStart()); 67ef238923SStefan Gränitz } 68ef238923SStefan Gränitz } 69ef238923SStefan Gränitz 70ef238923SStefan Gränitz template <typename ELFT> 71ef238923SStefan Gränitz bool ELFDebugObjectSection<ELFT>::isTextOrDataSection() const { 72ef238923SStefan Gränitz switch (Header->sh_type) { 73ef238923SStefan Gränitz case ELF::SHT_PROGBITS: 74ef238923SStefan Gränitz case ELF::SHT_X86_64_UNWIND: 75ef238923SStefan Gränitz return Header->sh_flags & (ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); 76ef238923SStefan Gränitz } 77ef238923SStefan Gränitz return false; 78ef238923SStefan Gränitz } 79ef238923SStefan Gränitz 80265bc5afSStefan Gränitz template <typename ELFT> 81265bc5afSStefan Gränitz Error ELFDebugObjectSection<ELFT>::validateInBounds(StringRef Buffer, 82265bc5afSStefan Gränitz const char *Name) const { 83265bc5afSStefan Gränitz const uint8_t *Start = Buffer.bytes_begin(); 84265bc5afSStefan Gränitz const uint8_t *End = Buffer.bytes_end(); 85265bc5afSStefan Gränitz const uint8_t *HeaderPtr = reinterpret_cast<uint8_t *>(Header); 86265bc5afSStefan Gränitz if (HeaderPtr < Start || HeaderPtr + sizeof(typename ELFT::Shdr) > End) 87265bc5afSStefan Gränitz return make_error<StringError>( 88265bc5afSStefan Gränitz formatv("{0} section header at {1:x16} not within bounds of the " 89265bc5afSStefan Gränitz "given debug object buffer [{2:x16} - {3:x16}]", 90265bc5afSStefan Gränitz Name, &Header->sh_addr, Start, End), 91265bc5afSStefan Gränitz inconvertibleErrorCode()); 92265bc5afSStefan Gränitz if (Header->sh_offset + Header->sh_size > Buffer.size()) 93265bc5afSStefan Gränitz return make_error<StringError>( 94265bc5afSStefan Gränitz formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of " 95265bc5afSStefan Gränitz "the given debug object buffer [{3:x16} - {4:x16}]", 96265bc5afSStefan Gränitz Name, Start + Header->sh_offset, 97265bc5afSStefan Gränitz Start + Header->sh_offset + Header->sh_size, Start, End), 98265bc5afSStefan Gränitz inconvertibleErrorCode()); 99265bc5afSStefan Gränitz return Error::success(); 100265bc5afSStefan Gränitz } 101265bc5afSStefan Gränitz 102265bc5afSStefan Gränitz template <typename ELFT> 103265bc5afSStefan Gränitz void ELFDebugObjectSection<ELFT>::dump(raw_ostream &OS, StringRef Name) { 104265bc5afSStefan Gränitz if (auto Addr = static_cast<JITTargetAddress>(Header->sh_addr)) { 105265bc5afSStefan Gränitz OS << formatv(" {0:x16} {1}\n", Addr, Name); 106265bc5afSStefan Gränitz } else { 107265bc5afSStefan Gränitz OS << formatv(" {0}\n", Name); 108265bc5afSStefan Gränitz } 109265bc5afSStefan Gränitz } 110265bc5afSStefan Gränitz 111ef238923SStefan Gränitz static constexpr sys::Memory::ProtectionFlags ReadOnly = 112ef238923SStefan Gränitz static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ); 113ef238923SStefan Gränitz 114ef238923SStefan Gränitz enum class Requirement { 115ef238923SStefan Gränitz // Request final target memory load-addresses for all sections. 116ef238923SStefan Gränitz ReportFinalSectionLoadAddresses, 117ef238923SStefan Gränitz }; 118ef238923SStefan Gränitz 119ef238923SStefan Gränitz /// The plugin creates a debug object from JITLinkContext when JITLink starts 120ef238923SStefan Gränitz /// processing the corresponding LinkGraph. It provides access to the pass 121ef238923SStefan Gränitz /// configuration of the LinkGraph and calls the finalization function, once 122ef238923SStefan Gränitz /// the resulting link artifact was emitted. 123ef238923SStefan Gränitz /// 124ef238923SStefan Gränitz class DebugObject { 125ef238923SStefan Gränitz public: 126ef238923SStefan Gränitz DebugObject(JITLinkContext &Ctx) : Ctx(Ctx) {} 127ee5e7a3aSStefan Gränitz virtual ~DebugObject() = default; 128ef238923SStefan Gränitz 129ef238923SStefan Gränitz void set(Requirement Req) { Reqs.insert(Req); } 130ef238923SStefan Gränitz bool has(Requirement Req) const { return Reqs.count(Req) > 0; } 131ef238923SStefan Gränitz 132ef238923SStefan Gränitz using FinalizeContinuation = std::function<void(Expected<sys::MemoryBlock>)>; 133ef238923SStefan Gränitz void finalizeAsync(FinalizeContinuation OnFinalize); 134ef238923SStefan Gränitz 135ee5e7a3aSStefan Gränitz Error deallocate() { 136ee5e7a3aSStefan Gränitz if (Alloc) 137ee5e7a3aSStefan Gränitz return Alloc->deallocate(); 138ee5e7a3aSStefan Gränitz return Error::success(); 139ee5e7a3aSStefan Gränitz } 140ee5e7a3aSStefan Gränitz 141ef238923SStefan Gränitz virtual void reportSectionTargetMemoryRange(StringRef Name, 142ef238923SStefan Gränitz SectionRange TargetMem) {} 143ef238923SStefan Gränitz 144ef238923SStefan Gränitz protected: 145ef238923SStefan Gränitz using Allocation = JITLinkMemoryManager::Allocation; 146ef238923SStefan Gränitz 147ef238923SStefan Gränitz virtual Expected<std::unique_ptr<Allocation>> 148ef238923SStefan Gränitz finalizeWorkingMemory(JITLinkContext &Ctx) = 0; 149ef238923SStefan Gränitz 150ef238923SStefan Gränitz private: 151ef238923SStefan Gränitz JITLinkContext &Ctx; 152ef238923SStefan Gränitz std::set<Requirement> Reqs; 153ef238923SStefan Gränitz std::unique_ptr<Allocation> Alloc{nullptr}; 154ef238923SStefan Gränitz }; 155ef238923SStefan Gränitz 156ef238923SStefan Gränitz // Finalize working memory and take ownership of the resulting allocation. Start 157ef238923SStefan Gränitz // copying memory over to the target and pass on the result once we're done. 158ef238923SStefan Gränitz // Ownership of the allocation remains with us for the rest of our lifetime. 159ef238923SStefan Gränitz void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize) { 160ef238923SStefan Gränitz assert(Alloc == nullptr && "Cannot finalize more than once"); 161ef238923SStefan Gränitz 162ef238923SStefan Gränitz auto AllocOrErr = finalizeWorkingMemory(Ctx); 163ef238923SStefan Gränitz if (!AllocOrErr) 164ef238923SStefan Gränitz OnFinalize(AllocOrErr.takeError()); 165ef238923SStefan Gränitz Alloc = std::move(*AllocOrErr); 166ef238923SStefan Gränitz 167ef238923SStefan Gränitz Alloc->finalizeAsync([this, OnFinalize](Error Err) { 168ef238923SStefan Gränitz if (Err) 169ef238923SStefan Gränitz OnFinalize(std::move(Err)); 170ef238923SStefan Gränitz else 171ef238923SStefan Gränitz OnFinalize(sys::MemoryBlock( 172ef238923SStefan Gränitz jitTargetAddressToPointer<void *>(Alloc->getTargetMemory(ReadOnly)), 173ef238923SStefan Gränitz Alloc->getWorkingMemory(ReadOnly).size())); 174ef238923SStefan Gränitz }); 175ef238923SStefan Gränitz } 176ef238923SStefan Gränitz 177ef238923SStefan Gränitz /// The current implementation of ELFDebugObject replicates the approach used in 178ef238923SStefan Gränitz /// RuntimeDyld: It patches executable and data section headers in the given 179ef238923SStefan Gränitz /// object buffer with load-addresses of their corresponding sections in target 180ef238923SStefan Gränitz /// memory. 181ef238923SStefan Gränitz /// 182ef238923SStefan Gränitz class ELFDebugObject : public DebugObject { 183ef238923SStefan Gränitz public: 184ef238923SStefan Gränitz static Expected<std::unique_ptr<DebugObject>> Create(MemoryBufferRef Buffer, 185ef238923SStefan Gränitz JITLinkContext &Ctx); 186ef238923SStefan Gränitz 187ef238923SStefan Gränitz void reportSectionTargetMemoryRange(StringRef Name, 188ef238923SStefan Gränitz SectionRange TargetMem) override; 189ef238923SStefan Gränitz 1907d18cd93SStefan Gränitz StringRef getBuffer() const { return Buffer->getMemBufferRef().getBuffer(); } 1917d18cd93SStefan Gränitz 192ef238923SStefan Gränitz protected: 193ef238923SStefan Gränitz Expected<std::unique_ptr<Allocation>> 194ef238923SStefan Gränitz finalizeWorkingMemory(JITLinkContext &Ctx) override; 195ef238923SStefan Gränitz 196265bc5afSStefan Gränitz template <typename ELFT> 197ef238923SStefan Gränitz Error recordSection(StringRef Name, 198265bc5afSStefan Gränitz std::unique_ptr<ELFDebugObjectSection<ELFT>> Section); 199ef238923SStefan Gränitz DebugObjectSection *getSection(StringRef Name); 200ef238923SStefan Gränitz 201ef238923SStefan Gränitz private: 202ef238923SStefan Gränitz template <typename ELFT> 203ef238923SStefan Gränitz static Expected<std::unique_ptr<ELFDebugObject>> 204ef238923SStefan Gränitz CreateArchType(MemoryBufferRef Buffer, JITLinkContext &Ctx); 205ef238923SStefan Gränitz 2067d18cd93SStefan Gränitz static std::unique_ptr<WritableMemoryBuffer> 2077d18cd93SStefan Gränitz CopyBuffer(MemoryBufferRef Buffer, Error &Err); 208ef238923SStefan Gränitz 209ef238923SStefan Gränitz ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer, 210ef238923SStefan Gränitz JITLinkContext &Ctx) 211ef238923SStefan Gränitz : DebugObject(Ctx), Buffer(std::move(Buffer)) { 212ef238923SStefan Gränitz set(Requirement::ReportFinalSectionLoadAddresses); 213ef238923SStefan Gränitz } 214ef238923SStefan Gränitz 215ef238923SStefan Gränitz std::unique_ptr<WritableMemoryBuffer> Buffer; 216ef238923SStefan Gränitz StringMap<std::unique_ptr<DebugObjectSection>> Sections; 217ef238923SStefan Gränitz }; 218ef238923SStefan Gränitz 219ef238923SStefan Gränitz static const std::set<StringRef> DwarfSectionNames = { 220ef238923SStefan Gränitz #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \ 221ef238923SStefan Gränitz ELF_NAME, 222ef238923SStefan Gränitz #include "llvm/BinaryFormat/Dwarf.def" 223ef238923SStefan Gränitz #undef HANDLE_DWARF_SECTION 224ef238923SStefan Gränitz }; 225ef238923SStefan Gränitz 226ef238923SStefan Gränitz static bool isDwarfSection(StringRef SectionName) { 227ef238923SStefan Gränitz return DwarfSectionNames.count(SectionName) == 1; 228ef238923SStefan Gränitz } 229ef238923SStefan Gränitz 2307d18cd93SStefan Gränitz std::unique_ptr<WritableMemoryBuffer> 2317d18cd93SStefan Gränitz ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) { 2327d18cd93SStefan Gränitz ErrorAsOutParameter _(&Err); 233ef238923SStefan Gränitz size_t Size = Buffer.getBufferSize(); 234ef238923SStefan Gränitz StringRef Name = Buffer.getBufferIdentifier(); 2357d18cd93SStefan Gränitz if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) { 236ef238923SStefan Gränitz memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size); 2377d18cd93SStefan Gränitz return Copy; 2387d18cd93SStefan Gränitz } 2397d18cd93SStefan Gränitz 2407d18cd93SStefan Gränitz Err = errorCodeToError(make_error_code(errc::not_enough_memory)); 2417d18cd93SStefan Gränitz return nullptr; 242ef238923SStefan Gränitz } 243ef238923SStefan Gränitz 244ef238923SStefan Gränitz template <typename ELFT> 245ef238923SStefan Gränitz Expected<std::unique_ptr<ELFDebugObject>> 246ef238923SStefan Gränitz ELFDebugObject::CreateArchType(MemoryBufferRef Buffer, JITLinkContext &Ctx) { 247ef238923SStefan Gränitz using SectionHeader = typename ELFT::Shdr; 248ef238923SStefan Gränitz 2497d18cd93SStefan Gränitz Error Err = Error::success(); 2507d18cd93SStefan Gränitz std::unique_ptr<ELFDebugObject> DebugObj( 2517d18cd93SStefan Gränitz new ELFDebugObject(CopyBuffer(Buffer, Err), Ctx)); 2527d18cd93SStefan Gränitz if (Err) 2537d18cd93SStefan Gränitz return std::move(Err); 2547d18cd93SStefan Gränitz 2557d18cd93SStefan Gränitz Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer()); 256ef238923SStefan Gränitz if (!ObjRef) 257ef238923SStefan Gränitz return ObjRef.takeError(); 258ef238923SStefan Gränitz 259ef238923SStefan Gränitz // TODO: Add support for other architectures. 260ef238923SStefan Gränitz uint16_t TargetMachineArch = ObjRef->getHeader().e_machine; 261ef238923SStefan Gränitz if (TargetMachineArch != ELF::EM_X86_64) 262ef238923SStefan Gränitz return nullptr; 263ef238923SStefan Gränitz 264ef238923SStefan Gränitz Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections(); 265ef238923SStefan Gränitz if (!Sections) 266ef238923SStefan Gränitz return Sections.takeError(); 267ef238923SStefan Gränitz 268ef238923SStefan Gränitz bool HasDwarfSection = false; 269ef238923SStefan Gränitz for (const SectionHeader &Header : *Sections) { 270ef238923SStefan Gränitz Expected<StringRef> Name = ObjRef->getSectionName(Header); 271ef238923SStefan Gränitz if (!Name) 272ef238923SStefan Gränitz return Name.takeError(); 273ef238923SStefan Gränitz if (Name->empty()) 274ef238923SStefan Gränitz continue; 275ef238923SStefan Gränitz HasDwarfSection |= isDwarfSection(*Name); 276ef238923SStefan Gränitz 277ef238923SStefan Gränitz auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header); 278ef238923SStefan Gränitz if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped))) 279ef238923SStefan Gränitz return std::move(Err); 280ef238923SStefan Gränitz } 281ef238923SStefan Gränitz 282ef238923SStefan Gränitz if (!HasDwarfSection) { 283ef238923SStefan Gränitz LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \"" 284ef238923SStefan Gränitz << DebugObj->Buffer->getBufferIdentifier() 285ef238923SStefan Gränitz << "\": input object contains no debug info\n"); 286ef238923SStefan Gränitz return nullptr; 287ef238923SStefan Gränitz } 288ef238923SStefan Gränitz 289ef238923SStefan Gränitz return std::move(DebugObj); 290ef238923SStefan Gränitz } 291ef238923SStefan Gränitz 292ef238923SStefan Gränitz Expected<std::unique_ptr<DebugObject>> 293ef238923SStefan Gränitz ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx) { 294ef238923SStefan Gränitz unsigned char Class, Endian; 295ef238923SStefan Gränitz std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer()); 296ef238923SStefan Gränitz 297ef238923SStefan Gränitz if (Class == ELF::ELFCLASS32) { 298ef238923SStefan Gränitz if (Endian == ELF::ELFDATA2LSB) 299ef238923SStefan Gränitz return CreateArchType<ELF32LE>(Buffer, Ctx); 300ef238923SStefan Gränitz if (Endian == ELF::ELFDATA2MSB) 301ef238923SStefan Gränitz return CreateArchType<ELF32BE>(Buffer, Ctx); 302ef238923SStefan Gränitz return nullptr; 303ef238923SStefan Gränitz } 304ef238923SStefan Gränitz if (Class == ELF::ELFCLASS64) { 305ef238923SStefan Gränitz if (Endian == ELF::ELFDATA2LSB) 306ef238923SStefan Gränitz return CreateArchType<ELF64LE>(Buffer, Ctx); 307ef238923SStefan Gränitz if (Endian == ELF::ELFDATA2MSB) 308ef238923SStefan Gränitz return CreateArchType<ELF64BE>(Buffer, Ctx); 309ef238923SStefan Gränitz return nullptr; 310ef238923SStefan Gränitz } 311ef238923SStefan Gränitz return nullptr; 312ef238923SStefan Gränitz } 313ef238923SStefan Gränitz 314ef238923SStefan Gränitz Expected<std::unique_ptr<DebugObject::Allocation>> 315ef238923SStefan Gränitz ELFDebugObject::finalizeWorkingMemory(JITLinkContext &Ctx) { 316ef238923SStefan Gränitz LLVM_DEBUG({ 317ef238923SStefan Gränitz dbgs() << "Section load-addresses in debug object for \"" 318ef238923SStefan Gränitz << Buffer->getBufferIdentifier() << "\":\n"; 319ef238923SStefan Gränitz for (const auto &KV : Sections) 320ef238923SStefan Gränitz KV.second->dump(dbgs(), KV.first()); 321ef238923SStefan Gränitz }); 322ef238923SStefan Gränitz 323ef238923SStefan Gränitz // TODO: This works, but what actual alignment requirements do we have? 324ef238923SStefan Gränitz unsigned Alignment = sys::Process::getPageSizeEstimate(); 325ef238923SStefan Gränitz JITLinkMemoryManager &MemMgr = Ctx.getMemoryManager(); 326ef238923SStefan Gränitz const JITLinkDylib *JD = Ctx.getJITLinkDylib(); 327ef238923SStefan Gränitz size_t Size = Buffer->getBufferSize(); 328ef238923SStefan Gränitz 329ef238923SStefan Gränitz // Allocate working memory for debug object in read-only segment. 330a747e35cSStefan Gränitz JITLinkMemoryManager::SegmentsRequestMap SingleReadOnlySegment; 331a747e35cSStefan Gränitz SingleReadOnlySegment[ReadOnly] = 332a747e35cSStefan Gränitz JITLinkMemoryManager::SegmentRequest(Alignment, Size, 0); 333a747e35cSStefan Gränitz 334a747e35cSStefan Gränitz auto AllocOrErr = MemMgr.allocate(JD, SingleReadOnlySegment); 335ef238923SStefan Gränitz if (!AllocOrErr) 336ef238923SStefan Gränitz return AllocOrErr.takeError(); 337ef238923SStefan Gränitz 338ef238923SStefan Gränitz // Initialize working memory with a copy of our object buffer. 339ef238923SStefan Gränitz // TODO: Use our buffer as working memory directly. 340ef238923SStefan Gränitz std::unique_ptr<Allocation> Alloc = std::move(*AllocOrErr); 341ef238923SStefan Gränitz MutableArrayRef<char> WorkingMem = Alloc->getWorkingMemory(ReadOnly); 342ef238923SStefan Gränitz memcpy(WorkingMem.data(), Buffer->getBufferStart(), Size); 343ef238923SStefan Gränitz Buffer.reset(); 344ef238923SStefan Gränitz 345ef238923SStefan Gränitz return std::move(Alloc); 346ef238923SStefan Gränitz } 347ef238923SStefan Gränitz 348ef238923SStefan Gränitz void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name, 349ef238923SStefan Gränitz SectionRange TargetMem) { 350ef238923SStefan Gränitz if (auto *DebugObjSection = getSection(Name)) 351ef238923SStefan Gränitz DebugObjSection->setTargetMemoryRange(TargetMem); 352ef238923SStefan Gränitz } 353ef238923SStefan Gränitz 354265bc5afSStefan Gränitz template <typename ELFT> 355ef238923SStefan Gränitz Error ELFDebugObject::recordSection( 356265bc5afSStefan Gränitz StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) { 357265bc5afSStefan Gränitz if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data())) 358265bc5afSStefan Gränitz return Err; 359ef238923SStefan Gränitz auto ItInserted = Sections.try_emplace(Name, std::move(Section)); 360ef238923SStefan Gränitz if (!ItInserted.second) 361ef238923SStefan Gränitz return make_error<StringError>("Duplicate section", 362ef238923SStefan Gränitz inconvertibleErrorCode()); 363ef238923SStefan Gränitz return Error::success(); 364ef238923SStefan Gränitz } 365ef238923SStefan Gränitz 366ef238923SStefan Gränitz DebugObjectSection *ELFDebugObject::getSection(StringRef Name) { 367ef238923SStefan Gränitz auto It = Sections.find(Name); 368ef238923SStefan Gränitz return It == Sections.end() ? nullptr : It->second.get(); 369ef238923SStefan Gränitz } 370ef238923SStefan Gränitz 371ef238923SStefan Gränitz static ResourceKey getResourceKey(MaterializationResponsibility &MR) { 372ef238923SStefan Gränitz ResourceKey Key; 373ef238923SStefan Gränitz if (auto Err = MR.withResourceKeyDo([&](ResourceKey K) { Key = K; })) { 374ef238923SStefan Gränitz MR.getExecutionSession().reportError(std::move(Err)); 375ef238923SStefan Gränitz return ResourceKey{}; 376ef238923SStefan Gränitz } 377ef238923SStefan Gränitz assert(Key && "Invalid key"); 378ef238923SStefan Gränitz return Key; 379ef238923SStefan Gränitz } 380ef238923SStefan Gränitz 381ef238923SStefan Gränitz /// Creates a debug object based on the input object file from 382ef238923SStefan Gränitz /// ObjectLinkingLayerJITLinkContext. 383ef238923SStefan Gränitz /// 384ef238923SStefan Gränitz static Expected<std::unique_ptr<DebugObject>> 385ef238923SStefan Gränitz createDebugObjectFromBuffer(LinkGraph &G, JITLinkContext &Ctx, 386ef238923SStefan Gränitz MemoryBufferRef ObjBuffer) { 387ef238923SStefan Gränitz switch (G.getTargetTriple().getObjectFormat()) { 388ef238923SStefan Gränitz case Triple::ELF: 389ef238923SStefan Gränitz return ELFDebugObject::Create(ObjBuffer, Ctx); 390ef238923SStefan Gränitz 391ef238923SStefan Gränitz default: 392ef238923SStefan Gränitz // TODO: Once we add support for other formats, we might want to split this 393ef238923SStefan Gränitz // into multiple files. 394ef238923SStefan Gränitz return nullptr; 395ef238923SStefan Gränitz } 396ef238923SStefan Gränitz } 397ef238923SStefan Gränitz 398ef238923SStefan Gränitz DebugObjectManagerPlugin::DebugObjectManagerPlugin( 399ef238923SStefan Gränitz ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 400ef238923SStefan Gränitz : ES(ES), Target(std::move(Target)) {} 401ef238923SStefan Gränitz 402ee5e7a3aSStefan Gränitz DebugObjectManagerPlugin::~DebugObjectManagerPlugin() { 403ee5e7a3aSStefan Gränitz for (auto &KV : PendingObjs) { 404ee5e7a3aSStefan Gränitz std::unique_ptr<DebugObject> &DebugObj = KV.second; 405ee5e7a3aSStefan Gränitz if (Error Err = DebugObj->deallocate()) 406ee5e7a3aSStefan Gränitz ES.reportError(std::move(Err)); 407ee5e7a3aSStefan Gränitz } 408ee5e7a3aSStefan Gränitz for (auto &KV : RegisteredObjs) { 409ee5e7a3aSStefan Gränitz for (std::unique_ptr<DebugObject> &DebugObj : KV.second) 410ee5e7a3aSStefan Gränitz if (Error Err = DebugObj->deallocate()) 411ee5e7a3aSStefan Gränitz ES.reportError(std::move(Err)); 412ee5e7a3aSStefan Gränitz } 413ee5e7a3aSStefan Gränitz } 414ef238923SStefan Gränitz 415ef238923SStefan Gränitz void DebugObjectManagerPlugin::notifyMaterializing( 416ef238923SStefan Gränitz MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx, 417ef238923SStefan Gränitz MemoryBufferRef ObjBuffer) { 418ef238923SStefan Gränitz assert(PendingObjs.count(getResourceKey(MR)) == 0 && 419ef238923SStefan Gränitz "Cannot have more than one pending debug object per " 420ef238923SStefan Gränitz "MaterializationResponsibility"); 421ef238923SStefan Gränitz 422ef238923SStefan Gränitz std::lock_guard<std::mutex> Lock(PendingObjsLock); 423ef238923SStefan Gränitz if (auto DebugObj = createDebugObjectFromBuffer(G, Ctx, ObjBuffer)) { 424ef238923SStefan Gränitz // Not all link artifacts allow debugging. 425ef238923SStefan Gränitz if (*DebugObj != nullptr) { 426ef238923SStefan Gränitz ResourceKey Key = getResourceKey(MR); 427ef238923SStefan Gränitz PendingObjs[Key] = std::move(*DebugObj); 428ef238923SStefan Gränitz } 429ef238923SStefan Gränitz } else { 430ef238923SStefan Gränitz ES.reportError(DebugObj.takeError()); 431ef238923SStefan Gränitz } 432ef238923SStefan Gränitz } 433ef238923SStefan Gränitz 434ef238923SStefan Gränitz void DebugObjectManagerPlugin::modifyPassConfig( 435*4e30b20bSLang Hames MaterializationResponsibility &MR, LinkGraph &G, 436ef238923SStefan Gränitz PassConfiguration &PassConfig) { 437ef238923SStefan Gränitz // Not all link artifacts have associated debug objects. 438ef238923SStefan Gränitz std::lock_guard<std::mutex> Lock(PendingObjsLock); 439ef238923SStefan Gränitz auto It = PendingObjs.find(getResourceKey(MR)); 440ef238923SStefan Gränitz if (It == PendingObjs.end()) 441ef238923SStefan Gränitz return; 442ef238923SStefan Gränitz 443ef238923SStefan Gränitz DebugObject &DebugObj = *It->second; 444ef238923SStefan Gränitz if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) { 445ef238923SStefan Gränitz PassConfig.PostAllocationPasses.push_back( 446ef238923SStefan Gränitz [&DebugObj](LinkGraph &Graph) -> Error { 447ef238923SStefan Gränitz for (const Section &GraphSection : Graph.sections()) 448ef238923SStefan Gränitz DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(), 449ef238923SStefan Gränitz SectionRange(GraphSection)); 450ef238923SStefan Gränitz return Error::success(); 451ef238923SStefan Gränitz }); 452ef238923SStefan Gränitz } 453ef238923SStefan Gränitz } 454ef238923SStefan Gränitz 455ef238923SStefan Gränitz Error DebugObjectManagerPlugin::notifyEmitted( 456ef238923SStefan Gränitz MaterializationResponsibility &MR) { 457ef238923SStefan Gränitz ResourceKey Key = getResourceKey(MR); 458ef238923SStefan Gränitz 459ef238923SStefan Gränitz std::lock_guard<std::mutex> Lock(PendingObjsLock); 460ef238923SStefan Gränitz auto It = PendingObjs.find(Key); 461ef238923SStefan Gränitz if (It == PendingObjs.end()) 462ef238923SStefan Gränitz return Error::success(); 463ef238923SStefan Gränitz 464ef238923SStefan Gränitz DebugObject *UnownedDebugObj = It->second.release(); 465ef238923SStefan Gränitz PendingObjs.erase(It); 466ef238923SStefan Gränitz 467ff52121bSStefan Gränitz // During finalization the debug object is registered with the target. 468ff52121bSStefan Gränitz // Materialization must wait for this process to finish. Otherwise we might 469ff52121bSStefan Gränitz // start running code before the debugger processed the corresponding debug 470ff52121bSStefan Gränitz // info. 471ff52121bSStefan Gränitz std::promise<MSVCPError> FinalizePromise; 472ff52121bSStefan Gränitz std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future(); 473ff52121bSStefan Gränitz 474ef238923SStefan Gränitz // FIXME: We released ownership of the DebugObject, so we can easily capture 475ef238923SStefan Gränitz // the raw pointer in the continuation function, which re-owns it immediately. 476ef238923SStefan Gränitz if (UnownedDebugObj) 477ef238923SStefan Gränitz UnownedDebugObj->finalizeAsync( 478ff52121bSStefan Gränitz [this, Key, UnownedDebugObj, 479ff52121bSStefan Gränitz &FinalizePromise](Expected<sys::MemoryBlock> TargetMem) { 480ef238923SStefan Gränitz std::unique_ptr<DebugObject> ReownedDebugObj(UnownedDebugObj); 481ef238923SStefan Gränitz if (!TargetMem) { 482ff52121bSStefan Gränitz FinalizePromise.set_value(TargetMem.takeError()); 483ef238923SStefan Gränitz return; 484ef238923SStefan Gränitz } 485ef238923SStefan Gränitz if (Error Err = Target->registerDebugObject(*TargetMem)) { 486ff52121bSStefan Gränitz FinalizePromise.set_value(std::move(Err)); 487ef238923SStefan Gränitz return; 488ef238923SStefan Gränitz } 489ef238923SStefan Gränitz 490ff52121bSStefan Gränitz // Registration successful, notifyEmitted() can return now and 491ff52121bSStefan Gränitz // materialization can finish. 492ff52121bSStefan Gränitz FinalizePromise.set_value(Error::success()); 493ff52121bSStefan Gränitz 494ef238923SStefan Gränitz std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 495ef238923SStefan Gränitz RegisteredObjs[Key].push_back(std::move(ReownedDebugObj)); 496ef238923SStefan Gränitz }); 497ef238923SStefan Gränitz 498ff52121bSStefan Gränitz return FinalizeErr.get(); 499ef238923SStefan Gränitz } 500ef238923SStefan Gränitz 501ef238923SStefan Gränitz Error DebugObjectManagerPlugin::notifyFailed( 502ef238923SStefan Gränitz MaterializationResponsibility &MR) { 503ef238923SStefan Gränitz std::lock_guard<std::mutex> Lock(PendingObjsLock); 504ef238923SStefan Gränitz PendingObjs.erase(getResourceKey(MR)); 505ef238923SStefan Gränitz return Error::success(); 506ef238923SStefan Gränitz } 507ef238923SStefan Gränitz 508ef238923SStefan Gränitz void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey, 509ef238923SStefan Gränitz ResourceKey SrcKey) { 510ef238923SStefan Gränitz { 511ef238923SStefan Gränitz std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 512ef238923SStefan Gränitz auto SrcIt = RegisteredObjs.find(SrcKey); 513ef238923SStefan Gränitz if (SrcIt != RegisteredObjs.end()) { 514ef238923SStefan Gränitz // Resources from distinct MaterializationResponsibilitys can get merged 515ef238923SStefan Gränitz // after emission, so we can have multiple debug objects per resource key. 516ef238923SStefan Gränitz for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second) 517ef238923SStefan Gränitz RegisteredObjs[DstKey].push_back(std::move(DebugObj)); 518ef238923SStefan Gränitz RegisteredObjs.erase(SrcIt); 519ef238923SStefan Gränitz } 520ef238923SStefan Gränitz } 521ef238923SStefan Gränitz { 522ef238923SStefan Gränitz std::lock_guard<std::mutex> Lock(PendingObjsLock); 523ef238923SStefan Gränitz auto SrcIt = PendingObjs.find(SrcKey); 524ef238923SStefan Gränitz if (SrcIt != PendingObjs.end()) { 525ef238923SStefan Gränitz assert(PendingObjs.count(DstKey) == 0 && 526ef238923SStefan Gränitz "Cannot have more than one pending debug object per " 527ef238923SStefan Gränitz "MaterializationResponsibility"); 528ef238923SStefan Gränitz PendingObjs[DstKey] = std::move(SrcIt->second); 529ef238923SStefan Gränitz PendingObjs.erase(SrcIt); 530ef238923SStefan Gränitz } 531ef238923SStefan Gränitz } 532ef238923SStefan Gränitz } 533ef238923SStefan Gränitz 534ef238923SStefan Gränitz Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey K) { 535ef238923SStefan Gränitz { 536ef238923SStefan Gränitz std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 537ef238923SStefan Gränitz RegisteredObjs.erase(K); 538ef238923SStefan Gränitz // TODO: Implement unregister notifications. 539ef238923SStefan Gränitz } 540ef238923SStefan Gränitz std::lock_guard<std::mutex> Lock(PendingObjsLock); 541ef238923SStefan Gränitz PendingObjs.erase(K); 542ef238923SStefan Gränitz 543ef238923SStefan Gränitz return Error::success(); 544ef238923SStefan Gränitz } 545ef238923SStefan Gränitz 546ef238923SStefan Gränitz } // namespace orc 547ef238923SStefan Gränitz } // namespace llvm 548