1//===--- DebugInfoSupport.cpp -- Utils for debug info support ---*- C++ -*-===//
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// Utilities to preserve and parse debug info from LinkGraphs.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
14
15#include "llvm/Support/SmallVectorMemoryBuffer.h"
16
17#define DEBUG_TYPE "orc"
18
19using namespace llvm;
20using namespace llvm::orc;
21using namespace llvm::jitlink;
22
23namespace {
24static DenseSet<StringRef> DWARFSectionNames = {
25#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
26 StringRef(ELF_NAME),
27#include "llvm/BinaryFormat/Dwarf.def"
28#undef HANDLE_DWARF_SECTION
29};
30
31// We might be able to drop relocations to symbols that do end up
32// being pruned by the linker, but for now we just preserve all
33static void preserveDWARFSection(LinkGraph &G, Section &Sec) {
34 DenseMap<Block *, Symbol *> Preserved;
35 for (auto Sym : Sec.symbols()) {
36 auto [It, Inserted] = Preserved.try_emplace(Key: &Sym->getBlock());
37 if (Inserted || Sym->isLive())
38 It->second = Sym;
39 }
40 for (auto Block : Sec.blocks()) {
41 auto &PSym = Preserved[Block];
42 if (!PSym)
43 PSym = &G.addAnonymousSymbol(Content&: *Block, Offset: 0, Size: 0, IsCallable: false, IsLive: true);
44 else if (!PSym->isLive())
45 PSym->setLive(true);
46 }
47}
48
49static SmallVector<char, 0> getSectionData(Section &Sec) {
50 SmallVector<char, 0> SecData;
51 SmallVector<Block *, 8> SecBlocks(Sec.blocks().begin(), Sec.blocks().end());
52 std::sort(first: SecBlocks.begin(), last: SecBlocks.end(), comp: [](Block *LHS, Block *RHS) {
53 return LHS->getAddress() < RHS->getAddress();
54 });
55 // Convert back to what object file would have, one blob of section content
56 // Assumes all zerofill
57 // TODO handle alignment?
58 // TODO handle alignment offset?
59 for (auto *Block : SecBlocks) {
60 if (Block->isZeroFill())
61 SecData.resize(N: SecData.size() + Block->getSize(), NV: 0);
62 else
63 SecData.append(in_start: Block->getContent().begin(), in_end: Block->getContent().end());
64 }
65 return SecData;
66}
67
68static void dumpDWARFContext(DWARFContext &DC) {
69 auto options = llvm::DIDumpOptions();
70 options.DumpType &= ~DIDT_UUID;
71 options.DumpType &= ~(1 << DIDT_ID_DebugFrame);
72 LLVM_DEBUG(DC.dump(dbgs(), options));
73}
74
75} // namespace
76
77Error llvm::orc::preserveDebugSections(LinkGraph &G) {
78 if (!G.getTargetTriple().isOSBinFormatELF()) {
79 return make_error<StringError>(
80 Args: "preserveDebugSections only supports ELF LinkGraphs!",
81 Args: inconvertibleErrorCode());
82 }
83 for (auto &Sec : G.sections()) {
84 if (DWARFSectionNames.count(V: Sec.getName())) {
85 LLVM_DEBUG(dbgs() << "Preserving DWARF section " << Sec.getName()
86 << "\n");
87 preserveDWARFSection(G, Sec);
88 }
89 }
90 return Error::success();
91}
92
93Expected<std::pair<std::unique_ptr<DWARFContext>,
94 StringMap<std::unique_ptr<MemoryBuffer>>>>
95llvm::orc::createDWARFContext(LinkGraph &G) {
96 if (!G.getTargetTriple().isOSBinFormatELF()) {
97 return make_error<StringError>(
98 Args: "createDWARFContext only supports ELF LinkGraphs!",
99 Args: inconvertibleErrorCode());
100 }
101 StringMap<std::unique_ptr<MemoryBuffer>> DWARFSectionData;
102 for (auto &Sec : G.sections()) {
103 if (DWARFSectionNames.count(V: Sec.getName())) {
104 auto SecData = getSectionData(Sec);
105 auto Name = Sec.getName();
106 // DWARFContext expects the section name to not start with a dot
107 Name.consume_front(Prefix: ".");
108 LLVM_DEBUG(dbgs() << "Creating DWARFContext section " << Name
109 << " with size " << SecData.size() << "\n");
110 DWARFSectionData[Name] =
111 std::make_unique<SmallVectorMemoryBuffer>(args: std::move(SecData));
112 }
113 }
114 auto Ctx =
115 DWARFContext::create(Sections: DWARFSectionData, AddrSize: G.getPointerSize(),
116 isLittleEndian: G.getEndianness() == llvm::endianness::little);
117 dumpDWARFContext(DC&: *Ctx);
118 return std::make_pair(x: std::move(Ctx), y: std::move(DWARFSectionData));
119}
120