1*5f757f3fSDimitry Andric //===------- DebuggerSupportPlugin.cpp - Utils for debugger support -------===// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric // 9*5f757f3fSDimitry Andric // 10*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 11*5f757f3fSDimitry Andric 12*5f757f3fSDimitry Andric #include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.h" 13*5f757f3fSDimitry Andric #include "llvm/ExecutionEngine/Orc/MachOBuilder.h" 14*5f757f3fSDimitry Andric 15*5f757f3fSDimitry Andric #include "llvm/ADT/SmallSet.h" 16*5f757f3fSDimitry Andric #include "llvm/ADT/SmallVector.h" 17*5f757f3fSDimitry Andric #include "llvm/BinaryFormat/MachO.h" 18*5f757f3fSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 19*5f757f3fSDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" 20*5f757f3fSDimitry Andric 21*5f757f3fSDimitry Andric #include <chrono> 22*5f757f3fSDimitry Andric 23*5f757f3fSDimitry Andric #define DEBUG_TYPE "orc" 24*5f757f3fSDimitry Andric 25*5f757f3fSDimitry Andric using namespace llvm; 26*5f757f3fSDimitry Andric using namespace llvm::jitlink; 27*5f757f3fSDimitry Andric using namespace llvm::orc; 28*5f757f3fSDimitry Andric 29*5f757f3fSDimitry Andric static const char *SynthDebugSectionName = "__jitlink_synth_debug_object"; 30*5f757f3fSDimitry Andric 31*5f757f3fSDimitry Andric namespace { 32*5f757f3fSDimitry Andric 33*5f757f3fSDimitry Andric class MachODebugObjectSynthesizerBase 34*5f757f3fSDimitry Andric : public GDBJITDebugInfoRegistrationPlugin::DebugSectionSynthesizer { 35*5f757f3fSDimitry Andric public: 36*5f757f3fSDimitry Andric static bool isDebugSection(Section &Sec) { 37*5f757f3fSDimitry Andric return Sec.getName().starts_with("__DWARF,"); 38*5f757f3fSDimitry Andric } 39*5f757f3fSDimitry Andric 40*5f757f3fSDimitry Andric MachODebugObjectSynthesizerBase(LinkGraph &G, ExecutorAddr RegisterActionAddr) 41*5f757f3fSDimitry Andric : G(G), RegisterActionAddr(RegisterActionAddr) {} 42*5f757f3fSDimitry Andric virtual ~MachODebugObjectSynthesizerBase() = default; 43*5f757f3fSDimitry Andric 44*5f757f3fSDimitry Andric Error preserveDebugSections() { 45*5f757f3fSDimitry Andric if (G.findSectionByName(SynthDebugSectionName)) { 46*5f757f3fSDimitry Andric LLVM_DEBUG({ 47*5f757f3fSDimitry Andric dbgs() << "MachODebugObjectSynthesizer skipping graph " << G.getName() 48*5f757f3fSDimitry Andric << " which contains an unexpected existing " 49*5f757f3fSDimitry Andric << SynthDebugSectionName << " section.\n"; 50*5f757f3fSDimitry Andric }); 51*5f757f3fSDimitry Andric return Error::success(); 52*5f757f3fSDimitry Andric } 53*5f757f3fSDimitry Andric 54*5f757f3fSDimitry Andric LLVM_DEBUG({ 55*5f757f3fSDimitry Andric dbgs() << "MachODebugObjectSynthesizer visiting graph " << G.getName() 56*5f757f3fSDimitry Andric << "\n"; 57*5f757f3fSDimitry Andric }); 58*5f757f3fSDimitry Andric for (auto &Sec : G.sections()) { 59*5f757f3fSDimitry Andric if (!isDebugSection(Sec)) 60*5f757f3fSDimitry Andric continue; 61*5f757f3fSDimitry Andric // Preserve blocks in this debug section by marking one existing symbol 62*5f757f3fSDimitry Andric // live for each block, and introducing a new live, anonymous symbol for 63*5f757f3fSDimitry Andric // each currently unreferenced block. 64*5f757f3fSDimitry Andric LLVM_DEBUG({ 65*5f757f3fSDimitry Andric dbgs() << " Preserving debug section " << Sec.getName() << "\n"; 66*5f757f3fSDimitry Andric }); 67*5f757f3fSDimitry Andric SmallSet<Block *, 8> PreservedBlocks; 68*5f757f3fSDimitry Andric for (auto *Sym : Sec.symbols()) { 69*5f757f3fSDimitry Andric bool NewPreservedBlock = 70*5f757f3fSDimitry Andric PreservedBlocks.insert(&Sym->getBlock()).second; 71*5f757f3fSDimitry Andric if (NewPreservedBlock) 72*5f757f3fSDimitry Andric Sym->setLive(true); 73*5f757f3fSDimitry Andric } 74*5f757f3fSDimitry Andric for (auto *B : Sec.blocks()) 75*5f757f3fSDimitry Andric if (!PreservedBlocks.count(B)) 76*5f757f3fSDimitry Andric G.addAnonymousSymbol(*B, 0, 0, false, true); 77*5f757f3fSDimitry Andric } 78*5f757f3fSDimitry Andric 79*5f757f3fSDimitry Andric return Error::success(); 80*5f757f3fSDimitry Andric } 81*5f757f3fSDimitry Andric 82*5f757f3fSDimitry Andric protected: 83*5f757f3fSDimitry Andric LinkGraph &G; 84*5f757f3fSDimitry Andric ExecutorAddr RegisterActionAddr; 85*5f757f3fSDimitry Andric }; 86*5f757f3fSDimitry Andric 87*5f757f3fSDimitry Andric template <typename MachOTraits> 88*5f757f3fSDimitry Andric class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase { 89*5f757f3fSDimitry Andric public: 90*5f757f3fSDimitry Andric MachODebugObjectSynthesizer(ExecutionSession &ES, LinkGraph &G, 91*5f757f3fSDimitry Andric ExecutorAddr RegisterActionAddr) 92*5f757f3fSDimitry Andric : MachODebugObjectSynthesizerBase(G, RegisterActionAddr), 93*5f757f3fSDimitry Andric Builder(ES.getPageSize()) {} 94*5f757f3fSDimitry Andric 95*5f757f3fSDimitry Andric using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase; 96*5f757f3fSDimitry Andric 97*5f757f3fSDimitry Andric Error startSynthesis() override { 98*5f757f3fSDimitry Andric LLVM_DEBUG({ 99*5f757f3fSDimitry Andric dbgs() << "Creating " << SynthDebugSectionName << " for " << G.getName() 100*5f757f3fSDimitry Andric << "\n"; 101*5f757f3fSDimitry Andric }); 102*5f757f3fSDimitry Andric 103*5f757f3fSDimitry Andric for (auto &Sec : G.sections()) { 104*5f757f3fSDimitry Andric if (Sec.blocks().empty()) 105*5f757f3fSDimitry Andric continue; 106*5f757f3fSDimitry Andric 107*5f757f3fSDimitry Andric // Skip sections whose name's don't fit the MachO standard. 108*5f757f3fSDimitry Andric if (Sec.getName().empty() || Sec.getName().size() > 33 || 109*5f757f3fSDimitry Andric Sec.getName().find(',') > 16) 110*5f757f3fSDimitry Andric continue; 111*5f757f3fSDimitry Andric 112*5f757f3fSDimitry Andric if (isDebugSection(Sec)) 113*5f757f3fSDimitry Andric DebugSections.push_back({&Sec, nullptr}); 114*5f757f3fSDimitry Andric else if (Sec.getMemLifetime() != MemLifetime::NoAlloc) 115*5f757f3fSDimitry Andric NonDebugSections.push_back({&Sec, nullptr}); 116*5f757f3fSDimitry Andric } 117*5f757f3fSDimitry Andric 118*5f757f3fSDimitry Andric // Bail out early if no debug sections. 119*5f757f3fSDimitry Andric if (DebugSections.empty()) 120*5f757f3fSDimitry Andric return Error::success(); 121*5f757f3fSDimitry Andric 122*5f757f3fSDimitry Andric // Write MachO header and debug section load commands. 123*5f757f3fSDimitry Andric Builder.Header.filetype = MachO::MH_OBJECT; 124*5f757f3fSDimitry Andric switch (G.getTargetTriple().getArch()) { 125*5f757f3fSDimitry Andric case Triple::x86_64: 126*5f757f3fSDimitry Andric Builder.Header.cputype = MachO::CPU_TYPE_X86_64; 127*5f757f3fSDimitry Andric Builder.Header.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL; 128*5f757f3fSDimitry Andric break; 129*5f757f3fSDimitry Andric case Triple::aarch64: 130*5f757f3fSDimitry Andric Builder.Header.cputype = MachO::CPU_TYPE_ARM64; 131*5f757f3fSDimitry Andric Builder.Header.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL; 132*5f757f3fSDimitry Andric break; 133*5f757f3fSDimitry Andric default: 134*5f757f3fSDimitry Andric llvm_unreachable("Unsupported architecture"); 135*5f757f3fSDimitry Andric } 136*5f757f3fSDimitry Andric 137*5f757f3fSDimitry Andric Seg = &Builder.addSegment(""); 138*5f757f3fSDimitry Andric 139*5f757f3fSDimitry Andric StringMap<std::unique_ptr<MemoryBuffer>> DebugSectionMap; 140*5f757f3fSDimitry Andric StringRef DebugLineSectionData; 141*5f757f3fSDimitry Andric for (auto &DSec : DebugSections) { 142*5f757f3fSDimitry Andric auto [SegName, SecName] = DSec.GraphSec->getName().split(','); 143*5f757f3fSDimitry Andric DSec.BuilderSec = &Seg->addSection(SecName, SegName); 144*5f757f3fSDimitry Andric 145*5f757f3fSDimitry Andric SectionRange SR(*DSec.GraphSec); 146*5f757f3fSDimitry Andric DSec.BuilderSec->Content.Size = SR.getSize(); 147*5f757f3fSDimitry Andric if (!SR.empty()) { 148*5f757f3fSDimitry Andric DSec.BuilderSec->align = Log2_64(SR.getFirstBlock()->getAlignment()); 149*5f757f3fSDimitry Andric StringRef SectionData(SR.getFirstBlock()->getContent().data(), 150*5f757f3fSDimitry Andric SR.getFirstBlock()->getSize()); 151*5f757f3fSDimitry Andric DebugSectionMap[SecName] = 152*5f757f3fSDimitry Andric MemoryBuffer::getMemBuffer(SectionData, G.getName(), false); 153*5f757f3fSDimitry Andric if (SecName == "__debug_line") 154*5f757f3fSDimitry Andric DebugLineSectionData = SectionData; 155*5f757f3fSDimitry Andric } 156*5f757f3fSDimitry Andric } 157*5f757f3fSDimitry Andric 158*5f757f3fSDimitry Andric std::optional<StringRef> FileName; 159*5f757f3fSDimitry Andric if (!DebugLineSectionData.empty()) { 160*5f757f3fSDimitry Andric assert((G.getEndianness() == llvm::endianness::big || 161*5f757f3fSDimitry Andric G.getEndianness() == llvm::endianness::little) && 162*5f757f3fSDimitry Andric "G.getEndianness() must be either big or little"); 163*5f757f3fSDimitry Andric auto DWARFCtx = 164*5f757f3fSDimitry Andric DWARFContext::create(DebugSectionMap, G.getPointerSize(), 165*5f757f3fSDimitry Andric G.getEndianness() == llvm::endianness::little); 166*5f757f3fSDimitry Andric DWARFDataExtractor DebugLineData( 167*5f757f3fSDimitry Andric DebugLineSectionData, G.getEndianness() == llvm::endianness::little, 168*5f757f3fSDimitry Andric G.getPointerSize()); 169*5f757f3fSDimitry Andric uint64_t Offset = 0; 170*5f757f3fSDimitry Andric DWARFDebugLine::LineTable LineTable; 171*5f757f3fSDimitry Andric 172*5f757f3fSDimitry Andric // Try to parse line data. Consume error on failure. 173*5f757f3fSDimitry Andric if (auto Err = LineTable.parse(DebugLineData, &Offset, *DWARFCtx, nullptr, 174*5f757f3fSDimitry Andric consumeError)) { 175*5f757f3fSDimitry Andric handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) { 176*5f757f3fSDimitry Andric LLVM_DEBUG({ 177*5f757f3fSDimitry Andric dbgs() << "Cannot parse line table for \"" << G.getName() << "\": "; 178*5f757f3fSDimitry Andric EIB.log(dbgs()); 179*5f757f3fSDimitry Andric dbgs() << "\n"; 180*5f757f3fSDimitry Andric }); 181*5f757f3fSDimitry Andric }); 182*5f757f3fSDimitry Andric } else { 183*5f757f3fSDimitry Andric if (!LineTable.Prologue.FileNames.empty()) 184*5f757f3fSDimitry Andric FileName = *dwarf::toString(LineTable.Prologue.FileNames[0].Name); 185*5f757f3fSDimitry Andric } 186*5f757f3fSDimitry Andric } 187*5f757f3fSDimitry Andric 188*5f757f3fSDimitry Andric // If no line table (or unable to use) then use graph name. 189*5f757f3fSDimitry Andric // FIXME: There are probably other debug sections we should look in first. 190*5f757f3fSDimitry Andric if (!FileName) 191*5f757f3fSDimitry Andric FileName = StringRef(G.getName()); 192*5f757f3fSDimitry Andric 193*5f757f3fSDimitry Andric Builder.addSymbol("", MachO::N_SO, 0, 0, 0); 194*5f757f3fSDimitry Andric Builder.addSymbol(*FileName, MachO::N_SO, 0, 0, 0); 195*5f757f3fSDimitry Andric auto TimeStamp = std::chrono::duration_cast<std::chrono::seconds>( 196*5f757f3fSDimitry Andric std::chrono::system_clock::now().time_since_epoch()) 197*5f757f3fSDimitry Andric .count(); 198*5f757f3fSDimitry Andric Builder.addSymbol("", MachO::N_OSO, 3, 1, TimeStamp); 199*5f757f3fSDimitry Andric 200*5f757f3fSDimitry Andric for (auto &NDSP : NonDebugSections) { 201*5f757f3fSDimitry Andric auto [SegName, SecName] = NDSP.GraphSec->getName().split(','); 202*5f757f3fSDimitry Andric NDSP.BuilderSec = &Seg->addSection(SecName, SegName); 203*5f757f3fSDimitry Andric SectionRange SR(*NDSP.GraphSec); 204*5f757f3fSDimitry Andric if (!SR.empty()) 205*5f757f3fSDimitry Andric NDSP.BuilderSec->align = Log2_64(SR.getFirstBlock()->getAlignment()); 206*5f757f3fSDimitry Andric 207*5f757f3fSDimitry Andric // Add stabs. 208*5f757f3fSDimitry Andric for (auto *Sym : NDSP.GraphSec->symbols()) { 209*5f757f3fSDimitry Andric // Skip anonymous symbols. 210*5f757f3fSDimitry Andric if (!Sym->hasName()) 211*5f757f3fSDimitry Andric continue; 212*5f757f3fSDimitry Andric 213*5f757f3fSDimitry Andric uint8_t SymType = Sym->isCallable() ? MachO::N_FUN : MachO::N_GSYM; 214*5f757f3fSDimitry Andric 215*5f757f3fSDimitry Andric Builder.addSymbol("", MachO::N_BNSYM, 1, 0, 0); 216*5f757f3fSDimitry Andric StabSymbols.push_back( 217*5f757f3fSDimitry Andric {*Sym, Builder.addSymbol(Sym->getName(), SymType, 1, 0, 0), 218*5f757f3fSDimitry Andric Builder.addSymbol(Sym->getName(), SymType, 0, 0, 0)}); 219*5f757f3fSDimitry Andric Builder.addSymbol("", MachO::N_ENSYM, 1, 0, 0); 220*5f757f3fSDimitry Andric } 221*5f757f3fSDimitry Andric } 222*5f757f3fSDimitry Andric 223*5f757f3fSDimitry Andric Builder.addSymbol("", MachO::N_SO, 1, 0, 0); 224*5f757f3fSDimitry Andric 225*5f757f3fSDimitry Andric // Lay out the debug object, create a section and block for it. 226*5f757f3fSDimitry Andric size_t DebugObjectSize = Builder.layout(); 227*5f757f3fSDimitry Andric 228*5f757f3fSDimitry Andric auto &SDOSec = G.createSection(SynthDebugSectionName, MemProt::Read); 229*5f757f3fSDimitry Andric MachOContainerBlock = &G.createMutableContentBlock( 230*5f757f3fSDimitry Andric SDOSec, G.allocateBuffer(DebugObjectSize), orc::ExecutorAddr(), 8, 0); 231*5f757f3fSDimitry Andric 232*5f757f3fSDimitry Andric return Error::success(); 233*5f757f3fSDimitry Andric } 234*5f757f3fSDimitry Andric 235*5f757f3fSDimitry Andric Error completeSynthesisAndRegister() override { 236*5f757f3fSDimitry Andric if (!MachOContainerBlock) { 237*5f757f3fSDimitry Andric LLVM_DEBUG({ 238*5f757f3fSDimitry Andric dbgs() << "Not writing MachO debug object header for " << G.getName() 239*5f757f3fSDimitry Andric << " since createDebugSection failed\n"; 240*5f757f3fSDimitry Andric }); 241*5f757f3fSDimitry Andric 242*5f757f3fSDimitry Andric return Error::success(); 243*5f757f3fSDimitry Andric } 244*5f757f3fSDimitry Andric ExecutorAddr MaxAddr; 245*5f757f3fSDimitry Andric for (auto &NDSec : NonDebugSections) { 246*5f757f3fSDimitry Andric SectionRange SR(*NDSec.GraphSec); 247*5f757f3fSDimitry Andric NDSec.BuilderSec->addr = SR.getStart().getValue(); 248*5f757f3fSDimitry Andric NDSec.BuilderSec->size = SR.getSize(); 249*5f757f3fSDimitry Andric NDSec.BuilderSec->offset = SR.getStart().getValue(); 250*5f757f3fSDimitry Andric if (SR.getEnd() > MaxAddr) 251*5f757f3fSDimitry Andric MaxAddr = SR.getEnd(); 252*5f757f3fSDimitry Andric } 253*5f757f3fSDimitry Andric 254*5f757f3fSDimitry Andric for (auto &DSec : DebugSections) { 255*5f757f3fSDimitry Andric if (DSec.GraphSec->blocks_size() != 1) 256*5f757f3fSDimitry Andric return make_error<StringError>( 257*5f757f3fSDimitry Andric "Unexpected number of blocks in debug info section", 258*5f757f3fSDimitry Andric inconvertibleErrorCode()); 259*5f757f3fSDimitry Andric 260*5f757f3fSDimitry Andric if (ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size > MaxAddr) 261*5f757f3fSDimitry Andric MaxAddr = ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size; 262*5f757f3fSDimitry Andric 263*5f757f3fSDimitry Andric auto &B = **DSec.GraphSec->blocks().begin(); 264*5f757f3fSDimitry Andric DSec.BuilderSec->Content.Data = B.getContent().data(); 265*5f757f3fSDimitry Andric DSec.BuilderSec->Content.Size = B.getContent().size(); 266*5f757f3fSDimitry Andric DSec.BuilderSec->flags |= MachO::S_ATTR_DEBUG; 267*5f757f3fSDimitry Andric } 268*5f757f3fSDimitry Andric 269*5f757f3fSDimitry Andric LLVM_DEBUG({ 270*5f757f3fSDimitry Andric dbgs() << "Writing MachO debug object header for " << G.getName() << "\n"; 271*5f757f3fSDimitry Andric }); 272*5f757f3fSDimitry Andric 273*5f757f3fSDimitry Andric // Update stab symbol addresses. 274*5f757f3fSDimitry Andric for (auto &SS : StabSymbols) { 275*5f757f3fSDimitry Andric SS.StartStab.nlist().n_value = SS.Sym.getAddress().getValue(); 276*5f757f3fSDimitry Andric SS.EndStab.nlist().n_value = SS.Sym.getSize(); 277*5f757f3fSDimitry Andric } 278*5f757f3fSDimitry Andric 279*5f757f3fSDimitry Andric Builder.write(MachOContainerBlock->getAlreadyMutableContent()); 280*5f757f3fSDimitry Andric 281*5f757f3fSDimitry Andric static constexpr bool AutoRegisterCode = true; 282*5f757f3fSDimitry Andric SectionRange R(MachOContainerBlock->getSection()); 283*5f757f3fSDimitry Andric G.allocActions().push_back( 284*5f757f3fSDimitry Andric {cantFail(shared::WrapperFunctionCall::Create< 285*5f757f3fSDimitry Andric shared::SPSArgList<shared::SPSExecutorAddrRange, bool>>( 286*5f757f3fSDimitry Andric RegisterActionAddr, R.getRange(), AutoRegisterCode)), 287*5f757f3fSDimitry Andric {}}); 288*5f757f3fSDimitry Andric 289*5f757f3fSDimitry Andric return Error::success(); 290*5f757f3fSDimitry Andric } 291*5f757f3fSDimitry Andric 292*5f757f3fSDimitry Andric private: 293*5f757f3fSDimitry Andric struct SectionPair { 294*5f757f3fSDimitry Andric Section *GraphSec = nullptr; 295*5f757f3fSDimitry Andric typename MachOBuilder<MachOTraits>::Section *BuilderSec = nullptr; 296*5f757f3fSDimitry Andric }; 297*5f757f3fSDimitry Andric 298*5f757f3fSDimitry Andric struct StabSymbolsEntry { 299*5f757f3fSDimitry Andric using RelocTarget = typename MachOBuilder<MachOTraits>::RelocTarget; 300*5f757f3fSDimitry Andric 301*5f757f3fSDimitry Andric StabSymbolsEntry(Symbol &Sym, RelocTarget StartStab, RelocTarget EndStab) 302*5f757f3fSDimitry Andric : Sym(Sym), StartStab(StartStab), EndStab(EndStab) {} 303*5f757f3fSDimitry Andric 304*5f757f3fSDimitry Andric Symbol &Sym; 305*5f757f3fSDimitry Andric RelocTarget StartStab, EndStab; 306*5f757f3fSDimitry Andric }; 307*5f757f3fSDimitry Andric 308*5f757f3fSDimitry Andric using BuilderType = MachOBuilder<MachOTraits>; 309*5f757f3fSDimitry Andric 310*5f757f3fSDimitry Andric Block *MachOContainerBlock = nullptr; 311*5f757f3fSDimitry Andric MachOBuilder<MachOTraits> Builder; 312*5f757f3fSDimitry Andric typename MachOBuilder<MachOTraits>::Segment *Seg = nullptr; 313*5f757f3fSDimitry Andric std::vector<StabSymbolsEntry> StabSymbols; 314*5f757f3fSDimitry Andric SmallVector<SectionPair, 16> DebugSections; 315*5f757f3fSDimitry Andric SmallVector<SectionPair, 16> NonDebugSections; 316*5f757f3fSDimitry Andric }; 317*5f757f3fSDimitry Andric 318*5f757f3fSDimitry Andric } // end anonymous namespace 319*5f757f3fSDimitry Andric 320*5f757f3fSDimitry Andric namespace llvm { 321*5f757f3fSDimitry Andric namespace orc { 322*5f757f3fSDimitry Andric 323*5f757f3fSDimitry Andric Expected<std::unique_ptr<GDBJITDebugInfoRegistrationPlugin>> 324*5f757f3fSDimitry Andric GDBJITDebugInfoRegistrationPlugin::Create(ExecutionSession &ES, 325*5f757f3fSDimitry Andric JITDylib &ProcessJD, 326*5f757f3fSDimitry Andric const Triple &TT) { 327*5f757f3fSDimitry Andric auto RegisterActionAddr = 328*5f757f3fSDimitry Andric TT.isOSBinFormatMachO() 329*5f757f3fSDimitry Andric ? ES.intern("_llvm_orc_registerJITLoaderGDBAllocAction") 330*5f757f3fSDimitry Andric : ES.intern("llvm_orc_registerJITLoaderGDBAllocAction"); 331*5f757f3fSDimitry Andric 332*5f757f3fSDimitry Andric if (auto RegisterSym = ES.lookup({&ProcessJD}, RegisterActionAddr)) 333*5f757f3fSDimitry Andric return std::make_unique<GDBJITDebugInfoRegistrationPlugin>( 334*5f757f3fSDimitry Andric RegisterSym->getAddress()); 335*5f757f3fSDimitry Andric else 336*5f757f3fSDimitry Andric return RegisterSym.takeError(); 337*5f757f3fSDimitry Andric } 338*5f757f3fSDimitry Andric 339*5f757f3fSDimitry Andric Error GDBJITDebugInfoRegistrationPlugin::notifyFailed( 340*5f757f3fSDimitry Andric MaterializationResponsibility &MR) { 341*5f757f3fSDimitry Andric return Error::success(); 342*5f757f3fSDimitry Andric } 343*5f757f3fSDimitry Andric 344*5f757f3fSDimitry Andric Error GDBJITDebugInfoRegistrationPlugin::notifyRemovingResources( 345*5f757f3fSDimitry Andric JITDylib &JD, ResourceKey K) { 346*5f757f3fSDimitry Andric return Error::success(); 347*5f757f3fSDimitry Andric } 348*5f757f3fSDimitry Andric 349*5f757f3fSDimitry Andric void GDBJITDebugInfoRegistrationPlugin::notifyTransferringResources( 350*5f757f3fSDimitry Andric JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {} 351*5f757f3fSDimitry Andric 352*5f757f3fSDimitry Andric void GDBJITDebugInfoRegistrationPlugin::modifyPassConfig( 353*5f757f3fSDimitry Andric MaterializationResponsibility &MR, LinkGraph &LG, 354*5f757f3fSDimitry Andric PassConfiguration &PassConfig) { 355*5f757f3fSDimitry Andric 356*5f757f3fSDimitry Andric if (LG.getTargetTriple().getObjectFormat() == Triple::MachO) 357*5f757f3fSDimitry Andric modifyPassConfigForMachO(MR, LG, PassConfig); 358*5f757f3fSDimitry Andric else { 359*5f757f3fSDimitry Andric LLVM_DEBUG({ 360*5f757f3fSDimitry Andric dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unspported graph " 361*5f757f3fSDimitry Andric << LG.getName() << "(triple = " << LG.getTargetTriple().str() 362*5f757f3fSDimitry Andric << "\n"; 363*5f757f3fSDimitry Andric }); 364*5f757f3fSDimitry Andric } 365*5f757f3fSDimitry Andric } 366*5f757f3fSDimitry Andric 367*5f757f3fSDimitry Andric void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO( 368*5f757f3fSDimitry Andric MaterializationResponsibility &MR, jitlink::LinkGraph &LG, 369*5f757f3fSDimitry Andric jitlink::PassConfiguration &PassConfig) { 370*5f757f3fSDimitry Andric 371*5f757f3fSDimitry Andric switch (LG.getTargetTriple().getArch()) { 372*5f757f3fSDimitry Andric case Triple::x86_64: 373*5f757f3fSDimitry Andric case Triple::aarch64: 374*5f757f3fSDimitry Andric // Supported, continue. 375*5f757f3fSDimitry Andric assert(LG.getPointerSize() == 8 && "Graph has incorrect pointer size"); 376*5f757f3fSDimitry Andric assert(LG.getEndianness() == llvm::endianness::little && 377*5f757f3fSDimitry Andric "Graph has incorrect endianness"); 378*5f757f3fSDimitry Andric break; 379*5f757f3fSDimitry Andric default: 380*5f757f3fSDimitry Andric // Unsupported. 381*5f757f3fSDimitry Andric LLVM_DEBUG({ 382*5f757f3fSDimitry Andric dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unsupported " 383*5f757f3fSDimitry Andric << "MachO graph " << LG.getName() 384*5f757f3fSDimitry Andric << "(triple = " << LG.getTargetTriple().str() 385*5f757f3fSDimitry Andric << ", pointer size = " << LG.getPointerSize() << ", endianness = " 386*5f757f3fSDimitry Andric << (LG.getEndianness() == llvm::endianness::big ? "big" : "little") 387*5f757f3fSDimitry Andric << ")\n"; 388*5f757f3fSDimitry Andric }); 389*5f757f3fSDimitry Andric return; 390*5f757f3fSDimitry Andric } 391*5f757f3fSDimitry Andric 392*5f757f3fSDimitry Andric // Scan for debug sections. If we find one then install passes. 393*5f757f3fSDimitry Andric bool HasDebugSections = false; 394*5f757f3fSDimitry Andric for (auto &Sec : LG.sections()) 395*5f757f3fSDimitry Andric if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) { 396*5f757f3fSDimitry Andric HasDebugSections = true; 397*5f757f3fSDimitry Andric break; 398*5f757f3fSDimitry Andric } 399*5f757f3fSDimitry Andric 400*5f757f3fSDimitry Andric if (HasDebugSections) { 401*5f757f3fSDimitry Andric LLVM_DEBUG({ 402*5f757f3fSDimitry Andric dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName() 403*5f757f3fSDimitry Andric << " contains debug info. Installing debugger support passes.\n"; 404*5f757f3fSDimitry Andric }); 405*5f757f3fSDimitry Andric 406*5f757f3fSDimitry Andric auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>( 407*5f757f3fSDimitry Andric MR.getTargetJITDylib().getExecutionSession(), LG, RegisterActionAddr); 408*5f757f3fSDimitry Andric PassConfig.PrePrunePasses.push_back( 409*5f757f3fSDimitry Andric [=](LinkGraph &G) { return MDOS->preserveDebugSections(); }); 410*5f757f3fSDimitry Andric PassConfig.PostPrunePasses.push_back( 411*5f757f3fSDimitry Andric [=](LinkGraph &G) { return MDOS->startSynthesis(); }); 412*5f757f3fSDimitry Andric PassConfig.PostFixupPasses.push_back( 413*5f757f3fSDimitry Andric [=](LinkGraph &G) { return MDOS->completeSynthesisAndRegister(); }); 414*5f757f3fSDimitry Andric } else { 415*5f757f3fSDimitry Andric LLVM_DEBUG({ 416*5f757f3fSDimitry Andric dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName() 417*5f757f3fSDimitry Andric << " contains no debug info. Skipping.\n"; 418*5f757f3fSDimitry Andric }); 419*5f757f3fSDimitry Andric } 420*5f757f3fSDimitry Andric } 421*5f757f3fSDimitry Andric 422*5f757f3fSDimitry Andric } // namespace orc 423*5f757f3fSDimitry Andric } // namespace llvm 424