DebuggerSupportPlugin.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. //===------- DebuggerSupportPlugin.cpp - Utils for debugger support -------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. //
  10. //===----------------------------------------------------------------------===//
  11. #include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h"
  12. #include "llvm/ADT/SmallSet.h"
  13. #include "llvm/ADT/SmallVector.h"
  14. #include "llvm/ADT/StringSet.h"
  15. #include "llvm/BinaryFormat/MachO.h"
  16. #define DEBUG_TYPE "orc"
  17. using namespace llvm;
  18. using namespace llvm::jitlink;
  19. using namespace llvm::orc;
  20. static const char *SynthDebugSectionName = "__jitlink_synth_debug_object";
  21. namespace {
  22. struct MachO64LE {
  23. using UIntPtr = uint64_t;
  24. using Header = MachO::mach_header_64;
  25. using SegmentLC = MachO::segment_command_64;
  26. using Section = MachO::section_64;
  27. using NList = MachO::nlist_64;
  28. static constexpr support::endianness Endianness = support::little;
  29. static constexpr const uint32_t Magic = MachO::MH_MAGIC_64;
  30. static constexpr const uint32_t SegmentCmd = MachO::LC_SEGMENT_64;
  31. };
  32. class MachODebugObjectSynthesizerBase
  33. : public GDBJITDebugInfoRegistrationPlugin::DebugSectionSynthesizer {
  34. public:
  35. static bool isDebugSection(Section &Sec) {
  36. return Sec.getName().startswith("__DWARF,");
  37. }
  38. MachODebugObjectSynthesizerBase(LinkGraph &G, ExecutorAddr RegisterActionAddr)
  39. : G(G), RegisterActionAddr(RegisterActionAddr) {}
  40. virtual ~MachODebugObjectSynthesizerBase() = default;
  41. Error preserveDebugSections() {
  42. if (G.findSectionByName(SynthDebugSectionName)) {
  43. LLVM_DEBUG({
  44. dbgs() << "MachODebugObjectSynthesizer skipping graph " << G.getName()
  45. << " which contains an unexpected existing "
  46. << SynthDebugSectionName << " section.\n";
  47. });
  48. return Error::success();
  49. }
  50. LLVM_DEBUG({
  51. dbgs() << "MachODebugObjectSynthesizer visiting graph " << G.getName()
  52. << "\n";
  53. });
  54. for (auto &Sec : G.sections()) {
  55. if (!isDebugSection(Sec))
  56. continue;
  57. // Preserve blocks in this debug section by marking one existing symbol
  58. // live for each block, and introducing a new live, anonymous symbol for
  59. // each currently unreferenced block.
  60. LLVM_DEBUG({
  61. dbgs() << " Preserving debug section " << Sec.getName() << "\n";
  62. });
  63. SmallSet<Block *, 8> PreservedBlocks;
  64. for (auto *Sym : Sec.symbols()) {
  65. bool NewPreservedBlock =
  66. PreservedBlocks.insert(&Sym->getBlock()).second;
  67. if (NewPreservedBlock)
  68. Sym->setLive(true);
  69. }
  70. for (auto *B : Sec.blocks())
  71. if (!PreservedBlocks.count(B))
  72. G.addAnonymousSymbol(*B, 0, 0, false, true);
  73. }
  74. return Error::success();
  75. }
  76. protected:
  77. LinkGraph &G;
  78. ExecutorAddr RegisterActionAddr;
  79. };
  80. template <typename MachOTraits>
  81. class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase {
  82. private:
  83. class MachOStructWriter {
  84. public:
  85. MachOStructWriter(MutableArrayRef<char> Buffer) : Buffer(Buffer) {}
  86. size_t getOffset() const { return Offset; }
  87. template <typename MachOStruct> void write(MachOStruct S) {
  88. assert(Offset + sizeof(S) <= Buffer.size() &&
  89. "Container block overflow while constructing debug MachO");
  90. if (MachOTraits::Endianness != support::endian::system_endianness())
  91. MachO::swapStruct(S);
  92. memcpy(Buffer.data() + Offset, &S, sizeof(S));
  93. Offset += sizeof(S);
  94. }
  95. private:
  96. MutableArrayRef<char> Buffer;
  97. size_t Offset = 0;
  98. };
  99. public:
  100. using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase;
  101. Error startSynthesis() override {
  102. LLVM_DEBUG({
  103. dbgs() << "Creating " << SynthDebugSectionName << " for " << G.getName()
  104. << "\n";
  105. });
  106. auto &SDOSec = G.createSection(SynthDebugSectionName, MemProt::Read);
  107. struct DebugSectionInfo {
  108. Section *Sec = nullptr;
  109. StringRef SegName;
  110. StringRef SecName;
  111. uint64_t Alignment = 0;
  112. orc::ExecutorAddr StartAddr;
  113. uint64_t Size = 0;
  114. };
  115. SmallVector<DebugSectionInfo, 12> DebugSecInfos;
  116. size_t NumSections = 0;
  117. for (auto &Sec : G.sections()) {
  118. if (Sec.blocks().empty())
  119. continue;
  120. ++NumSections;
  121. if (isDebugSection(Sec)) {
  122. size_t SepPos = Sec.getName().find(',');
  123. if (SepPos > 16 || (Sec.getName().size() - (SepPos + 1) > 16)) {
  124. LLVM_DEBUG({
  125. dbgs() << "Skipping debug object synthesis for graph "
  126. << G.getName()
  127. << ": encountered non-standard DWARF section name \""
  128. << Sec.getName() << "\"\n";
  129. });
  130. return Error::success();
  131. }
  132. DebugSecInfos.push_back({&Sec, Sec.getName().substr(0, SepPos),
  133. Sec.getName().substr(SepPos + 1), 0,
  134. orc::ExecutorAddr(), 0});
  135. } else {
  136. NonDebugSections.push_back(&Sec);
  137. // If the first block in the section has a non-zero alignment offset
  138. // then we need to add a padding block, since the section command in
  139. // the header doesn't allow for aligment offsets.
  140. SectionRange R(Sec);
  141. if (!R.empty()) {
  142. auto &FB = *R.getFirstBlock();
  143. if (FB.getAlignmentOffset() != 0) {
  144. auto Padding = G.allocateBuffer(FB.getAlignmentOffset());
  145. memset(Padding.data(), 0, Padding.size());
  146. G.createContentBlock(Sec, Padding,
  147. FB.getAddress() - FB.getAlignmentOffset(),
  148. FB.getAlignment(), 0);
  149. }
  150. }
  151. }
  152. }
  153. // Create container block.
  154. size_t SectionsCmdSize =
  155. sizeof(typename MachOTraits::Section) * NumSections;
  156. size_t SegmentLCSize =
  157. sizeof(typename MachOTraits::SegmentLC) + SectionsCmdSize;
  158. size_t ContainerBlockSize =
  159. sizeof(typename MachOTraits::Header) + SegmentLCSize;
  160. auto ContainerBlockContent = G.allocateBuffer(ContainerBlockSize);
  161. MachOContainerBlock = &G.createMutableContentBlock(
  162. SDOSec, ContainerBlockContent, orc::ExecutorAddr(), 8, 0);
  163. // Copy debug section blocks and symbols.
  164. orc::ExecutorAddr NextBlockAddr(MachOContainerBlock->getSize());
  165. for (auto &SI : DebugSecInfos) {
  166. assert(!SI.Sec->blocks().empty() && "Empty debug info section?");
  167. // Update addresses in debug section.
  168. LLVM_DEBUG({
  169. dbgs() << " Appending " << SI.Sec->getName() << " ("
  170. << SI.Sec->blocks_size() << " block(s)) at "
  171. << formatv("{0:x8}", NextBlockAddr) << "\n";
  172. });
  173. for (auto *B : SI.Sec->blocks()) {
  174. NextBlockAddr = alignToBlock(NextBlockAddr, *B);
  175. B->setAddress(NextBlockAddr);
  176. NextBlockAddr += B->getSize();
  177. }
  178. auto &FirstBlock = **SI.Sec->blocks().begin();
  179. if (FirstBlock.getAlignmentOffset() != 0)
  180. return make_error<StringError>(
  181. "First block in " + SI.Sec->getName() +
  182. " section has non-zero alignment offset",
  183. inconvertibleErrorCode());
  184. if (FirstBlock.getAlignment() > std::numeric_limits<uint32_t>::max())
  185. return make_error<StringError>("First block in " + SI.Sec->getName() +
  186. " has alignment >4Gb",
  187. inconvertibleErrorCode());
  188. SI.Alignment = FirstBlock.getAlignment();
  189. SI.StartAddr = FirstBlock.getAddress();
  190. SI.Size = NextBlockAddr - SI.StartAddr;
  191. G.mergeSections(SDOSec, *SI.Sec);
  192. SI.Sec = nullptr;
  193. }
  194. size_t DebugSectionsSize =
  195. NextBlockAddr - orc::ExecutorAddr(MachOContainerBlock->getSize());
  196. // Write MachO header and debug section load commands.
  197. MachOStructWriter Writer(MachOContainerBlock->getAlreadyMutableContent());
  198. typename MachOTraits::Header Hdr;
  199. memset(&Hdr, 0, sizeof(Hdr));
  200. Hdr.magic = MachOTraits::Magic;
  201. switch (G.getTargetTriple().getArch()) {
  202. case Triple::x86_64:
  203. Hdr.cputype = MachO::CPU_TYPE_X86_64;
  204. Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
  205. break;
  206. case Triple::aarch64:
  207. Hdr.cputype = MachO::CPU_TYPE_ARM64;
  208. Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
  209. break;
  210. default:
  211. llvm_unreachable("Unsupported architecture");
  212. }
  213. Hdr.filetype = MachO::MH_OBJECT;
  214. Hdr.ncmds = 1;
  215. Hdr.sizeofcmds = SegmentLCSize;
  216. Hdr.flags = 0;
  217. Writer.write(Hdr);
  218. typename MachOTraits::SegmentLC SegLC;
  219. memset(&SegLC, 0, sizeof(SegLC));
  220. SegLC.cmd = MachOTraits::SegmentCmd;
  221. SegLC.cmdsize = SegmentLCSize;
  222. SegLC.vmaddr = ContainerBlockSize;
  223. SegLC.vmsize = DebugSectionsSize;
  224. SegLC.fileoff = ContainerBlockSize;
  225. SegLC.filesize = DebugSectionsSize;
  226. SegLC.maxprot =
  227. MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
  228. SegLC.initprot =
  229. MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
  230. SegLC.nsects = NumSections;
  231. SegLC.flags = 0;
  232. Writer.write(SegLC);
  233. StringSet<> ExistingLongNames;
  234. for (auto &SI : DebugSecInfos) {
  235. typename MachOTraits::Section Sec;
  236. memset(&Sec, 0, sizeof(Sec));
  237. memcpy(Sec.sectname, SI.SecName.data(), SI.SecName.size());
  238. memcpy(Sec.segname, SI.SegName.data(), SI.SegName.size());
  239. Sec.addr = SI.StartAddr.getValue();
  240. Sec.size = SI.Size;
  241. Sec.offset = SI.StartAddr.getValue();
  242. Sec.align = SI.Alignment;
  243. Sec.reloff = 0;
  244. Sec.nreloc = 0;
  245. Sec.flags = MachO::S_ATTR_DEBUG;
  246. Writer.write(Sec);
  247. }
  248. // Set MachOContainerBlock to indicate success to
  249. // completeSynthesisAndRegister.
  250. NonDebugSectionsStart = Writer.getOffset();
  251. return Error::success();
  252. }
  253. Error completeSynthesisAndRegister() override {
  254. if (!MachOContainerBlock) {
  255. LLVM_DEBUG({
  256. dbgs() << "Not writing MachO debug object header for " << G.getName()
  257. << " since createDebugSection failed\n";
  258. });
  259. return Error::success();
  260. }
  261. LLVM_DEBUG({
  262. dbgs() << "Writing MachO debug object header for " << G.getName() << "\n";
  263. });
  264. MachOStructWriter Writer(
  265. MachOContainerBlock->getAlreadyMutableContent().drop_front(
  266. NonDebugSectionsStart));
  267. unsigned LongSectionNameIdx = 0;
  268. for (auto *Sec : NonDebugSections) {
  269. size_t SepPos = Sec->getName().find(',');
  270. StringRef SegName, SecName;
  271. std::string CustomSecName;
  272. if ((SepPos == StringRef::npos && Sec->getName().size() <= 16)) {
  273. // No embedded segment name, short section name.
  274. SegName = "__JITLINK_CUSTOM";
  275. SecName = Sec->getName();
  276. } else if (SepPos < 16 && (Sec->getName().size() - (SepPos + 1) <= 16)) {
  277. // Canonical embedded segment and section name.
  278. SegName = Sec->getName().substr(0, SepPos);
  279. SecName = Sec->getName().substr(SepPos + 1);
  280. } else {
  281. // Long section name that needs to be truncated.
  282. assert(Sec->getName().size() > 16 &&
  283. "Short section name should have been handled above");
  284. SegName = "__JITLINK_CUSTOM";
  285. auto IdxStr = std::to_string(++LongSectionNameIdx);
  286. CustomSecName = Sec->getName().substr(0, 15 - IdxStr.size()).str();
  287. CustomSecName += ".";
  288. CustomSecName += IdxStr;
  289. SecName = StringRef(CustomSecName.data(), 16);
  290. }
  291. SectionRange R(*Sec);
  292. if (R.getFirstBlock()->getAlignmentOffset() != 0)
  293. return make_error<StringError>(
  294. "While building MachO debug object for " + G.getName() +
  295. " first block has non-zero alignment offset",
  296. inconvertibleErrorCode());
  297. typename MachOTraits::Section SecCmd;
  298. memset(&SecCmd, 0, sizeof(SecCmd));
  299. memcpy(SecCmd.sectname, SecName.data(), SecName.size());
  300. memcpy(SecCmd.segname, SegName.data(), SegName.size());
  301. SecCmd.addr = R.getStart().getValue();
  302. SecCmd.size = R.getSize();
  303. SecCmd.offset = 0;
  304. SecCmd.align = R.getFirstBlock()->getAlignment();
  305. SecCmd.reloff = 0;
  306. SecCmd.nreloc = 0;
  307. SecCmd.flags = 0;
  308. Writer.write(SecCmd);
  309. }
  310. SectionRange R(MachOContainerBlock->getSection());
  311. G.allocActions().push_back(
  312. {cantFail(shared::WrapperFunctionCall::Create<
  313. shared::SPSArgList<shared::SPSExecutorAddrRange>>(
  314. RegisterActionAddr, R.getRange())),
  315. {}});
  316. return Error::success();
  317. }
  318. private:
  319. Block *MachOContainerBlock = nullptr;
  320. SmallVector<Section *, 16> NonDebugSections;
  321. size_t NonDebugSectionsStart = 0;
  322. };
  323. } // end anonymous namespace
  324. namespace llvm {
  325. namespace orc {
  326. Expected<std::unique_ptr<GDBJITDebugInfoRegistrationPlugin>>
  327. GDBJITDebugInfoRegistrationPlugin::Create(ExecutionSession &ES,
  328. JITDylib &ProcessJD,
  329. const Triple &TT) {
  330. auto RegisterActionAddr =
  331. TT.isOSBinFormatMachO()
  332. ? ES.intern("_llvm_orc_registerJITLoaderGDBAllocAction")
  333. : ES.intern("llvm_orc_registerJITLoaderGDBAllocAction");
  334. if (auto Addr = ES.lookup({&ProcessJD}, RegisterActionAddr))
  335. return std::make_unique<GDBJITDebugInfoRegistrationPlugin>(
  336. ExecutorAddr(Addr->getAddress()));
  337. else
  338. return Addr.takeError();
  339. }
  340. Error GDBJITDebugInfoRegistrationPlugin::notifyFailed(
  341. MaterializationResponsibility &MR) {
  342. return Error::success();
  343. }
  344. Error GDBJITDebugInfoRegistrationPlugin::notifyRemovingResources(
  345. JITDylib &JD, ResourceKey K) {
  346. return Error::success();
  347. }
  348. void GDBJITDebugInfoRegistrationPlugin::notifyTransferringResources(
  349. JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {}
  350. void GDBJITDebugInfoRegistrationPlugin::modifyPassConfig(
  351. MaterializationResponsibility &MR, LinkGraph &LG,
  352. PassConfiguration &PassConfig) {
  353. if (LG.getTargetTriple().getObjectFormat() == Triple::MachO)
  354. modifyPassConfigForMachO(MR, LG, PassConfig);
  355. else {
  356. LLVM_DEBUG({
  357. dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unspported graph "
  358. << LG.getName() << "(triple = " << LG.getTargetTriple().str()
  359. << "\n";
  360. });
  361. }
  362. }
  363. void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO(
  364. MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
  365. jitlink::PassConfiguration &PassConfig) {
  366. switch (LG.getTargetTriple().getArch()) {
  367. case Triple::x86_64:
  368. case Triple::aarch64:
  369. // Supported, continue.
  370. assert(LG.getPointerSize() == 8 && "Graph has incorrect pointer size");
  371. assert(LG.getEndianness() == support::little &&
  372. "Graph has incorrect endianness");
  373. break;
  374. default:
  375. // Unsupported.
  376. LLVM_DEBUG({
  377. dbgs() << "GDBJITDebugInfoRegistrationPlugin skipping unsupported "
  378. << "MachO graph " << LG.getName()
  379. << "(triple = " << LG.getTargetTriple().str()
  380. << ", pointer size = " << LG.getPointerSize() << ", endianness = "
  381. << (LG.getEndianness() == support::big ? "big" : "little")
  382. << ")\n";
  383. });
  384. return;
  385. }
  386. // Scan for debug sections. If we find one then install passes.
  387. bool HasDebugSections = false;
  388. for (auto &Sec : LG.sections())
  389. if (MachODebugObjectSynthesizerBase::isDebugSection(Sec)) {
  390. HasDebugSections = true;
  391. break;
  392. }
  393. if (HasDebugSections) {
  394. LLVM_DEBUG({
  395. dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName()
  396. << " contains debug info. Installing debugger support passes.\n";
  397. });
  398. auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>(
  399. LG, RegisterActionAddr);
  400. PassConfig.PrePrunePasses.push_back(
  401. [=](LinkGraph &G) { return MDOS->preserveDebugSections(); });
  402. PassConfig.PostPrunePasses.push_back(
  403. [=](LinkGraph &G) { return MDOS->startSynthesis(); });
  404. PassConfig.PreFixupPasses.push_back(
  405. [=](LinkGraph &G) { return MDOS->completeSynthesisAndRegister(); });
  406. } else {
  407. LLVM_DEBUG({
  408. dbgs() << "GDBJITDebugInfoRegistrationPlugin: Graph " << LG.getName()
  409. << " contains no debug info. Skipping.\n";
  410. });
  411. }
  412. }
  413. } // namespace orc
  414. } // namespace llvm