1 //===- bolt/Rewrite/DebugNames.cpp -------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "bolt/Core/DebugNames.h"
10 #include "bolt/Core/BinaryContext.h"
11 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
12 #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
13 #include "llvm/Support/EndianStream.h"
14 #include "llvm/Support/LEB128.h"
20 DWARF5AcceleratorTable::DWARF5AcceleratorTable(
21 const bool CreateDebugNames
, BinaryContext
&BC
,
22 DebugStrWriter
&MainBinaryStrWriter
)
23 : BC(BC
), MainBinaryStrWriter(MainBinaryStrWriter
) {
24 NeedToCreate
= CreateDebugNames
|| BC
.getDebugNamesSection();
27 FullTableBuffer
= std::make_unique
<DebugStrBufferVector
>();
28 FullTableStream
= std::make_unique
<raw_svector_ostream
>(*FullTableBuffer
);
29 StrBuffer
= std::make_unique
<DebugStrBufferVector
>();
30 StrStream
= std::make_unique
<raw_svector_ostream
>(*StrBuffer
);
31 EntriesBuffer
= std::make_unique
<DebugStrBufferVector
>();
32 Entriestream
= std::make_unique
<raw_svector_ostream
>(*EntriesBuffer
);
33 AugStringBuffer
= std::make_unique
<DebugStrBufferVector
>();
34 AugStringtream
= std::make_unique
<raw_svector_ostream
>(*AugStringBuffer
);
36 // Binary has split-dwarf CUs.
37 // Even thought for non-skeleton-cu all names are in .debug_str.dwo section,
38 // for the .debug_names contributions they are in .debug_str section.
39 if (BC
.getNumDWOCUs()) {
40 DataExtractor
StrData(BC
.DwCtx
->getDWARFObj().getStrSection(),
41 BC
.DwCtx
->isLittleEndian(), 0);
43 uint64_t StrOffset
= 0;
44 while (StrData
.isValidOffset(Offset
)) {
45 Error Err
= Error::success();
46 const char *CStr
= StrData
.getCStr(&Offset
, &Err
);
49 BC
.errs() << "BOLT-WARNING: [internal-dwarf-error]: Could not extract "
50 "string from .debug_str section at offset: "
51 << Twine::utohexstr(StrOffset
) << ".\n";
54 auto R
= StrCacheToOffsetMap
.try_emplace(
55 llvm::hash_value(llvm::StringRef(CStr
)), StrOffset
);
58 << "BOLT-WARNING: [internal-dwarf-error]: collision occured on "
59 << CStr
<< " at offset : 0x" << Twine::utohexstr(StrOffset
)
60 << ". Previous string offset is: 0x"
61 << Twine::utohexstr(R
.first
->second
) << ".\n";
67 void DWARF5AcceleratorTable::setCurrentUnit(DWARFUnit
&Unit
,
68 const uint64_t UnitStartOffset
) {
69 CurrentUnit
= nullptr;
70 CurrentUnitOffset
= UnitStartOffset
;
71 std::optional
<uint64_t> DWOID
= Unit
.getDWOId();
72 // We process skeleton CUs after DWO Units for it.
73 // Patching offset in CU list to correct one.
74 if (!Unit
.isDWOUnit() && DWOID
) {
75 auto Iter
= CUOffsetsToPatch
.find(*DWOID
);
76 // Check in case no entries were added from non skeleton DWO section.
77 if (Iter
!= CUOffsetsToPatch
.end())
78 CUList
[Iter
->second
] = UnitStartOffset
;
82 void DWARF5AcceleratorTable::addUnit(DWARFUnit
&Unit
,
83 const std::optional
<uint64_t> &DWOID
) {
84 constexpr uint32_t BADCUOFFSET
= 0xBADBAD;
85 StrSection
= Unit
.getStringSection();
86 if (Unit
.isTypeUnit()) {
88 // We adding an entry for a DWO TU. The DWO CU might not have any entries,
89 // so need to add it to the list pre-emptively.
90 auto Iter
= CUOffsetsToPatch
.insert({*DWOID
, CUList
.size()});
92 CUList
.push_back(BADCUOFFSET
);
93 const uint64_t TUHash
= cast
<DWARFTypeUnit
>(&Unit
)->getTypeHash();
94 if (!TUHashToIndexMap
.count(TUHash
)) {
95 TUHashToIndexMap
.insert({TUHash
, ForeignTUList
.size()});
96 ForeignTUList
.push_back(TUHash
);
99 LocalTUList
.push_back(CurrentUnitOffset
);
103 // This is a path for split dwarf without type units.
104 // We process DWO Units before Skeleton CU. So at this point we don't know
105 // the offset of Skeleton CU. Adding CULit index to a map to patch later
106 // with the correct offset.
107 auto Iter
= CUOffsetsToPatch
.insert({*DWOID
, CUList
.size()});
109 CUList
.push_back(BADCUOFFSET
);
111 CUList
.push_back(CurrentUnitOffset
);
116 // Returns true if DW_TAG_variable should be included in .debug-names based on
117 // section 6.1.1.1 for DWARF5 spec.
118 static bool shouldIncludeVariable(const DWARFUnit
&Unit
, const DIE
&Die
) {
119 const DIEValue LocAttrInfo
=
120 Die
.findAttribute(dwarf::Attribute::DW_AT_location
);
123 if (!(doesFormBelongToClass(LocAttrInfo
.getForm(), DWARFFormValue::FC_Exprloc
,
124 Unit
.getVersion()) ||
125 doesFormBelongToClass(LocAttrInfo
.getForm(), DWARFFormValue::FC_Block
,
128 std::vector
<uint8_t> Sblock
;
130 [&](const DIEValueList::const_value_range
&Iter
) -> void {
131 for (const DIEValue
&Val
: Iter
)
132 Sblock
.push_back(Val
.getDIEInteger().getValue());
134 if (doesFormBelongToClass(LocAttrInfo
.getForm(), DWARFFormValue::FC_Exprloc
,
136 constructVect(LocAttrInfo
.getDIELoc().values());
138 constructVect(LocAttrInfo
.getDIEBlock().values());
139 ArrayRef
<uint8_t> Expr
= ArrayRef
<uint8_t>(Sblock
);
140 DataExtractor
Data(StringRef((const char *)Expr
.data(), Expr
.size()),
141 Unit
.getContext().isLittleEndian(), 0);
142 DWARFExpression
LocExpr(Data
, Unit
.getAddressByteSize(),
143 Unit
.getFormParams().Format
);
144 for (const DWARFExpression::Operation
&Expr
: LocExpr
)
145 if (Expr
.getCode() == dwarf::DW_OP_addrx
||
146 Expr
.getCode() == dwarf::DW_OP_form_tls_address
||
147 Expr
.getCode() == dwarf::DW_OP_GNU_push_tls_address
)
152 bool static canProcess(const DWARFUnit
&Unit
, const DIE
&Die
,
153 std::string
&NameToUse
, const bool TagsOnly
) {
154 if (Die
.findAttribute(dwarf::Attribute::DW_AT_declaration
))
156 switch (Die
.getTag()) {
157 case dwarf::DW_TAG_base_type
:
158 case dwarf::DW_TAG_class_type
:
159 case dwarf::DW_TAG_enumeration_type
:
160 case dwarf::DW_TAG_imported_declaration
:
161 case dwarf::DW_TAG_pointer_type
:
162 case dwarf::DW_TAG_structure_type
:
163 case dwarf::DW_TAG_typedef
:
164 case dwarf::DW_TAG_unspecified_type
:
165 case dwarf::DW_TAG_union_type
:
166 if (TagsOnly
|| Die
.findAttribute(dwarf::Attribute::DW_AT_name
))
169 case dwarf::DW_TAG_namespace
:
170 // According to DWARF5 spec namespaces without DW_AT_name needs to have
171 // "(anonymous namespace)"
172 if (!Die
.findAttribute(dwarf::Attribute::DW_AT_name
))
173 NameToUse
= "(anonymous namespace)";
175 case dwarf::DW_TAG_inlined_subroutine
:
176 case dwarf::DW_TAG_label
:
177 case dwarf::DW_TAG_subprogram
:
178 if (TagsOnly
|| Die
.findAttribute(dwarf::Attribute::DW_AT_low_pc
) ||
179 Die
.findAttribute(dwarf::Attribute::DW_AT_high_pc
) ||
180 Die
.findAttribute(dwarf::Attribute::DW_AT_ranges
) ||
181 Die
.findAttribute(dwarf::Attribute::DW_AT_entry_pc
))
184 case dwarf::DW_TAG_variable
:
185 return TagsOnly
|| shouldIncludeVariable(Unit
, Die
);
192 bool DWARF5AcceleratorTable::canGenerateEntryWithCrossCUReference(
193 const DWARFUnit
&Unit
, const DIE
&Die
,
194 const DWARFAbbreviationDeclaration::AttributeSpec
&AttrSpec
) {
197 std::string NameToUse
= "";
198 if (!canProcess(Unit
, Die
, NameToUse
, true))
200 return (AttrSpec
.Attr
== dwarf::Attribute::DW_AT_abstract_origin
||
201 AttrSpec
.Attr
== dwarf::Attribute::DW_AT_specification
) &&
202 AttrSpec
.Form
== dwarf::DW_FORM_ref_addr
;
204 /// Returns name offset in String Offset section.
205 static uint64_t getNameOffset(BinaryContext
&BC
, DWARFUnit
&Unit
,
206 const uint64_t Index
) {
207 const DWARFSection
&StrOffsetsSection
= Unit
.getStringOffsetSection();
208 const std::optional
<StrOffsetsContributionDescriptor
> &Contr
=
209 Unit
.getStringOffsetsTableContribution();
211 BC
.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not get "
212 "StringOffsetsTableContribution for unit at offset: "
213 << Twine::utohexstr(Unit
.getOffset()) << ".\n";
217 const uint8_t DwarfOffsetByteSize
= Contr
->getDwarfOffsetByteSize();
218 return support::endian::read32le(StrOffsetsSection
.Data
.data() + Contr
->Base
+
219 Index
* DwarfOffsetByteSize
);
222 static uint64_t getEntryID(const BOLTDWARF5AccelTableData
&Entry
) {
223 return reinterpret_cast<uint64_t>(&Entry
);
226 uint32_t DWARF5AcceleratorTable::getUnitID(const DWARFUnit
&Unit
,
227 const std::optional
<uint64_t> &DWOID
,
229 IsTU
= Unit
.isTypeUnit();
232 const uint64_t TUHash
= cast
<DWARFTypeUnit
>(&Unit
)->getTypeHash();
233 auto Iter
= TUHashToIndexMap
.find(TUHash
);
234 assert(Iter
!= TUHashToIndexMap
.end() && "Could not find TU hash in map");
237 return LocalTUList
.size() - 1;
239 return CUList
.size() - 1;
242 std::optional
<std::string
> DWARF5AcceleratorTable::getName(
243 DWARFUnit
&Unit
, const std::optional
<uint64_t> &DWOID
,
244 const std::string
&NameToUse
, DIEValue ValName
) {
245 if ((!ValName
|| ValName
.getForm() == dwarf::DW_FORM_string
) &&
248 std::string Name
= "";
249 uint64_t NameIndexOffset
= 0;
250 if (NameToUse
.empty()) {
251 NameIndexOffset
= ValName
.getDIEInteger().getValue();
252 if (ValName
.getForm() != dwarf::DW_FORM_strp
)
253 NameIndexOffset
= getNameOffset(BC
, Unit
, NameIndexOffset
);
254 // Counts on strings end with '\0'.
255 Name
= std::string(&StrSection
.data()[NameIndexOffset
]);
259 auto &It
= Entries
[Name
];
260 if (It
.Values
.empty()) {
261 if (DWOID
&& NameToUse
.empty()) {
262 // For DWO Unit the offset is in the .debug_str.dwo section.
263 // Need to find offset for the name in the .debug_str section.
264 llvm::hash_code Hash
= llvm::hash_value(llvm::StringRef(Name
));
265 auto ItCache
= StrCacheToOffsetMap
.find(Hash
);
266 if (ItCache
== StrCacheToOffsetMap
.end())
267 NameIndexOffset
= MainBinaryStrWriter
.addString(Name
);
269 NameIndexOffset
= ItCache
->second
;
271 if (!NameToUse
.empty())
272 NameIndexOffset
= MainBinaryStrWriter
.addString(Name
);
273 It
.StrOffset
= NameIndexOffset
;
274 // This is the same hash function used in DWARF5AccelTableData.
275 It
.HashValue
= caseFoldingDjbHash(Name
);
280 std::optional
<BOLTDWARF5AccelTableData
*> DWARF5AcceleratorTable::addEntry(
281 DWARFUnit
&DU
, const DIE
&CurrDie
, const std::optional
<uint64_t> &DWOID
,
282 const std::optional
<BOLTDWARF5AccelTableData
*> &Parent
,
283 const std::optional
<std::string
> &Name
,
284 const uint32_t NumberParentsInChain
) {
288 auto &It
= Entries
[*Name
];
290 uint32_t DieTag
= CurrDie
.getTag();
291 uint32_t UnitID
= getUnitID(DU
, DWOID
, IsTU
);
292 std::optional
<unsigned> SecondIndex
= std::nullopt
;
294 auto Iter
= CUOffsetsToPatch
.find(*DWOID
);
295 if (Iter
== CUOffsetsToPatch
.end())
296 BC
.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "
297 "DWO ID in CU offsets for second Unit Index "
298 << *Name
<< ". For DIE at offset: "
299 << Twine::utohexstr(CurrentUnitOffset
+ CurrDie
.getOffset())
301 SecondIndex
= Iter
->second
;
303 std::optional
<uint64_t> ParentOffset
=
304 (Parent
? std::optional
<uint64_t>(getEntryID(**Parent
)) : std::nullopt
);
305 // This will be only populated in writeEntry, in order to keep only the parent
306 // entries, and keep the footprint down.
308 EntryRelativeOffsets
.insert({*ParentOffset
, 0});
309 bool IsParentRoot
= false;
310 // If there is no parent and no valid Entries in parent chain this is a root
311 // to be marked with a flag.
312 if (!Parent
&& !NumberParentsInChain
)
314 It
.Values
.push_back(new (Allocator
) BOLTDWARF5AccelTableData(
315 CurrDie
.getOffset(), ParentOffset
, DieTag
, UnitID
, IsParentRoot
, IsTU
,
317 return It
.Values
.back();
320 std::optional
<BOLTDWARF5AccelTableData
*>
321 DWARF5AcceleratorTable::processReferencedDie(
322 DWARFUnit
&Unit
, const DIE
&Die
, const std::optional
<uint64_t> &DWOID
,
323 const std::optional
<BOLTDWARF5AccelTableData
*> &Parent
,
324 const std::string
&NameToUse
, const uint32_t NumberParentsInChain
,
325 const dwarf::Attribute
&Attr
) {
326 DIEValue Value
= Die
.findAttribute(Attr
);
329 auto getReferenceDie
= [&](const DIEValue
&Value
, const DIE
*RefDieUsed
)
330 -> std::optional
<std::pair
<DWARFUnit
*, const DIE
*>> {
333 if (Value
.getForm() == dwarf::DW_FORM_ref_addr
) {
334 auto Iter
= CrossCUDies
.find(Value
.getDIEInteger().getValue());
335 if (Iter
== CrossCUDies
.end()) {
336 BC
.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "
337 "referenced DIE in CrossCUDies for "
338 << Twine::utohexstr(Value
.getDIEInteger().getValue())
344 const DIEEntry
&DIEENtry
= Value
.getDIEEntry();
345 return {{&Unit
, &DIEENtry
.getEntry()}};
348 DIEValue AttrValLinkageName
;
349 DIEValue AttrValName
= Die
.findAttribute(dwarf::Attribute::DW_AT_name
);
350 DWARFUnit
*RefUnit
= &Unit
;
351 const DIE
*RefDieUsed
= &Die
;
352 // It is possible to have DW_TAG_subprogram only with DW_AT_linkage_name that
353 // DW_AT_abstract_origin/DW_AT_specification point to.
354 while (!AttrValName
) {
355 std::optional
<std::pair
<DWARFUnit
*, const DIE
*>> RefDUDie
=
356 getReferenceDie(Value
, RefDieUsed
);
359 RefUnit
= RefDUDie
->first
;
360 const DIE
&RefDie
= *RefDUDie
->second
;
361 RefDieUsed
= &RefDie
;
362 if (!AttrValLinkageName
)
364 RefDie
.findAttribute(dwarf::Attribute::DW_AT_linkage_name
);
365 AttrValName
= RefDie
.findAttribute(dwarf::Attribute::DW_AT_name
);
366 Value
= RefDie
.findAttribute(dwarf::Attribute::DW_AT_abstract_origin
);
368 Value
= RefDie
.findAttribute(dwarf::Attribute::DW_AT_specification
);
370 addEntry(Unit
, Die
, DWOID
, Parent
,
371 getName(*RefUnit
, DWOID
, NameToUse
, AttrValLinkageName
),
372 NumberParentsInChain
);
373 return addEntry(Unit
, Die
, DWOID
, Parent
,
374 getName(*RefUnit
, DWOID
, NameToUse
, AttrValName
),
375 NumberParentsInChain
);
378 std::optional
<BOLTDWARF5AccelTableData
*>
379 DWARF5AcceleratorTable::addAccelTableEntry(
380 DWARFUnit
&Unit
, const DIE
&Die
, const std::optional
<uint64_t> &DWOID
,
381 const uint32_t NumberParentsInChain
,
382 std::optional
<BOLTDWARF5AccelTableData
*> &Parent
) {
383 if (Unit
.getVersion() < 5 || !NeedToCreate
)
385 std::string NameToUse
= "";
387 if (!canProcess(Unit
, Die
, NameToUse
, false))
390 // Adds a Unit to either CU, LocalTU or ForeignTU list the first time we
392 // Invoking it here so that we don't add Units that don't have any entries.
393 if (&Unit
!= CurrentUnit
) {
395 addUnit(Unit
, DWOID
);
398 // Minor optimization not to add entry twice for DW_TAG_namespace if it has no
400 std::optional
<BOLTDWARF5AccelTableData
*> LinkageEntry
= std::nullopt
;
401 DIEValue NameVal
= Die
.findAttribute(dwarf::Attribute::DW_AT_name
);
402 DIEValue LinkageNameVal
=
403 Die
.findAttribute(dwarf::Attribute::DW_AT_linkage_name
);
404 if (!(Die
.getTag() == dwarf::DW_TAG_namespace
&& !NameVal
))
405 LinkageEntry
= addEntry(Unit
, Die
, DWOID
, Parent
,
406 getName(Unit
, DWOID
, NameToUse
, LinkageNameVal
),
407 NumberParentsInChain
);
409 std::optional
<BOLTDWARF5AccelTableData
*> NameEntry
=
410 addEntry(Unit
, Die
, DWOID
, Parent
,
411 getName(Unit
, DWOID
, NameToUse
, NameVal
), NumberParentsInChain
);
415 // The DIE doesn't have DW_AT_name or DW_AT_linkage_name, so we need to see if
416 // we can follow other attributes to find them. For the purposes of
417 // determining whether a debug information entry has a particular
418 // attribute (such as DW_AT_name), if debug information entry A has a
419 // DW_AT_specification or DW_AT_abstract_origin attribute pointing to another
420 // debug information entry B, any attributes of B are considered to be
422 if (std::optional
<BOLTDWARF5AccelTableData
*> Entry
= processReferencedDie(
423 Unit
, Die
, DWOID
, Parent
, NameToUse
, NumberParentsInChain
,
424 dwarf::Attribute::DW_AT_abstract_origin
))
426 if (std::optional
<BOLTDWARF5AccelTableData
*> Entry
= processReferencedDie(
427 Unit
, Die
, DWOID
, Parent
, NameToUse
, NumberParentsInChain
,
428 dwarf::Attribute::DW_AT_specification
))
431 // This point can be hit by DW_TAG_varialbe that has no DW_AT_name.
435 /// Algorithm from llvm implementation.
436 void DWARF5AcceleratorTable::computeBucketCount() {
437 // First get the number of unique hashes.
438 std::vector
<uint32_t> Uniques
;
439 Uniques
.reserve(Entries
.size());
440 for (const auto &E
: Entries
)
441 Uniques
.push_back(E
.second
.HashValue
);
442 array_pod_sort(Uniques
.begin(), Uniques
.end());
443 std::vector
<uint32_t>::iterator P
=
444 std::unique(Uniques
.begin(), Uniques
.end());
446 UniqueHashCount
= std::distance(Uniques
.begin(), P
);
448 if (UniqueHashCount
> 1024)
449 BucketCount
= UniqueHashCount
/ 4;
450 else if (UniqueHashCount
> 16)
451 BucketCount
= UniqueHashCount
/ 2;
453 BucketCount
= std::max
<uint32_t>(UniqueHashCount
, 1);
456 /// Bucket code as in: AccelTableBase::finalize()
457 void DWARF5AcceleratorTable::finalize() {
460 // Figure out how many buckets we need, then compute the bucket contents and
461 // the final ordering. The hashes and offsets can be emitted by walking these
463 computeBucketCount();
465 // Compute bucket contents and final ordering.
466 Buckets
.resize(BucketCount
);
467 for (auto &E
: Entries
) {
468 uint32_t Bucket
= E
.second
.HashValue
% BucketCount
;
469 Buckets
[Bucket
].push_back(&E
.second
);
472 // Sort the contents of the buckets by hash value so that hash collisions end
473 // up together. Stable sort makes testing easier and doesn't cost much more.
474 for (HashList
&Bucket
: Buckets
) {
475 llvm::stable_sort(Bucket
, [](const HashData
*LHS
, const HashData
*RHS
) {
476 return LHS
->HashValue
< RHS
->HashValue
;
478 for (HashData
*H
: Bucket
)
479 llvm::stable_sort(H
->Values
, [](const BOLTDWARF5AccelTableData
*LHS
,
480 const BOLTDWARF5AccelTableData
*RHS
) {
481 return LHS
->getDieOffset() < RHS
->getDieOffset();
485 CUIndexForm
= DIEInteger::BestForm(/*IsSigned*/ false, CUList
.size() - 1);
486 TUIndexForm
= DIEInteger::BestForm(
487 /*IsSigned*/ false, LocalTUList
.size() + ForeignTUList
.size() - 1);
488 const dwarf::FormParams FormParams
{5, 4, dwarf::DwarfFormat::DWARF32
, false};
489 CUIndexEncodingSize
= *dwarf::getFixedFormByteSize(CUIndexForm
, FormParams
);
490 TUIndexEncodingSize
= *dwarf::getFixedFormByteSize(TUIndexForm
, FormParams
);
493 std::optional
<DWARF5AccelTable::UnitIndexAndEncoding
>
494 DWARF5AcceleratorTable::getIndexForEntry(
495 const BOLTDWARF5AccelTableData
&Value
) const {
496 // The foreign TU list immediately follows the local TU list and they both
497 // use the same index, so that if there are N local TU entries, the index for
498 // the first foreign TU is N.
500 return {{(Value
.getSecondUnitID() ? (unsigned)LocalTUList
.size() : 0) +
502 {dwarf::DW_IDX_type_unit
, TUIndexForm
}}};
503 if (CUList
.size() > 1)
504 return {{Value
.getUnitID(), {dwarf::DW_IDX_compile_unit
, CUIndexForm
}}};
508 std::optional
<DWARF5AccelTable::UnitIndexAndEncoding
>
509 DWARF5AcceleratorTable::getSecondIndexForEntry(
510 const BOLTDWARF5AccelTableData
&Value
) const {
511 if (Value
.isTU() && CUList
.size() > 1 && Value
.getSecondUnitID())
513 {*Value
.getSecondUnitID(), {dwarf::DW_IDX_compile_unit
, CUIndexForm
}}};
517 void DWARF5AcceleratorTable::populateAbbrevsMap() {
518 for (auto &Bucket
: getBuckets()) {
519 for (DWARF5AcceleratorTable::HashData
*Hash
: Bucket
) {
520 for (BOLTDWARF5AccelTableData
*Value
: Hash
->Values
) {
521 const std::optional
<DWARF5AccelTable::UnitIndexAndEncoding
> EntryRet
=
522 getIndexForEntry(*Value
);
523 // For entries that need to refer to the foreign type units and to
525 const std::optional
<DWARF5AccelTable::UnitIndexAndEncoding
>
526 SecondEntryRet
= getSecondIndexForEntry(*Value
);
527 DebugNamesAbbrev
Abbrev(Value
->getDieTag());
529 Abbrev
.addAttribute(EntryRet
->Encoding
);
531 Abbrev
.addAttribute(SecondEntryRet
->Encoding
);
532 Abbrev
.addAttribute({dwarf::DW_IDX_die_offset
, dwarf::DW_FORM_ref4
});
533 if (std::optional
<uint64_t> Offset
= Value
->getParentDieOffset())
534 Abbrev
.addAttribute({dwarf::DW_IDX_parent
, dwarf::DW_FORM_ref4
});
535 else if (Value
->isParentRoot())
537 {dwarf::DW_IDX_parent
, dwarf::DW_FORM_flag_present
});
541 if (DebugNamesAbbrev
*Existing
=
542 AbbreviationsSet
.FindNodeOrInsertPos(ID
, InsertPos
)) {
543 Value
->setAbbrevNumber(Existing
->getNumber());
546 DebugNamesAbbrev
*NewAbbrev
=
547 new (Alloc
) DebugNamesAbbrev(std::move(Abbrev
));
548 AbbreviationsVector
.push_back(NewAbbrev
);
549 NewAbbrev
->setNumber(AbbreviationsVector
.size());
550 AbbreviationsSet
.InsertNode(NewAbbrev
, InsertPos
);
551 Value
->setAbbrevNumber(NewAbbrev
->getNumber());
557 void DWARF5AcceleratorTable::writeEntry(BOLTDWARF5AccelTableData
&Entry
) {
558 const uint64_t EntryID
= getEntryID(Entry
);
559 if (EntryRelativeOffsets
.find(EntryID
) != EntryRelativeOffsets
.end())
560 EntryRelativeOffsets
[EntryID
] = EntriesBuffer
->size();
562 const std::optional
<DWARF5AccelTable::UnitIndexAndEncoding
> EntryRet
=
563 getIndexForEntry(Entry
);
564 // For forgeign type (FTU) units that need to refer to the FTU and to the CU.
565 const std::optional
<DWARF5AccelTable::UnitIndexAndEncoding
> SecondEntryRet
=
566 getSecondIndexForEntry(Entry
);
567 const unsigned AbbrevIndex
= Entry
.getAbbrevNumber() - 1;
568 assert(AbbrevIndex
< AbbreviationsVector
.size() &&
569 "Entry abbrev index is outside of abbreviations vector range.");
570 const DebugNamesAbbrev
*Abbrev
= AbbreviationsVector
[AbbrevIndex
];
571 encodeULEB128(Entry
.getAbbrevNumber(), *Entriestream
);
572 auto writeIndex
= [&](uint32_t Index
, uint32_t IndexSize
) -> void {
575 llvm_unreachable("Unsupported Index Size!");
578 support::endian::write(*Entriestream
, static_cast<uint8_t>(Index
),
579 llvm::endianness::little
);
582 support::endian::write(*Entriestream
, static_cast<uint16_t>(Index
),
583 llvm::endianness::little
);
586 support::endian::write(*Entriestream
, static_cast<uint32_t>(Index
),
587 llvm::endianness::little
);
592 for (const DebugNamesAbbrev::AttributeEncoding
&AttrEnc
:
593 Abbrev
->getAttributes()) {
594 switch (AttrEnc
.Index
) {
596 llvm_unreachable("Unexpected index attribute!");
599 case dwarf::DW_IDX_compile_unit
: {
600 const unsigned CUIndex
=
601 SecondEntryRet
? SecondEntryRet
->Index
: EntryRet
->Index
;
602 writeIndex(CUIndex
, CUIndexEncodingSize
);
605 case dwarf::DW_IDX_type_unit
: {
606 writeIndex(EntryRet
->Index
, TUIndexEncodingSize
);
609 case dwarf::DW_IDX_die_offset
: {
610 assert(AttrEnc
.Form
== dwarf::DW_FORM_ref4
);
611 support::endian::write(*Entriestream
,
612 static_cast<uint32_t>(Entry
.getDieOffset()),
613 llvm::endianness::little
);
616 case dwarf::DW_IDX_parent
: {
618 (AttrEnc
.Form
== dwarf::DW_FORM_ref4
&& Entry
.getParentDieOffset()) ||
619 AttrEnc
.Form
== dwarf::DW_FORM_flag_present
);
620 if (std::optional
<uint64_t> ParentOffset
= Entry
.getParentDieOffset()) {
621 Entry
.setPatchOffset(EntriesBuffer
->size());
622 support::endian::write(*Entriestream
, static_cast<uint32_t>(UINT32_MAX
),
623 llvm::endianness::little
);
631 void DWARF5AcceleratorTable::writeEntries() {
632 for (auto &Bucket
: getBuckets()) {
633 for (DWARF5AcceleratorTable::HashData
*Hash
: Bucket
) {
634 Hash
->EntryOffset
= EntriesBuffer
->size();
635 for (BOLTDWARF5AccelTableData
*Value
: Hash
->Values
) {
638 support::endian::write(*Entriestream
, static_cast<uint8_t>(0),
639 llvm::endianness::little
);
642 // Patching parent offsets.
643 for (auto &Bucket
: getBuckets()) {
644 for (DWARF5AcceleratorTable::HashData
*Hash
: Bucket
) {
645 for (BOLTDWARF5AccelTableData
*Entry
: Hash
->Values
) {
646 std::optional
<uint64_t> ParentOffset
= Entry
->getParentDieOffset();
649 if (const auto Iter
= EntryRelativeOffsets
.find(*ParentOffset
);
650 Iter
!= EntryRelativeOffsets
.end()) {
651 const uint64_t PatchOffset
= Entry
->getPatchOffset();
652 uint32_t *Ptr
= reinterpret_cast<uint32_t *>(
653 &EntriesBuffer
.get()->data()[PatchOffset
]);
656 BC
.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "
658 << *ParentOffset
<< "\n";
665 void DWARF5AcceleratorTable::writeAugmentationString() {
666 // String needs to be multiple of 4 bytes.
667 *AugStringtream
<< "BOLT";
668 AugmentationStringSize
= AugStringBuffer
->size();
671 /// Calculates size of .debug_names header without Length field.
672 static constexpr uint32_t getDebugNamesHeaderSize() {
673 constexpr uint16_t VersionLength
= sizeof(uint16_t);
674 constexpr uint16_t PaddingLength
= sizeof(uint16_t);
675 constexpr uint32_t CompUnitCountLength
= sizeof(uint32_t);
676 constexpr uint32_t LocalTypeUnitCountLength
= sizeof(uint32_t);
677 constexpr uint32_t ForeignTypeUnitCountLength
= sizeof(uint32_t);
678 constexpr uint32_t BucketCountLength
= sizeof(uint32_t);
679 constexpr uint32_t NameCountLength
= sizeof(uint32_t);
680 constexpr uint32_t AbbrevTableSizeLength
= sizeof(uint32_t);
681 constexpr uint32_t AugmentationStringSizeLenght
= sizeof(uint32_t);
682 return VersionLength
+ PaddingLength
+ CompUnitCountLength
+
683 LocalTypeUnitCountLength
+ ForeignTypeUnitCountLength
+
684 BucketCountLength
+ NameCountLength
+ AbbrevTableSizeLength
+
685 AugmentationStringSizeLenght
;
688 void DWARF5AcceleratorTable::emitHeader() const {
689 constexpr uint32_t HeaderSize
= getDebugNamesHeaderSize();
691 support::endian::write(*FullTableStream
,
692 static_cast<uint32_t>(HeaderSize
+ StrBuffer
->size() +
693 AugmentationStringSize
),
694 llvm::endianness::little
);
696 support::endian::write(*FullTableStream
, static_cast<uint16_t>(5),
697 llvm::endianness::little
);
699 support::endian::write(*FullTableStream
, static_cast<uint16_t>(0),
700 llvm::endianness::little
);
701 // Compilation Unit Count
702 support::endian::write(*FullTableStream
, static_cast<uint32_t>(CUList
.size()),
703 llvm::endianness::little
);
704 // Local Type Unit Count
705 support::endian::write(*FullTableStream
,
706 static_cast<uint32_t>(LocalTUList
.size()),
707 llvm::endianness::little
);
708 // Foreign Type Unit Count
709 support::endian::write(*FullTableStream
,
710 static_cast<uint32_t>(ForeignTUList
.size()),
711 llvm::endianness::little
);
713 support::endian::write(*FullTableStream
, static_cast<uint32_t>(BucketCount
),
714 llvm::endianness::little
);
716 support::endian::write(*FullTableStream
,
717 static_cast<uint32_t>(Entries
.size()),
718 llvm::endianness::little
);
720 support::endian::write(*FullTableStream
,
721 static_cast<uint32_t>(AbbrevTableSize
),
722 llvm::endianness::little
);
723 // Augmentation String Size
724 support::endian::write(*FullTableStream
,
725 static_cast<uint32_t>(AugmentationStringSize
),
726 llvm::endianness::little
);
728 emitAugmentationString();
729 FullTableStream
->write(StrBuffer
->data(), StrBuffer
->size());
732 void DWARF5AcceleratorTable::emitCUList() const {
733 for (const uint32_t CUID
: CUList
)
734 support::endian::write(*StrStream
, CUID
, llvm::endianness::little
);
736 void DWARF5AcceleratorTable::emitTUList() const {
737 for (const uint32_t TUID
: LocalTUList
)
738 support::endian::write(*StrStream
, TUID
, llvm::endianness::little
);
740 for (const uint64_t TUID
: ForeignTUList
)
741 support::endian::write(*StrStream
, TUID
, llvm::endianness::little
);
743 void DWARF5AcceleratorTable::emitBuckets() const {
745 for (const auto &Bucket
: enumerate(getBuckets())) {
746 const uint32_t TempIndex
= Bucket
.value().empty() ? 0 : Index
;
747 support::endian::write(*StrStream
, TempIndex
, llvm::endianness::little
);
748 Index
+= Bucket
.value().size();
751 void DWARF5AcceleratorTable::emitHashes() const {
752 for (const auto &Bucket
: getBuckets()) {
753 for (const DWARF5AcceleratorTable::HashData
*Hash
: Bucket
)
754 support::endian::write(*StrStream
, Hash
->HashValue
,
755 llvm::endianness::little
);
758 void DWARF5AcceleratorTable::emitStringOffsets() const {
759 for (const auto &Bucket
: getBuckets()) {
760 for (const DWARF5AcceleratorTable::HashData
*Hash
: Bucket
)
761 support::endian::write(*StrStream
, static_cast<uint32_t>(Hash
->StrOffset
),
762 llvm::endianness::little
);
765 void DWARF5AcceleratorTable::emitOffsets() const {
766 for (const auto &Bucket
: getBuckets()) {
767 for (const DWARF5AcceleratorTable::HashData
*Hash
: Bucket
)
768 support::endian::write(*StrStream
,
769 static_cast<uint32_t>(Hash
->EntryOffset
),
770 llvm::endianness::little
);
773 void DWARF5AcceleratorTable::emitAbbrevs() {
774 const uint32_t AbbrevTableStart
= StrBuffer
->size();
775 for (const auto *Abbrev
: AbbreviationsVector
) {
776 encodeULEB128(Abbrev
->getNumber(), *StrStream
);
777 encodeULEB128(Abbrev
->getDieTag(), *StrStream
);
778 for (const auto &AttrEnc
: Abbrev
->getAttributes()) {
779 encodeULEB128(AttrEnc
.Index
, *StrStream
);
780 encodeULEB128(AttrEnc
.Form
, *StrStream
);
782 encodeULEB128(0, *StrStream
);
783 encodeULEB128(0, *StrStream
);
785 encodeULEB128(0, *StrStream
);
786 AbbrevTableSize
= StrBuffer
->size() - AbbrevTableStart
;
788 void DWARF5AcceleratorTable::emitData() {
789 StrStream
->write(EntriesBuffer
->data(), EntriesBuffer
->size());
791 void DWARF5AcceleratorTable::emitAugmentationString() const {
792 FullTableStream
->write(AugStringBuffer
->data(), AugStringBuffer
->size());
794 void DWARF5AcceleratorTable::emitAccelTable() {
798 populateAbbrevsMap();
800 writeAugmentationString();