xref: /llvm-project/bolt/include/bolt/Core/DIEBuilder.h (revision 4b825c7417f72ee88ee3e4316d0c01ed463f1241)
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   /// Adds separate UnitSize counter for updating DebugNames
131   /// so there is no dependency between the functions.
132   uint64_t DebugNamesUnitSize{0};
133   llvm::DenseSet<uint64_t> AllProcessed;
134   DWARF5AcceleratorTable &DebugNamesTable;
135   // Unordered map to handle name collision if output DWO directory is
136   // specified.
137   std::unordered_map<std::string, uint32_t> NameToIndexMap;
138 
139   /// Returns current state of the DIEBuilder
140   State &getState() { return *BuilderState.get(); }
141 
142   /// Resolve the reference in DIE, if target is not loaded into IR,
143   /// pre-allocate it. \p RefCU will be updated to the Unit specific by \p
144   /// RefValue.
145   DWARFDie resolveDIEReference(
146       const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
147       const uint64_t ReffOffset, DWARFUnit *&RefCU,
148       DWARFDebugInfoEntry &DwarfDebugInfoEntry);
149 
150   /// Clone one attribute according to the format. \return the size of this
151   /// attribute.
152   void
153   cloneAttribute(DIE &Die, const DWARFDie &InputDIE, DWARFUnit &U,
154                  const DWARFFormValue &Val,
155                  const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec);
156 
157   /// Clone an attribute in string format.
158   void cloneStringAttribute(
159       DIE &Die, const DWARFUnit &U,
160       const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
161       const DWARFFormValue &Val);
162 
163   /// Clone an attribute in reference format.
164   void cloneDieOffsetReferenceAttribute(
165       DIE &Die, DWARFUnit &U, const DWARFDie &InputDIE,
166       const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, uint64_t Ref);
167 
168   /// Clone an attribute in block format.
169   void cloneBlockAttribute(
170       DIE &Die, DWARFUnit &U,
171       const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
172       const DWARFFormValue &Val);
173 
174   enum class CloneExpressionStage { INIT, PATCH };
175   /// Clone an attribute in expression format. \p OutputBuffer will hold the
176   /// output content.
177   /// Returns true if Expression contains a reference.
178   bool cloneExpression(const DataExtractor &Data,
179                        const DWARFExpression &Expression, DWARFUnit &U,
180                        SmallVectorImpl<uint8_t> &OutputBuffer,
181                        const CloneExpressionStage &Stage);
182 
183   /// Clone an attribute in address format.
184   void cloneAddressAttribute(
185       DIE &Die, const DWARFUnit &U,
186       const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
187       const DWARFFormValue &Val);
188 
189   /// Clone an attribute in refsig format.
190   void cloneRefsigAttribute(
191       DIE &Die, const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
192       const DWARFFormValue &Val);
193 
194   /// Clone an attribute in scalar format.
195   void cloneScalarAttribute(
196       DIE &Die, const DWARFDie &InputDIE,
197       const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
198       const DWARFFormValue &Val);
199 
200   /// Clone an attribute in loclist format.
201   void cloneLoclistAttrubute(
202       DIE &Die, const DWARFDie &InputDIE,
203       const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
204       const DWARFFormValue &Val);
205 
206   /// Update references once the layout is finalized.
207   void updateReferences();
208 
209   /// Update the Offset and Size of DIE.
210   /// Along with current CU, and DIE being processed and the new DIE offset to
211   /// be updated, it takes in Parents vector that can be empty if this DIE has
212   /// no parents.
213   uint32_t finalizeDIEs(DWARFUnit &CU, DIE &Die, uint32_t &CurOffset);
214 
215   /// Populates DebugNames table.
216   void populateDebugNamesTable(DWARFUnit &CU, const DIE &Die,
217                                std::optional<BOLTDWARF5AccelTableData *> Parent,
218                                uint32_t NumberParentsInChain);
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(DU);
243     auto Iter = DWARFUnitInfo.DIEIDMap.find(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, 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(DwarfUnit);
258     std::optional<uint32_t> HasDieId = getAllocDIEId(DwarfUnit, DwarfDie);
259     assert(HasDieId);
260 
261     return getDIEInfo(*UnitId, *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(DwarfUnit);
301     return getUnitInfo(*UnitId);
302   }
303 
304   const std::vector<std::unique_ptr<DIEInfo>> &getDIEsByUnit(DWARFUnit &DU) {
305     DWARFUnitInfo &U = getUnitInfoByDwarfUnit(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(&DU))
313       return getState().TypeDIEMap[&DU];
314 
315     BC.errs()
316         << "BOLT-ERROR: unable to find TypeUnit for Type Unit at offset 0x"
317         << Twine::utohexstr(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(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   /// Update debug names table.
348   void updateDebugNamesTable();
349 
350   // Interface to edit DIE
351   template <class T> T *allocateDIEValue() {
352     return new (getState().DIEAlloc) T;
353   }
354 
355   DIEValueList::value_iterator addValue(DIEValueList *Die, const DIEValue &V) {
356     return Die->addValue(getState().DIEAlloc, V);
357   }
358 
359   template <class T>
360   DIEValueList::value_iterator addValue(DIEValueList *Die,
361                                         dwarf::Attribute Attribute,
362                                         dwarf::Form Form, T &&Value) {
363     return Die->addValue(getState().DIEAlloc, Attribute, Form,
364                          std::forward<T>(Value));
365   }
366 
367   template <class T>
368   bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute,
369                     dwarf::Form Form, T &&NewValue) {
370     return Die->replaceValue(getState().DIEAlloc, Attribute, Form,
371                              std::forward<T>(NewValue));
372   }
373 
374   template <class T>
375   bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute,
376                     dwarf::Attribute NewAttribute, dwarf::Form Form,
377                     T &&NewValue) {
378     return Die->replaceValue(getState().DIEAlloc, Attribute, NewAttribute, Form,
379                              std::forward<T>(NewValue));
380   }
381 
382   bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute,
383                     dwarf::Form Form, DIEValue &NewValue) {
384     return Die->replaceValue(getState().DIEAlloc, Attribute, Form, NewValue);
385   }
386 
387   bool deleteValue(DIEValueList *Die, dwarf::Attribute Attribute) {
388     return Die->deleteValue(Attribute);
389   }
390   /// Updates DWO Name and Compilation directory for Skeleton CU \p Unit.
391   std::string updateDWONameCompDir(DebugStrOffsetsWriter &StrOffstsWriter,
392                                    DebugStrWriter &StrWriter,
393                                    DWARFUnit &SkeletonCU,
394                                    std::optional<StringRef> DwarfOutputPath,
395                                    std::optional<StringRef> DWONameToUse);
396   /// Updates DWO Name and Compilation directory for Type Units.
397   void updateDWONameCompDirForTypes(DebugStrOffsetsWriter &StrOffstsWriter,
398                                     DebugStrWriter &StrWriter, DWARFUnit &Unit,
399                                     std::optional<StringRef> DwarfOutputPath,
400                                     const StringRef DWOName);
401 };
402 } // namespace bolt
403 } // namespace llvm
404 
405 #endif
406