169be352aSLang Hames //===------- DebuggerSupportPlugin.cpp - Utils for debugger support -------===//
269be352aSLang Hames //
369be352aSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
469be352aSLang Hames // See https://llvm.org/LICENSE.txt for license information.
569be352aSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
669be352aSLang Hames //
769be352aSLang Hames //===----------------------------------------------------------------------===//
869be352aSLang Hames //
969be352aSLang Hames //
1069be352aSLang Hames //===----------------------------------------------------------------------===//
1169be352aSLang Hames 
1269be352aSLang Hames #include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h"
1369be352aSLang Hames 
1469be352aSLang Hames #include "llvm/ADT/SmallSet.h"
1569be352aSLang Hames #include "llvm/ADT/SmallVector.h"
1669be352aSLang Hames #include "llvm/ADT/StringSet.h"
1769be352aSLang Hames #include "llvm/BinaryFormat/MachO.h"
1869be352aSLang Hames 
1969be352aSLang Hames #define DEBUG_TYPE "orc"
2069be352aSLang Hames 
2169be352aSLang Hames using namespace llvm;
2269be352aSLang Hames using namespace llvm::jitlink;
2369be352aSLang Hames using namespace llvm::orc;
2469be352aSLang Hames 
2569be352aSLang Hames static const char *SynthDebugSectionName = "__jitlink_synth_debug_object";
2669be352aSLang Hames 
2769be352aSLang Hames namespace {
2869be352aSLang Hames 
2969be352aSLang Hames struct MachO64LE {
3069be352aSLang Hames   using UIntPtr = uint64_t;
3169be352aSLang Hames 
3269be352aSLang Hames   using Header = MachO::mach_header_64;
3369be352aSLang Hames   using SegmentLC = MachO::segment_command_64;
3469be352aSLang Hames   using Section = MachO::section_64;
3569be352aSLang Hames   using NList = MachO::nlist_64;
3669be352aSLang Hames 
3769be352aSLang Hames   static constexpr support::endianness Endianness = support::little;
3869be352aSLang Hames   static constexpr const uint32_t Magic = MachO::MH_MAGIC_64;
3969be352aSLang Hames   static constexpr const uint32_t SegmentCmd = MachO::LC_SEGMENT_64;
4069be352aSLang Hames };
4169be352aSLang Hames 
4269be352aSLang Hames class MachODebugObjectSynthesizerBase
4369be352aSLang Hames     : public GDBJITDebugInfoRegistrationPlugin::DebugSectionSynthesizer {
4469be352aSLang Hames public:
isDebugSection(Section & Sec)4569be352aSLang Hames   static bool isDebugSection(Section &Sec) {
4669be352aSLang Hames     return Sec.getName().startswith("__DWARF,");
4769be352aSLang Hames   }
4869be352aSLang Hames 
MachODebugObjectSynthesizerBase(LinkGraph & G,ExecutorAddr RegisterActionAddr)4969be352aSLang Hames   MachODebugObjectSynthesizerBase(LinkGraph &G, ExecutorAddr RegisterActionAddr)
5069be352aSLang Hames       : G(G), RegisterActionAddr(RegisterActionAddr) {}
513a3cb929SKazu Hirata   virtual ~MachODebugObjectSynthesizerBase() = default;
5269be352aSLang Hames 
preserveDebugSections()5369be352aSLang Hames   Error preserveDebugSections() {
5469be352aSLang Hames     if (G.findSectionByName(SynthDebugSectionName)) {
5569be352aSLang Hames       LLVM_DEBUG({
5669be352aSLang Hames         dbgs() << "MachODebugObjectSynthesizer skipping graph " << G.getName()
5769be352aSLang Hames                << " which contains an unexpected existing "
5869be352aSLang Hames                << SynthDebugSectionName << " section.\n";
5969be352aSLang Hames       });
6069be352aSLang Hames       return Error::success();
6169be352aSLang Hames     }
6269be352aSLang Hames 
6369be352aSLang Hames     LLVM_DEBUG({
6469be352aSLang Hames       dbgs() << "MachODebugObjectSynthesizer visiting graph " << G.getName()
6569be352aSLang Hames              << "\n";
6669be352aSLang Hames     });
6769be352aSLang Hames     for (auto &Sec : G.sections()) {
6869be352aSLang Hames       if (!isDebugSection(Sec))
6969be352aSLang Hames         continue;
7069be352aSLang Hames       // Preserve blocks in this debug section by marking one existing symbol
7169be352aSLang Hames       // live for each block, and introducing a new live, anonymous symbol for
7269be352aSLang Hames       // each currently unreferenced block.
7369be352aSLang Hames       LLVM_DEBUG({
7469be352aSLang Hames         dbgs() << "  Preserving debug section " << Sec.getName() << "\n";
7569be352aSLang Hames       });
7669be352aSLang Hames       SmallSet<Block *, 8> PreservedBlocks;
7769be352aSLang Hames       for (auto *Sym : Sec.symbols()) {
7869be352aSLang Hames         bool NewPreservedBlock =
7969be352aSLang Hames             PreservedBlocks.insert(&Sym->getBlock()).second;
8069be352aSLang Hames         if (NewPreservedBlock)
8169be352aSLang Hames           Sym->setLive(true);
8269be352aSLang Hames       }
8369be352aSLang Hames       for (auto *B : Sec.blocks())
8469be352aSLang Hames         if (!PreservedBlocks.count(B))
8569be352aSLang Hames           G.addAnonymousSymbol(*B, 0, 0, false, true);
8669be352aSLang Hames     }
8769be352aSLang Hames     return Error::success();
8869be352aSLang Hames   }
8969be352aSLang Hames 
9069be352aSLang Hames protected:
9169be352aSLang Hames   LinkGraph &G;
9269be352aSLang Hames   ExecutorAddr RegisterActionAddr;
9369be352aSLang Hames };
9469be352aSLang Hames 
9569be352aSLang Hames template <typename MachOTraits>
9669be352aSLang Hames class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase {
9769be352aSLang Hames private:
9869be352aSLang Hames   class MachOStructWriter {
9969be352aSLang Hames   public:
MachOStructWriter(MutableArrayRef<char> Buffer)10069be352aSLang Hames     MachOStructWriter(MutableArrayRef<char> Buffer) : Buffer(Buffer) {}
10169be352aSLang Hames 
getOffset() const10269be352aSLang Hames     size_t getOffset() const { return Offset; }
10369be352aSLang Hames 
write(MachOStruct S)10469be352aSLang Hames     template <typename MachOStruct> void write(MachOStruct S) {
10569be352aSLang Hames       assert(Offset + sizeof(S) <= Buffer.size() &&
10669be352aSLang Hames              "Container block overflow while constructing debug MachO");
10769be352aSLang Hames       if (MachOTraits::Endianness != support::endian::system_endianness())
10869be352aSLang Hames         MachO::swapStruct(S);
10969be352aSLang Hames       memcpy(Buffer.data() + Offset, &S, sizeof(S));
11069be352aSLang Hames       Offset += sizeof(S);
11169be352aSLang Hames     }
11269be352aSLang Hames 
11369be352aSLang Hames   private:
11469be352aSLang Hames     MutableArrayRef<char> Buffer;
11569be352aSLang Hames     size_t Offset = 0;
11669be352aSLang Hames   };
11769be352aSLang Hames 
11869be352aSLang Hames public:
11969be352aSLang Hames   using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase;
12069be352aSLang Hames 
startSynthesis()12169be352aSLang Hames   Error startSynthesis() override {
12269be352aSLang Hames     LLVM_DEBUG({
12369be352aSLang Hames       dbgs() << "Creating " << SynthDebugSectionName << " for " << G.getName()
12469be352aSLang Hames              << "\n";
12569be352aSLang Hames     });
12669be352aSLang Hames     auto &SDOSec = G.createSection(SynthDebugSectionName, MemProt::Read);
12769be352aSLang Hames 
12869be352aSLang Hames     struct DebugSectionInfo {
12969be352aSLang Hames       Section *Sec = nullptr;
13069be352aSLang Hames       StringRef SegName;
13169be352aSLang Hames       StringRef SecName;
132118e953bSLang Hames       uint64_t Alignment = 0;
133118e953bSLang Hames       orc::ExecutorAddr StartAddr;
13469be352aSLang Hames       uint64_t Size = 0;
13569be352aSLang Hames     };
13669be352aSLang Hames 
13769be352aSLang Hames     SmallVector<DebugSectionInfo, 12> DebugSecInfos;
13869be352aSLang Hames     size_t NumSections = 0;
13969be352aSLang Hames     for (auto &Sec : G.sections()) {
14069be352aSLang Hames       if (llvm::empty(Sec.blocks()))
14169be352aSLang Hames         continue;
14269be352aSLang Hames 
14369be352aSLang Hames       ++NumSections;
14469be352aSLang Hames       if (isDebugSection(Sec)) {
14569be352aSLang Hames         size_t SepPos = Sec.getName().find(',');
14669be352aSLang Hames         if (SepPos > 16 || (Sec.getName().size() - (SepPos + 1) > 16)) {
14769be352aSLang Hames           LLVM_DEBUG({
14869be352aSLang Hames             dbgs() << "Skipping debug object synthesis for graph "
14969be352aSLang Hames                    << G.getName()
15069be352aSLang Hames                    << ": encountered non-standard DWARF section name \""
15169be352aSLang Hames                    << Sec.getName() << "\"\n";
15269be352aSLang Hames           });
15369be352aSLang Hames           return Error::success();
15469be352aSLang Hames         }
15569be352aSLang Hames         DebugSecInfos.push_back({&Sec, Sec.getName().substr(0, SepPos),
156118e953bSLang Hames                                  Sec.getName().substr(SepPos + 1), 0,
157118e953bSLang Hames                                  orc::ExecutorAddr(), 0});
15802095f2dSLang Hames       } else {
15969be352aSLang Hames         NonDebugSections.push_back(&Sec);
16002095f2dSLang Hames 
16102095f2dSLang Hames         // If the first block in the section has a non-zero alignment offset
16202095f2dSLang Hames         // then we need to add a padding block, since the section command in
16302095f2dSLang Hames         // the header doesn't allow for aligment offsets.
16402095f2dSLang Hames         SectionRange R(Sec);
16502095f2dSLang Hames         if (!R.empty()) {
16602095f2dSLang Hames           auto &FB = *R.getFirstBlock();
16702095f2dSLang Hames           if (FB.getAlignmentOffset() != 0) {
16802095f2dSLang Hames             auto Padding = G.allocateBuffer(FB.getAlignmentOffset());
16902095f2dSLang Hames             memset(Padding.data(), 0, Padding.size());
17002095f2dSLang Hames             G.createContentBlock(Sec, Padding,
17102095f2dSLang Hames                                  FB.getAddress() - FB.getAlignmentOffset(),
17202095f2dSLang Hames                                  FB.getAlignment(), 0);
17302095f2dSLang Hames           }
17402095f2dSLang Hames         }
17502095f2dSLang Hames       }
17669be352aSLang Hames     }
17769be352aSLang Hames 
17869be352aSLang Hames     // Create container block.
17969be352aSLang Hames     size_t SectionsCmdSize =
18069be352aSLang Hames         sizeof(typename MachOTraits::Section) * NumSections;
18169be352aSLang Hames     size_t SegmentLCSize =
18269be352aSLang Hames         sizeof(typename MachOTraits::SegmentLC) + SectionsCmdSize;
18369be352aSLang Hames     size_t ContainerBlockSize =
18469be352aSLang Hames         sizeof(typename MachOTraits::Header) + SegmentLCSize;
18569be352aSLang Hames     auto ContainerBlockContent = G.allocateBuffer(ContainerBlockSize);
186118e953bSLang Hames     MachOContainerBlock = &G.createMutableContentBlock(
187118e953bSLang Hames         SDOSec, ContainerBlockContent, orc::ExecutorAddr(), 8, 0);
18869be352aSLang Hames 
18969be352aSLang Hames     // Copy debug section blocks and symbols.
190118e953bSLang Hames     orc::ExecutorAddr NextBlockAddr(MachOContainerBlock->getSize());
19169be352aSLang Hames     for (auto &SI : DebugSecInfos) {
19269be352aSLang Hames       assert(!llvm::empty(SI.Sec->blocks()) && "Empty debug info section?");
19369be352aSLang Hames 
19469be352aSLang Hames       // Update addresses in debug section.
19569be352aSLang Hames       LLVM_DEBUG({
19669be352aSLang Hames         dbgs() << "  Appending " << SI.Sec->getName() << " ("
19769be352aSLang Hames                << SI.Sec->blocks_size() << " block(s)) at "
19869be352aSLang Hames                << formatv("{0:x8}", NextBlockAddr) << "\n";
19969be352aSLang Hames       });
20069be352aSLang Hames       for (auto *B : SI.Sec->blocks()) {
20169be352aSLang Hames         NextBlockAddr = alignToBlock(NextBlockAddr, *B);
20269be352aSLang Hames         B->setAddress(NextBlockAddr);
20369be352aSLang Hames         NextBlockAddr += B->getSize();
20469be352aSLang Hames       }
20569be352aSLang Hames 
20669be352aSLang Hames       auto &FirstBlock = **SI.Sec->blocks().begin();
20769be352aSLang Hames       if (FirstBlock.getAlignmentOffset() != 0)
20869be352aSLang Hames         return make_error<StringError>(
20969be352aSLang Hames             "First block in " + SI.Sec->getName() +
21069be352aSLang Hames                 " section has non-zero alignment offset",
21169be352aSLang Hames             inconvertibleErrorCode());
21269be352aSLang Hames       if (FirstBlock.getAlignment() > std::numeric_limits<uint32_t>::max())
21369be352aSLang Hames         return make_error<StringError>("First block in " + SI.Sec->getName() +
21469be352aSLang Hames                                            " has alignment >4Gb",
21569be352aSLang Hames                                        inconvertibleErrorCode());
21669be352aSLang Hames 
21769be352aSLang Hames       SI.Alignment = FirstBlock.getAlignment();
21869be352aSLang Hames       SI.StartAddr = FirstBlock.getAddress();
21969be352aSLang Hames       SI.Size = NextBlockAddr - SI.StartAddr;
22069be352aSLang Hames       G.mergeSections(SDOSec, *SI.Sec);
22169be352aSLang Hames       SI.Sec = nullptr;
22269be352aSLang Hames     }
223118e953bSLang Hames     size_t DebugSectionsSize =
224118e953bSLang Hames         NextBlockAddr - orc::ExecutorAddr(MachOContainerBlock->getSize());
22569be352aSLang Hames 
22669be352aSLang Hames     // Write MachO header and debug section load commands.
22769be352aSLang Hames     MachOStructWriter Writer(MachOContainerBlock->getAlreadyMutableContent());
22869be352aSLang Hames     typename MachOTraits::Header Hdr;
22969be352aSLang Hames     memset(&Hdr, 0, sizeof(Hdr));
23069be352aSLang Hames     Hdr.magic = MachOTraits::Magic;
23169be352aSLang Hames     switch (G.getTargetTriple().getArch()) {
23269be352aSLang Hames     case Triple::x86_64:
23369be352aSLang Hames       Hdr.cputype = MachO::CPU_TYPE_X86_64;
23469be352aSLang Hames       Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
23569be352aSLang Hames       break;
23669be352aSLang Hames     case Triple::aarch64:
23769be352aSLang Hames       Hdr.cputype = MachO::CPU_TYPE_ARM64;
23869be352aSLang Hames       Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
23969be352aSLang Hames       break;
24069be352aSLang Hames     default:
24169be352aSLang Hames       llvm_unreachable("Unsupported architecture");
24269be352aSLang Hames     }
24369be352aSLang Hames     Hdr.filetype = MachO::MH_OBJECT;
24469be352aSLang Hames     Hdr.ncmds = 1;
24569be352aSLang Hames     Hdr.sizeofcmds = SegmentLCSize;
24669be352aSLang Hames     Hdr.flags = 0;
24769be352aSLang Hames     Writer.write(Hdr);
24869be352aSLang Hames 
24969be352aSLang Hames     typename MachOTraits::SegmentLC SegLC;
25069be352aSLang Hames     memset(&SegLC, 0, sizeof(SegLC));
25169be352aSLang Hames     SegLC.cmd = MachOTraits::SegmentCmd;
25269be352aSLang Hames     SegLC.cmdsize = SegmentLCSize;
25369be352aSLang Hames     SegLC.vmaddr = ContainerBlockSize;
25469be352aSLang Hames     SegLC.vmsize = DebugSectionsSize;
25569be352aSLang Hames     SegLC.fileoff = ContainerBlockSize;
25669be352aSLang Hames     SegLC.filesize = DebugSectionsSize;
25769be352aSLang Hames     SegLC.maxprot =
25869be352aSLang Hames         MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
25969be352aSLang Hames     SegLC.initprot =
26069be352aSLang Hames         MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
26169be352aSLang Hames     SegLC.nsects = NumSections;
26269be352aSLang Hames     SegLC.flags = 0;
26369be352aSLang Hames     Writer.write(SegLC);
26469be352aSLang Hames 
26569be352aSLang Hames     StringSet<> ExistingLongNames;
26669be352aSLang Hames     for (auto &SI : DebugSecInfos) {
26769be352aSLang Hames       typename MachOTraits::Section Sec;
26869be352aSLang Hames       memset(&Sec, 0, sizeof(Sec));
26969be352aSLang Hames       memcpy(Sec.sectname, SI.SecName.data(), SI.SecName.size());
27069be352aSLang Hames       memcpy(Sec.segname, SI.SegName.data(), SI.SegName.size());
271118e953bSLang Hames       Sec.addr = SI.StartAddr.getValue();
27269be352aSLang Hames       Sec.size = SI.Size;
273118e953bSLang Hames       Sec.offset = SI.StartAddr.getValue();
27469be352aSLang Hames       Sec.align = SI.Alignment;
27569be352aSLang Hames       Sec.reloff = 0;
27669be352aSLang Hames       Sec.nreloc = 0;
27769be352aSLang Hames       Sec.flags = MachO::S_ATTR_DEBUG;
27869be352aSLang Hames       Writer.write(Sec);
27969be352aSLang Hames     }
28069be352aSLang Hames 
28169be352aSLang Hames     // Set MachOContainerBlock to indicate success to
28269be352aSLang Hames     // completeSynthesisAndRegister.
28369be352aSLang Hames     NonDebugSectionsStart = Writer.getOffset();
28469be352aSLang Hames     return Error::success();
28569be352aSLang Hames   }
28669be352aSLang Hames 
completeSynthesisAndRegister()28769be352aSLang Hames   Error completeSynthesisAndRegister() override {
28869be352aSLang Hames     if (!MachOContainerBlock) {
28969be352aSLang Hames       LLVM_DEBUG({
29069be352aSLang Hames         dbgs() << "Not writing MachO debug object header for " << G.getName()
29169be352aSLang Hames                << " since createDebugSection failed\n";
29269be352aSLang Hames       });
29369be352aSLang Hames       return Error::success();
29469be352aSLang Hames     }
29569be352aSLang Hames 
29669be352aSLang Hames     LLVM_DEBUG({
29769be352aSLang Hames       dbgs() << "Writing MachO debug object header for " << G.getName() << "\n";
29869be352aSLang Hames     });
29969be352aSLang Hames 
30069be352aSLang Hames     MachOStructWriter Writer(
30169be352aSLang Hames         MachOContainerBlock->getAlreadyMutableContent().drop_front(
30269be352aSLang Hames             NonDebugSectionsStart));
30369be352aSLang Hames 
30469be352aSLang Hames     unsigned LongSectionNameIdx = 0;
30569be352aSLang Hames     for (auto *Sec : NonDebugSections) {
30669be352aSLang Hames       size_t SepPos = Sec->getName().find(',');
30769be352aSLang Hames       StringRef SegName, SecName;
30869be352aSLang Hames       std::string CustomSecName;
30969be352aSLang Hames 
31069be352aSLang Hames       if ((SepPos == StringRef::npos && Sec->getName().size() <= 16)) {
31169be352aSLang Hames         // No embedded segment name, short section name.
31269be352aSLang Hames         SegName = "__JITLINK_CUSTOM";
31369be352aSLang Hames         SecName = Sec->getName();
31469be352aSLang Hames       } else if (SepPos < 16 && (Sec->getName().size() - (SepPos + 1) <= 16)) {
31569be352aSLang Hames         // Canonical embedded segment and section name.
31669be352aSLang Hames         SegName = Sec->getName().substr(0, SepPos);
31769be352aSLang Hames         SecName = Sec->getName().substr(SepPos + 1);
31869be352aSLang Hames       } else {
31969be352aSLang Hames         // Long section name that needs to be truncated.
32069be352aSLang Hames         assert(Sec->getName().size() > 16 &&
32169be352aSLang Hames                "Short section name should have been handled above");
32269be352aSLang Hames         SegName = "__JITLINK_CUSTOM";
32369be352aSLang Hames         auto IdxStr = std::to_string(++LongSectionNameIdx);
32469be352aSLang Hames         CustomSecName = Sec->getName().substr(0, 15 - IdxStr.size()).str();
32569be352aSLang Hames         CustomSecName += ".";
32669be352aSLang Hames         CustomSecName += IdxStr;
32769be352aSLang Hames         SecName = StringRef(CustomSecName.data(), 16);
32869be352aSLang Hames       }
32969be352aSLang Hames 
33069be352aSLang Hames       SectionRange R(*Sec);
33169be352aSLang Hames       if (R.getFirstBlock()->getAlignmentOffset() != 0)
33269be352aSLang Hames         return make_error<StringError>(
33369be352aSLang Hames             "While building MachO debug object for " + G.getName() +
33469be352aSLang Hames                 " first block has non-zero alignment offset",
33569be352aSLang Hames             inconvertibleErrorCode());
33669be352aSLang Hames 
33769be352aSLang Hames       typename MachOTraits::Section SecCmd;
33869be352aSLang Hames       memset(&SecCmd, 0, sizeof(SecCmd));
33969be352aSLang Hames       memcpy(SecCmd.sectname, SecName.data(), SecName.size());
34069be352aSLang Hames       memcpy(SecCmd.segname, SegName.data(), SegName.size());
341118e953bSLang Hames       SecCmd.addr = R.getStart().getValue();
34269be352aSLang Hames       SecCmd.size = R.getSize();
34369be352aSLang Hames       SecCmd.offset = 0;
34469be352aSLang Hames       SecCmd.align = R.getFirstBlock()->getAlignment();
34569be352aSLang Hames       SecCmd.reloff = 0;
34669be352aSLang Hames       SecCmd.nreloc = 0;
34769be352aSLang Hames       SecCmd.flags = 0;
34869be352aSLang Hames       Writer.write(SecCmd);
34969be352aSLang Hames     }
35069be352aSLang Hames 
35169be352aSLang Hames     SectionRange R(MachOContainerBlock->getSection());
352*ec6d6210SPavel Labath     G.allocActions().push_back(
353*ec6d6210SPavel Labath         {cantFail(shared::WrapperFunctionCall::Create<
354*ec6d6210SPavel Labath                   shared::SPSArgList<shared::SPSExecutorAddrRange>>(
355089acf25SLang Hames              RegisterActionAddr, R.getRange())),
356089acf25SLang Hames          {}});
35769be352aSLang Hames     return Error::success();
35869be352aSLang Hames   }
35969be352aSLang Hames 
36069be352aSLang Hames private:
36169be352aSLang Hames   Block *MachOContainerBlock = nullptr;
36269be352aSLang Hames   SmallVector<Section *, 16> NonDebugSections;
36369be352aSLang Hames   size_t NonDebugSectionsStart = 0;
36469be352aSLang Hames };
36569be352aSLang Hames 
36669be352aSLang Hames } // end anonymous namespace
36769be352aSLang Hames 
36869be352aSLang Hames namespace llvm {
36969be352aSLang Hames namespace orc {
37069be352aSLang Hames 
37169be352aSLang Hames Expected<std::unique_ptr<GDBJITDebugInfoRegistrationPlugin>>
Create(ExecutionSession & ES,JITDylib & ProcessJD,const Triple & TT)37269be352aSLang Hames GDBJITDebugInfoRegistrationPlugin::Create(ExecutionSession &ES,
37369be352aSLang Hames                                           JITDylib &ProcessJD,
37469be352aSLang Hames                                           const Triple &TT) {
37569be352aSLang Hames   auto RegisterActionAddr =
37669be352aSLang Hames       TT.isOSBinFormatMachO()
37769be352aSLang Hames           ? ES.intern("_llvm_orc_registerJITLoaderGDBAllocAction")
37869be352aSLang Hames           : ES.intern("llvm_orc_registerJITLoaderGDBAllocAction");
37969be352aSLang Hames 
38069be352aSLang Hames   if (auto Addr = ES.lookup({&ProcessJD}, RegisterActionAddr))
38169be352aSLang Hames     return std::make_unique<GDBJITDebugInfoRegistrationPlugin>(
38269be352aSLang Hames         ExecutorAddr(Addr->getAddress()));
38369be352aSLang Hames   else
38469be352aSLang Hames     return Addr.takeError();
38569be352aSLang Hames }
38669be352aSLang Hames 
notifyFailed(MaterializationResponsibility & MR)38769be352aSLang Hames Error GDBJITDebugInfoRegistrationPlugin::notifyFailed(
38869be352aSLang Hames     MaterializationResponsibility &MR) {
38969be352aSLang Hames   return Error::success();
39069be352aSLang Hames }
39169be352aSLang Hames 
notifyRemovingResources(ResourceKey K)39269be352aSLang Hames Error GDBJITDebugInfoRegistrationPlugin::notifyRemovingResources(
39369be352aSLang Hames     ResourceKey K) {
39469be352aSLang Hames   return Error::success();
39569be352aSLang Hames }
39669be352aSLang Hames 
notifyTransferringResources(ResourceKey DstKey,ResourceKey SrcKey)39769be352aSLang Hames void GDBJITDebugInfoRegistrationPlugin::notifyTransferringResources(
39869be352aSLang Hames     ResourceKey DstKey, ResourceKey SrcKey) {}
39969be352aSLang Hames 
modifyPassConfig(MaterializationResponsibility & MR,LinkGraph & LG,PassConfiguration & PassConfig)40069be352aSLang Hames void GDBJITDebugInfoRegistrationPlugin::modifyPassConfig(
40169be352aSLang Hames     MaterializationResponsibility &MR, LinkGraph &LG,
40269be352aSLang Hames     PassConfiguration &PassConfig) {
40369be352aSLang Hames 
40469be352aSLang Hames   if (LG.getTargetTriple().getObjectFormat() == Triple::MachO)
40569be352aSLang Hames     modifyPassConfigForMachO(MR, LG, PassConfig);
40669be352aSLang Hames   else {
40769be352aSLang Hames     LLVM_DEBUG({
40869be352aSLang Hames       dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unspported graph "
40969be352aSLang Hames              << LG.getName() << "(triple = " << LG.getTargetTriple().str()
41069be352aSLang Hames              << "\n";
41169be352aSLang Hames     });
41269be352aSLang Hames   }
41369be352aSLang Hames }
41469be352aSLang Hames 
modifyPassConfigForMachO(MaterializationResponsibility & MR,jitlink::LinkGraph & LG,jitlink::PassConfiguration & PassConfig)41569be352aSLang Hames void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO(
41669be352aSLang Hames     MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
41769be352aSLang Hames     jitlink::PassConfiguration &PassConfig) {
41869be352aSLang Hames 
41969be352aSLang Hames   switch (LG.getTargetTriple().getArch()) {
42069be352aSLang Hames   case Triple::x86_64:
42169be352aSLang Hames   case Triple::aarch64:
42269be352aSLang Hames     // Supported, continue.
42369be352aSLang Hames     assert(LG.getPointerSize() == 8 && "Graph has incorrect pointer size");
42469be352aSLang Hames     assert(LG.getEndianness() == support::little &&
42569be352aSLang Hames            "Graph has incorrect endianness");
42669be352aSLang Hames     break;
42769be352aSLang Hames   default:
42869be352aSLang Hames     // Unsupported.
42969be352aSLang Hames     LLVM_DEBUG({
43069be352aSLang Hames       dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unsupported "
43169be352aSLang Hames              << "MachO graph " << LG.getName()
43269be352aSLang Hames              << "(triple = " << LG.getTargetTriple().str()
43369be352aSLang Hames              << ", pointer size = " << LG.getPointerSize() << ", endianness = "
43469be352aSLang Hames              << (LG.getEndianness() == support::big ? "big" : "little")
43569be352aSLang Hames              << ")\n";
43669be352aSLang Hames     });
43769be352aSLang Hames     return;
43869be352aSLang Hames   }
43969be352aSLang Hames 
44069be352aSLang Hames   // Scan for debug sections. If we find one then install passes.
44169be352aSLang Hames   bool HasDebugSections = false;
44269be352aSLang Hames   for (auto &Sec : LG.sections())
44369be352aSLang Hames     if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) {
44469be352aSLang Hames       HasDebugSections = true;
44569be352aSLang Hames       break;
44669be352aSLang Hames     }
44769be352aSLang Hames 
44869be352aSLang Hames   if (HasDebugSections) {
44969be352aSLang Hames     LLVM_DEBUG({
45069be352aSLang Hames       dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName()
45169be352aSLang Hames              << " contains debug info. Installing debugger support passes.\n";
45269be352aSLang Hames     });
45369be352aSLang Hames 
45469be352aSLang Hames     auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>(
45569be352aSLang Hames         LG, RegisterActionAddr);
45669be352aSLang Hames     PassConfig.PrePrunePasses.push_back(
45769be352aSLang Hames         [=](LinkGraph &G) { return MDOS->preserveDebugSections(); });
45869be352aSLang Hames     PassConfig.PostPrunePasses.push_back(
45969be352aSLang Hames         [=](LinkGraph &G) { return MDOS->startSynthesis(); });
46069be352aSLang Hames     PassConfig.PreFixupPasses.push_back(
46169be352aSLang Hames         [=](LinkGraph &G) { return MDOS->completeSynthesisAndRegister(); });
46269be352aSLang Hames   } else {
46369be352aSLang Hames     LLVM_DEBUG({
46469be352aSLang Hames       dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName()
46569be352aSLang Hames              << " contains no debug info. Skipping.\n";
46669be352aSLang Hames     });
46769be352aSLang Hames   }
46869be352aSLang Hames }
46969be352aSLang Hames 
47069be352aSLang Hames } // namespace orc
47169be352aSLang Hames } // namespace llvm
472