1//===- bolt/Core/DIEBuilder.cpp -------------------------------------===//
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#include "bolt/Core/DIEBuilder.h"
10#include "bolt/Core/BinaryContext.h"
11#include "bolt/Core/ParallelUtilities.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/BinaryFormat/Dwarf.h"
14#include "llvm/CodeGen/DIE.h"
15#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
16#include "llvm/DebugInfo/DWARF/DWARFDie.h"
17#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
18#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
19#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
20#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
21#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
22#include "llvm/Support/Casting.h"
23#include "llvm/Support/Debug.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Support/FileSystem.h"
26#include "llvm/Support/LEB128.h"
27
28#include <algorithm>
29#include <cstdint>
30#include <memory>
31#include <mutex>
32#include <optional>
33#include <unordered_map>
34#include <utility>
35#include <vector>
36
37#undef DEBUG_TYPE
38#define DEBUG_TYPE "bolt"
39namespace opts {
40extern cl::opt<unsigned> Verbosity;
41}
42namespace llvm {
43namespace bolt {
44
45/// Returns DWO Name to be used to update DW_AT_dwo_name/DW_AT_GNU_dwo_name
46/// either in CU or TU unit die. Handles case where user specifies output DWO
47/// directory, and there are duplicate names. Assumes DWO ID is unique.
48static std::string
49getDWOName(llvm::DWARFUnit &CU,
50 std::unordered_map<std::string, uint32_t> &NameToIndexMap,
51 std::optional<StringRef> &DwarfOutputPath) {
52 assert(CU.getDWOId() && "DWO ID not found.");
53 std::string DWOName = dwarf::toString(
54 V: CU.getUnitDIE().find(Attrs: {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
55 Default: "");
56 assert(!DWOName.empty() &&
57 "DW_AT_dwo_name/DW_AT_GNU_dwo_name does not exist.");
58 if (DwarfOutputPath) {
59 DWOName = std::string(sys::path::filename(path: DWOName));
60 uint32_t &Index = NameToIndexMap[DWOName];
61 DWOName.append(str: std::to_string(val: Index));
62 ++Index;
63 }
64 DWOName.append(s: ".dwo");
65 return DWOName;
66}
67
68/// Adds a \p Str to .debug_str section.
69/// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using
70/// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets
71/// for this contribution of \p Unit.
72static void addStringHelper(DebugStrOffsetsWriter &StrOffstsWriter,
73 DebugStrWriter &StrWriter, DIEBuilder &DIEBldr,
74 DIE &Die, const DWARFUnit &Unit,
75 DIEValue &DIEAttrInfo, StringRef Str) {
76 uint32_t NewOffset = StrWriter.addString(Str);
77 if (Unit.getVersion() >= 5) {
78 StrOffstsWriter.updateAddressMap(Index: DIEAttrInfo.getDIEInteger().getValue(),
79 Address: NewOffset, Unit);
80 return;
81 }
82 DIEBldr.replaceValue(Die: &Die, Attribute: DIEAttrInfo.getAttribute(), Form: DIEAttrInfo.getForm(),
83 NewValue: DIEInteger(NewOffset));
84}
85
86std::string DIEBuilder::updateDWONameCompDir(
87 DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,
88 DWARFUnit &SkeletonCU, std::optional<StringRef> DwarfOutputPath,
89 std::optional<StringRef> DWONameToUse) {
90 DIE &UnitDIE = *getUnitDIEbyUnit(DU: SkeletonCU);
91 DIEValue DWONameAttrInfo = UnitDIE.findAttribute(Attribute: dwarf::DW_AT_dwo_name);
92 if (!DWONameAttrInfo)
93 DWONameAttrInfo = UnitDIE.findAttribute(Attribute: dwarf::DW_AT_GNU_dwo_name);
94 if (!DWONameAttrInfo)
95 return "";
96 std::string ObjectName;
97 if (DWONameToUse)
98 ObjectName = *DWONameToUse;
99 else
100 ObjectName = getDWOName(CU&: SkeletonCU, NameToIndexMap, DwarfOutputPath);
101 addStringHelper(StrOffstsWriter, StrWriter, DIEBldr&: *this, Die&: UnitDIE, Unit: SkeletonCU,
102 DIEAttrInfo&: DWONameAttrInfo, Str: ObjectName);
103
104 DIEValue CompDirAttrInfo = UnitDIE.findAttribute(Attribute: dwarf::DW_AT_comp_dir);
105 assert(CompDirAttrInfo && "DW_AT_comp_dir is not in Skeleton CU.");
106
107 if (DwarfOutputPath) {
108 if (!sys::fs::exists(Path: *DwarfOutputPath))
109 sys::fs::create_directory(path: *DwarfOutputPath);
110 addStringHelper(StrOffstsWriter, StrWriter, DIEBldr&: *this, Die&: UnitDIE, Unit: SkeletonCU,
111 DIEAttrInfo&: CompDirAttrInfo, Str: *DwarfOutputPath);
112 }
113 return ObjectName;
114}
115
116void DIEBuilder::updateDWONameCompDirForTypes(
117 DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,
118 DWARFUnit &Unit, std::optional<StringRef> DwarfOutputPath,
119 const StringRef DWOName) {
120 for (DWARFUnit *DU : getState().DWARF5TUVector)
121 updateDWONameCompDir(StrOffstsWriter, StrWriter, SkeletonCU&: *DU, DwarfOutputPath,
122 DWONameToUse: DWOName);
123 if (StrOffstsWriter.isStrOffsetsSectionModified())
124 StrOffstsWriter.finalizeSection(Unit, DIEBldr&: *this);
125}
126
127void DIEBuilder::updateReferences() {
128 for (auto &[SrcDIEInfo, ReferenceInfo] : getState().AddrReferences) {
129 DIEInfo *DstDIEInfo = ReferenceInfo.Dst;
130 DWARFUnitInfo &DstUnitInfo = getUnitInfo(UnitId: DstDIEInfo->UnitId);
131 dwarf::Attribute Attr = ReferenceInfo.AttrSpec.Attr;
132 dwarf::Form Form = ReferenceInfo.AttrSpec.Form;
133
134 const uint64_t NewAddr =
135 DstDIEInfo->Die->getOffset() + DstUnitInfo.UnitOffset;
136 SrcDIEInfo->Die->replaceValue(Alloc&: getState().DIEAlloc, Attribute: Attr, Form,
137 NewValue: DIEInteger(NewAddr));
138 }
139
140 // Handling referenes in location expressions.
141 for (LocWithReference &LocExpr : getState().LocWithReferencesToProcess) {
142 SmallVector<uint8_t, 32> Buffer;
143 DataExtractor Data(StringRef((const char *)LocExpr.BlockData.data(),
144 LocExpr.BlockData.size()),
145 LocExpr.U.isLittleEndian(),
146 LocExpr.U.getAddressByteSize());
147 DWARFExpression Expr(Data, LocExpr.U.getAddressByteSize(),
148 LocExpr.U.getFormParams().Format);
149 cloneExpression(Data, Expression: Expr, U&: LocExpr.U, OutputBuffer&: Buffer, Stage: CloneExpressionStage::PATCH);
150
151 DIEValueList *AttrVal;
152 if (LocExpr.Form == dwarf::DW_FORM_exprloc) {
153 DIELoc *DL = new (getState().DIEAlloc) DIELoc;
154 DL->setSize(Buffer.size());
155 AttrVal = static_cast<DIEValueList *>(DL);
156 } else {
157 DIEBlock *DBL = new (getState().DIEAlloc) DIEBlock;
158 DBL->setSize(Buffer.size());
159 AttrVal = static_cast<DIEValueList *>(DBL);
160 }
161 for (auto Byte : Buffer)
162 AttrVal->addValue(Alloc&: getState().DIEAlloc, Attribute: static_cast<dwarf::Attribute>(0),
163 Form: dwarf::DW_FORM_data1, Value: DIEInteger(Byte));
164
165 DIEValue Value;
166 if (LocExpr.Form == dwarf::DW_FORM_exprloc)
167 Value =
168 DIEValue(dwarf::Attribute(LocExpr.Attr), dwarf::Form(LocExpr.Form),
169 static_cast<DIELoc *>(AttrVal));
170 else
171 Value =
172 DIEValue(dwarf::Attribute(LocExpr.Attr), dwarf::Form(LocExpr.Form),
173 static_cast<DIEBlock *>(AttrVal));
174
175 LocExpr.Die.replaceValue(Alloc&: getState().DIEAlloc, Attribute: LocExpr.Attr, Form: LocExpr.Form,
176 NewValue&: Value);
177 }
178}
179
180uint32_t DIEBuilder::allocDIE(const DWARFUnit &DU, const DWARFDie &DDie,
181 BumpPtrAllocator &Alloc, const uint32_t UId) {
182 DWARFUnitInfo &DWARFUnitInfo = getUnitInfo(UnitId: UId);
183 const uint64_t DDieOffset = DDie.getOffset();
184 if (DWARFUnitInfo.DIEIDMap.count(x: DDieOffset))
185 return DWARFUnitInfo.DIEIDMap[DDieOffset];
186
187 DIE *Die = DIE::get(Alloc, Tag: dwarf::Tag(DDie.getTag()));
188 // This handles the case where there is a DIE ref which points to
189 // invalid DIE. This prevents assert when IR is written out.
190 // Also it makes debugging easier.
191 // DIE dump is not very useful.
192 // It's nice to know original offset from which this DIE was constructed.
193 Die->setOffset(DDie.getOffset());
194 if (opts::Verbosity >= 1)
195 getState().DWARFDieAddressesParsed.insert(x: DDie.getOffset());
196 const uint32_t DId = DWARFUnitInfo.DieInfoVector.size();
197 DWARFUnitInfo.DIEIDMap[DDieOffset] = DId;
198 DWARFUnitInfo.DieInfoVector.emplace_back(
199 args: std::make_unique<DIEInfo>(args: DIEInfo{.Die: Die, .DieId: DId, .UnitId: UId}));
200 return DId;
201}
202
203void DIEBuilder::constructFromUnit(DWARFUnit &DU) {
204 std::optional<uint32_t> UnitId = getUnitId(DU);
205 if (!UnitId) {
206 BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: "
207 << "Skip Unit at " << Twine::utohexstr(Val: DU.getOffset()) << "\n";
208 return;
209 }
210
211 const uint32_t UnitHeaderSize = DU.getHeaderSize();
212 uint64_t DIEOffset = DU.getOffset() + UnitHeaderSize;
213 uint64_t NextCUOffset = DU.getNextUnitOffset();
214 DWARFDataExtractor DebugInfoData = DU.getDebugInfoExtractor();
215 DWARFDebugInfoEntry DIEEntry;
216 std::vector<DIE *> CurParentDIEStack;
217 std::vector<uint32_t> Parents;
218 uint32_t TUTypeOffset = 0;
219
220 if (DWARFTypeUnit *TU = dyn_cast_or_null<DWARFTypeUnit>(Val: &DU))
221 TUTypeOffset = TU->getTypeOffset();
222
223 assert(DebugInfoData.isValidOffset(NextCUOffset - 1));
224 Parents.push_back(UINT32_MAX);
225 do {
226 const bool IsTypeDIE = (TUTypeOffset == DIEOffset - DU.getOffset());
227 if (!DIEEntry.extractFast(U: DU, OffsetPtr: &DIEOffset, DebugInfoData, UEndOffset: NextCUOffset,
228 ParentIdx: Parents.back()))
229 break;
230
231 if (const DWARFAbbreviationDeclaration *AbbrDecl =
232 DIEEntry.getAbbreviationDeclarationPtr()) {
233 DWARFDie DDie(&DU, &DIEEntry);
234
235 DIE *CurDIE = constructDIEFast(DDie, U&: DU, UnitId: *UnitId);
236 DWARFUnitInfo &UI = getUnitInfo(UnitId: *UnitId);
237 // Can't rely on first element in DieVector due to cross CU forward
238 // references.
239 if (!UI.UnitDie)
240 UI.UnitDie = CurDIE;
241 if (IsTypeDIE)
242 getState().TypeDIEMap[&DU] = CurDIE;
243
244 if (!CurParentDIEStack.empty())
245 CurParentDIEStack.back()->addChild(Child: CurDIE);
246
247 if (AbbrDecl->hasChildren())
248 CurParentDIEStack.push_back(x: CurDIE);
249 } else {
250 // NULL DIE: finishes current children scope.
251 CurParentDIEStack.pop_back();
252 }
253 } while (CurParentDIEStack.size() > 0);
254
255 getState().CloneUnitCtxMap[*UnitId].IsConstructed = true;
256}
257
258DIEBuilder::DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext,
259 DWARF5AcceleratorTable &DebugNamesTable,
260 DWARFUnit *SkeletonCU)
261 : BC(BC), DwarfContext(DwarfContext), SkeletonCU(SkeletonCU),
262 DebugNamesTable(DebugNamesTable) {}
263
264static unsigned int getCUNum(DWARFContext *DwarfContext, bool IsDWO) {
265 unsigned int CUNum = IsDWO ? DwarfContext->getNumDWOCompileUnits()
266 : DwarfContext->getNumCompileUnits();
267 CUNum += IsDWO ? DwarfContext->getNumDWOTypeUnits()
268 : DwarfContext->getNumTypeUnits();
269 return CUNum;
270}
271
272void DIEBuilder::buildTypeUnits(DebugStrOffsetsWriter *StrOffsetWriter,
273 const bool Init) {
274 if (Init)
275 BuilderState.reset(p: new State());
276
277 const DWARFUnitIndex &TUIndex = DwarfContext->getTUIndex();
278 if (!TUIndex.getRows().empty()) {
279 for (auto &Row : TUIndex.getRows()) {
280 uint64_t Signature = Row.getSignature();
281 // manually populate TypeUnit to UnitVector
282 DwarfContext->getTypeUnitForHash(Hash: Signature, IsDWO: true);
283 }
284 }
285 const unsigned int CUNum = getCUNum(DwarfContext, IsDWO: isDWO());
286 getState().CloneUnitCtxMap.resize(new_size: CUNum);
287 DWARFContext::unit_iterator_range CU4TURanges =
288 isDWO() ? DwarfContext->dwo_types_section_units()
289 : DwarfContext->types_section_units();
290
291 getState().Type = ProcessingType::DWARF4TUs;
292 for (std::unique_ptr<DWARFUnit> &DU : CU4TURanges)
293 registerUnit(DU&: *DU, NeedSort: false);
294
295 for (std::unique_ptr<DWARFUnit> &DU : CU4TURanges)
296 constructFromUnit(DU&: *DU);
297
298 DWARFContext::unit_iterator_range CURanges =
299 isDWO() ? DwarfContext->dwo_info_section_units()
300 : DwarfContext->info_section_units();
301
302 // This handles DWARF4 CUs and DWARF5 CU/TUs.
303 // Creating a vector so that for reference handling only DWARF5 CU/TUs are
304 // used, and not DWARF4 TUs.
305 getState().Type = ProcessingType::DWARF5TUs;
306 for (std::unique_ptr<DWARFUnit> &DU : CURanges) {
307 if (!DU->isTypeUnit())
308 continue;
309 registerUnit(DU&: *DU, NeedSort: false);
310 }
311
312 for (DWARFUnit *DU : getState().DWARF5TUVector) {
313 constructFromUnit(DU&: *DU);
314 if (StrOffsetWriter)
315 StrOffsetWriter->finalizeSection(Unit&: *DU, DIEBldr&: *this);
316 }
317}
318
319void DIEBuilder::buildCompileUnits(const bool Init) {
320 if (Init)
321 BuilderState.reset(p: new State());
322
323 unsigned int CUNum = getCUNum(DwarfContext, IsDWO: isDWO());
324 getState().CloneUnitCtxMap.resize(new_size: CUNum);
325 DWARFContext::unit_iterator_range CURanges =
326 isDWO() ? DwarfContext->dwo_info_section_units()
327 : DwarfContext->info_section_units();
328
329 // This handles DWARF4 CUs and DWARF5 CU/TUs.
330 // Creating a vector so that for reference handling only DWARF5 CU/TUs are
331 // used, and not DWARF4 TUs.getState().DUList
332 getState().Type = ProcessingType::CUs;
333 for (std::unique_ptr<DWARFUnit> &DU : CURanges) {
334 if (DU->isTypeUnit())
335 continue;
336 registerUnit(DU&: *DU, NeedSort: false);
337 }
338
339 // Using DULIst since it can be modified by cross CU refrence resolution.
340 for (DWARFUnit *DU : getState().DUList) {
341 if (DU->isTypeUnit())
342 continue;
343 constructFromUnit(DU&: *DU);
344 }
345}
346void DIEBuilder::buildCompileUnits(const std::vector<DWARFUnit *> &CUs) {
347 BuilderState.reset(p: new State());
348 // Allocating enough for current batch being processed.
349 // In real use cases we either processing a batch of CUs with no cross
350 // references, or if they do have them it is due to LTO. With clang they will
351 // share the same abbrev table. In either case this vector will not grow.
352 getState().CloneUnitCtxMap.resize(new_size: CUs.size());
353 getState().Type = ProcessingType::CUs;
354 for (DWARFUnit *CU : CUs)
355 registerUnit(DU&: *CU, NeedSort: false);
356
357 for (DWARFUnit *DU : getState().DUList)
358 constructFromUnit(DU&: *DU);
359}
360
361void DIEBuilder::buildDWOUnit(DWARFUnit &U) {
362 BuilderState.release();
363 BuilderState = std::make_unique<State>();
364 buildTypeUnits(StrOffsetWriter: nullptr, Init: false);
365 getState().Type = ProcessingType::CUs;
366 registerUnit(DU&: U, NeedSort: false);
367 constructFromUnit(DU&: U);
368}
369
370DIE *DIEBuilder::constructDIEFast(DWARFDie &DDie, DWARFUnit &U,
371 uint32_t UnitId) {
372
373 std::optional<uint32_t> Idx = getAllocDIEId(DU: U, DDie);
374 if (Idx) {
375 DWARFUnitInfo &DWARFUnitInfo = getUnitInfo(UnitId);
376 DIEInfo &DieInfo = getDIEInfo(UnitId, DIEId: *Idx);
377 if (DWARFUnitInfo.IsConstructed && DieInfo.Die)
378 return DieInfo.Die;
379 } else {
380 Idx = allocDIE(DU: U, DDie, Alloc&: getState().DIEAlloc, UId: UnitId);
381 }
382
383 DIEInfo &DieInfo = getDIEInfo(UnitId, DIEId: *Idx);
384
385 uint64_t Offset = DDie.getOffset();
386 uint64_t NextOffset = Offset;
387 DWARFDataExtractor Data = U.getDebugInfoExtractor();
388 DWARFDebugInfoEntry DDIEntry;
389
390 if (DDIEntry.extractFast(U, OffsetPtr: &NextOffset, DebugInfoData: Data, UEndOffset: U.getNextUnitOffset(), ParentIdx: 0))
391 assert(NextOffset - U.getOffset() <= Data.getData().size() &&
392 "NextOffset OOB");
393
394 SmallString<40> DIECopy(Data.getData().substr(Start: Offset, N: NextOffset - Offset));
395 Data =
396 DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
397
398 const DWARFAbbreviationDeclaration *Abbrev =
399 DDie.getAbbreviationDeclarationPtr();
400 uint64_t AttrOffset = getULEB128Size(Value: Abbrev->getCode());
401
402 using AttrSpec = DWARFAbbreviationDeclaration::AttributeSpec;
403 for (const AttrSpec &AttrSpec : Abbrev->attributes()) {
404 DWARFFormValue Val(AttrSpec.Form);
405 Val.extractValue(Data, OffsetPtr: &AttrOffset, FormParams: U.getFormParams(), U: &U);
406 cloneAttribute(Die&: *DieInfo.Die, InputDIE: DDie, U, Val, AttrSpec);
407 }
408 return DieInfo.Die;
409}
410
411static DWARFUnit *
412getUnitForOffset(DIEBuilder &Builder, DWARFContext &DWCtx,
413 const uint64_t Offset,
414 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec) {
415 auto findUnit = [&](std::vector<DWARFUnit *> &Units) -> DWARFUnit * {
416 auto CUIter = llvm::upper_bound(Range&: Units, Value: Offset,
417 C: [](uint64_t LHS, const DWARFUnit *RHS) {
418 return LHS < RHS->getNextUnitOffset();
419 });
420 static std::vector<DWARFUnit *> CUOffsets;
421 static std::once_flag InitVectorFlag;
422 auto initCUVector = [&]() {
423 CUOffsets.reserve(n: DWCtx.getNumCompileUnits());
424 for (const std::unique_ptr<DWARFUnit> &CU : DWCtx.compile_units())
425 CUOffsets.emplace_back(args: CU.get());
426 };
427 DWARFUnit *CU = CUIter != Units.end() ? *CUIter : nullptr;
428 // Above algorithm breaks when there is only one CU, and reference is
429 // outside of it. Fall through slower path, that searches all the CUs.
430 // For example when src and destination of cross CU references have
431 // different abbrev section.
432 if (!CU ||
433 (CU && AttrSpec.Form == dwarf::DW_FORM_ref_addr &&
434 !(CU->getOffset() < Offset && CU->getNextUnitOffset() > Offset))) {
435 // This is a work around for XCode clang. There is a build error when we
436 // pass DWCtx.compile_units() to llvm::upper_bound
437 std::call_once(once&: InitVectorFlag, f&: initCUVector);
438 auto CUIter = llvm::upper_bound(Range&: CUOffsets, Value: Offset,
439 C: [](uint64_t LHS, const DWARFUnit *RHS) {
440 return LHS < RHS->getNextUnitOffset();
441 });
442 CU = CUIter != CUOffsets.end() ? (*CUIter) : nullptr;
443 }
444 return CU;
445 };
446
447 switch (Builder.getCurrentProcessingState()) {
448 case DIEBuilder::ProcessingType::DWARF4TUs:
449 return findUnit(Builder.getDWARF4TUVector());
450 case DIEBuilder::ProcessingType::DWARF5TUs:
451 return findUnit(Builder.getDWARF5TUVector());
452 case DIEBuilder::ProcessingType::CUs:
453 return findUnit(Builder.getDWARFCUVector());
454 };
455
456 return nullptr;
457}
458
459uint32_t DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die,
460 uint32_t &CurOffset) {
461 getState().DWARFDieAddressesParsed.erase(x: Die.getOffset());
462 uint32_t CurSize = 0;
463 Die.setOffset(CurOffset);
464 // It is possible that an indexed debugging information entry has a parent
465 // that is not indexed (for example, if its parent does not have a name
466 // attribute). In such a case, a parent attribute may point to a nameless
467 // index entry (that is, one that cannot be reached from any entry in the name
468 // table), or it may point to the nearest ancestor that does have an index
469 // entry.
470 // Skipping entry is not very useful for LLDB. This follows clang where
471 // children of forward declaration won't have DW_IDX_parent.
472 // https://github.com/llvm/llvm-project/pull/91808
473
474 // If Parent is nullopt and NumberParentsInChain is not zero, then forward
475 // declaration was encountered in this DF traversal. Propagating nullopt for
476 // Parent to children.
477 for (DIEValue &Val : Die.values())
478 CurSize += Val.sizeOf(FormParams: CU.getFormParams());
479 CurSize += getULEB128Size(Value: Die.getAbbrevNumber());
480 CurOffset += CurSize;
481
482 for (DIE &Child : Die.children()) {
483 uint32_t ChildSize = finalizeDIEs(CU, Die&: Child, CurOffset);
484 CurSize += ChildSize;
485 }
486 // for children end mark.
487 if (Die.hasChildren()) {
488 CurSize += sizeof(uint8_t);
489 CurOffset += sizeof(uint8_t);
490 }
491
492 Die.setSize(CurSize);
493 return CurSize;
494}
495
496void DIEBuilder::finish() {
497 auto finalizeCU = [&](DWARFUnit &CU, uint64_t &UnitStartOffset) -> void {
498 DIE *UnitDIE = getUnitDIEbyUnit(DU: CU);
499 uint32_t HeaderSize = CU.getHeaderSize();
500 uint32_t CurOffset = HeaderSize;
501 std::vector<std::optional<BOLTDWARF5AccelTableData *>> Parents;
502 Parents.push_back(x: std::nullopt);
503 finalizeDIEs(CU, Die&: *UnitDIE, CurOffset);
504
505 DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(DwarfUnit: CU);
506 CurUnitInfo.UnitOffset = UnitStartOffset;
507 CurUnitInfo.UnitLength = HeaderSize + UnitDIE->getSize();
508 UnitStartOffset += CurUnitInfo.UnitLength;
509 };
510 // Computing offsets for .debug_types section.
511 // It's processed first when CU is registered so will be at the begginnig of
512 // the vector.
513 uint64_t TypeUnitStartOffset = 0;
514 for (DWARFUnit *CU : getState().DUList) {
515 // We process DWARF$ types first.
516 if (!(CU->getVersion() < 5 && CU->isTypeUnit()))
517 break;
518 finalizeCU(*CU, TypeUnitStartOffset);
519 }
520
521 for (DWARFUnit *CU : getState().DUList) {
522 // Skipping DWARF4 types.
523 if (CU->getVersion() < 5 && CU->isTypeUnit())
524 continue;
525 finalizeCU(*CU, UnitSize);
526 }
527 if (opts::Verbosity >= 1) {
528 if (!getState().DWARFDieAddressesParsed.empty())
529 dbgs() << "Referenced DIE offsets not in .debug_info\n";
530 for (const uint64_t Address : getState().DWARFDieAddressesParsed) {
531 dbgs() << Twine::utohexstr(Val: Address) << "\n";
532 }
533 }
534}
535
536void DIEBuilder::populateDebugNamesTable(
537 DWARFUnit &CU, const DIE &Die,
538 std::optional<BOLTDWARF5AccelTableData *> Parent,
539 uint32_t NumberParentsInChain) {
540 std::optional<BOLTDWARF5AccelTableData *> NameEntry =
541 DebugNamesTable.addAccelTableEntry(
542 Unit&: CU, Die, DWOID: SkeletonCU ? SkeletonCU->getDWOId() : std::nullopt,
543 NumberParentsInChain, Parent);
544 if (!Parent && NumberParentsInChain)
545 NameEntry = std::nullopt;
546 if (NameEntry)
547 ++NumberParentsInChain;
548
549 for (const DIE &Child : Die.children())
550 populateDebugNamesTable(CU, Die: Child, Parent: NameEntry, NumberParentsInChain);
551}
552
553void DIEBuilder::updateDebugNamesTable() {
554 auto finalizeDebugNamesTableForCU = [&](DWARFUnit &CU,
555 uint64_t &UnitStartOffset) -> void {
556 DIE *UnitDIE = getUnitDIEbyUnit(DU: CU);
557 DebugNamesTable.setCurrentUnit(Unit&: CU, UnitStartOffset);
558 populateDebugNamesTable(CU, Die: *UnitDIE, Parent: std::nullopt, NumberParentsInChain: 0);
559
560 DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(DwarfUnit: CU);
561 UnitStartOffset += CurUnitInfo.UnitLength;
562 };
563
564 uint64_t TypeUnitStartOffset = 0;
565 for (DWARFUnit *CU : getState().DUList) {
566 if (!(CU->getVersion() < 5 && CU->isTypeUnit()))
567 break;
568 finalizeDebugNamesTableForCU(*CU, TypeUnitStartOffset);
569 }
570
571 for (DWARFUnit *CU : getState().DUList) {
572 if (CU->getVersion() < 5 && CU->isTypeUnit())
573 continue;
574 finalizeDebugNamesTableForCU(*CU, DebugNamesUnitSize);
575 }
576 updateReferences();
577}
578
579DWARFDie DIEBuilder::resolveDIEReference(
580 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
581 const uint64_t RefOffset, DWARFUnit *&RefCU,
582 DWARFDebugInfoEntry &DwarfDebugInfoEntry) {
583 uint64_t TmpRefOffset = RefOffset;
584 if ((RefCU =
585 getUnitForOffset(Builder&: *this, DWCtx&: *DwarfContext, Offset: TmpRefOffset, AttrSpec))) {
586 /// Trying to add to current working set in case it's cross CU reference.
587 registerUnit(DU&: *RefCU, NeedSort: true);
588 DWARFDataExtractor DebugInfoData = RefCU->getDebugInfoExtractor();
589 if (DwarfDebugInfoEntry.extractFast(U: *RefCU, OffsetPtr: &TmpRefOffset, DebugInfoData,
590 UEndOffset: RefCU->getNextUnitOffset(), ParentIdx: 0)) {
591 // In a file with broken references, an attribute might point to a NULL
592 // DIE.
593 DWARFDie RefDie = DWARFDie(RefCU, &DwarfDebugInfoEntry);
594 if (!RefDie.isNULL()) {
595 std::optional<uint32_t> UnitId = getUnitId(DU: *RefCU);
596
597 // forward reference
598 if (UnitId && !getState().CloneUnitCtxMap[*UnitId].IsConstructed &&
599 !getAllocDIEId(DU: *RefCU, DDie: RefDie))
600 allocDIE(DU: *RefCU, DDie: RefDie, Alloc&: getState().DIEAlloc, UId: *UnitId);
601 return RefDie;
602 }
603 BC.errs()
604 << "BOLT-WARNING: [internal-dwarf-error]: invalid referenced DIE "
605 "at offset: "
606 << Twine::utohexstr(Val: RefOffset) << ".\n";
607
608 } else {
609 BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: could not parse "
610 "referenced DIE at offset: "
611 << Twine::utohexstr(Val: RefOffset) << ".\n";
612 }
613 } else {
614 BC.errs()
615 << "BOLT-WARNING: [internal-dwarf-error]: could not find referenced "
616 "CU. Referenced DIE offset: "
617 << Twine::utohexstr(Val: RefOffset) << ".\n";
618 }
619 return DWARFDie();
620}
621
622void DIEBuilder::cloneDieOffsetReferenceAttribute(
623 DIE &Die, DWARFUnit &U, const DWARFDie &InputDIE,
624 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec, uint64_t Ref) {
625 DIE *NewRefDie = nullptr;
626 DWARFUnit *RefUnit = nullptr;
627
628 DWARFDebugInfoEntry DDIEntry;
629 const DWARFDie RefDie = resolveDIEReference(AttrSpec, RefOffset: Ref, RefCU&: RefUnit, DwarfDebugInfoEntry&: DDIEntry);
630
631 if (!RefDie)
632 return;
633
634 const std::optional<uint32_t> UnitId = getUnitId(DU: *RefUnit);
635 const std::optional<uint32_t> IsAllocId = getAllocDIEId(DU: *RefUnit, DDie: RefDie);
636 assert(IsAllocId.has_value() && "Encountered unexpected unallocated DIE.");
637 const uint32_t DIEId = *IsAllocId;
638 DIEInfo &DieInfo = getDIEInfo(UnitId: *UnitId, DIEId);
639
640 if (!DieInfo.Die) {
641 assert(Ref > InputDIE.getOffset());
642 (void)Ref;
643 BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: encounter unexpected "
644 "unallocated DIE. Should be alloc!\n";
645 // We haven't cloned this DIE yet. Just create an empty one and
646 // store it. It'll get really cloned when we process it.
647 DieInfo.Die = DIE::get(Alloc&: getState().DIEAlloc, Tag: dwarf::Tag(RefDie.getTag()));
648 }
649 NewRefDie = DieInfo.Die;
650
651 if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) {
652 // Adding referenced DIE to DebugNames to be used when entries are created
653 // that contain cross cu references.
654 if (DebugNamesTable.canGenerateEntryWithCrossCUReference(Unit: U, Die, AttrSpec))
655 DebugNamesTable.addCrossCUDie(Unit: &U, Die: DieInfo.Die);
656 // no matter forward reference or backward reference, we are supposed
657 // to calculate them in `finish` due to the possible modification of
658 // the DIE.
659 DWARFDie CurDie = const_cast<DWARFDie &>(InputDIE);
660 DIEInfo *CurDieInfo = &getDIEInfoByDwarfDie(DwarfDie&: CurDie);
661 getState().AddrReferences.push_back(
662 x: std::make_pair(x&: CurDieInfo, y: AddrReferenceInfo(&DieInfo, AttrSpec)));
663
664 Die.addValue(Alloc&: getState().DIEAlloc, Attribute: AttrSpec.Attr, Form: dwarf::DW_FORM_ref_addr,
665 Value: DIEInteger(DieInfo.Die->getOffset()));
666 return;
667 }
668
669 Die.addValue(Alloc&: getState().DIEAlloc, Attribute: AttrSpec.Attr, Form: AttrSpec.Form,
670 Value: DIEEntry(*NewRefDie));
671}
672
673void DIEBuilder::cloneStringAttribute(
674 DIE &Die, const DWARFUnit &U,
675 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
676 const DWARFFormValue &Val) {
677 if (AttrSpec.Form == dwarf::DW_FORM_string) {
678 Expected<const char *> StrAddr = Val.getAsCString();
679 if (!StrAddr) {
680 consumeError(Err: StrAddr.takeError());
681 return;
682 }
683 Die.addValue(Alloc&: getState().DIEAlloc, Attribute: AttrSpec.Attr, Form: dwarf::DW_FORM_string,
684 Value: new (getState().DIEAlloc)
685 DIEInlineString(StrAddr.get(), getState().DIEAlloc));
686 } else {
687 std::optional<uint64_t> OffsetIndex = Val.getRawUValue();
688 Die.addValue(Alloc&: getState().DIEAlloc, Attribute: AttrSpec.Attr, Form: AttrSpec.Form,
689 Value: DIEInteger(*OffsetIndex));
690 }
691}
692
693bool DIEBuilder::cloneExpression(const DataExtractor &Data,
694 const DWARFExpression &Expression,
695 DWARFUnit &U,
696 SmallVectorImpl<uint8_t> &OutputBuffer,
697 const CloneExpressionStage &Stage) {
698 using Encoding = DWARFExpression::Operation::Encoding;
699 using Descr = DWARFExpression::Operation::Description;
700 uint64_t OpOffset = 0;
701 bool DoesContainReference = false;
702 for (const DWARFExpression::Operation &Op : Expression) {
703 const Descr &Description = Op.getDescription();
704 // DW_OP_const_type is variable-length and has 3
705 // operands. Thus far we only support 2.
706 if ((Description.Op.size() == 2 &&
707 Description.Op[0] == Encoding::BaseTypeRef) ||
708 (Description.Op.size() == 2 &&
709 Description.Op[1] == Encoding::BaseTypeRef &&
710 Description.Op[0] != Encoding::Size1))
711 BC.outs() << "BOLT-WARNING: [internal-dwarf-error]: unsupported DW_OP "
712 "encoding.\n";
713
714 if ((Description.Op.size() == 1 &&
715 Description.Op[0] == Encoding::BaseTypeRef) ||
716 (Description.Op.size() == 2 &&
717 Description.Op[1] == Encoding::BaseTypeRef &&
718 Description.Op[0] == Encoding::Size1)) {
719 // This code assumes that the other non-typeref operand fits into 1
720 // byte.
721 assert(OpOffset < Op.getEndOffset());
722 const uint32_t ULEBsize = Op.getEndOffset() - OpOffset - 1;
723 (void)ULEBsize;
724 assert(ULEBsize <= 16);
725
726 // Copy over the operation.
727 OutputBuffer.push_back(Elt: Op.getCode());
728 uint64_t RefOffset;
729 if (Description.Op.size() == 1) {
730 RefOffset = Op.getRawOperand(Idx: 0);
731 } else {
732 OutputBuffer.push_back(Elt: Op.getRawOperand(Idx: 0));
733 RefOffset = Op.getRawOperand(Idx: 1);
734 }
735 uint32_t Offset = 0;
736 if (RefOffset > 0 || Op.getCode() != dwarf::DW_OP_convert) {
737 DoesContainReference = true;
738 std::optional<uint32_t> RefDieID =
739 getAllocDIEId(DU: U, Offset: U.getOffset() + RefOffset);
740 std::optional<uint32_t> RefUnitID = getUnitId(DU: U);
741 if (RefDieID.has_value() && RefUnitID.has_value()) {
742 DIEInfo &RefDieInfo = getDIEInfo(UnitId: *RefUnitID, DIEId: *RefDieID);
743 if (DIE *Clone = RefDieInfo.Die)
744 Offset = Stage == CloneExpressionStage::INIT ? RefOffset
745 : Clone->getOffset();
746 else
747 BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: base type ref "
748 "doesn't point to "
749 "DW_TAG_base_type.\n";
750 }
751 }
752 uint8_t ULEB[16];
753 // Hard coding to max size so size doesn't change when we update the
754 // offset.
755 encodeULEB128(Value: Offset, p: ULEB, PadTo: 4);
756 ArrayRef<uint8_t> ULEBbytes(ULEB, 4);
757 OutputBuffer.append(in_start: ULEBbytes.begin(), in_end: ULEBbytes.end());
758 } else {
759 // Copy over everything else unmodified.
760 const StringRef Bytes = Data.getData().slice(Start: OpOffset, End: Op.getEndOffset());
761 OutputBuffer.append(in_start: Bytes.begin(), in_end: Bytes.end());
762 }
763 OpOffset = Op.getEndOffset();
764 }
765 return DoesContainReference;
766}
767
768void DIEBuilder::cloneBlockAttribute(
769 DIE &Die, DWARFUnit &U,
770 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
771 const DWARFFormValue &Val) {
772 DIEValueList *Attr;
773 DIEValue Value;
774 DIELoc *Loc = nullptr;
775 DIEBlock *Block = nullptr;
776
777 if (AttrSpec.Form == dwarf::DW_FORM_exprloc) {
778 Loc = new (getState().DIEAlloc) DIELoc;
779 } else if (doesFormBelongToClass(Form: AttrSpec.Form, FC: DWARFFormValue::FC_Block,
780 DwarfVersion: U.getVersion())) {
781 Block = new (getState().DIEAlloc) DIEBlock;
782 } else {
783 BC.errs()
784 << "BOLT-WARNING: [internal-dwarf-error]: Unexpected Form value in "
785 "cloneBlockAttribute\n";
786 return;
787 }
788 Attr = Loc ? static_cast<DIEValueList *>(Loc)
789 : static_cast<DIEValueList *>(Block);
790
791 SmallVector<uint8_t, 32> Buffer;
792 ArrayRef<uint8_t> Bytes = *Val.getAsBlock();
793 if (DWARFAttribute::mayHaveLocationExpr(Attr: AttrSpec.Attr) &&
794 (Val.isFormClass(FC: DWARFFormValue::FC_Block) ||
795 Val.isFormClass(FC: DWARFFormValue::FC_Exprloc))) {
796 DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()),
797 U.isLittleEndian(), U.getAddressByteSize());
798 DWARFExpression Expr(Data, U.getAddressByteSize(),
799 U.getFormParams().Format);
800 if (cloneExpression(Data, Expression: Expr, U, OutputBuffer&: Buffer, Stage: CloneExpressionStage::INIT))
801 getState().LocWithReferencesToProcess.emplace_back(
802 args: Bytes.vec(), args&: U, args&: Die, args: AttrSpec.Form, args: AttrSpec.Attr);
803 Bytes = Buffer;
804 }
805 for (auto Byte : Bytes)
806 Attr->addValue(Alloc&: getState().DIEAlloc, Attribute: static_cast<dwarf::Attribute>(0),
807 Form: dwarf::DW_FORM_data1, Value: DIEInteger(Byte));
808
809 if (Loc)
810 Loc->setSize(Bytes.size());
811 else
812 Block->setSize(Bytes.size());
813
814 if (Loc)
815 Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),
816 dwarf::Form(AttrSpec.Form), Loc);
817 else
818 Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),
819 dwarf::Form(AttrSpec.Form), Block);
820 Die.addValue(Alloc&: getState().DIEAlloc, V: Value);
821}
822
823void DIEBuilder::cloneAddressAttribute(
824 DIE &Die, const DWARFUnit &U,
825 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
826 const DWARFFormValue &Val) {
827 Die.addValue(Alloc&: getState().DIEAlloc, Attribute: AttrSpec.Attr, Form: AttrSpec.Form,
828 Value: DIEInteger(Val.getRawUValue()));
829}
830
831void DIEBuilder::cloneRefsigAttribute(
832 DIE &Die, DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
833 const DWARFFormValue &Val) {
834 const std::optional<uint64_t> SigVal = Val.getAsSignatureReference();
835 Die.addValue(Alloc&: getState().DIEAlloc, Attribute: AttrSpec.Attr, Form: dwarf::DW_FORM_ref_sig8,
836 Value: DIEInteger(*SigVal));
837}
838
839void DIEBuilder::cloneScalarAttribute(
840 DIE &Die, const DWARFDie &InputDIE,
841 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
842 const DWARFFormValue &Val) {
843 uint64_t Value;
844
845 if (auto OptionalValue = Val.getAsUnsignedConstant())
846 Value = *OptionalValue;
847 else if (auto OptionalValue = Val.getAsSignedConstant())
848 Value = *OptionalValue;
849 else if (auto OptionalValue = Val.getAsSectionOffset())
850 Value = *OptionalValue;
851 else {
852 BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: Unsupported scalar "
853 "attribute form. Dropping "
854 "attribute.\n";
855 return;
856 }
857
858 Die.addValue(Alloc&: getState().DIEAlloc, Attribute: AttrSpec.Attr, Form: AttrSpec.Form,
859 Value: DIEInteger(Value));
860}
861
862void DIEBuilder::cloneLoclistAttrubute(
863 DIE &Die, const DWARFDie &InputDIE,
864 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
865 const DWARFFormValue &Val) {
866 std::optional<uint64_t> Value = std::nullopt;
867
868 if (auto OptionalValue = Val.getAsUnsignedConstant())
869 Value = OptionalValue;
870 else if (auto OptionalValue = Val.getAsSignedConstant())
871 Value = OptionalValue;
872 else if (auto OptionalValue = Val.getAsSectionOffset())
873 Value = OptionalValue;
874 else
875 BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: Unsupported scalar "
876 "attribute form. Dropping "
877 "attribute.\n";
878
879 if (!Value.has_value())
880 return;
881
882 Die.addValue(Alloc&: getState().DIEAlloc, Attribute: AttrSpec.Attr, Form: AttrSpec.Form,
883 Value: DIELocList(*Value));
884}
885
886void DIEBuilder::cloneAttribute(
887 DIE &Die, const DWARFDie &InputDIE, DWARFUnit &U, const DWARFFormValue &Val,
888 const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec) {
889 switch (AttrSpec.Form) {
890 case dwarf::DW_FORM_strp:
891 case dwarf::DW_FORM_string:
892 case dwarf::DW_FORM_strx:
893 case dwarf::DW_FORM_strx1:
894 case dwarf::DW_FORM_strx2:
895 case dwarf::DW_FORM_strx3:
896 case dwarf::DW_FORM_strx4:
897 case dwarf::DW_FORM_GNU_str_index:
898 case dwarf::DW_FORM_line_strp:
899 cloneStringAttribute(Die, U, AttrSpec, Val);
900 break;
901 case dwarf::DW_FORM_ref_addr:
902 cloneDieOffsetReferenceAttribute(Die, U, InputDIE, AttrSpec,
903 Ref: *Val.getAsDebugInfoReference());
904 break;
905 case dwarf::DW_FORM_ref1:
906 case dwarf::DW_FORM_ref2:
907 case dwarf::DW_FORM_ref4:
908 case dwarf::DW_FORM_ref8:
909 cloneDieOffsetReferenceAttribute(Die, U, InputDIE, AttrSpec,
910 Ref: Val.getUnit()->getOffset() +
911 *Val.getAsRelativeReference());
912 break;
913 case dwarf::DW_FORM_block:
914 case dwarf::DW_FORM_block1:
915 case dwarf::DW_FORM_block2:
916 case dwarf::DW_FORM_block4:
917 case dwarf::DW_FORM_exprloc:
918 cloneBlockAttribute(Die, U, AttrSpec, Val);
919 break;
920 case dwarf::DW_FORM_addr:
921 case dwarf::DW_FORM_addrx:
922 case dwarf::DW_FORM_GNU_addr_index:
923 cloneAddressAttribute(Die, U, AttrSpec, Val);
924 break;
925 case dwarf::DW_FORM_data1:
926 case dwarf::DW_FORM_data2:
927 case dwarf::DW_FORM_data4:
928 case dwarf::DW_FORM_data8:
929 case dwarf::DW_FORM_udata:
930 case dwarf::DW_FORM_sdata:
931 case dwarf::DW_FORM_sec_offset:
932 case dwarf::DW_FORM_rnglistx:
933 case dwarf::DW_FORM_flag:
934 case dwarf::DW_FORM_flag_present:
935 case dwarf::DW_FORM_implicit_const:
936 cloneScalarAttribute(Die, InputDIE, AttrSpec, Val);
937 break;
938 case dwarf::DW_FORM_loclistx:
939 cloneLoclistAttrubute(Die, InputDIE, AttrSpec, Val);
940 break;
941 case dwarf::DW_FORM_ref_sig8:
942 cloneRefsigAttribute(Die, AttrSpec, Val);
943 break;
944 default:
945 BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: Unsupported attribute "
946 "form " +
947 dwarf::FormEncodingString(Encoding: AttrSpec.Form).str() +
948 " in cloneAttribute. Dropping.";
949 }
950}
951void DIEBuilder::assignAbbrev(DIEAbbrev &Abbrev) {
952 // Check the set for priors.
953 FoldingSetNodeID ID;
954 Abbrev.Profile(ID);
955 void *InsertToken;
956 DIEAbbrev *InSet = AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos&: InsertToken);
957
958 // If it's newly added.
959 if (InSet) {
960 // Assign existing abbreviation number.
961 Abbrev.setNumber(InSet->getNumber());
962 } else {
963 // Add to abbreviation list.
964 Abbreviations.push_back(
965 x: std::make_unique<DIEAbbrev>(args: Abbrev.getTag(), args: Abbrev.hasChildren()));
966 for (const auto &Attr : Abbrev.getData())
967 Abbreviations.back()->AddAttribute(Attribute: Attr.getAttribute(), Form: Attr.getForm());
968 AbbreviationsSet.InsertNode(N: Abbreviations.back().get(), InsertPos: InsertToken);
969 // Assign the unique abbreviation number.
970 Abbrev.setNumber(Abbreviations.size());
971 Abbreviations.back()->setNumber(Abbreviations.size());
972 }
973}
974
975void DIEBuilder::generateAbbrevs() {
976 if (isEmpty())
977 return;
978
979 for (DWARFUnit *DU : getState().DUList) {
980 DIE *UnitDIE = getUnitDIEbyUnit(DU: *DU);
981 generateUnitAbbrevs(Die: UnitDIE);
982 }
983}
984
985void DIEBuilder::generateUnitAbbrevs(DIE *Die) {
986 DIEAbbrev NewAbbrev = Die->generateAbbrev();
987
988 if (Die->hasChildren())
989 NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);
990 assignAbbrev(Abbrev&: NewAbbrev);
991 Die->setAbbrevNumber(NewAbbrev.getNumber());
992
993 for (auto &Child : Die->children()) {
994 generateUnitAbbrevs(Die: &Child);
995 }
996}
997
998static uint64_t getHash(const DWARFUnit &DU) {
999 // Before DWARF5 TU units are in their own section, so at least one offset,
1000 // first one, will be the same as CUs in .debug_info.dwo section
1001 if (DU.getVersion() < 5 && DU.isTypeUnit()) {
1002 const uint64_t TypeUnitHash =
1003 cast_or_null<DWARFTypeUnit>(Val: &DU)->getTypeHash();
1004 const uint64_t Offset = DU.getOffset();
1005 return llvm::hash_combine(args: llvm::hash_value(value: TypeUnitHash),
1006 args: llvm::hash_value(value: Offset));
1007 }
1008 return DU.getOffset();
1009}
1010
1011void DIEBuilder::registerUnit(DWARFUnit &DU, bool NeedSort) {
1012 auto IterGlobal = AllProcessed.insert(V: getHash(DU));
1013 // If DU is already in a current working set or was already processed we can
1014 // skip it.
1015 if (!IterGlobal.second)
1016 return;
1017 if (getState().Type == ProcessingType::DWARF4TUs) {
1018 getState().DWARF4TUVector.push_back(x: &DU);
1019 } else if (getState().Type == ProcessingType::DWARF5TUs) {
1020 getState().DWARF5TUVector.push_back(x: &DU);
1021 } else {
1022 getState().DWARFCUVector.push_back(x: &DU);
1023 /// Sorting for cross CU reference resolution.
1024 if (NeedSort)
1025 std::sort(first: getState().DWARFCUVector.begin(),
1026 last: getState().DWARFCUVector.end(),
1027 comp: [](const DWARFUnit *A, const DWARFUnit *B) {
1028 return A->getOffset() < B->getOffset();
1029 });
1030 }
1031 getState().UnitIDMap[getHash(DU)] = getState().DUList.size();
1032 // This handles the case where we do have cross cu references, but CUs do not
1033 // share the same abbrev table.
1034 if (getState().DUList.size() == getState().CloneUnitCtxMap.size())
1035 getState().CloneUnitCtxMap.emplace_back();
1036 getState().DUList.push_back(x: &DU);
1037}
1038
1039std::optional<uint32_t> DIEBuilder::getUnitId(const DWARFUnit &DU) {
1040 auto Iter = getState().UnitIDMap.find(x: getHash(DU));
1041 if (Iter != getState().UnitIDMap.end())
1042 return Iter->second;
1043 return std::nullopt;
1044}
1045
1046} // namespace bolt
1047} // namespace llvm
1048

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of bolt/lib/Core/DIEBuilder.cpp