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