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 | |
19 | using namespace llvm; |
20 | using namespace llvm::orc; |
21 | using namespace llvm::jitlink; |
22 | |
23 | namespace { |
24 | static 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 |
33 | static void preserveDWARFSection(LinkGraph &G, Section &Sec) { |
34 | DenseMap<Block *, Symbol *> Preserved; |
35 | for (auto Sym : Sec.symbols()) { |
36 | if (Sym->isLive()) |
37 | Preserved[&Sym->getBlock()] = Sym; |
38 | else if (!Preserved.count(Val: &Sym->getBlock())) |
39 | Preserved[&Sym->getBlock()] = Sym; |
40 | } |
41 | for (auto Block : Sec.blocks()) { |
42 | auto &PSym = Preserved[Block]; |
43 | if (!PSym) |
44 | PSym = &G.addAnonymousSymbol(Content&: *Block, Offset: 0, Size: 0, IsCallable: false, IsLive: true); |
45 | else if (!PSym->isLive()) |
46 | PSym->setLive(true); |
47 | } |
48 | } |
49 | |
50 | static SmallVector<char, 0> getSectionData(Section &Sec) { |
51 | SmallVector<char, 0> SecData; |
52 | SmallVector<Block *, 8> SecBlocks(Sec.blocks().begin(), Sec.blocks().end()); |
53 | std::sort(first: SecBlocks.begin(), last: SecBlocks.end(), comp: [](Block *LHS, Block *RHS) { |
54 | return LHS->getAddress() < RHS->getAddress(); |
55 | }); |
56 | // Convert back to what object file would have, one blob of section content |
57 | // Assumes all zerofill |
58 | // TODO handle alignment? |
59 | // TODO handle alignment offset? |
60 | for (auto *Block : SecBlocks) { |
61 | if (Block->isZeroFill()) |
62 | SecData.resize(N: SecData.size() + Block->getSize(), NV: 0); |
63 | else |
64 | SecData.append(in_start: Block->getContent().begin(), in_end: Block->getContent().end()); |
65 | } |
66 | return SecData; |
67 | } |
68 | |
69 | static void dumpDWARFContext(DWARFContext &DC) { |
70 | auto options = llvm::DIDumpOptions(); |
71 | options.DumpType &= ~DIDT_UUID; |
72 | options.DumpType &= ~(1 << DIDT_ID_DebugFrame); |
73 | LLVM_DEBUG(DC.dump(dbgs(), options)); |
74 | } |
75 | |
76 | } // namespace |
77 | |
78 | Error llvm::orc::preserveDebugSections(LinkGraph &G) { |
79 | if (!G.getTargetTriple().isOSBinFormatELF()) { |
80 | return make_error<StringError>( |
81 | Args: "preserveDebugSections only supports ELF LinkGraphs!" , |
82 | Args: inconvertibleErrorCode()); |
83 | } |
84 | for (auto &Sec : G.sections()) { |
85 | if (DWARFSectionNames.count(V: Sec.getName())) { |
86 | LLVM_DEBUG(dbgs() << "Preserving DWARF section " << Sec.getName() |
87 | << "\n" ); |
88 | preserveDWARFSection(G, Sec); |
89 | } |
90 | } |
91 | return Error::success(); |
92 | } |
93 | |
94 | Expected<std::pair<std::unique_ptr<DWARFContext>, |
95 | StringMap<std::unique_ptr<MemoryBuffer>>>> |
96 | llvm::orc::createDWARFContext(LinkGraph &G) { |
97 | if (!G.getTargetTriple().isOSBinFormatELF()) { |
98 | return make_error<StringError>( |
99 | Args: "createDWARFContext only supports ELF LinkGraphs!" , |
100 | Args: inconvertibleErrorCode()); |
101 | } |
102 | StringMap<std::unique_ptr<MemoryBuffer>> DWARFSectionData; |
103 | for (auto &Sec : G.sections()) { |
104 | if (DWARFSectionNames.count(V: Sec.getName())) { |
105 | auto SecData = getSectionData(Sec); |
106 | auto Name = Sec.getName(); |
107 | // DWARFContext expects the section name to not start with a dot |
108 | Name.consume_front(Prefix: "." ); |
109 | LLVM_DEBUG(dbgs() << "Creating DWARFContext section " << Name |
110 | << " with size " << SecData.size() << "\n" ); |
111 | DWARFSectionData[Name] = |
112 | std::make_unique<SmallVectorMemoryBuffer>(args: std::move(SecData)); |
113 | } |
114 | } |
115 | auto Ctx = |
116 | DWARFContext::create(Sections: DWARFSectionData, AddrSize: G.getPointerSize(), |
117 | isLittleEndian: G.getEndianness() == llvm::endianness::little); |
118 | dumpDWARFContext(DC&: *Ctx); |
119 | return std::make_pair(x: std::move(Ctx), y: std::move(DWARFSectionData)); |
120 | } |
121 | |