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:
isDebugSection(Section & Sec)36*5f757f3fSDimitry Andric   static bool isDebugSection(Section &Sec) {
37*5f757f3fSDimitry Andric     return Sec.getName().starts_with("__DWARF,");
38*5f757f3fSDimitry Andric   }
39*5f757f3fSDimitry Andric 
MachODebugObjectSynthesizerBase(LinkGraph & G,ExecutorAddr RegisterActionAddr)40*5f757f3fSDimitry Andric   MachODebugObjectSynthesizerBase(LinkGraph &G, ExecutorAddr RegisterActionAddr)
41*5f757f3fSDimitry Andric       : G(G), RegisterActionAddr(RegisterActionAddr) {}
42*5f757f3fSDimitry Andric   virtual ~MachODebugObjectSynthesizerBase() = default;
43*5f757f3fSDimitry Andric 
preserveDebugSections()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:
MachODebugObjectSynthesizer(ExecutionSession & ES,LinkGraph & G,ExecutorAddr RegisterActionAddr)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 
startSynthesis()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 
completeSynthesisAndRegister()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 
StabSymbolsEntry__anona2d7caf00111::MachODebugObjectSynthesizer::StabSymbolsEntry301*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>>
Create(ExecutionSession & ES,JITDylib & ProcessJD,const Triple & TT)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 
notifyFailed(MaterializationResponsibility & MR)339*5f757f3fSDimitry Andric Error GDBJITDebugInfoRegistrationPlugin::notifyFailed(
340*5f757f3fSDimitry Andric     MaterializationResponsibility &MR) {
341*5f757f3fSDimitry Andric   return Error::success();
342*5f757f3fSDimitry Andric }
343*5f757f3fSDimitry Andric 
notifyRemovingResources(JITDylib & JD,ResourceKey K)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 
notifyTransferringResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)349*5f757f3fSDimitry Andric void GDBJITDebugInfoRegistrationPlugin::notifyTransferringResources(
350*5f757f3fSDimitry Andric     JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {}
351*5f757f3fSDimitry Andric 
modifyPassConfig(MaterializationResponsibility & MR,LinkGraph & LG,PassConfiguration & PassConfig)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 
modifyPassConfigForMachO(MaterializationResponsibility & MR,jitlink::LinkGraph & LG,jitlink::PassConfiguration & PassConfig)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