Skip to content

Commit 6de5fcc

Browse files
authored
[BOLT][DWARF] Add support for .debug_names (llvm#81062)
DWARF5 spec supports the .debug_names acceleration table. This is the formalized version of combination of gdb-index/pubnames/types. Added implementation of it to BOLT. It supports both monolothic and split dwarf, with and without Type Units. It does not include parent indices. This will be in followup PR. Unlike LLVM output this will put all the CUs and TUs into one Module.
1 parent 21d8332 commit 6de5fcc

27 files changed

+6571
-29
lines changed

bolt/include/bolt/Core/BinaryContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,10 @@ class BinaryContext {
997997
return getUniqueSectionByName(".gdb_index");
998998
}
999999

1000+
ErrorOr<BinarySection &> getDebugNamesSection() const {
1001+
return getUniqueSectionByName(".debug_names");
1002+
}
1003+
10001004
/// @}
10011005

10021006
/// Register \p TargetFunction as a fragment of \p Function if checks pass:

bolt/include/bolt/Core/DIEBuilder.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define BOLT_CORE_DIE_BUILDER_H
1717

1818
#include "bolt/Core/BinaryContext.h"
19+
#include "bolt/Core/DebugNames.h"
1920
#include "llvm/CodeGen/DIE.h"
2021
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
2122
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
@@ -127,6 +128,7 @@ class DIEBuilder {
127128
DWARFUnit *SkeletonCU{nullptr};
128129
uint64_t UnitSize{0};
129130
llvm::DenseSet<uint64_t> AllProcessed;
131+
DWARF5AcceleratorTable &DebugNamesTable;
130132

131133
/// Returns current state of the DIEBuilder
132134
State &getState() { return *BuilderState.get(); }
@@ -206,8 +208,8 @@ class DIEBuilder {
206208
/// Update references once the layout is finalized.
207209
void updateReferences();
208210

209-
/// Update the Offset and Size of DIE.
210-
uint32_t computeDIEOffset(const DWARFUnit &CU, DIE &Die, uint32_t &CurOffset);
211+
/// Update the Offset and Size of DIE, populate DebugNames table.
212+
uint32_t finalizeDIEs(DWARFUnit &CU, DIE &Die, uint32_t &CurOffset);
211213

212214
void registerUnit(DWARFUnit &DU, bool NeedSort);
213215

@@ -269,6 +271,7 @@ class DIEBuilder {
269271

270272
public:
271273
DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext,
274+
DWARF5AcceleratorTable &DebugNamesTable,
272275
DWARFUnit *SkeletonCU = nullptr);
273276

274277
/// Returns enum to what we are currently processing.

bolt/include/bolt/Core/DebugData.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,8 @@ class DebugStrOffsetsWriter {
439439
/// Update Str offset in .debug_str in .debug_str_offsets.
440440
void updateAddressMap(uint32_t Index, uint32_t Address);
441441

442+
/// Get offset for given index in original .debug_str_offsets section.
443+
uint64_t getOffset(uint32_t Index) const { return StrOffsets[Index]; }
442444
/// Writes out current sections entry into .debug_str_offsets.
443445
void finalizeSection(DWARFUnit &Unit, DIEBuilder &DIEBldr);
444446

@@ -463,7 +465,7 @@ class DebugStrOffsetsWriter {
463465
std::unique_ptr<DebugStrOffsetsBufferVector> StrOffsetsBuffer;
464466
std::unique_ptr<raw_svector_ostream> StrOffsetsStream;
465467
std::map<uint32_t, uint32_t> IndexToAddressMap;
466-
std::vector<uint32_t> StrOffsets;
468+
SmallVector<uint32_t, 5> StrOffsets;
467469
std::unordered_map<uint64_t, uint64_t> ProcessedBaseOffsets;
468470
bool StrOffsetSectionWasModified = false;
469471
};
@@ -484,11 +486,12 @@ class DebugStrWriter {
484486
/// Returns False if no strings were added to .debug_str.
485487
bool isInitialized() const { return !StrBuffer->empty(); }
486488

489+
/// Initializes Buffer and Stream.
490+
void initialize();
491+
487492
private:
488493
/// Mutex used for parallel processing of debug info.
489494
std::mutex WriterMutex;
490-
/// Initializes Buffer and Stream.
491-
void initialize();
492495
/// Creates internal data structures.
493496
void create();
494497
std::unique_ptr<DebugStrBufferVector> StrBuffer;

bolt/include/bolt/Core/DebugNames.h

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//===- bolt/Core/DebugNames.h - Debug names support ---*- 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+
// This file contains declaration of classes required for generation of
10+
// .debug_names section.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef BOLT_CORE_DEBUG_NAMES_H
15+
#define BOLT_CORE_DEBUG_NAMES_H
16+
17+
#include "DebugData.h"
18+
#include "llvm/CodeGen/AccelTable.h"
19+
20+
namespace llvm {
21+
namespace bolt {
22+
class BOLTDWARF5AccelTableData : public DWARF5AccelTableData {
23+
public:
24+
BOLTDWARF5AccelTableData(const uint64_t DieOffset,
25+
const std::optional<uint64_t> DefiningParentOffset,
26+
const unsigned DieTag, const unsigned UnitID,
27+
const bool IsTU,
28+
const std::optional<unsigned> SecondUnitID)
29+
: DWARF5AccelTableData(DieOffset, DefiningParentOffset, DieTag, UnitID,
30+
IsTU),
31+
SecondUnitID(SecondUnitID) {}
32+
33+
uint64_t getDieOffset() const { return DWARF5AccelTableData::getDieOffset(); }
34+
unsigned getDieTag() const { return DWARF5AccelTableData::getDieTag(); }
35+
unsigned getUnitID() const { return DWARF5AccelTableData::getUnitID(); }
36+
bool isTU() const { return DWARF5AccelTableData::isTU(); }
37+
std::optional<unsigned> getSecondUnitID() const { return SecondUnitID; }
38+
39+
private:
40+
std::optional<unsigned> SecondUnitID;
41+
};
42+
43+
class DWARF5AcceleratorTable {
44+
public:
45+
DWARF5AcceleratorTable(const bool CreateDebugNames, BinaryContext &BC,
46+
DebugStrWriter &MainBinaryStrWriter);
47+
~DWARF5AcceleratorTable() {
48+
for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)
49+
Abbrev->~DebugNamesAbbrev();
50+
}
51+
/// Add DWARF5 Accelerator table entry.
52+
/// Input is DWARFUnit being processed, DIE that belongs to it, and potential
53+
/// SkeletonCU if the Unit comes from a DWO section.
54+
void addAccelTableEntry(DWARFUnit &Unit, const DIE &Die,
55+
const std::optional<uint64_t> &DWOID);
56+
/// Set current unit being processed.
57+
void setCurrentUnit(DWARFUnit &Unit, const uint64_t UnitStartOffset);
58+
/// Emit Accelerator table.
59+
void emitAccelTable();
60+
/// Returns true if the table was crated.
61+
bool isCreated() const { return NeedToCreate; }
62+
/// Returns buffer containing the accelerator table.
63+
std::unique_ptr<DebugBufferVector> releaseBuffer() {
64+
return std::move(FullTableBuffer);
65+
}
66+
67+
private:
68+
BinaryContext &BC;
69+
bool NeedToCreate = false;
70+
BumpPtrAllocator Allocator;
71+
DebugStrWriter &MainBinaryStrWriter;
72+
StringRef StrSection;
73+
uint64_t CurrentUnitOffset = 0;
74+
const DWARFUnit *CurrentUnit = nullptr;
75+
std::unordered_map<uint32_t, uint32_t> AbbrevTagToIndexMap;
76+
77+
/// Represents a group of entries with identical name (and hence, hash value).
78+
struct HashData {
79+
uint64_t StrOffset;
80+
uint32_t HashValue;
81+
uint32_t EntryOffset;
82+
std::vector<BOLTDWARF5AccelTableData *> Values;
83+
};
84+
using HashList = std::vector<HashData *>;
85+
using BucketList = std::vector<HashList>;
86+
/// Contains all the offsets of CUs.
87+
SmallVector<uint32_t, 1> CUList;
88+
/// Contains all the offsets of local TUs.
89+
SmallVector<uint32_t, 1> LocalTUList;
90+
/// Contains all the type hashes for split dwarf TUs.
91+
SmallVector<uint64_t, 1> ForeignTUList;
92+
using StringEntries =
93+
MapVector<std::string, HashData, llvm::StringMap<unsigned>>;
94+
StringEntries Entries;
95+
/// FoldingSet that uniques the abbreviations.
96+
FoldingSet<DebugNamesAbbrev> AbbreviationsSet;
97+
/// Vector containing DebugNames abbreviations for iteration in order.
98+
SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;
99+
/// The bump allocator to use when creating DIEAbbrev objects in the uniqued
100+
/// storage container.
101+
BumpPtrAllocator Alloc;
102+
uint32_t BucketCount = 0;
103+
uint32_t UniqueHashCount = 0;
104+
uint32_t AbbrevTableSize = 0;
105+
uint32_t CUIndexEncodingSize = 4;
106+
uint32_t TUIndexEncodingSize = 4;
107+
uint32_t AugmentationStringSize = 0;
108+
dwarf::Form CUIndexForm = dwarf::DW_FORM_data4;
109+
dwarf::Form TUIndexForm = dwarf::DW_FORM_data4;
110+
111+
BucketList Buckets;
112+
113+
std::unique_ptr<DebugBufferVector> FullTableBuffer;
114+
std::unique_ptr<raw_svector_ostream> FullTableStream;
115+
std::unique_ptr<DebugBufferVector> StrBuffer;
116+
std::unique_ptr<raw_svector_ostream> StrStream;
117+
std::unique_ptr<DebugBufferVector> EntriesBuffer;
118+
std::unique_ptr<raw_svector_ostream> Entriestream;
119+
std::unique_ptr<DebugBufferVector> AugStringBuffer;
120+
std::unique_ptr<raw_svector_ostream> AugStringtream;
121+
llvm::DenseMap<llvm::hash_code, uint64_t> StrCacheToOffsetMap;
122+
// Contains DWO ID to CUList Index.
123+
llvm::DenseMap<uint64_t, uint32_t> CUOffsetsToPatch;
124+
/// Adds Unit to either CUList, LocalTUList or ForeignTUList.
125+
/// Input Unit being processed, and DWO ID if Unit is being processed comes
126+
/// from a DWO section.
127+
void addUnit(DWARFUnit &Unit, const std::optional<uint64_t> &DWOID);
128+
/// Returns number of buckets in .debug_name table.
129+
ArrayRef<HashList> getBuckets() const { return Buckets; }
130+
/// Get encoding for a given attribute.
131+
std::optional<DWARF5AccelTable::UnitIndexAndEncoding>
132+
getIndexForEntry(const BOLTDWARF5AccelTableData &Value) const;
133+
/// Get encoding for a given attribute for second index.
134+
/// Returns nullopt if there is no second index.
135+
std::optional<DWARF5AccelTable::UnitIndexAndEncoding>
136+
getSecondIndexForEntry(const BOLTDWARF5AccelTableData &Value) const;
137+
/// Uniquify Entries.
138+
void finalize();
139+
/// Computes bucket count.
140+
void computeBucketCount();
141+
/// Populate Abbreviations Map.
142+
void populateAbbrevsMap();
143+
/// Write Entries.
144+
void writeEntries();
145+
/// Write an Entry.
146+
void writeEntry(const BOLTDWARF5AccelTableData &Entry);
147+
/// Write augmentation_string for BOLT.
148+
void writeAugmentationString();
149+
/// Emit out Header for DWARF5 Accelerator table.
150+
void emitHeader() const;
151+
/// Emit out CU list.
152+
void emitCUList() const;
153+
/// Emit out TU List. Combination of LocalTUList and ForeignTUList.
154+
void emitTUList() const;
155+
/// Emit buckets.
156+
void emitBuckets() const;
157+
/// Emit hashes for hash table.
158+
void emitHashes() const;
159+
/// Emit string offsets for hash table.
160+
void emitStringOffsets() const;
161+
/// Emit Entry Offsets for hash table.
162+
void emitOffsets() const;
163+
/// Emit abbreviation table.
164+
void emitAbbrevs();
165+
/// Emit entries.
166+
void emitData();
167+
/// Emit augmentation string.
168+
void emitAugmentationString() const;
169+
};
170+
} // namespace bolt
171+
} // namespace llvm
172+
#endif

bolt/include/bolt/Rewrite/DWARFRewriter.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "bolt/Core/DIEBuilder.h"
1313
#include "bolt/Core/DebugData.h"
14+
#include "bolt/Core/DebugNames.h"
1415
#include "llvm/ADT/StringRef.h"
1516
#include "llvm/CodeGen/DIE.h"
1617
#include "llvm/DWP/DWP.h"
@@ -140,8 +141,10 @@ class DWARFRewriter {
140141
const std::list<DWARFUnit *> &CUs);
141142

142143
/// Finalize debug sections in the main binary.
143-
void finalizeDebugSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
144-
raw_svector_ostream &ObjOS, CUOffsetMap &CUMap);
144+
void finalizeDebugSections(DIEBuilder &DIEBlder,
145+
DWARF5AcceleratorTable &DebugNamesTable,
146+
DIEStreamer &Streamer, raw_svector_ostream &ObjOS,
147+
CUOffsetMap &CUMap);
145148

146149
/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
147150
/// blocks) to be updated.

bolt/lib/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ add_llvm_library(LLVMBOLTCore
2020
BinaryFunctionProfile.cpp
2121
BinarySection.cpp
2222
DebugData.cpp
23+
DebugNames.cpp
2324
DIEBuilder.cpp
2425
DynoStats.cpp
2526
Exceptions.cpp

bolt/lib/Core/DIEBuilder.cpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,17 @@
1919
#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
2020
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
2121
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
22-
#include "llvm/ObjectYAML/DWARFYAML.h"
2322
#include "llvm/Support/Casting.h"
2423
#include "llvm/Support/Debug.h"
2524
#include "llvm/Support/ErrorHandling.h"
2625
#include "llvm/Support/Format.h"
2726
#include "llvm/Support/LEB128.h"
28-
#include "llvm/Support/ThreadPool.h"
29-
#include "llvm/Support/YAMLTraits.h"
3027

3128
#include <algorithm>
3229
#include <cstdint>
3330
#include <memory>
3431
#include <mutex>
35-
#include <string>
32+
#include <optional>
3633
#include <unordered_map>
3734
#include <utility>
3835
#include <vector>
@@ -179,8 +176,10 @@ void DIEBuilder::constructFromUnit(DWARFUnit &DU) {
179176
}
180177

181178
DIEBuilder::DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext,
179+
DWARF5AcceleratorTable &DebugNamesTable,
182180
DWARFUnit *SkeletonCU)
183-
: BC(BC), DwarfContext(DwarfContext), SkeletonCU(SkeletonCU) {}
181+
: BC(BC), DwarfContext(DwarfContext), SkeletonCU(SkeletonCU),
182+
DebugNamesTable(DebugNamesTable) {}
184183

185184
static unsigned int getCUNum(DWARFContext *DwarfContext, bool IsDWO) {
186185
unsigned int CUNum = IsDWO ? DwarfContext->getNumDWOCompileUnits()
@@ -378,18 +377,20 @@ getUnitForOffset(DIEBuilder &Builder, DWARFContext &DWCtx,
378377
return nullptr;
379378
}
380379

381-
uint32_t DIEBuilder::computeDIEOffset(const DWARFUnit &CU, DIE &Die,
382-
uint32_t &CurOffset) {
380+
uint32_t DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die,
381+
uint32_t &CurOffset) {
383382
getState().DWARFDieAddressesParsed.erase(Die.getOffset());
384383
uint32_t CurSize = 0;
385384
Die.setOffset(CurOffset);
385+
DebugNamesTable.addAccelTableEntry(
386+
CU, Die, SkeletonCU ? SkeletonCU->getDWOId() : std::nullopt);
386387
for (DIEValue &Val : Die.values())
387388
CurSize += Val.sizeOf(CU.getFormParams());
388389
CurSize += getULEB128Size(Die.getAbbrevNumber());
389390
CurOffset += CurSize;
390391

391392
for (DIE &Child : Die.children()) {
392-
uint32_t ChildSize = computeDIEOffset(CU, Child, CurOffset);
393+
uint32_t ChildSize = finalizeDIEs(CU, Child, CurOffset);
393394
CurSize += ChildSize;
394395
}
395396
// for children end mark.
@@ -404,12 +405,12 @@ uint32_t DIEBuilder::computeDIEOffset(const DWARFUnit &CU, DIE &Die,
404405
}
405406

406407
void DIEBuilder::finish() {
407-
auto computeOffset = [&](const DWARFUnit &CU,
408-
uint64_t &UnitStartOffset) -> void {
408+
auto finalizeCU = [&](DWARFUnit &CU, uint64_t &UnitStartOffset) -> void {
409409
DIE *UnitDIE = getUnitDIEbyUnit(CU);
410410
uint32_t HeaderSize = CU.getHeaderSize();
411411
uint32_t CurOffset = HeaderSize;
412-
computeDIEOffset(CU, *UnitDIE, CurOffset);
412+
DebugNamesTable.setCurrentUnit(CU, UnitStartOffset);
413+
finalizeDIEs(CU, *UnitDIE, CurOffset);
413414

414415
DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(CU);
415416
CurUnitInfo.UnitOffset = UnitStartOffset;
@@ -420,18 +421,18 @@ void DIEBuilder::finish() {
420421
// It's processed first when CU is registered so will be at the begginnig of
421422
// the vector.
422423
uint64_t TypeUnitStartOffset = 0;
423-
for (const DWARFUnit *CU : getState().DUList) {
424+
for (DWARFUnit *CU : getState().DUList) {
424425
// We process DWARF$ types first.
425426
if (!(CU->getVersion() < 5 && CU->isTypeUnit()))
426427
break;
427-
computeOffset(*CU, TypeUnitStartOffset);
428+
finalizeCU(*CU, TypeUnitStartOffset);
428429
}
429430

430-
for (const DWARFUnit *CU : getState().DUList) {
431+
for (DWARFUnit *CU : getState().DUList) {
431432
// Skipping DWARF4 types.
432433
if (CU->getVersion() < 5 && CU->isTypeUnit())
433434
continue;
434-
computeOffset(*CU, UnitSize);
435+
finalizeCU(*CU, UnitSize);
435436
}
436437
if (opts::Verbosity >= 1) {
437438
if (!getState().DWARFDieAddressesParsed.empty())

0 commit comments

Comments
 (0)