1//===- bolt/Rewrite/DWARFRewriter.h -----------------------------*- 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#ifndef BOLT_REWRITE_DWARF_REWRITER_H
10#define BOLT_REWRITE_DWARF_REWRITER_H
11
12#include "bolt/Core/DIEBuilder.h"
13#include "bolt/Core/DebugData.h"
14#include "bolt/Core/DebugNames.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/CodeGen/DIE.h"
17#include "llvm/DWP/DWP.h"
18#include "llvm/MC/MCAsmLayout.h"
19#include "llvm/MC/MCContext.h"
20#include "llvm/Support/ToolOutputFile.h"
21#include <cstdint>
22#include <memory>
23#include <mutex>
24#include <optional>
25#include <unordered_map>
26#include <vector>
27
28namespace llvm {
29
30namespace bolt {
31
32class BinaryContext;
33
34class DWARFRewriter {
35public:
36 DWARFRewriter() = delete;
37 /// Contains information about TU so we can write out correct entries in GDB
38 /// index.
39 struct GDBIndexTUEntry {
40 uint64_t UnitOffset;
41 uint64_t TypeHash;
42 uint64_t TypeDIERelativeOffset;
43 };
44 /// Contains information for CU or TU so we can output correct {cu, tu}-index.
45 struct UnitMeta {
46 uint64_t Offset;
47 uint64_t Length;
48 uint64_t TUHash;
49 };
50 using UnitMetaVectorType = std::vector<UnitMeta>;
51
52private:
53 BinaryContext &BC;
54
55 std::mutex DWARFRewriterMutex;
56
57 /// Stores and serializes information that will be put into the
58 /// .debug_ranges DWARF section.
59 std::unique_ptr<DebugRangesSectionWriter> LegacyRangesSectionWriter;
60
61 /// Stores and serializes information that will be put into the
62 /// .debug_rnglists DWARF section.
63 std::unique_ptr<DebugRangeListsSectionWriter> RangeListsSectionWriter;
64
65 /// Stores and serializes information that will be put into the
66 /// .debug_aranges DWARF section.
67 std::unique_ptr<DebugARangesSectionWriter> ARangesSectionWriter;
68
69 /// Stores and serializes information that will be put into the
70 /// .debug_addr DWARF section.
71 std::unique_ptr<DebugAddrWriter> AddrWriter;
72
73 /// Stores and serializes information that will be put in to the
74 /// .debug_addr DWARF section.
75 /// Does not do de-duplication.
76 std::unique_ptr<DebugStrWriter> StrWriter;
77
78 /// Stores and serializes information that will be put in to the
79 /// .debug_str_offsets DWARF section.
80 std::unique_ptr<DebugStrOffsetsWriter> StrOffstsWriter;
81
82 using LocWriters = std::map<uint64_t, std::unique_ptr<DebugLocWriter>>;
83 /// Use a separate location list writer for each compilation unit
84 LocWriters LocListWritersByCU;
85
86 using RangeListsDWOWriers =
87 std::unordered_map<uint64_t,
88 std::unique_ptr<DebugRangeListsSectionWriter>>;
89 /// Store Rangelists writer for each DWO CU.
90 RangeListsDWOWriers RangeListsWritersByCU;
91
92 std::mutex LocListDebugInfoPatchesMutex;
93
94 /// Dwo id specific its RangesBase.
95 std::unordered_map<uint64_t, uint64_t> DwoRangesBase;
96
97 std::unordered_map<DWARFUnit *, uint64_t> LineTablePatchMap;
98 std::unordered_map<const DWARFUnit *, uint64_t> TypeUnitRelocMap;
99
100 /// Entries for GDB Index Types CU List
101 using GDBIndexTUEntryType = std::vector<GDBIndexTUEntry>;
102 GDBIndexTUEntryType GDBIndexTUEntryVector;
103
104 /// DWARFLegacy is all DWARF versions before DWARF 5.
105 enum class DWARFVersion { DWARFLegacy, DWARF5 };
106
107 /// Used to track last CU offset for GDB Index.
108 uint32_t CUOffset{0};
109
110 /// Update debug info for all DIEs in \p Unit.
111 void updateUnitDebugInfo(DWARFUnit &Unit, DIEBuilder &DIEBldr,
112 DebugLocWriter &DebugLocWriter,
113 DebugRangesSectionWriter &RangesSectionWriter,
114 std::optional<uint64_t> RangesBase = std::nullopt);
115
116 /// Patches the binary for an object's address ranges to be updated.
117 /// The object can be anything that has associated address ranges via either
118 /// DW_AT_low/high_pc or DW_AT_ranges (i.e. functions, lexical blocks, etc).
119 /// \p DebugRangesOffset is the offset in .debug_ranges of the object's
120 /// new address ranges in the output binary.
121 /// \p Unit Compile unit the object belongs to.
122 /// \p DIE is the object's DIE in the input binary.
123 /// \p RangesBase if present, update \p DIE to use DW_AT_GNU_ranges_base
124 /// attribute.
125 void updateDWARFObjectAddressRanges(
126 DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
127 uint64_t DebugRangesOffset,
128 std::optional<uint64_t> RangesBase = std::nullopt);
129
130 std::unique_ptr<DebugBufferVector>
131 makeFinalLocListsSection(DWARFVersion Version);
132
133 /// Finalize type sections in the main binary.
134 CUOffsetMap finalizeTypeSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer);
135
136 /// Process and write out CUs that are passsed in.
137 void finalizeCompileUnits(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
138 CUOffsetMap &CUMap,
139 const std::list<DWARFUnit *> &CUs);
140
141 /// Finalize debug sections in the main binary.
142 void finalizeDebugSections(DIEBuilder &DIEBlder,
143 DWARF5AcceleratorTable &DebugNamesTable,
144 DIEStreamer &Streamer, raw_svector_ostream &ObjOS,
145 CUOffsetMap &CUMap);
146
147 /// Patches the binary for DWARF address ranges (e.g. in functions and lexical
148 /// blocks) to be updated.
149 void updateDebugAddressRanges();
150
151 /// Rewrite .gdb_index section if present.
152 void updateGdbIndexSection(CUOffsetMap &CUMap, uint32_t NumCUs);
153
154 /// DWARFDie contains a pointer to a DIE and hence gets invalidated once the
155 /// embedded DIE is destroyed. This wrapper class stores a DIE internally and
156 /// could be cast to a DWARFDie that is valid even after the initial DIE is
157 /// destroyed.
158 struct DWARFDieWrapper {
159 DWARFUnit *Unit;
160 DWARFDebugInfoEntry DIE;
161
162 DWARFDieWrapper(DWARFUnit *Unit, DWARFDebugInfoEntry DIE)
163 : Unit(Unit), DIE(DIE) {}
164
165 DWARFDieWrapper(DWARFDie &Die)
166 : Unit(Die.getDwarfUnit()), DIE(*Die.getDebugInfoEntry()) {}
167
168 operator DWARFDie() { return DWARFDie(Unit, &DIE); }
169 };
170
171 /// Update \p DIE that was using DW_AT_(low|high)_pc with DW_AT_ranges offset.
172 /// Updates to the DIE should be synced with abbreviation updates using the
173 /// function above.
174 void convertToRangesPatchDebugInfo(
175 DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,
176 uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo,
177 DIEValue &HighPCAttrInfo,
178 std::optional<uint64_t> RangesBase = std::nullopt);
179
180 /// Adds a \p Str to .debug_str section.
181 /// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using
182 /// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets
183 /// for this contribution of \p Unit.
184 void addStringHelper(DIEBuilder &DIEBldr, DIE &Die, const DWARFUnit &Unit,
185 DIEValue &DIEAttrInfo, StringRef Str);
186
187public:
188 DWARFRewriter(BinaryContext &BC) : BC(BC) {}
189
190 /// Main function for updating the DWARF debug info.
191 void updateDebugInfo();
192
193 /// Update stmt_list for CUs based on the new .debug_line \p Layout.
194 void updateLineTableOffsets(const MCAsmLayout &Layout);
195
196 uint64_t getDwoRangesBase(uint64_t DWOId) { return DwoRangesBase[DWOId]; }
197
198 void setDwoRangesBase(uint64_t DWOId, uint64_t RangesBase) {
199 DwoRangesBase[DWOId] = RangesBase;
200 }
201
202 /// Adds an GDBIndexTUEntry if .gdb_index seciton exists.
203 void addGDBTypeUnitEntry(const GDBIndexTUEntry &&Entry);
204
205 /// Returns all entries needed for Types CU list
206 const GDBIndexTUEntryType &getGDBIndexTUEntryVector() const {
207 return GDBIndexTUEntryVector;
208 }
209
210 using OverriddenSectionsMap = std::unordered_map<DWARFSectionKind, StringRef>;
211 /// Output .dwo files.
212 void writeDWOFiles(DWARFUnit &, const OverriddenSectionsMap &,
213 const std::string &, DebugLocWriter &);
214 using KnownSectionsEntry = std::pair<MCSection *, DWARFSectionKind>;
215 struct DWPState {
216 std::unique_ptr<ToolOutputFile> Out;
217 std::unique_ptr<BinaryContext> TmpBC;
218 std::unique_ptr<MCStreamer> Streamer;
219 std::unique_ptr<DWPStringPool> Strings;
220 const MCObjectFileInfo *MCOFI = nullptr;
221 const DWARFUnitIndex *CUIndex = nullptr;
222 std::deque<SmallString<32>> UncompressedSections;
223 MapVector<uint64_t, UnitIndexEntry> IndexEntries;
224 MapVector<uint64_t, UnitIndexEntry> TypeIndexEntries;
225 StringMap<KnownSectionsEntry> KnownSections;
226 uint32_t ContributionOffsets[8] = {};
227 uint32_t IndexVersion = 2;
228 uint64_t DebugInfoSize = 0;
229 uint16_t Version = 0;
230 bool IsDWP = false;
231 };
232 /// Init .dwp file
233 void initDWPState(DWPState &);
234
235 /// Write out .dwp File
236 void finalizeDWP(DWPState &);
237
238 /// add content of dwo to .dwp file.
239 void updateDWP(DWARFUnit &, const OverriddenSectionsMap &, const UnitMeta &,
240 UnitMetaVectorType &, DWPState &, DebugLocWriter &);
241};
242
243} // namespace bolt
244} // namespace llvm
245
246#endif
247

source code of bolt/include/bolt/Rewrite/DWARFRewriter.h