1*349cc55cSDimitry Andric //===------- DebugObjectManagerPlugin.cpp - JITLink debug objects ---------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8*349cc55cSDimitry Andric // 9*349cc55cSDimitry Andric // FIXME: Update Plugin to poke the debug object into a new JITLink section, 10*349cc55cSDimitry Andric // rather than creating a new allocation. 11*349cc55cSDimitry Andric // 12*349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 13fe6060f1SDimitry Andric 14fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h" 15fe6060f1SDimitry Andric 16fe6060f1SDimitry Andric #include "llvm/ADT/ArrayRef.h" 17fe6060f1SDimitry Andric #include "llvm/ADT/StringMap.h" 18fe6060f1SDimitry Andric #include "llvm/ADT/StringRef.h" 19fe6060f1SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 20fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h" 21fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" 22fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITSymbol.h" 23fe6060f1SDimitry Andric #include "llvm/Object/ELFObjectFile.h" 24fe6060f1SDimitry Andric #include "llvm/Object/ObjectFile.h" 25fe6060f1SDimitry Andric #include "llvm/Support/Errc.h" 26fe6060f1SDimitry Andric #include "llvm/Support/MSVCErrorWorkarounds.h" 27fe6060f1SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 28fe6060f1SDimitry Andric #include "llvm/Support/Process.h" 29fe6060f1SDimitry Andric #include "llvm/Support/raw_ostream.h" 30fe6060f1SDimitry Andric 31fe6060f1SDimitry Andric #include <set> 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric #define DEBUG_TYPE "orc" 34fe6060f1SDimitry Andric 35fe6060f1SDimitry Andric using namespace llvm::jitlink; 36fe6060f1SDimitry Andric using namespace llvm::object; 37fe6060f1SDimitry Andric 38fe6060f1SDimitry Andric namespace llvm { 39fe6060f1SDimitry Andric namespace orc { 40fe6060f1SDimitry Andric 41fe6060f1SDimitry Andric class DebugObjectSection { 42fe6060f1SDimitry Andric public: 43fe6060f1SDimitry Andric virtual void setTargetMemoryRange(SectionRange Range) = 0; 44fe6060f1SDimitry Andric virtual void dump(raw_ostream &OS, StringRef Name) {} 45fe6060f1SDimitry Andric virtual ~DebugObjectSection() {} 46fe6060f1SDimitry Andric }; 47fe6060f1SDimitry Andric 48fe6060f1SDimitry Andric template <typename ELFT> 49fe6060f1SDimitry Andric class ELFDebugObjectSection : public DebugObjectSection { 50fe6060f1SDimitry Andric public: 51fe6060f1SDimitry Andric // BinaryFormat ELF is not meant as a mutable format. We can only make changes 52fe6060f1SDimitry Andric // that don't invalidate the file structure. 53fe6060f1SDimitry Andric ELFDebugObjectSection(const typename ELFT::Shdr *Header) 54fe6060f1SDimitry Andric : Header(const_cast<typename ELFT::Shdr *>(Header)) {} 55fe6060f1SDimitry Andric 56fe6060f1SDimitry Andric void setTargetMemoryRange(SectionRange Range) override; 57fe6060f1SDimitry Andric void dump(raw_ostream &OS, StringRef Name) override; 58fe6060f1SDimitry Andric 59fe6060f1SDimitry Andric Error validateInBounds(StringRef Buffer, const char *Name) const; 60fe6060f1SDimitry Andric 61fe6060f1SDimitry Andric private: 62fe6060f1SDimitry Andric typename ELFT::Shdr *Header; 63fe6060f1SDimitry Andric 64fe6060f1SDimitry Andric bool isTextOrDataSection() const; 65fe6060f1SDimitry Andric }; 66fe6060f1SDimitry Andric 67fe6060f1SDimitry Andric template <typename ELFT> 68fe6060f1SDimitry Andric void ELFDebugObjectSection<ELFT>::setTargetMemoryRange(SectionRange Range) { 69fe6060f1SDimitry Andric // Only patch load-addresses for executable and data sections. 70fe6060f1SDimitry Andric if (isTextOrDataSection()) { 71fe6060f1SDimitry Andric Header->sh_addr = static_cast<typename ELFT::uint>(Range.getStart()); 72fe6060f1SDimitry Andric } 73fe6060f1SDimitry Andric } 74fe6060f1SDimitry Andric 75fe6060f1SDimitry Andric template <typename ELFT> 76fe6060f1SDimitry Andric bool ELFDebugObjectSection<ELFT>::isTextOrDataSection() const { 77fe6060f1SDimitry Andric switch (Header->sh_type) { 78fe6060f1SDimitry Andric case ELF::SHT_PROGBITS: 79fe6060f1SDimitry Andric case ELF::SHT_X86_64_UNWIND: 80fe6060f1SDimitry Andric return Header->sh_flags & (ELF::SHF_EXECINSTR | ELF::SHF_ALLOC); 81fe6060f1SDimitry Andric } 82fe6060f1SDimitry Andric return false; 83fe6060f1SDimitry Andric } 84fe6060f1SDimitry Andric 85fe6060f1SDimitry Andric template <typename ELFT> 86fe6060f1SDimitry Andric Error ELFDebugObjectSection<ELFT>::validateInBounds(StringRef Buffer, 87fe6060f1SDimitry Andric const char *Name) const { 88fe6060f1SDimitry Andric const uint8_t *Start = Buffer.bytes_begin(); 89fe6060f1SDimitry Andric const uint8_t *End = Buffer.bytes_end(); 90fe6060f1SDimitry Andric const uint8_t *HeaderPtr = reinterpret_cast<uint8_t *>(Header); 91fe6060f1SDimitry Andric if (HeaderPtr < Start || HeaderPtr + sizeof(typename ELFT::Shdr) > End) 92fe6060f1SDimitry Andric return make_error<StringError>( 93fe6060f1SDimitry Andric formatv("{0} section header at {1:x16} not within bounds of the " 94fe6060f1SDimitry Andric "given debug object buffer [{2:x16} - {3:x16}]", 95fe6060f1SDimitry Andric Name, &Header->sh_addr, Start, End), 96fe6060f1SDimitry Andric inconvertibleErrorCode()); 97fe6060f1SDimitry Andric if (Header->sh_offset + Header->sh_size > Buffer.size()) 98fe6060f1SDimitry Andric return make_error<StringError>( 99fe6060f1SDimitry Andric formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of " 100fe6060f1SDimitry Andric "the given debug object buffer [{3:x16} - {4:x16}]", 101fe6060f1SDimitry Andric Name, Start + Header->sh_offset, 102fe6060f1SDimitry Andric Start + Header->sh_offset + Header->sh_size, Start, End), 103fe6060f1SDimitry Andric inconvertibleErrorCode()); 104fe6060f1SDimitry Andric return Error::success(); 105fe6060f1SDimitry Andric } 106fe6060f1SDimitry Andric 107fe6060f1SDimitry Andric template <typename ELFT> 108fe6060f1SDimitry Andric void ELFDebugObjectSection<ELFT>::dump(raw_ostream &OS, StringRef Name) { 109fe6060f1SDimitry Andric if (auto Addr = static_cast<JITTargetAddress>(Header->sh_addr)) { 110fe6060f1SDimitry Andric OS << formatv(" {0:x16} {1}\n", Addr, Name); 111fe6060f1SDimitry Andric } else { 112fe6060f1SDimitry Andric OS << formatv(" {0}\n", Name); 113fe6060f1SDimitry Andric } 114fe6060f1SDimitry Andric } 115fe6060f1SDimitry Andric 116fe6060f1SDimitry Andric enum class Requirement { 117fe6060f1SDimitry Andric // Request final target memory load-addresses for all sections. 118fe6060f1SDimitry Andric ReportFinalSectionLoadAddresses, 119fe6060f1SDimitry Andric }; 120fe6060f1SDimitry Andric 121*349cc55cSDimitry Andric /// The plugin creates a debug object from when JITLink starts processing the 122*349cc55cSDimitry Andric /// corresponding LinkGraph. It provides access to the pass configuration of 123*349cc55cSDimitry Andric /// the LinkGraph and calls the finalization function, once the resulting link 124*349cc55cSDimitry Andric /// artifact was emitted. 125fe6060f1SDimitry Andric /// 126fe6060f1SDimitry Andric class DebugObject { 127fe6060f1SDimitry Andric public: 128*349cc55cSDimitry Andric DebugObject(JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD, 129*349cc55cSDimitry Andric ExecutionSession &ES) 130*349cc55cSDimitry Andric : MemMgr(MemMgr), JD(JD), ES(ES) {} 131fe6060f1SDimitry Andric 132fe6060f1SDimitry Andric void set(Requirement Req) { Reqs.insert(Req); } 133fe6060f1SDimitry Andric bool has(Requirement Req) const { return Reqs.count(Req) > 0; } 134fe6060f1SDimitry Andric 135*349cc55cSDimitry Andric using FinalizeContinuation = std::function<void(Expected<ExecutorAddrRange>)>; 136*349cc55cSDimitry Andric 137fe6060f1SDimitry Andric void finalizeAsync(FinalizeContinuation OnFinalize); 138fe6060f1SDimitry Andric 139fe6060f1SDimitry Andric virtual ~DebugObject() { 140*349cc55cSDimitry Andric if (Alloc) { 141*349cc55cSDimitry Andric std::vector<FinalizedAlloc> Allocs; 142*349cc55cSDimitry Andric Allocs.push_back(std::move(Alloc)); 143*349cc55cSDimitry Andric if (Error Err = MemMgr.deallocate(std::move(Allocs))) 144fe6060f1SDimitry Andric ES.reportError(std::move(Err)); 145fe6060f1SDimitry Andric } 146*349cc55cSDimitry Andric } 147fe6060f1SDimitry Andric 148fe6060f1SDimitry Andric virtual void reportSectionTargetMemoryRange(StringRef Name, 149fe6060f1SDimitry Andric SectionRange TargetMem) {} 150fe6060f1SDimitry Andric 151fe6060f1SDimitry Andric protected: 152*349cc55cSDimitry Andric using InFlightAlloc = JITLinkMemoryManager::InFlightAlloc; 153*349cc55cSDimitry Andric using FinalizedAlloc = JITLinkMemoryManager::FinalizedAlloc; 154fe6060f1SDimitry Andric 155*349cc55cSDimitry Andric virtual Expected<SimpleSegmentAlloc> finalizeWorkingMemory() = 0; 156*349cc55cSDimitry Andric 157*349cc55cSDimitry Andric JITLinkMemoryManager &MemMgr; 158*349cc55cSDimitry Andric const JITLinkDylib *JD = nullptr; 159fe6060f1SDimitry Andric 160fe6060f1SDimitry Andric private: 161fe6060f1SDimitry Andric ExecutionSession &ES; 162fe6060f1SDimitry Andric std::set<Requirement> Reqs; 163*349cc55cSDimitry Andric FinalizedAlloc Alloc; 164fe6060f1SDimitry Andric }; 165fe6060f1SDimitry Andric 166fe6060f1SDimitry Andric // Finalize working memory and take ownership of the resulting allocation. Start 167fe6060f1SDimitry Andric // copying memory over to the target and pass on the result once we're done. 168fe6060f1SDimitry Andric // Ownership of the allocation remains with us for the rest of our lifetime. 169fe6060f1SDimitry Andric void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize) { 170*349cc55cSDimitry Andric assert(!Alloc && "Cannot finalize more than once"); 171fe6060f1SDimitry Andric 172*349cc55cSDimitry Andric if (auto SimpleSegAlloc = finalizeWorkingMemory()) { 173*349cc55cSDimitry Andric auto ROSeg = SimpleSegAlloc->getSegInfo(MemProt::Read); 174*349cc55cSDimitry Andric ExecutorAddrRange DebugObjRange(ExecutorAddr(ROSeg.Addr), 175*349cc55cSDimitry Andric ExecutorAddrDiff(ROSeg.WorkingMem.size())); 176*349cc55cSDimitry Andric SimpleSegAlloc->finalize( 177*349cc55cSDimitry Andric [this, DebugObjRange, 178*349cc55cSDimitry Andric OnFinalize = std::move(OnFinalize)](Expected<FinalizedAlloc> FA) { 179*349cc55cSDimitry Andric if (FA) { 180*349cc55cSDimitry Andric Alloc = std::move(*FA); 181*349cc55cSDimitry Andric OnFinalize(DebugObjRange); 182*349cc55cSDimitry Andric } else 183*349cc55cSDimitry Andric OnFinalize(FA.takeError()); 184fe6060f1SDimitry Andric }); 185*349cc55cSDimitry Andric } else 186*349cc55cSDimitry Andric OnFinalize(SimpleSegAlloc.takeError()); 187fe6060f1SDimitry Andric } 188fe6060f1SDimitry Andric 189fe6060f1SDimitry Andric /// The current implementation of ELFDebugObject replicates the approach used in 190fe6060f1SDimitry Andric /// RuntimeDyld: It patches executable and data section headers in the given 191fe6060f1SDimitry Andric /// object buffer with load-addresses of their corresponding sections in target 192fe6060f1SDimitry Andric /// memory. 193fe6060f1SDimitry Andric /// 194fe6060f1SDimitry Andric class ELFDebugObject : public DebugObject { 195fe6060f1SDimitry Andric public: 196fe6060f1SDimitry Andric static Expected<std::unique_ptr<DebugObject>> 197fe6060f1SDimitry Andric Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, ExecutionSession &ES); 198fe6060f1SDimitry Andric 199fe6060f1SDimitry Andric void reportSectionTargetMemoryRange(StringRef Name, 200fe6060f1SDimitry Andric SectionRange TargetMem) override; 201fe6060f1SDimitry Andric 202fe6060f1SDimitry Andric StringRef getBuffer() const { return Buffer->getMemBufferRef().getBuffer(); } 203fe6060f1SDimitry Andric 204fe6060f1SDimitry Andric protected: 205*349cc55cSDimitry Andric Expected<SimpleSegmentAlloc> finalizeWorkingMemory() override; 206fe6060f1SDimitry Andric 207fe6060f1SDimitry Andric template <typename ELFT> 208fe6060f1SDimitry Andric Error recordSection(StringRef Name, 209fe6060f1SDimitry Andric std::unique_ptr<ELFDebugObjectSection<ELFT>> Section); 210fe6060f1SDimitry Andric DebugObjectSection *getSection(StringRef Name); 211fe6060f1SDimitry Andric 212fe6060f1SDimitry Andric private: 213fe6060f1SDimitry Andric template <typename ELFT> 214fe6060f1SDimitry Andric static Expected<std::unique_ptr<ELFDebugObject>> 215*349cc55cSDimitry Andric CreateArchType(MemoryBufferRef Buffer, JITLinkMemoryManager &MemMgr, 216*349cc55cSDimitry Andric const JITLinkDylib *JD, ExecutionSession &ES); 217fe6060f1SDimitry Andric 218fe6060f1SDimitry Andric static std::unique_ptr<WritableMemoryBuffer> 219fe6060f1SDimitry Andric CopyBuffer(MemoryBufferRef Buffer, Error &Err); 220fe6060f1SDimitry Andric 221fe6060f1SDimitry Andric ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer, 222*349cc55cSDimitry Andric JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD, 223*349cc55cSDimitry Andric ExecutionSession &ES) 224*349cc55cSDimitry Andric : DebugObject(MemMgr, JD, ES), Buffer(std::move(Buffer)) { 225fe6060f1SDimitry Andric set(Requirement::ReportFinalSectionLoadAddresses); 226fe6060f1SDimitry Andric } 227fe6060f1SDimitry Andric 228fe6060f1SDimitry Andric std::unique_ptr<WritableMemoryBuffer> Buffer; 229fe6060f1SDimitry Andric StringMap<std::unique_ptr<DebugObjectSection>> Sections; 230fe6060f1SDimitry Andric }; 231fe6060f1SDimitry Andric 232fe6060f1SDimitry Andric static const std::set<StringRef> DwarfSectionNames = { 233fe6060f1SDimitry Andric #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \ 234fe6060f1SDimitry Andric ELF_NAME, 235fe6060f1SDimitry Andric #include "llvm/BinaryFormat/Dwarf.def" 236fe6060f1SDimitry Andric #undef HANDLE_DWARF_SECTION 237fe6060f1SDimitry Andric }; 238fe6060f1SDimitry Andric 239fe6060f1SDimitry Andric static bool isDwarfSection(StringRef SectionName) { 240fe6060f1SDimitry Andric return DwarfSectionNames.count(SectionName) == 1; 241fe6060f1SDimitry Andric } 242fe6060f1SDimitry Andric 243fe6060f1SDimitry Andric std::unique_ptr<WritableMemoryBuffer> 244fe6060f1SDimitry Andric ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) { 245fe6060f1SDimitry Andric ErrorAsOutParameter _(&Err); 246fe6060f1SDimitry Andric size_t Size = Buffer.getBufferSize(); 247fe6060f1SDimitry Andric StringRef Name = Buffer.getBufferIdentifier(); 248fe6060f1SDimitry Andric if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) { 249fe6060f1SDimitry Andric memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size); 250fe6060f1SDimitry Andric return Copy; 251fe6060f1SDimitry Andric } 252fe6060f1SDimitry Andric 253fe6060f1SDimitry Andric Err = errorCodeToError(make_error_code(errc::not_enough_memory)); 254fe6060f1SDimitry Andric return nullptr; 255fe6060f1SDimitry Andric } 256fe6060f1SDimitry Andric 257fe6060f1SDimitry Andric template <typename ELFT> 258fe6060f1SDimitry Andric Expected<std::unique_ptr<ELFDebugObject>> 259*349cc55cSDimitry Andric ELFDebugObject::CreateArchType(MemoryBufferRef Buffer, 260*349cc55cSDimitry Andric JITLinkMemoryManager &MemMgr, 261*349cc55cSDimitry Andric const JITLinkDylib *JD, ExecutionSession &ES) { 262fe6060f1SDimitry Andric using SectionHeader = typename ELFT::Shdr; 263fe6060f1SDimitry Andric 264fe6060f1SDimitry Andric Error Err = Error::success(); 265fe6060f1SDimitry Andric std::unique_ptr<ELFDebugObject> DebugObj( 266*349cc55cSDimitry Andric new ELFDebugObject(CopyBuffer(Buffer, Err), MemMgr, JD, ES)); 267fe6060f1SDimitry Andric if (Err) 268fe6060f1SDimitry Andric return std::move(Err); 269fe6060f1SDimitry Andric 270fe6060f1SDimitry Andric Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer()); 271fe6060f1SDimitry Andric if (!ObjRef) 272fe6060f1SDimitry Andric return ObjRef.takeError(); 273fe6060f1SDimitry Andric 274fe6060f1SDimitry Andric // TODO: Add support for other architectures. 275fe6060f1SDimitry Andric uint16_t TargetMachineArch = ObjRef->getHeader().e_machine; 276fe6060f1SDimitry Andric if (TargetMachineArch != ELF::EM_X86_64) 277fe6060f1SDimitry Andric return nullptr; 278fe6060f1SDimitry Andric 279fe6060f1SDimitry Andric Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections(); 280fe6060f1SDimitry Andric if (!Sections) 281fe6060f1SDimitry Andric return Sections.takeError(); 282fe6060f1SDimitry Andric 283fe6060f1SDimitry Andric bool HasDwarfSection = false; 284fe6060f1SDimitry Andric for (const SectionHeader &Header : *Sections) { 285fe6060f1SDimitry Andric Expected<StringRef> Name = ObjRef->getSectionName(Header); 286fe6060f1SDimitry Andric if (!Name) 287fe6060f1SDimitry Andric return Name.takeError(); 288fe6060f1SDimitry Andric if (Name->empty()) 289fe6060f1SDimitry Andric continue; 290fe6060f1SDimitry Andric HasDwarfSection |= isDwarfSection(*Name); 291fe6060f1SDimitry Andric 292fe6060f1SDimitry Andric auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header); 293fe6060f1SDimitry Andric if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped))) 294fe6060f1SDimitry Andric return std::move(Err); 295fe6060f1SDimitry Andric } 296fe6060f1SDimitry Andric 297fe6060f1SDimitry Andric if (!HasDwarfSection) { 298fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \"" 299fe6060f1SDimitry Andric << DebugObj->Buffer->getBufferIdentifier() 300fe6060f1SDimitry Andric << "\": input object contains no debug info\n"); 301fe6060f1SDimitry Andric return nullptr; 302fe6060f1SDimitry Andric } 303fe6060f1SDimitry Andric 304fe6060f1SDimitry Andric return std::move(DebugObj); 305fe6060f1SDimitry Andric } 306fe6060f1SDimitry Andric 307fe6060f1SDimitry Andric Expected<std::unique_ptr<DebugObject>> 308fe6060f1SDimitry Andric ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, 309fe6060f1SDimitry Andric ExecutionSession &ES) { 310fe6060f1SDimitry Andric unsigned char Class, Endian; 311fe6060f1SDimitry Andric std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer()); 312fe6060f1SDimitry Andric 313fe6060f1SDimitry Andric if (Class == ELF::ELFCLASS32) { 314fe6060f1SDimitry Andric if (Endian == ELF::ELFDATA2LSB) 315*349cc55cSDimitry Andric return CreateArchType<ELF32LE>(Buffer, Ctx.getMemoryManager(), 316*349cc55cSDimitry Andric Ctx.getJITLinkDylib(), ES); 317fe6060f1SDimitry Andric if (Endian == ELF::ELFDATA2MSB) 318*349cc55cSDimitry Andric return CreateArchType<ELF32BE>(Buffer, Ctx.getMemoryManager(), 319*349cc55cSDimitry Andric Ctx.getJITLinkDylib(), ES); 320fe6060f1SDimitry Andric return nullptr; 321fe6060f1SDimitry Andric } 322fe6060f1SDimitry Andric if (Class == ELF::ELFCLASS64) { 323fe6060f1SDimitry Andric if (Endian == ELF::ELFDATA2LSB) 324*349cc55cSDimitry Andric return CreateArchType<ELF64LE>(Buffer, Ctx.getMemoryManager(), 325*349cc55cSDimitry Andric Ctx.getJITLinkDylib(), ES); 326fe6060f1SDimitry Andric if (Endian == ELF::ELFDATA2MSB) 327*349cc55cSDimitry Andric return CreateArchType<ELF64BE>(Buffer, Ctx.getMemoryManager(), 328*349cc55cSDimitry Andric Ctx.getJITLinkDylib(), ES); 329fe6060f1SDimitry Andric return nullptr; 330fe6060f1SDimitry Andric } 331fe6060f1SDimitry Andric return nullptr; 332fe6060f1SDimitry Andric } 333fe6060f1SDimitry Andric 334*349cc55cSDimitry Andric Expected<SimpleSegmentAlloc> ELFDebugObject::finalizeWorkingMemory() { 335fe6060f1SDimitry Andric LLVM_DEBUG({ 336fe6060f1SDimitry Andric dbgs() << "Section load-addresses in debug object for \"" 337fe6060f1SDimitry Andric << Buffer->getBufferIdentifier() << "\":\n"; 338fe6060f1SDimitry Andric for (const auto &KV : Sections) 339fe6060f1SDimitry Andric KV.second->dump(dbgs(), KV.first()); 340fe6060f1SDimitry Andric }); 341fe6060f1SDimitry Andric 342fe6060f1SDimitry Andric // TODO: This works, but what actual alignment requirements do we have? 343*349cc55cSDimitry Andric unsigned PageSize = sys::Process::getPageSizeEstimate(); 344fe6060f1SDimitry Andric size_t Size = Buffer->getBufferSize(); 345fe6060f1SDimitry Andric 346fe6060f1SDimitry Andric // Allocate working memory for debug object in read-only segment. 347*349cc55cSDimitry Andric auto Alloc = SimpleSegmentAlloc::Create( 348*349cc55cSDimitry Andric MemMgr, JD, {{MemProt::Read, {Size, Align(PageSize)}}}); 349*349cc55cSDimitry Andric if (!Alloc) 350*349cc55cSDimitry Andric return Alloc; 351fe6060f1SDimitry Andric 352fe6060f1SDimitry Andric // Initialize working memory with a copy of our object buffer. 353*349cc55cSDimitry Andric auto SegInfo = Alloc->getSegInfo(MemProt::Read); 354*349cc55cSDimitry Andric memcpy(SegInfo.WorkingMem.data(), Buffer->getBufferStart(), Size); 355fe6060f1SDimitry Andric Buffer.reset(); 356fe6060f1SDimitry Andric 357*349cc55cSDimitry Andric return Alloc; 358fe6060f1SDimitry Andric } 359fe6060f1SDimitry Andric 360fe6060f1SDimitry Andric void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name, 361fe6060f1SDimitry Andric SectionRange TargetMem) { 362fe6060f1SDimitry Andric if (auto *DebugObjSection = getSection(Name)) 363fe6060f1SDimitry Andric DebugObjSection->setTargetMemoryRange(TargetMem); 364fe6060f1SDimitry Andric } 365fe6060f1SDimitry Andric 366fe6060f1SDimitry Andric template <typename ELFT> 367fe6060f1SDimitry Andric Error ELFDebugObject::recordSection( 368fe6060f1SDimitry Andric StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) { 369fe6060f1SDimitry Andric if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data())) 370fe6060f1SDimitry Andric return Err; 371fe6060f1SDimitry Andric auto ItInserted = Sections.try_emplace(Name, std::move(Section)); 372fe6060f1SDimitry Andric if (!ItInserted.second) 373fe6060f1SDimitry Andric return make_error<StringError>("Duplicate section", 374fe6060f1SDimitry Andric inconvertibleErrorCode()); 375fe6060f1SDimitry Andric return Error::success(); 376fe6060f1SDimitry Andric } 377fe6060f1SDimitry Andric 378fe6060f1SDimitry Andric DebugObjectSection *ELFDebugObject::getSection(StringRef Name) { 379fe6060f1SDimitry Andric auto It = Sections.find(Name); 380fe6060f1SDimitry Andric return It == Sections.end() ? nullptr : It->second.get(); 381fe6060f1SDimitry Andric } 382fe6060f1SDimitry Andric 383fe6060f1SDimitry Andric /// Creates a debug object based on the input object file from 384fe6060f1SDimitry Andric /// ObjectLinkingLayerJITLinkContext. 385fe6060f1SDimitry Andric /// 386fe6060f1SDimitry Andric static Expected<std::unique_ptr<DebugObject>> 387fe6060f1SDimitry Andric createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G, 388fe6060f1SDimitry Andric JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) { 389fe6060f1SDimitry Andric switch (G.getTargetTriple().getObjectFormat()) { 390fe6060f1SDimitry Andric case Triple::ELF: 391fe6060f1SDimitry Andric return ELFDebugObject::Create(ObjBuffer, Ctx, ES); 392fe6060f1SDimitry Andric 393fe6060f1SDimitry Andric default: 394fe6060f1SDimitry Andric // TODO: Once we add support for other formats, we might want to split this 395fe6060f1SDimitry Andric // into multiple files. 396fe6060f1SDimitry Andric return nullptr; 397fe6060f1SDimitry Andric } 398fe6060f1SDimitry Andric } 399fe6060f1SDimitry Andric 400fe6060f1SDimitry Andric DebugObjectManagerPlugin::DebugObjectManagerPlugin( 401fe6060f1SDimitry Andric ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target) 402fe6060f1SDimitry Andric : ES(ES), Target(std::move(Target)) {} 403fe6060f1SDimitry Andric 404fe6060f1SDimitry Andric DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default; 405fe6060f1SDimitry Andric 406fe6060f1SDimitry Andric void DebugObjectManagerPlugin::notifyMaterializing( 407fe6060f1SDimitry Andric MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx, 408fe6060f1SDimitry Andric MemoryBufferRef ObjBuffer) { 409fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PendingObjsLock); 410fe6060f1SDimitry Andric assert(PendingObjs.count(&MR) == 0 && 411fe6060f1SDimitry Andric "Cannot have more than one pending debug object per " 412fe6060f1SDimitry Andric "MaterializationResponsibility"); 413fe6060f1SDimitry Andric 414fe6060f1SDimitry Andric if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) { 415fe6060f1SDimitry Andric // Not all link artifacts allow debugging. 416fe6060f1SDimitry Andric if (*DebugObj != nullptr) 417fe6060f1SDimitry Andric PendingObjs[&MR] = std::move(*DebugObj); 418fe6060f1SDimitry Andric } else { 419fe6060f1SDimitry Andric ES.reportError(DebugObj.takeError()); 420fe6060f1SDimitry Andric } 421fe6060f1SDimitry Andric } 422fe6060f1SDimitry Andric 423fe6060f1SDimitry Andric void DebugObjectManagerPlugin::modifyPassConfig( 424fe6060f1SDimitry Andric MaterializationResponsibility &MR, LinkGraph &G, 425fe6060f1SDimitry Andric PassConfiguration &PassConfig) { 426fe6060f1SDimitry Andric // Not all link artifacts have associated debug objects. 427fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PendingObjsLock); 428fe6060f1SDimitry Andric auto It = PendingObjs.find(&MR); 429fe6060f1SDimitry Andric if (It == PendingObjs.end()) 430fe6060f1SDimitry Andric return; 431fe6060f1SDimitry Andric 432fe6060f1SDimitry Andric DebugObject &DebugObj = *It->second; 433fe6060f1SDimitry Andric if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) { 434fe6060f1SDimitry Andric PassConfig.PostAllocationPasses.push_back( 435fe6060f1SDimitry Andric [&DebugObj](LinkGraph &Graph) -> Error { 436fe6060f1SDimitry Andric for (const Section &GraphSection : Graph.sections()) 437fe6060f1SDimitry Andric DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(), 438fe6060f1SDimitry Andric SectionRange(GraphSection)); 439fe6060f1SDimitry Andric return Error::success(); 440fe6060f1SDimitry Andric }); 441fe6060f1SDimitry Andric } 442fe6060f1SDimitry Andric } 443fe6060f1SDimitry Andric 444fe6060f1SDimitry Andric Error DebugObjectManagerPlugin::notifyEmitted( 445fe6060f1SDimitry Andric MaterializationResponsibility &MR) { 446fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PendingObjsLock); 447fe6060f1SDimitry Andric auto It = PendingObjs.find(&MR); 448fe6060f1SDimitry Andric if (It == PendingObjs.end()) 449fe6060f1SDimitry Andric return Error::success(); 450fe6060f1SDimitry Andric 451fe6060f1SDimitry Andric // During finalization the debug object is registered with the target. 452fe6060f1SDimitry Andric // Materialization must wait for this process to finish. Otherwise we might 453fe6060f1SDimitry Andric // start running code before the debugger processed the corresponding debug 454fe6060f1SDimitry Andric // info. 455fe6060f1SDimitry Andric std::promise<MSVCPError> FinalizePromise; 456fe6060f1SDimitry Andric std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future(); 457fe6060f1SDimitry Andric 458fe6060f1SDimitry Andric It->second->finalizeAsync( 459*349cc55cSDimitry Andric [this, &FinalizePromise, &MR](Expected<ExecutorAddrRange> TargetMem) { 460fe6060f1SDimitry Andric // Any failure here will fail materialization. 461fe6060f1SDimitry Andric if (!TargetMem) { 462fe6060f1SDimitry Andric FinalizePromise.set_value(TargetMem.takeError()); 463fe6060f1SDimitry Andric return; 464fe6060f1SDimitry Andric } 465fe6060f1SDimitry Andric if (Error Err = Target->registerDebugObject(*TargetMem)) { 466fe6060f1SDimitry Andric FinalizePromise.set_value(std::move(Err)); 467fe6060f1SDimitry Andric return; 468fe6060f1SDimitry Andric } 469fe6060f1SDimitry Andric 470fe6060f1SDimitry Andric // Once our tracking info is updated, notifyEmitted() can return and 471fe6060f1SDimitry Andric // finish materialization. 472fe6060f1SDimitry Andric FinalizePromise.set_value(MR.withResourceKeyDo([&](ResourceKey K) { 473fe6060f1SDimitry Andric assert(PendingObjs.count(&MR) && "We still hold PendingObjsLock"); 474fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 475fe6060f1SDimitry Andric RegisteredObjs[K].push_back(std::move(PendingObjs[&MR])); 476fe6060f1SDimitry Andric PendingObjs.erase(&MR); 477fe6060f1SDimitry Andric })); 478fe6060f1SDimitry Andric }); 479fe6060f1SDimitry Andric 480fe6060f1SDimitry Andric return FinalizeErr.get(); 481fe6060f1SDimitry Andric } 482fe6060f1SDimitry Andric 483fe6060f1SDimitry Andric Error DebugObjectManagerPlugin::notifyFailed( 484fe6060f1SDimitry Andric MaterializationResponsibility &MR) { 485fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(PendingObjsLock); 486fe6060f1SDimitry Andric PendingObjs.erase(&MR); 487fe6060f1SDimitry Andric return Error::success(); 488fe6060f1SDimitry Andric } 489fe6060f1SDimitry Andric 490fe6060f1SDimitry Andric void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey, 491fe6060f1SDimitry Andric ResourceKey SrcKey) { 492fe6060f1SDimitry Andric // Debug objects are stored by ResourceKey only after registration. 493fe6060f1SDimitry Andric // Thus, pending objects don't need to be updated here. 494fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 495fe6060f1SDimitry Andric auto SrcIt = RegisteredObjs.find(SrcKey); 496fe6060f1SDimitry Andric if (SrcIt != RegisteredObjs.end()) { 497fe6060f1SDimitry Andric // Resources from distinct MaterializationResponsibilitys can get merged 498fe6060f1SDimitry Andric // after emission, so we can have multiple debug objects per resource key. 499fe6060f1SDimitry Andric for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second) 500fe6060f1SDimitry Andric RegisteredObjs[DstKey].push_back(std::move(DebugObj)); 501fe6060f1SDimitry Andric RegisteredObjs.erase(SrcIt); 502fe6060f1SDimitry Andric } 503fe6060f1SDimitry Andric } 504fe6060f1SDimitry Andric 505fe6060f1SDimitry Andric Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey Key) { 506fe6060f1SDimitry Andric // Removing the resource for a pending object fails materialization, so they 507fe6060f1SDimitry Andric // get cleaned up in the notifyFailed() handler. 508fe6060f1SDimitry Andric std::lock_guard<std::mutex> Lock(RegisteredObjsLock); 509fe6060f1SDimitry Andric RegisteredObjs.erase(Key); 510fe6060f1SDimitry Andric 511fe6060f1SDimitry Andric // TODO: Implement unregister notifications. 512fe6060f1SDimitry Andric return Error::success(); 513fe6060f1SDimitry Andric } 514fe6060f1SDimitry Andric 515fe6060f1SDimitry Andric } // namespace orc 516fe6060f1SDimitry Andric } // namespace llvm 517