LLVM: lib/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
14
19
20#include
21
22#define DEBUG_TYPE "orc"
23
24using namespace llvm;
27
29
30namespace {
31
32class MachODebugObjectSynthesizerBase
34public:
37 }
38
40 : G(G), RegisterActionAddr(RegisterActionAddr) {}
41 ~MachODebugObjectSynthesizerBase() override = default;
42
46 dbgs() << "MachODebugObjectSynthesizer skipping graph " << G.getName()
47 << " which contains an unexpected existing "
49 });
51 }
52
54 dbgs() << "MachODebugObjectSynthesizer visiting graph " << G.getName()
55 << "\n";
56 });
57 for (auto &Sec : G.sections()) {
59 continue;
60
61
62
64 dbgs() << " Preserving debug section " << Sec.getName() << "\n";
65 });
67 for (auto *Sym : Sec.symbols()) {
68 bool NewPreservedBlock =
69 PreservedBlocks.insert(&Sym->getBlock()).second;
70 if (NewPreservedBlock)
71 Sym->setLive(true);
72 }
73 for (auto *B : Sec.blocks())
74 if (!PreservedBlocks.count(B))
75 G.addAnonymousSymbol(*B, 0, 0, false, true);
76 }
77
79 }
80
81protected:
84};
85
86template
87class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase {
88public:
91 : MachODebugObjectSynthesizerBase(G, RegisterActionAddr),
93
94 using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase;
95
96 Error startSynthesis() override {
99 << "\n";
100 });
101
102 for (auto &Sec : G.sections()) {
103 if (Sec.blocks().empty())
104 continue;
105
106
107 if (Sec.getName().empty() || Sec.getName().size() > 33 ||
108 Sec.getName().find(',') > 16)
109 continue;
110
112 DebugSections.push_back({&Sec, nullptr});
114 NonDebugSections.push_back({&Sec, nullptr});
115 }
116
117
118 if (DebugSections.empty())
120
121
124 Builder.Header.cputype = *CPUType;
125 else
126 return CPUType.takeError();
128 Builder.Header.cpusubtype = *CPUSubType;
129 else
130 return CPUSubType.takeError();
131
132 Seg = &Builder.addSegment("");
133
136 for (auto &DSec : DebugSections) {
137 auto [SegName, SecName] = DSec.GraphSec->getName().split(',');
138 DSec.BuilderSec = &Seg->addSection(SecName, SegName);
139
141 DSec.BuilderSec->Content.Size = SR.getSize();
142 if (!SR.empty()) {
146 DebugSectionMap[SecName.drop_front(2)] =
148 if (SecName == "__debug_line")
149 DebugLineSectionData = SectionData;
150 }
151 }
152
153 std::optional FileName;
154 if (!DebugLineSectionData.empty()) {
157 "G.getEndianness() must be either big or little");
158 auto DWARFCtx =
163 G.getPointerSize());
166
167
168 if (auto Err = P.parse(DebugLineData, &Offset, consumeError, *DWARFCtx)) {
171 dbgs() << "Cannot parse line table for \"" << G.getName() << "\": ";
173 dbgs() << "\n";
174 });
175 });
176 } else {
177 for (auto &FN : P.FileNames)
180 dbgs() << "Using FileName = \"" << *FileName
181 << "\" from DWARF line table\n";
182 });
183 break;
184 }
185 }
186 }
187
188
189
190 if (!FileName) {
192 dbgs() << "Could not find source name from DWARF line table. "
193 "Using FileName = \"\"\n";
194 });
195 FileName = "";
196 }
197
198 Builder.addSymbol("", MachO::N_SO, 0, 0, 0);
199 Builder.addSymbol(*FileName, MachO::N_SO, 0, 0, 0);
200 auto TimeStamp = std::chrono::duration_caststd::chrono::seconds(
201 std::chrono::system_clock::now().time_since_epoch())
203 Builder.addSymbol("", MachO::N_OSO, 3, 1, TimeStamp);
204
205 for (auto &NDSP : NonDebugSections) {
206 auto [SegName, SecName] = NDSP.GraphSec->getName().split(',');
207 NDSP.BuilderSec = &Seg->addSection(SecName, SegName);
211
212
213 for (auto *Sym : NDSP.GraphSec->symbols()) {
214
215 if (!Sym->hasName())
216 continue;
217
219
221 StabSymbols.push_back(
222 {*Sym, Builder.addSymbol(*Sym->getName(), SymType, 1, 0, 0),
223 Builder.addSymbol(*Sym->getName(), SymType, 0, 0, 0)});
225 }
226 }
227
228 Builder.addSymbol("", MachO::N_SO, 1, 0, 0);
229
230
231 size_t DebugObjectSize = Builder.layout();
232
234 MachOContainerBlock = &G.createMutableContentBlock(
235 SDOSec, G.allocateBuffer(DebugObjectSize), orc::ExecutorAddr(), 8, 0);
236
238 }
239
240 Error completeSynthesisAndRegister() override {
241 if (!MachOContainerBlock) {
243 dbgs() << "Not writing MachO debug object header for " << G.getName()
244 << " since createDebugSection failed\n";
245 });
246
248 }
250 for (auto &NDSec : NonDebugSections) {
253 NDSec.BuilderSec->size = SR.getSize();
255 if (SR.getEnd() > MaxAddr)
256 MaxAddr = SR.getEnd();
257 }
258
259 for (auto &DSec : DebugSections) {
260 if (DSec.GraphSec->blocks_size() != 1)
262 "Unexpected number of blocks in debug info section",
264
265 if (ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size > MaxAddr)
266 MaxAddr = ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size;
267
268 auto &B = **DSec.GraphSec->blocks().begin();
269 DSec.BuilderSec->Content.Data = B.getContent().data();
270 DSec.BuilderSec->Content.Size = B.getContent().size();
272 }
273
275 dbgs() << "Writing MachO debug object header for " << G.getName() << "\n";
276 });
277
278
279 for (auto &SS : StabSymbols) {
280 SS.StartStab.nlist().n_value = SS.Sym.getAddress().getValue();
281 SS.EndStab.nlist().n_value = SS.Sym.getSize();
282 }
283
284 Builder.write(MachOContainerBlock->getAlreadyMutableContent());
285
286 static constexpr bool AutoRegisterCode = true;
287 SectionRange R(MachOContainerBlock->getSection());
288 G.allocActions().push_back(
291 RegisterActionAddr, R.getRange(), AutoRegisterCode)),
292 {}});
293
295 }
296
297private:
298 struct SectionPair {
299 Section *GraphSec = nullptr;
301 };
302
303 struct StabSymbolsEntry {
305
306 StabSymbolsEntry(Symbol &Sym, RelocTarget StartStab, RelocTarget EndStab)
307 : Sym(Sym), StartStab(StartStab), EndStab(EndStab) {}
308
310 RelocTarget StartStab, EndStab;
311 };
312
314
315 Block *MachOContainerBlock = nullptr;
318 std::vector StabSymbols;
321};
322
323}
324
325namespace llvm {
326namespace orc {
327
328Expected<std::unique_ptr>
332 auto RegisterActionAddr =
333 TT.isOSBinFormatMachO()
334 ? ES.intern("_llvm_orc_registerJITLoaderGDBAllocAction")
335 : ES.intern("llvm_orc_registerJITLoaderGDBAllocAction");
336
337 if (auto RegisterSym = ES.lookup({&ProcessJD}, RegisterActionAddr))
338 return std::make_unique(
339 RegisterSym->getAddress());
340 else
341 return RegisterSym.takeError();
342}
343
348
353
356
360
362 modifyPassConfigForMachO(MR, LG, PassConfig);
363 else {
365 dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unspported graph "
367 << "\n";
368 });
369 }
370}
371
372void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO(
375
379
382 "Graph has incorrect endianness");
383 break;
384 default:
385
387 dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unsupported "
388 << "MachO graph " << LG.getName()
390 << ", pointer size = " << LG.getPointerSize() << ", endianness = "
392 << ")\n";
393 });
394 return;
395 }
396
397
399 for (auto &Sec : LG.sections())
400 if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) {
402 break;
403 }
404
407 dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName()
408 << " contains debug info. Installing debugger support passes.\n";
409 });
410
411 auto MDOS = std::make_shared<MachODebugObjectSynthesizer>(
412 MR.getTargetJITDylib().getExecutionSession(), LG, RegisterActionAddr);
414 [=](LinkGraph &G) { return MDOS->preserveDebugSections(); });
416 [=](LinkGraph &G) { return MDOS->startSynthesis(); });
418 [=](LinkGraph &G) { return MDOS->completeSynthesisAndRegister(); });
419 } else {
421 dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName()
422 << " contains no debug info. Skipping.\n";
423 });
424 }
425}
426
427}
428}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static const char * SynthDebugSectionName
Definition DebuggerSupportPlugin.cpp:28
static bool isDebugSection(const SectionBase &Sec)
This file defines the SmallVector class.
static std::unique_ptr< DWARFContext > create(const object::ObjectFile &Obj, ProcessDebugRelocations RelocAction=ProcessDebugRelocations::Process, const LoadedObjectInfo *L=nullptr, std::string DWPName="", std::function< void(Error)> RecoverableErrorHandler=WithColor::defaultErrorHandler, std::function< void(Error)> WarningHandler=WithColor::defaultWarningHandler, bool ThreadSafe=false)
Base class for error info classes.
virtual void log(raw_ostream &OS) const =0
Print an error message to an output stream.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
StringRef - Represent a constant reference to a string, i.e.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
size_t count(char C) const
Return the number of occurrences of C in the string.
Triple - Helper class for working with autoconf configuration names.
ObjectFormatType getObjectFormat() const
Get the object format for this triple.
ArchType getArch() const
Get the parsed architecture type of this triple.
const std::string & str() const
An Addressable with content and edges.
ArrayRef< char > getContent() const
Get the content for this block. Block must not be a zero-fill block.
uint64_t getAlignment() const
Get the alignment for this content.
size_t getSize() const
Returns the size of this defined addressable.
const std::string & getName() const
Returns the name of this graph (usually the name of the original underlying MemoryBuffer).
unsigned getPointerSize() const
Returns the pointer size for use in this graph.
iterator_range< section_iterator > sections()
const Triple & getTargetTriple() const
Returns the target triple for this Graph.
llvm::endianness getEndianness() const
Returns the endianness of content in this graph.
Represents a section address range via a pair of Block pointers to the first and last Blocks in the s...
Block * getFirstBlock() const
orc::ExecutorAddr getEnd() const
orc::ExecutorAddrDiff getSize() const
orc::ExecutorAddr getStart() const
Represents an object file section.
iterator_range< symbol_iterator > symbols()
Returns an iterator over the symbols defined in this section.
StringRef getName() const
Returns the name of this section.
iterator_range< block_iterator > blocks()
Returns an iterator over the blocks defined in this section.
An ExecutionSession represents a running JIT program.
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
LLVM_ABI void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, SymbolLookupSet Symbols, SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete, RegisterDependenciesFunction RegisterDependencies)
Search the given JITDylibs for the given symbols.
size_t getPageSize() const
Represents an address in the executor process.
uint64_t getValue() const
void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &LG, jitlink::PassConfiguration &PassConfig) override
Definition DebuggerSupportPlugin.cpp:357
static Expected< std::unique_ptr< GDBJITDebugInfoRegistrationPlugin > > Create(ExecutionSession &ES, JITDylib &ProcessJD, const Triple &TT)
Definition DebuggerSupportPlugin.cpp:329
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) override
Definition DebuggerSupportPlugin.cpp:354
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override
Definition DebuggerSupportPlugin.cpp:349
Error notifyFailed(MaterializationResponsibility &MR) override
Definition DebuggerSupportPlugin.cpp:344
Represents a JIT'd dynamic library.
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
JITDylib & getTargetJITDylib() const
Returns the target JITDylib that these symbols are being materialized into.
LLVM_ABI Expected< uint32_t > getCPUSubType(const Triple &T)
LLVM_ABI Expected< uint32_t > getCPUType(const Triple &T)
@ S_ATTR_DEBUG
S_ATTR_DEBUG - A debug section.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
LLVM_ABI Error preserveDebugSections(jitlink::LinkGraph &G)
@ NoAlloc
NoAlloc memory should not be allocated by the JITLinkMemoryManager at all.
This is an optimization pass for GlobalISel generic memory operations.
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
void consumeError(Error Err)
Consume a Error without doing anything.
An LinkGraph pass configuration, consisting of a list of pre-prune, post-prune, and post-fixup passes...
LinkGraphPassList PostFixupPasses
Post-fixup passes.
LinkGraphPassList PostPrunePasses
Post-prune passes.
LinkGraphPassList PrePrunePasses
Pre-prune passes.