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
34namespace llvm {
35
36namespace bolt {
37
38class DIEStreamer;
39class DebugStrOffsetsWriter;
40
41class DIEBuilder {
42 friend DIEStreamer;
43
44public:
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
83private:
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 cloneExpression(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
278public:
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

source code of bolt/include/bolt/Core/DIEBuilder.h