24#define DEBUG_TYPE "orc"
34class MachODebugObjectSynthesizerBase
42 :
G(
G), RegisterActionAddr(RegisterActionAddr) {}
43 virtual ~MachODebugObjectSynthesizerBase() =
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";
70 bool NewPreservedBlock =
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});
115 else if (Sec.getMemLifetime() != MemLifetime::NoAlloc)
116 NonDebugSections.push_back({&Sec,
nullptr});
120 if (DebugSections.empty())
125 switch (
G.getTargetTriple().getArch()) {
142 for (
auto &DSec : DebugSections) {
143 auto [SegName, SecName] = DSec.GraphSec->getName().
split(
',');
144 DSec.BuilderSec = &Seg->addSection(SecName, SegName);
147 DSec.BuilderSec->Content.Size = SR.
getSize();
152 DebugSectionMap[SecName] =
154 if (SecName ==
"__debug_line")
155 DebugLineSectionData = SectionData;
159 std::optional<StringRef> FileName;
160 if (!DebugLineSectionData.
empty()) {
161 assert((
G.getEndianness() == support::endianness::big ||
162 G.getEndianness() == support::endianness::little) &&
163 "G.getEndianness() must be either big or little");
166 support::endianness::little);
168 DebugLineSectionData,
169 G.getEndianness() == support::endianness::little,
G.getPointerSize());
174 if (
auto Err = LineTable.
parse(DebugLineData, &
Offset, *DWARFCtx,
nullptr,
178 dbgs() <<
"Cannot parse line table for \"" <<
G.getName() <<
"\": ";
196 auto TimeStamp = std::chrono::duration_cast<std::chrono::seconds>(
197 std::chrono::system_clock::now().time_since_epoch())
201 for (
auto &NDSP : NonDebugSections) {
202 auto [SegName, SecName] = NDSP.GraphSec->getName().split(
',');
203 NDSP.BuilderSec = &Seg->addSection(SecName, SegName);
209 for (
auto *
Sym : NDSP.GraphSec->symbols()) {
217 StabSymbols.push_back(
227 size_t DebugObjectSize =
Builder.layout();
230 MachOContainerBlock = &
G.createMutableContentBlock(
236 Error completeSynthesisAndRegister()
override {
237 if (!MachOContainerBlock) {
239 dbgs() <<
"Not writing MachO debug object header for " <<
G.getName()
240 <<
" since createDebugSection failed\n";
246 for (
auto &NDSec : NonDebugSections) {
248 NDSec.BuilderSec->addr = SR.getStart().getValue();
249 NDSec.BuilderSec->size = SR.getSize();
250 NDSec.BuilderSec->offset = SR.getStart().getValue();
251 if (SR.getEnd() > MaxAddr)
252 MaxAddr = SR.getEnd();
255 for (
auto &DSec : DebugSections) {
256 if (DSec.GraphSec->blocks_size() != 1)
257 return make_error<StringError>(
258 "Unexpected number of blocks in debug info section",
261 if (
ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size > MaxAddr)
262 MaxAddr =
ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size;
264 auto &
B = **DSec.GraphSec->blocks().begin();
265 DSec.BuilderSec->Content.Data =
B.getContent().data();
266 DSec.BuilderSec->Content.Size =
B.getContent().size();
271 dbgs() <<
"Writing MachO debug object header for " <<
G.getName() <<
"\n";
275 for (
auto &SS : StabSymbols) {
276 SS.StartStab.nlist().n_value =
SS.Sym.getAddress().getValue();
277 SS.EndStab.nlist().n_value =
SS.Sym.getSize();
280 Builder.write(MachOContainerBlock->getAlreadyMutableContent());
282 static constexpr bool AutoRegisterCode =
true;
284 G.allocActions().push_back(
287 RegisterActionAddr,
R.getRange(), AutoRegisterCode)),
299 struct StabSymbolsEntry {
302 StabSymbolsEntry(
Symbol &
Sym, RelocTarget StartStab, RelocTarget EndStab)
303 :
Sym(
Sym), StartStab(StartStab), EndStab(EndStab) {}
306 RelocTarget StartStab, EndStab;
311 Block *MachOContainerBlock =
nullptr;
314 std::vector<StabSymbolsEntry> StabSymbols;
328 auto RegisterActionAddr =
329 TT.isOSBinFormatMachO()
330 ? ES.
intern(
"_llvm_orc_registerJITLoaderGDBAllocAction")
331 : ES.
intern(
"llvm_orc_registerJITLoaderGDBAllocAction");
333 if (
auto RegisterSym = ES.
lookup({&ProcessJD}, RegisterActionAddr))
334 return std::make_unique<GDBJITDebugInfoRegistrationPlugin>(
335 RegisterSym->getAddress());
337 return RegisterSym.takeError();
358 modifyPassConfigForMachO(MR, LG, PassConfig);
361 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin skipping unspported graph "
368void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO(
378 "Graph has incorrect endianness");
383 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin skipping unsupported "
384 <<
"MachO graph " << LG.
getName()
386 <<
", pointer size = " << LG.
getPointerSize() <<
", endianness = "
396 if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) {
403 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin: Graph " << LG.
getName()
404 <<
" contains debug info. Installing debugger support passes.\n";
407 auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>(
410 [=](
LinkGraph &
G) {
return MDOS->preserveDebugSections(); });
412 [=](
LinkGraph &
G) {
return MDOS->startSynthesis(); });
414 [=](
LinkGraph &
G) {
return MDOS->completeSynthesisAndRegister(); });
417 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin: Graph " << LG.
getName()
418 <<
" contains no debug info. Skipping.\n";
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static const char * SynthDebugSectionName
static bool isDebugSection(const SectionBase &Sec)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallSet class.
This file defines the SmallVector class.
StringSet - A set-like wrapper for the StringMap.
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.
Tagged union holding either a T or a Error.
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
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.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
constexpr bool empty() const
empty - Check if the string is empty.
bool startswith(StringRef Prefix) const
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).
support::endianness getEndianness() const
Returns the endianness of content in this graph.
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.
Represents a section address range via a pair of Block pointers to the first and last Blocks in the s...
Block * getFirstBlock() const
orc::ExecutorAddrDiff getSize() 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.
bool isCallable() const
Returns true is this symbol is callable.
StringRef getName() const
Returns the name of this symbol (empty if the symbol is anonymous).
void setLive(bool IsLive)
Set this symbol's live bit.
Block & getBlock()
Return the Block for this Symbol (Symbol must be defined).
bool hasName() const
Returns true if this symbol has a name.
An ExecutionSession represents a running JIT program.
SymbolStringPtr intern(StringRef SymName)
Add a symbol name to the SymbolStringPool and return a pointer to it.
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.
void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &LG, jitlink::PassConfiguration &PassConfig) override
static Expected< std::unique_ptr< GDBJITDebugInfoRegistrationPlugin > > Create(ExecutionSession &ES, JITDylib &ProcessJD, const Triple &TT)
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) override
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override
Error notifyFailed(MaterializationResponsibility &MR) override
Represents a JIT'd dynamic library.
ExecutionSession & getExecutionSession() const
Get a reference to the ExecutionSession for this JITDylib.
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.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ 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.
Error preserveDebugSections(jitlink::LinkGraph &G)
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...
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.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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.
Error parse(DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, const DWARFContext &Ctx, const DWARFUnit *U, function_ref< void(Error)> RecoverableErrorHandler, raw_ostream *OS=nullptr, bool Verbose=false)
Parse prologue and all rows.
std::vector< FileNameEntry > FileNames
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.