Skip to content

Commit 7f6b147

Browse files
committed
[BOLT][DWARF] Add support for .debug_names
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 3647ff1 commit 7f6b147

28 files changed

+6639
-38
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: 10 additions & 3 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"
@@ -124,9 +125,10 @@ class DIEBuilder {
124125
std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
125126
BinaryContext &BC;
126127
DWARFContext *DwarfContext{nullptr};
127-
bool IsDWO{false};
128+
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(); }
@@ -207,7 +209,7 @@ class DIEBuilder {
207209
void updateReferences();
208210

209211
/// Update the Offset and Size of DIE.
210-
uint32_t computeDIEOffset(const DWARFUnit &CU, DIE &Die, uint32_t &CurOffset);
212+
uint32_t computeDIEOffset(DWARFUnit &CU, DIE &Die, uint32_t &CurOffset);
211213

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

@@ -264,8 +266,13 @@ class DIEBuilder {
264266
/// current Section.
265267
DIE *constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId);
266268

269+
/// Returns true if this DIEBUilder is for DWO Unit.
270+
bool isDWO() const { return SkeletonCU != nullptr; }
271+
267272
public:
268-
DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext, bool IsDWO = false);
273+
DIEBuilder(BinaryContext &BC, DWARFContext *DwarfContext,
274+
DWARF5AcceleratorTable &DebugNamesTable,
275+
DWARFUnit *SkeletonCU = nullptr);
269276

270277
/// Returns enum to what we are currently processing.
271278
ProcessingType getCurrentProcessingState() { return getState().Type; }

bolt/include/bolt/Core/DebugData.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,12 @@ 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 {
444+
assert(StrOffsets.size() > Index && "Index is out of bounds.");
445+
return StrOffsets[Index];
446+
}
447+
442448
/// Writes out current sections entry into .debug_str_offsets.
443449
void finalizeSection(DWARFUnit &Unit, DIEBuilder &DIEBldr);
444450

@@ -450,10 +456,16 @@ class DebugStrOffsetsWriter {
450456
return std::move(StrOffsetsBuffer);
451457
}
452458

453-
private:
454459
/// Initializes Buffer and Stream.
455460
void initialize(DWARFUnit &Unit);
456461

462+
/// Clear data.
463+
void clear() {
464+
IndexToAddressMap.clear();
465+
StrOffsets.clear();
466+
}
467+
468+
private:
457469
std::unique_ptr<DebugStrOffsetsBufferVector> StrOffsetsBuffer;
458470
std::unique_ptr<raw_svector_ostream> StrOffsetsStream;
459471
std::map<uint32_t, uint32_t> IndexToAddressMap;
@@ -478,11 +490,12 @@ class DebugStrWriter {
478490
/// Returns False if no strings were added to .debug_str.
479491
bool isInitialized() const { return !StrBuffer->empty(); }
480492

493+
/// Initializes Buffer and Stream.
494+
void initialize();
495+
481496
private:
482497
/// Mutex used for parallel processing of debug info.
483498
std::mutex WriterMutex;
484-
/// Initializes Buffer and Stream.
485-
void initialize();
486499
/// Creates internal data structures.
487500
void create();
488501
std::unique_ptr<DebugStrBufferVector> StrBuffer;
@@ -798,6 +811,7 @@ class DwarfLineTable {
798811
// Returns DWARF Version for this line table.
799812
uint16_t getDwarfVersion() const { return DwarfVersion; }
800813
};
814+
801815
} // namespace bolt
802816
} // namespace llvm
803817

bolt/include/bolt/Core/DebugNames.h

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

0 commit comments

Comments
 (0)