1 | //===- bolt/Core/DIEBuilder.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 | /// \file |
10 | /// This file contains the declaration of the DIEBuilder class, which is the |
11 | /// base class for Debug Information IR construction. |
12 | /// |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #ifndef BOLT_CORE_DIE_BUILDER_H |
16 | #define BOLT_CORE_DIE_BUILDER_H |
17 | |
18 | #include "bolt/Core/BinaryContext.h" |
19 | #include "bolt/Core/DebugNames.h" |
20 | #include "llvm/CodeGen/DIE.h" |
21 | #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" |
22 | #include "llvm/DebugInfo/DWARF/DWARFDie.h" |
23 | #include "llvm/DebugInfo/DWARF/DWARFExpression.h" |
24 | #include "llvm/DebugInfo/DWARF/DWARFUnit.h" |
25 | #include "llvm/Support/Allocator.h" |
26 | |
27 | #include <list> |
28 | #include <memory> |
29 | #include <optional> |
30 | #include <unordered_map> |
31 | #include <unordered_set> |
32 | #include <vector> |
33 | |
34 | namespace llvm { |
35 | |
36 | namespace bolt { |
37 | |
38 | class DIEStreamer; |
39 | class DebugStrOffsetsWriter; |
40 | |
41 | class DIEBuilder { |
42 | friend DIEStreamer; |
43 | |
44 | public: |
45 | /// Wrapper around DIE so we can access DIEs easily. |
46 | struct DIEInfo { |
47 | DIE *Die; |
48 | uint32_t DieId; |
49 | uint32_t UnitId; |
50 | }; |
51 | |
52 | /// Contains information for the CU level of DWARF. |
53 | struct DWARFUnitInfo { |
54 | // Contains all the DIEs for the current unit. |
55 | // Accessed by DIE ID. |
56 | std::vector<std::unique_ptr<DIEInfo>> DieInfoVector; |
57 | DIE *UnitDie = nullptr; |
58 | uint32_t UnitId = 0; |
59 | uint32_t UnitOffset = 0; |
60 | uint32_t UnitLength = 0; |
61 | bool IsConstructed = false; |
62 | // A map of DIE offsets in original DWARF section to DIE ID. |
63 | // Whih is used to access DieInfoVector. |
64 | std::unordered_map<uint64_t, uint32_t> DIEIDMap; |
65 | |
66 | // Some STL implementations don't have a noexcept move constructor for |
67 | // unordered_map (e.g. https://github.com/microsoft/STL/issues/165 explains |
68 | // why the Microsoft STL doesn't). In that case, the default move |
69 | // constructor generated for DWARFUnitInfo isn't noexcept either, and thus |
70 | // resizing a vector of DWARFUnitInfo will copy elements instead of moving |
71 | // them (https://en.cppreference.com/w/cpp/utility/move_if_noexcept). |
72 | // DWARFUnitInfo isn't copyable though, since the DieInfoVector member is a |
73 | // vector of unique_ptrs and unique_ptr isn't copyable, so using a vector of |
74 | // DWARFUnitInfo causes build errors. Explicitly marking DWARFUnitInfo as |
75 | // non-copyable forces vector resizes to move instead and fixes the issue. |
76 | DWARFUnitInfo() = default; |
77 | DWARFUnitInfo(const DWARFUnitInfo &) = delete; |
78 | DWARFUnitInfo(DWARFUnitInfo &&) = default; |
79 | }; |
80 | |
81 | enum class ProcessingType { DWARF4TUs, DWARF5TUs, CUs }; |
82 | |
83 | private: |
84 | /// Contains information so that we we can update references in locexpr after |
85 | /// we calculated all the final DIE offsets. |
86 | struct LocWithReference { |
87 | LocWithReference(std::vector<uint8_t> &&BlockData, DWARFUnit &U, DIE &Die, |
88 | dwarf::Form Form, dwarf::Attribute Attr) |
89 | : BlockData(BlockData), U(U), Die(Die), Form(Form), Attr(Attr) {} |
90 | std::vector<uint8_t> BlockData; |
91 | DWARFUnit &U; |
92 | DIE &Die; |
93 | dwarf::Form Form; |
94 | dwarf::Attribute Attr; |
95 | }; |
96 | /// Contains information so that we can update cross CU references, after we |
97 | /// calculated all the final DIE offsets. |
98 | struct AddrReferenceInfo { |
99 | AddrReferenceInfo(DIEInfo *Die, |
100 | DWARFAbbreviationDeclaration::AttributeSpec Spec) |
101 | : Dst(Die), AttrSpec(Spec) {} |
102 | DIEInfo *Dst; |
103 | DWARFAbbreviationDeclaration::AttributeSpec AttrSpec; |
104 | }; |
105 | |
106 | struct State { |
107 | /// A map of Units to Unit Index. |
108 | std::unordered_map<uint64_t, uint32_t> UnitIDMap; |
109 | /// A map of Type Units to Type DIEs. |
110 | std::unordered_map<DWARFUnit *, DIE *> TypeDIEMap; |
111 | std::list<DWARFUnit *> DUList; |
112 | std::vector<DWARFUnitInfo> CloneUnitCtxMap; |
113 | std::vector<std::pair<DIEInfo *, AddrReferenceInfo>> AddrReferences; |
114 | std::vector<DWARFUnit *> DWARF4TUVector; |
115 | std::vector<DWARFUnit *> DWARF5TUVector; |
116 | std::vector<DWARFUnit *> DWARFCUVector; |
117 | std::vector<LocWithReference> LocWithReferencesToProcess; |
118 | BumpPtrAllocator DIEAlloc; |
119 | ProcessingType Type; |
120 | std::unordered_set<uint64_t> DWARFDieAddressesParsed; |
121 | }; |
122 | |
123 | std::unique_ptr<State> BuilderState; |
124 | FoldingSet<DIEAbbrev> AbbreviationsSet; |
125 | std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations; |
126 | BinaryContext &BC; |
127 | DWARFContext *DwarfContext{nullptr}; |
128 | DWARFUnit *SkeletonCU{nullptr}; |
129 | uint64_t UnitSize{0}; |
130 | llvm::DenseSet<uint64_t> AllProcessed; |
131 | DWARF5AcceleratorTable &DebugNamesTable; |
132 | |
133 | /// Returns current state of the DIEBuilder |
134 | State &getState() { return *BuilderState.get(); } |
135 | /// Resolve the reference in DIE, if target is not loaded into IR, |
136 | /// pre-allocate it. \p RefCU will be updated to the Unit specific by \p |
137 | /// RefValue. |
138 | DWARFDie resolveDIEReference( |
139 | const DWARFFormValue &RefValue, |
140 | const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, |
141 | DWARFUnit *&RefCU, DWARFDebugInfoEntry &DwarfDebugInfoEntry); |
142 | |
143 | /// Resolve the reference in DIE, if target is not loaded into IR, |
144 | /// pre-allocate it. \p RefCU will be updated to the Unit specific by \p |
145 | /// RefValue. |
146 | DWARFDie resolveDIEReference( |
147 | const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, |
148 | const uint64_t ReffOffset, DWARFUnit *&RefCU, |
149 | DWARFDebugInfoEntry &DwarfDebugInfoEntry); |
150 | |
151 | /// Clone one attribute according to the format. \return the size of this |
152 | /// attribute. |
153 | void |
154 | cloneAttribute(DIE &Die, const DWARFDie &InputDIE, DWARFUnit &U, |
155 | const DWARFFormValue &Val, |
156 | const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec); |
157 | |
158 | /// Clone an attribute in string format. |
159 | void cloneStringAttribute( |
160 | DIE &Die, const DWARFUnit &U, |
161 | const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, |
162 | const DWARFFormValue &Val); |
163 | |
164 | /// Clone an attribute in reference format. |
165 | void cloneDieReferenceAttribute( |
166 | DIE &Die, const DWARFUnit &U, const DWARFDie &InputDIE, |
167 | const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, |
168 | const DWARFFormValue &Val); |
169 | |
170 | /// Clone an attribute in block format. |
171 | void cloneBlockAttribute( |
172 | DIE &Die, DWARFUnit &U, |
173 | const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, |
174 | const DWARFFormValue &Val); |
175 | |
176 | enum class CloneExpressionStage { INIT, PATCH }; |
177 | /// Clone an attribute in expression format. \p OutputBuffer will hold the |
178 | /// output content. |
179 | /// Returns true if Expression contains a reference. |
180 | bool (const DataExtractor &Data, |
181 | const DWARFExpression &Expression, DWARFUnit &U, |
182 | SmallVectorImpl<uint8_t> &OutputBuffer, |
183 | const CloneExpressionStage &Stage); |
184 | |
185 | /// Clone an attribute in address format. |
186 | void cloneAddressAttribute( |
187 | DIE &Die, const DWARFUnit &U, |
188 | const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, |
189 | const DWARFFormValue &Val); |
190 | |
191 | /// Clone an attribute in refsig format. |
192 | void cloneRefsigAttribute( |
193 | DIE &Die, const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, |
194 | const DWARFFormValue &Val); |
195 | |
196 | /// Clone an attribute in scalar format. |
197 | void cloneScalarAttribute( |
198 | DIE &Die, const DWARFDie &InputDIE, |
199 | const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, |
200 | const DWARFFormValue &Val); |
201 | |
202 | /// Clone an attribute in loclist format. |
203 | void cloneLoclistAttrubute( |
204 | DIE &Die, const DWARFDie &InputDIE, |
205 | const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, |
206 | const DWARFFormValue &Val); |
207 | |
208 | /// Update references once the layout is finalized. |
209 | void updateReferences(); |
210 | |
211 | /// Update the Offset and Size of DIE, populate DebugNames table. |
212 | /// Along with current CU, and DIE being processed and the new DIE offset to |
213 | /// be updated, it takes in Parents vector that can be empty if this DIE has |
214 | /// no parents. |
215 | uint32_t |
216 | finalizeDIEs(DWARFUnit &CU, DIE &Die, |
217 | std::vector<std::optional<BOLTDWARF5AccelTableData *>> &Parents, |
218 | uint32_t &CurOffset); |
219 | |
220 | void registerUnit(DWARFUnit &DU, bool NeedSort); |
221 | |
222 | /// \return the unique ID of \p U if it exists. |
223 | std::optional<uint32_t> getUnitId(const DWARFUnit &DU); |
224 | |
225 | DWARFUnitInfo &getUnitInfo(uint32_t UnitId) { |
226 | return getState().CloneUnitCtxMap[UnitId]; |
227 | } |
228 | |
229 | DIEInfo &getDIEInfo(uint32_t UnitId, uint32_t DIEId) { |
230 | if (getState().CloneUnitCtxMap[UnitId].DieInfoVector.size() > DIEId) |
231 | return *getState().CloneUnitCtxMap[UnitId].DieInfoVector[DIEId].get(); |
232 | |
233 | BC.errs() |
234 | << "BOLT-WARNING: [internal-dwarf-error]: The DIE is not allocated " |
235 | "before looking up, some" |
236 | << "unexpected corner cases happened.\n" ; |
237 | return *getState().CloneUnitCtxMap[UnitId].DieInfoVector.front().get(); |
238 | } |
239 | |
240 | std::optional<uint32_t> getAllocDIEId(const DWARFUnit &DU, |
241 | const uint64_t Offset) { |
242 | const DWARFUnitInfo &DWARFUnitInfo = getUnitInfoByDwarfUnit(DwarfUnit: DU); |
243 | auto Iter = DWARFUnitInfo.DIEIDMap.find(x: Offset); |
244 | return (Iter == DWARFUnitInfo.DIEIDMap.end()) |
245 | ? std::nullopt |
246 | : std::optional<uint32_t>(Iter->second); |
247 | } |
248 | std::optional<uint32_t> getAllocDIEId(const DWARFUnit &DU, |
249 | const DWARFDie &DDie) { |
250 | return getAllocDIEId(DU, Offset: DDie.getOffset()); |
251 | } |
252 | |
253 | // To avoid overhead, do not use this unless we do get the DWARFUnitInfo |
254 | // first. We can use getDIEInfo with UnitId and DieId |
255 | DIEInfo &getDIEInfoByDwarfDie(DWARFDie &DwarfDie) { |
256 | DWARFUnit &DwarfUnit = *DwarfDie.getDwarfUnit(); |
257 | std::optional<uint32_t> UnitId = getUnitId(DU: DwarfUnit); |
258 | std::optional<uint32_t> HasDieId = getAllocDIEId(DU: DwarfUnit, DDie: DwarfDie); |
259 | assert(HasDieId); |
260 | |
261 | return getDIEInfo(UnitId: *UnitId, DIEId: *HasDieId); |
262 | } |
263 | |
264 | uint32_t allocDIE(const DWARFUnit &DU, const DWARFDie &DDie, |
265 | BumpPtrAllocator &Alloc, const uint32_t UId); |
266 | |
267 | /// Construct IR for \p DU. \p DUOffsetList specific the Unit in current |
268 | /// Section. |
269 | void constructFromUnit(DWARFUnit &DU); |
270 | |
271 | /// Construct a DIE for \p DDie in \p U. \p DUOffsetList specific the Unit in |
272 | /// current Section. |
273 | DIE *constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId); |
274 | |
275 | /// Returns true if this DIEBUilder is for DWO Unit. |
276 | bool isDWO() const { return SkeletonCU != nullptr; } |
277 | |
278 | public: |
279 | DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext, |
280 | DWARF5AcceleratorTable &DebugNamesTable, |
281 | DWARFUnit *SkeletonCU = nullptr); |
282 | |
283 | /// Returns enum to what we are currently processing. |
284 | ProcessingType getCurrentProcessingState() { return getState().Type; } |
285 | |
286 | /// Constructs IR for Type Units. |
287 | void buildTypeUnits(DebugStrOffsetsWriter *StrOffsetWriter = nullptr, |
288 | const bool Init = true); |
289 | /// Constructs IR for all the CUs. |
290 | void buildCompileUnits(const bool Init = true); |
291 | /// Constructs IR for CUs in a vector. |
292 | void buildCompileUnits(const std::vector<DWARFUnit *> &CUs); |
293 | /// Preventing implicit conversions. |
294 | template <class T> void buildCompileUnits(T) = delete; |
295 | /// Builds DWO Unit. For DWARF5 this includes the type units. |
296 | void buildDWOUnit(DWARFUnit &U); |
297 | |
298 | /// Returns DWARFUnitInfo for DWARFUnit |
299 | DWARFUnitInfo &getUnitInfoByDwarfUnit(const DWARFUnit &DwarfUnit) { |
300 | std::optional<uint32_t> UnitId = getUnitId(DU: DwarfUnit); |
301 | return getUnitInfo(UnitId: *UnitId); |
302 | } |
303 | |
304 | const std::vector<std::unique_ptr<DIEInfo>> &getDIEsByUnit(DWARFUnit &DU) { |
305 | DWARFUnitInfo &U = getUnitInfoByDwarfUnit(DwarfUnit: DU); |
306 | return U.DieInfoVector; |
307 | } |
308 | std::vector<std::unique_ptr<DIEAbbrev>> &getAbbrevs() { |
309 | return Abbreviations; |
310 | } |
311 | DIE *getTypeDIE(DWARFUnit &DU) { |
312 | if (getState().TypeDIEMap.count(x: &DU)) |
313 | return getState().TypeDIEMap[&DU]; |
314 | |
315 | BC.errs() |
316 | << "BOLT-ERROR: unable to find TypeUnit for Type Unit at offset 0x" |
317 | << DU.getOffset() << "\n" ; |
318 | return nullptr; |
319 | } |
320 | |
321 | std::vector<DWARFUnit *> &getDWARF4TUVector() { |
322 | return getState().DWARF4TUVector; |
323 | } |
324 | std::vector<DWARFUnit *> &getDWARF5TUVector() { |
325 | return getState().DWARF5TUVector; |
326 | } |
327 | std::vector<DWARFUnit *> &getDWARFCUVector() { |
328 | return getState().DWARFCUVector; |
329 | } |
330 | /// Returns list of CUs for which IR was build. |
331 | std::list<DWARFUnit *> &getProcessedCUs() { return getState().DUList; } |
332 | bool isEmpty() { return getState().CloneUnitCtxMap.empty(); } |
333 | |
334 | DIE *getUnitDIEbyUnit(const DWARFUnit &DU) { |
335 | const DWARFUnitInfo &U = getUnitInfoByDwarfUnit(DwarfUnit: DU); |
336 | return U.UnitDie; |
337 | } |
338 | |
339 | /// Generate and populate all Abbrevs. |
340 | void generateAbbrevs(); |
341 | void generateUnitAbbrevs(DIE *Die); |
342 | void assignAbbrev(DIEAbbrev &Abbrev); |
343 | |
344 | /// Finish current DIE construction. |
345 | void finish(); |
346 | |
347 | // Interface to edit DIE |
348 | template <class T> T *allocateDIEValue() { |
349 | return new (getState().DIEAlloc) T; |
350 | } |
351 | |
352 | DIEValueList::value_iterator addValue(DIEValueList *Die, const DIEValue &V) { |
353 | return Die->addValue(Alloc&: getState().DIEAlloc, V); |
354 | } |
355 | |
356 | template <class T> |
357 | DIEValueList::value_iterator addValue(DIEValueList *Die, |
358 | dwarf::Attribute Attribute, |
359 | dwarf::Form Form, T &&Value) { |
360 | return Die->addValue(getState().DIEAlloc, Attribute, Form, |
361 | std::forward<T>(Value)); |
362 | } |
363 | |
364 | template <class T> |
365 | bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute, |
366 | dwarf::Form Form, T &&NewValue) { |
367 | return Die->replaceValue(getState().DIEAlloc, Attribute, Form, |
368 | std::forward<T>(NewValue)); |
369 | } |
370 | |
371 | template <class T> |
372 | bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute, |
373 | dwarf::Attribute NewAttribute, dwarf::Form Form, |
374 | T &&NewValue) { |
375 | return Die->replaceValue(getState().DIEAlloc, Attribute, NewAttribute, Form, |
376 | std::forward<T>(NewValue)); |
377 | } |
378 | |
379 | bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute, |
380 | dwarf::Form Form, DIEValue &NewValue) { |
381 | return Die->replaceValue(Alloc&: getState().DIEAlloc, Attribute, Form, NewValue); |
382 | } |
383 | |
384 | bool deleteValue(DIEValueList *Die, dwarf::Attribute Attribute) { |
385 | return Die->deleteValue(Attribute); |
386 | } |
387 | }; |
388 | } // namespace bolt |
389 | } // namespace llvm |
390 | |
391 | #endif |
392 | |