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