19#define DEBUG_TYPE "orc"
39 static constexpr const uint32_t SegmentCmd = MachO::LC_SEGMENT_64;
42class MachODebugObjectSynthesizerBase
50 :
G(
G), RegisterActionAddr(RegisterActionAddr) {}
51 virtual ~MachODebugObjectSynthesizerBase() =
default;
53 Error preserveDebugSections() {
56 dbgs() <<
"MachODebugObjectSynthesizer skipping graph " <<
G.getName()
57 <<
" which contains an unexpected existing "
64 dbgs() <<
"MachODebugObjectSynthesizer visiting graph " <<
G.getName()
67 for (
auto &Sec :
G.sections()) {
74 dbgs() <<
" Preserving debug section " << Sec.
getName() <<
"\n";
77 for (
auto *Sym : Sec.
symbols()) {
78 bool NewPreservedBlock =
79 PreservedBlocks.
insert(&Sym->getBlock()).second;
80 if (NewPreservedBlock)
84 if (!PreservedBlocks.count(
B))
85 G.addAnonymousSymbol(*
B, 0, 0,
false,
true);
95template <
typename MachOTraits>
96class MachODebugObjectSynthesizer :
public MachODebugObjectSynthesizerBase {
98 class MachOStructWriter {
102 size_t getOffset()
const {
return Offset; }
104 template <
typename MachOStruct>
void write(MachOStruct S) {
106 "Container block overflow while constructing debug MachO");
109 memcpy(Buffer.
data() + Offset, &S,
sizeof(S));
119 using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase;
121 Error startSynthesis()
override {
128 struct DebugSectionInfo {
138 size_t NumSections = 0;
139 for (
auto &Sec :
G.sections()) {
140 if (Sec.blocks().empty())
145 size_t SepPos = Sec.getName().find(
',');
146 if (SepPos > 16 || (Sec.getName().size() - (SepPos + 1) > 16)) {
148 dbgs() <<
"Skipping debug object synthesis for graph "
150 <<
": encountered non-standard DWARF section name \""
151 << Sec.getName() <<
"\"\n";
156 Sec.getName().
substr(SepPos + 1), 0,
159 NonDebugSections.push_back(&Sec);
166 auto &FB = *R.getFirstBlock();
167 if (FB.getAlignmentOffset() != 0) {
168 auto Padding =
G.allocateBuffer(FB.getAlignmentOffset());
169 memset(Padding.data(), 0, Padding.size());
170 G.createContentBlock(Sec, Padding,
171 FB.getAddress() - FB.getAlignmentOffset(),
172 FB.getAlignment(), 0);
179 size_t SectionsCmdSize =
180 sizeof(
typename MachOTraits::Section) * NumSections;
181 size_t SegmentLCSize =
182 sizeof(
typename MachOTraits::SegmentLC) + SectionsCmdSize;
183 size_t ContainerBlockSize =
184 sizeof(
typename MachOTraits::Header) + SegmentLCSize;
185 auto ContainerBlockContent =
G.allocateBuffer(ContainerBlockSize);
186 MachOContainerBlock = &
G.createMutableContentBlock(
191 for (
auto &
SI : DebugSecInfos) {
192 assert(!
SI.Sec->blocks().empty() &&
"Empty debug info section?");
196 dbgs() <<
" Appending " <<
SI.Sec->getName() <<
" ("
197 <<
SI.Sec->blocks_size() <<
" block(s)) at "
198 <<
formatv(
"{0:x8}", NextBlockAddr) <<
"\n";
200 for (
auto *
B :
SI.Sec->blocks()) {
202 B->setAddress(NextBlockAddr);
203 NextBlockAddr +=
B->getSize();
206 auto &FirstBlock = **
SI.Sec->blocks().begin();
207 if (FirstBlock.getAlignmentOffset() != 0)
208 return make_error<StringError>(
209 "First block in " +
SI.Sec->getName() +
210 " section has non-zero alignment offset",
212 if (FirstBlock.getAlignment() > std::numeric_limits<uint32_t>::max())
213 return make_error<StringError>(
"First block in " +
SI.Sec->getName() +
214 " has alignment >4Gb",
217 SI.Alignment = FirstBlock.getAlignment();
218 SI.StartAddr = FirstBlock.getAddress();
219 SI.Size = NextBlockAddr -
SI.StartAddr;
220 G.mergeSections(SDOSec, *
SI.Sec);
223 size_t DebugSectionsSize =
227 MachOStructWriter Writer(MachOContainerBlock->getAlreadyMutableContent());
228 typename MachOTraits::Header Hdr;
229 memset(&Hdr, 0,
sizeof(Hdr));
230 Hdr.magic = MachOTraits::Magic;
231 switch (
G.getTargetTriple().getArch()) {
245 Hdr.sizeofcmds = SegmentLCSize;
249 typename MachOTraits::SegmentLC SegLC;
250 memset(&SegLC, 0,
sizeof(SegLC));
251 SegLC.cmd = MachOTraits::SegmentCmd;
252 SegLC.cmdsize = SegmentLCSize;
253 SegLC.vmaddr = ContainerBlockSize;
254 SegLC.vmsize = DebugSectionsSize;
255 SegLC.fileoff = ContainerBlockSize;
256 SegLC.filesize = DebugSectionsSize;
261 SegLC.nsects = NumSections;
266 for (
auto &
SI : DebugSecInfos) {
267 typename MachOTraits::Section Sec;
268 memset(&Sec, 0,
sizeof(Sec));
269 memcpy(Sec.sectname,
SI.SecName.data(),
SI.SecName.size());
270 memcpy(Sec.segname,
SI.SegName.data(),
SI.SegName.size());
271 Sec.addr =
SI.StartAddr.getValue();
273 Sec.offset =
SI.StartAddr.getValue();
274 Sec.align =
SI.Alignment;
283 NonDebugSectionsStart = Writer.getOffset();
287 Error completeSynthesisAndRegister()
override {
288 if (!MachOContainerBlock) {
290 dbgs() <<
"Not writing MachO debug object header for " <<
G.getName()
291 <<
" since createDebugSection failed\n";
297 dbgs() <<
"Writing MachO debug object header for " <<
G.getName() <<
"\n";
300 MachOStructWriter Writer(
301 MachOContainerBlock->getAlreadyMutableContent().drop_front(
302 NonDebugSectionsStart));
304 unsigned LongSectionNameIdx = 0;
305 for (
auto *Sec : NonDebugSections) {
306 size_t SepPos = Sec->getName().find(
',');
308 std::string CustomSecName;
312 SegName =
"__JITLINK_CUSTOM";
313 SecName = Sec->getName();
314 }
else if (SepPos < 16 && (Sec->getName().size() - (SepPos + 1) <= 16)) {
316 SegName = Sec->getName().
substr(0, SepPos);
317 SecName = Sec->getName().
substr(SepPos + 1);
320 assert(Sec->getName().size() > 16 &&
321 "Short section name should have been handled above");
322 SegName =
"__JITLINK_CUSTOM";
323 auto IdxStr = std::to_string(++LongSectionNameIdx);
324 CustomSecName = Sec->getName().substr(0, 15 - IdxStr.size()).str();
325 CustomSecName +=
".";
326 CustomSecName += IdxStr;
327 SecName =
StringRef(CustomSecName.data(), 16);
331 if (R.getFirstBlock()->getAlignmentOffset() != 0)
332 return make_error<StringError>(
333 "While building MachO debug object for " +
G.getName() +
334 " first block has non-zero alignment offset",
337 typename MachOTraits::Section SecCmd;
338 memset(&SecCmd, 0,
sizeof(SecCmd));
339 memcpy(SecCmd.sectname, SecName.
data(), SecName.
size());
340 memcpy(SecCmd.segname, SegName.
data(), SegName.
size());
341 SecCmd.addr = R.getStart().getValue();
342 SecCmd.size = R.getSize();
344 SecCmd.align = R.getFirstBlock()->getAlignment();
348 Writer.write(SecCmd);
352 G.allocActions().push_back(
355 RegisterActionAddr, R.getRange())),
361 Block *MachOContainerBlock =
nullptr;
363 size_t NonDebugSectionsStart = 0;
375 auto RegisterActionAddr =
376 TT.isOSBinFormatMachO()
377 ? ES.
intern(
"_llvm_orc_registerJITLoaderGDBAllocAction")
378 : ES.
intern(
"llvm_orc_registerJITLoaderGDBAllocAction");
380 if (
auto RegisterSym = ES.
lookup({&ProcessJD}, RegisterActionAddr))
381 return std::make_unique<GDBJITDebugInfoRegistrationPlugin>(
382 RegisterSym->getAddress());
384 return RegisterSym.takeError();
405 modifyPassConfigForMachO(MR, LG, PassConfig);
408 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin skipping unspported graph "
415void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO(
425 "Graph has incorrect endianness");
430 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin skipping unsupported "
431 <<
"MachO graph " << LG.
getName()
433 <<
", pointer size = " << LG.
getPointerSize() <<
", endianness = "
441 bool HasDebugSections =
false;
443 if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) {
444 HasDebugSections =
true;
448 if (HasDebugSections) {
450 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin: Graph " << LG.
getName()
451 <<
" contains debug info. Installing debugger support passes.\n";
454 auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>(
455 LG, RegisterActionAddr);
457 [=](
LinkGraph &
G) {
return MDOS->preserveDebugSections(); });
459 [=](
LinkGraph &
G) {
return MDOS->startSynthesis(); });
461 [=](
LinkGraph &
G) {
return MDOS->completeSynthesisAndRegister(); });
464 dbgs() <<
"GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName()
465 <<
" 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())
static StringRef substr(StringRef Str, uint64_t Len)
This file defines the SmallSet class.
This file defines the SmallVector class.
StringSet - A set-like wrapper for the StringMap.
size_t size() const
size - Get the array size.
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.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
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.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
constexpr size_t size() const
size - Get the string size.
bool startswith(StringRef Prefix) const
static constexpr size_t npos
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
StringSet - A wrapper for StringMap that provides set-like functionality.
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.
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...
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.
void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, SymbolLookupSet Symbols, SymbolState RequiredState, SymbolsResolvedCallback NotifyComplete, RegisterDependenciesFunction RegisterDependencies)
Search the given JITDylibs for the given symbols.
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.
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
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.
void swapStruct(fat_header &mh)
uint64_t alignToBlock(uint64_t Addr, Block &B)
constexpr endianness system_endianness()
This is an optimization pass for GlobalISel generic memory operations.
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs)
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
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.
An LinkGraph pass configuration, consisting of a list of pre-prune, post-prune, and post-fixup passes...
LinkGraphPassList PreFixupPasses
Pre-fixup passes.
LinkGraphPassList PostPrunePasses
Post-prune passes.
LinkGraphPassList PrePrunePasses
Pre-prune passes.