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