24#define DEBUG_TYPE "orc"
34class MachODebugObjectSynthesizerBase
42 :
G(
G), RegisterActionAddr(RegisterActionAddr) {}
43 ~MachODebugObjectSynthesizerBase()
override =
default;
48 dbgs() <<
"MachODebugObjectSynthesizer skipping graph " <<
G.getName()
49 <<
" which contains an unexpected existing "
56 dbgs() <<
"MachODebugObjectSynthesizer visiting graph " <<
G.getName()
59 for (
auto &Sec :
G.sections()) {
66 dbgs() <<
" Preserving debug section " << Sec.
getName() <<
"\n";
69 for (
auto *Sym : Sec.
symbols()) {
70 bool NewPreservedBlock =
71 PreservedBlocks.insert(&Sym->getBlock()).second;
72 if (NewPreservedBlock)
76 if (!PreservedBlocks.count(
B))
77 G.addAnonymousSymbol(*
B, 0, 0,
false,
true);
88template <
typename MachOTraits>
89class MachODebugObjectSynthesizer :
public MachODebugObjectSynthesizerBase {
93 : MachODebugObjectSynthesizerBase(
G, RegisterActionAddr),
96 using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase;
98 Error startSynthesis()
override {
104 for (
auto &Sec :
G.sections()) {
105 if (Sec.blocks().empty())
109 if (Sec.getName().empty() || Sec.getName().size() > 33 ||
110 Sec.getName().find(
',') > 16)
114 DebugSections.push_back({&Sec,
nullptr});
116 NonDebugSections.push_back({&Sec,
nullptr});
120 if (DebugSections.empty())
126 Builder.Header.cputype = *CPUType;
128 return CPUType.takeError();
130 Builder.Header.cpusubtype = *CPUSubType;
132 return CPUSubType.takeError();
134 Seg = &Builder.addSegment(
"");
138 for (
auto &DSec : DebugSections) {
139 auto [SegName, SecName] = DSec.GraphSec->getName().split(
',');
140 DSec.BuilderSec = &Seg->addSection(SecName, SegName);
143 DSec.BuilderSec->Content.Size = SR.
getSize();
148 DebugSectionMap[SecName.drop_front(2)] =
150 if (SecName ==
"__debug_line")
151 DebugLineSectionData = SectionData;
155 std::optional<StringRef> FileName;
156 if (!DebugLineSectionData.
empty()) {
159 "G.getEndianness() must be either big or little");
173 dbgs() <<
"Cannot parse line table for \"" <<
G.getName() <<
"\": ";
179 for (
auto &FN :
P.FileNames)
182 dbgs() <<
"Using FileName = \"" << *FileName
183 <<
"\" from DWARF line table\n";
194 dbgs() <<
"Could not find source name from DWARF line table. "
195 "Using FileName = \"\"\n";
201 Builder.addSymbol(*FileName,
MachO::N_SO, 0, 0, 0);
202 auto TimeStamp = std::chrono::duration_cast<std::chrono::seconds>(
203 std::chrono::system_clock::now().time_since_epoch())
207 for (
auto &NDSP : NonDebugSections) {
208 auto [SegName, SecName] = NDSP.GraphSec->getName().split(
',');
209 NDSP.BuilderSec = &Seg->addSection(SecName, SegName);
215 for (
auto *Sym : NDSP.GraphSec->symbols()) {
223 StabSymbols.push_back(
224 {*Sym, Builder.addSymbol(*Sym->getName(), SymType, 1, 0, 0),
225 Builder.addSymbol(*Sym->getName(), SymType, 0, 0, 0)});
233 size_t DebugObjectSize = Builder.layout();
236 MachOContainerBlock = &
G.createMutableContentBlock(
242 Error completeSynthesisAndRegister()
override {
243 if (!MachOContainerBlock) {
245 dbgs() <<
"Not writing MachO debug object header for " <<
G.getName()
246 <<
" since createDebugSection failed\n";
252 for (
auto &NDSec : NonDebugSections) {
255 NDSec.BuilderSec->size = SR.
getSize();
257 if (SR.
getEnd() > MaxAddr)
261 for (
auto &DSec : DebugSections) {
262 if (DSec.GraphSec->blocks_size() != 1)
264 "Unexpected number of blocks in debug info section",
267 if (
ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size > MaxAddr)
268 MaxAddr =
ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size;
270 auto &
B = **DSec.GraphSec->blocks().begin();
271 DSec.BuilderSec->Content.Data =
B.getContent().data();
272 DSec.BuilderSec->Content.Size =
B.getContent().size();
277 dbgs() <<
"Writing MachO debug object header for " <<
G.getName() <<
"\n";
281 for (
auto &SS : StabSymbols) {
282 SS.StartStab.nlist().n_value = SS.Sym.getAddress().getValue();
283 SS.EndStab.nlist().n_value = SS.Sym.getSize();
286 Builder.write(MachOContainerBlock->getAlreadyMutableContent());
289 G.allocActions().push_back(
292 RegisterActionAddr, R.getRange())),
304 struct StabSymbolsEntry {
307 StabSymbolsEntry(
Symbol &Sym, RelocTarget StartStab, RelocTarget EndStab)
308 : Sym(Sym), StartStab(StartStab), EndStab(EndStab) {}
311 RelocTarget StartStab, EndStab;
316 Block *MachOContainerBlock =
nullptr;
319 std::vector<StabSymbolsEntry> StabSymbols;
329Expected<std::unique_ptr<GDBJITDebugInfoRegistrationPlugin>>
332 auto RegisterActionName =
335 if (
auto RegisterSym = ES.
lookup({&BootstrapJD}, RegisterActionName))
336 return std::make_unique<GDBJITDebugInfoRegistrationPlugin>(
337 RegisterSym->getAddress());
339 return RegisterSym.takeError();
360 modifyPassConfigForMachO(MR, LG, PassConfig);
363 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin skipping unspported graph "
370void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO(
380 "Graph has incorrect endianness");
385 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin skipping unsupported "
386 <<
"MachO graph " << LG.
getName()
388 <<
", pointer size = " << LG.
getPointerSize() <<
", endianness = "
396 bool HasDebugSections =
false;
398 if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) {
399 HasDebugSections =
true;
403 if (HasDebugSections) {
405 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin: Graph " << LG.
getName()
406 <<
" contains debug info. Installing debugger support passes.\n";
409 auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>(
412 [=](LinkGraph &
G) {
return MDOS->preserveDebugSections(); });
414 [=](LinkGraph &
G) {
return MDOS->startSynthesis(); });
416 [=](LinkGraph &
G) {
return MDOS->completeSynthesisAndRegister(); });
419 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin: Graph " << LG.
getName()
420 <<
" contains no debug info. Skipping.\n";
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static const char * SynthDebugSectionName
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",...
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
Check if the string is empty.
size_t count(char C) const
Return the number of occurrences of C in the string.
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.
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
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) override
static Expected< std::unique_ptr< GDBJITDebugInfoRegistrationPlugin > > Create(ExecutionSession &ES, JITDylib &BootstrapJD)
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override
Error notifyFailed(MaterializationResponsibility &MR) override
Represents a JIT'd dynamic library.
Mangles symbol names then uniques them in the context of an ExecutionSession.
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
JITDylib & getTargetJITDylib() const
Returns the target JITDylib that these symbols are being materialized into.
A utility class for serializing to a blob from a variadic list.
static Expected< WrapperFunctionCall > Create(ExecutorAddr FnAddr, const ArgTs &...Args)
Create a WrapperFunctionCall using the given SPS serializer to serialize the arguments.
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 const SymbolNameSpec RegisterJITLoaderGDBAllocActionName
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.