Skip to content

Commit 9dc8694

Browse files
committed
Simplify and optimize .debug_names and removed dead TU code
[ELF] Add --debug-names to create merged .debug_names `clang -g -gpubnames` (with optional -gsplit-dwarf) creates the `.debug_names` section ("per-CU" index). By default lld concatenates input `.debug_names` sections into an output `.debug_names` section. LLDB can consume the concatenated section but the lookup performance is not good. This patch adds --debug-names to create a per-module index by combining the per-CU indexes into a single index that covers the entire load module. The produced `.debug_names` is a replacement for `.gdb_index`. Type units (-fdebug-types-section) are not handled yet. Co-authored-by: Fangrui Song <[email protected]>
1 parent c8b6904 commit 9dc8694

18 files changed

+1170
-1267
lines changed

lld/ELF/SyntheticSections.cpp

Lines changed: 521 additions & 689 deletions
Large diffs are not rendered by default.

lld/ELF/SyntheticSections.h

Lines changed: 81 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -793,35 +793,19 @@ class RelroPaddingSection final : public SyntheticSection {
793793
void writeTo(uint8_t *buf) override {}
794794
};
795795

796-
template <class ELFT> class DebugNamesSection final : public SyntheticSection {
797-
// N.B. Everything in this class assumes that we are using DWARF32.
798-
// If we move to DWARF64, most of this data will need to be re-sized,
799-
// and the code that handles or manipulates it will need to be updated
800-
// accordingly.
801-
796+
// Used by the merged DWARF32 .debug_names (a per-module index). If we
797+
// move to DWARF64, most of this data will need to be re-sized.
798+
class DebugNamesBaseSection : public SyntheticSection {
802799
public:
803-
DebugNamesSection();
804-
static DebugNamesSection *create();
805-
void writeTo(uint8_t *buf) override;
806-
size_t getSize() const override { return sectionSize; }
807-
bool isNeeded() const override;
808-
809-
template <class RelTy>
810-
void getNameRelocsImpl(InputSection *sec, ArrayRef<RelTy> rels,
811-
llvm::DenseMap<uint32_t, uint32_t> &relocs);
812-
813-
void getNameRelocs(InputSectionBase *base,
814-
llvm::DenseMap<uint32_t, uint32_t> &relocs);
815-
816-
struct Abbrev : public llvm::FoldingSetNode {
800+
struct Abbrev : llvm::FoldingSetNode {
817801
uint32_t code;
818802
uint32_t tag;
819803
SmallVector<llvm::DWARFDebugNames::AttributeEncoding, 2> attributes;
820804

821805
void Profile(llvm::FoldingSetNodeID &id) const;
822806
};
823807

824-
struct AttrValueData {
808+
struct AttrValue {
825809
uint32_t attrValue;
826810
uint8_t attrSize;
827811
};
@@ -830,86 +814,103 @@ template <class ELFT> class DebugNamesSection final : public SyntheticSection {
830814
uint32_t abbrevCode;
831815
uint32_t poolOffset;
832816
union {
833-
int32_t parentOffset = -1;
817+
uint64_t parentOffset = 0;
834818
IndexEntry *parentEntry;
835819
};
836-
SmallVector<AttrValueData, 3> attrValues;
820+
SmallVector<AttrValue, 3> attrValues;
837821
};
838822

839-
struct NamedEntry {
823+
struct NameEntry {
840824
const char *name;
841825
uint32_t hashValue;
842-
uint32_t stringOffsetOffset;
826+
uint32_t stringOffset;
843827
uint32_t entryOffset;
844-
uint32_t relocatedEntryOffset;
845-
// The index of the chunk that 'name' points into, for looking up
846-
// relocation data for this string.
828+
// Used to relocate `stringOffset` in the merged section.
847829
uint32_t chunkIdx;
848-
SmallVector<std::unique_ptr<IndexEntry>, 0> indexEntries;
849-
};
830+
SmallVector<IndexEntry *, 0> indexEntries;
850831

851-
struct SectionOffsetLocs {
852-
uint64_t stringOffsetsBase;
853-
uint64_t entryOffsetsBase;
854-
uint64_t entriesBase;
832+
llvm::iterator_range<
833+
llvm::pointee_iterator<typename SmallVector<IndexEntry *, 0>::iterator>>
834+
entries() {
835+
return llvm::make_pointee_range(indexEntries);
836+
}
855837
};
856838

857-
struct DebugNamesSectionData {
839+
// One name index described by an input .debug_names section. An InputChunk
840+
// typically contains one single name index.
841+
struct NameData {
858842
llvm::DWARFDebugNames::Header hdr;
859-
llvm::DWARFDebugNames::DWARFDebugNamesOffsets locs;
860-
SmallVector<uint32_t, 0> tuOffsets;
861-
SmallVector<Abbrev, 0> abbrevTable;
862-
SmallVector<uint32_t, 0> entryOffsets;
863-
SmallVector<NamedEntry, 0> namedEntries;
864-
uint16_t dwarfSize;
865-
uint16_t hdrSize;
843+
llvm::DenseMap<uint32_t, uint32_t> abbrevCodeMap;
844+
SmallVector<NameEntry, 0> nameEntries;
866845
};
867846

868-
// Per-file data used, while reading in the data, to generate the merged
869-
// section information.
870-
struct DebugNamesInputChunk {
871-
uint32_t baseCuOffsetIdx;
872-
std::unique_ptr<llvm::DWARFDebugNames> debugNamesData;
873-
std::unique_ptr<LLDDWARFSection> namesSection;
874-
SmallVector<DebugNamesSectionData, 0> sectionsData;
875-
SmallVector<uint32_t, 0> hashValues;
876-
llvm::DenseMap<uint32_t, uint32_t> abbrevCodeMap;
847+
// InputChunk and OutputChunk hold per-file contribution to the merged index.
848+
// InputChunk instances will be discarded after `create` completes.
849+
struct InputChunk {
850+
uint32_t baseCuIdx;
851+
LLDDWARFSection section;
852+
SmallVector<NameData, 0> nameData;
853+
std::optional<llvm::DWARFDebugNames> llvmDebugNames;
877854
};
878855

879-
// Per-file data needed for correctly writing out the .debug_names section.
880-
struct DebugNamesOutputChunk {
881-
// Pointer to .debug_info section for this chunk/file, used for
882-
// calculating correct relocated CU offsets in the merged index.
883-
InputSection *sec;
884-
SmallVector<uint32_t, 0> compilationUnits;
885-
SmallVector<uint32_t, 0> typeUnits;
856+
struct OutputChunk {
857+
// Pointer to the .debug_info section that contains compile units, used to
858+
// compute the relocated CU offsets.
859+
InputSection *infoSec;
860+
SmallVector<uint32_t, 0> compUnits;
886861
};
887862

888-
void collectMergedCounts(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
889-
std::pair<uint8_t, llvm::dwarf::Form> getMergedCuSizeData();
890-
void getMergedAbbrevTable(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
891-
void getMergedSymbols(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
892-
void computeUniqueHashes(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
893-
void generateBuckets();
894-
void calculateEntriesSizeAndOffsets();
895-
void updateParentIndexEntries();
896-
uint64_t calculateMergedSectionSize();
863+
DebugNamesBaseSection();
864+
size_t getSize() const override { return size; }
865+
bool isNeeded() const override { return numChunks > 0; }
897866

867+
protected:
868+
void init(llvm::function_ref<void(InputFile *, InputChunk &, OutputChunk &)>);
869+
static void
870+
parseDebugNames(InputChunk &inputChunk, OutputChunk &chunk,
871+
llvm::DWARFDataExtractor &namesExtractor,
872+
llvm::DataExtractor &strExtractor,
873+
llvm::function_ref<SmallVector<uint32_t, 0>(
874+
const llvm::DWARFDebugNames::Header &hdr,
875+
const llvm::DWARFDebugNames::DWARFDebugNamesOffsets &)>
876+
readOffsets);
877+
void computeHdrAndAbbrevTable(MutableArrayRef<InputChunk>);
878+
std::pair<uint32_t, uint32_t> computeEntryPool(MutableArrayRef<InputChunk>);
879+
880+
// Input .debug_names sections for relocating string offsets in the name table
881+
// in finalizeContents.
882+
SmallVector<InputSection *, 0> inputSections;
883+
884+
llvm::DWARFDebugNames::Header hdr;
885+
size_t numChunks;
886+
std::unique_ptr<OutputChunk[]> chunks;
898887
llvm::SpecificBumpPtrAllocator<Abbrev> abbrevAlloc;
888+
SmallVector<Abbrev *, 0> abbrevTable;
889+
SmallVector<char, 0> abbrevTableBuf;
890+
891+
// Sharded name entries that will be used to compute bucket_count and the
892+
// count name table.
893+
static constexpr size_t numShards = 32;
894+
SmallVector<NameEntry, 0> nameVecs[numShards];
895+
};
896+
897+
// Complement DebugNamesBaseSection for ELFT-aware code: reading offsets,
898+
// relocating string offsets, and writeTo.
899+
template <class ELFT>
900+
class DebugNamesSection final : public DebugNamesBaseSection {
901+
public:
902+
DebugNamesSection();
903+
void finalizeContents() override;
904+
void writeTo(uint8_t *buf) override;
905+
906+
template <class RelTy>
907+
void getNameRelocs(InputSection *sec, ArrayRef<RelTy> rels,
908+
llvm::DenseMap<uint32_t, uint32_t> &relocs);
899909

900910
private:
901-
size_t sectionSize;
902-
uint32_t mergedTotalEntriesSize;
903-
uint32_t numChunks;
904-
llvm::DWARFDebugNames::DWARFDebugNamesOffsets mergedOffsets;
905-
std::unique_ptr<DebugNamesOutputChunk[]> outputChunks;
906-
// Pointers to the original .debug_names sections; used for find the correct'
907-
// string relocation values when writing out the merged index.
908-
SmallVector<InputSectionBase *, 0> inputDebugNamesSections;
909-
llvm::DWARFDebugNames::Header mergedHdr;
910-
SmallVector<Abbrev *, 0> mergedAbbrevTable;
911-
SmallVector<NamedEntry, 0> mergedEntries;
912-
SmallVector<SmallVector<NamedEntry *, 0>, 0> bucketList;
911+
static void readOffsets(InputChunk &inputChunk, OutputChunk &chunk,
912+
llvm::DWARFDataExtractor &namesExtractor,
913+
llvm::DataExtractor &strExtractor);
913914
};
914915

915916
class GdbIndexSection final : public SyntheticSection {
@@ -1487,6 +1488,7 @@ struct InStruct {
14871488
std::unique_ptr<IBTPltSection> ibtPlt;
14881489
std::unique_ptr<RelocationBaseSection> relaPlt;
14891490
// Non-SHF_ALLOC sections
1491+
std::unique_ptr<SyntheticSection> debugNames;
14901492
std::unique_ptr<GdbIndexSection> gdbIndex;
14911493
std::unique_ptr<StringTableSection> shStrTab;
14921494
std::unique_ptr<StringTableSection> strTab;

lld/ELF/Writer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,6 +1957,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
19571957
// finalizeAddressDependentContent may have added local symbols to the
19581958
// static symbol table.
19591959
finalizeSynthetic(in.symTab.get());
1960+
finalizeSynthetic(in.debugNames.get());
19601961
finalizeSynthetic(in.ppc64LongBranchTarget.get());
19611962
finalizeSynthetic(in.armCmseSGSection.get());
19621963
}

lld/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ ELF Improvements
3232
* ``GNU_PROPERTY_AARCH64_FEATURE_PAUTH`` notes, ``R_AARCH64_AUTH_ABS64`` and
3333
``R_AARCH64_AUTH_RELATIVE`` relocations are now supported.
3434
(`#72714 <https://github.com/llvm/llvm-project/pull/72714>`_)
35+
* ``--debug-names`` is added to create a merged ``.debug_names`` index
36+
from input ``.debug_names`` sections.
3537

3638
Breaking changes
3739
----------------

lld/test/ELF/debug-names-bad-aug-string.s

Lines changed: 36 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,31 @@
1-
// This file was generated by copying debug-names.s and manually
2-
// editing the 'Header: augmentation string' in the .debug_names section.
1+
# This file was generated by copying debug-names.s and manually
2+
# editing the 'Header: augmentation string' in the .debug_names section.
33

4-
// REQUIRES: x86
5-
// RUN: rm -rf %t && split-file %s %t
6-
// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-bad-aug-string.s \
7-
// RUN: -o %t/debug-names-bad-aug-string.o
8-
// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-2.s \
9-
// RUN: -o %t/debug-names-2.o
10-
// RUN: ld.lld --debug-names %t/debug-names-bad-aug-string.o \
11-
// RUN: %t/debug-names-2.o -o %t/debug-names-bad-aug-string
4+
# REQUIRES: x86
5+
# RUN: rm -rf %t && split-file %s %t && cd %t
6+
# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-aug-string.s -o bad-aug-string.o
7+
# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
8+
# RUN: ld.lld --debug-names bad-aug-string.o b.o -o out
9+
# RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
1210

13-
// RUN: llvm-dwarfdump -debug-names %t/debug-names-bad-aug-string \
14-
// RUN: | FileCheck -DFILE=%t/debug-names-bad-aug-string.o \
15-
// RUN: -DFILE=%t/debug-names-2.o %s --check-prefix=DWARF
16-
17-
// DWARF: .debug_names contents:
18-
// DWARF: Name Index @ 0x0 {
19-
// DWARF-NEXT: Header {
20-
// DWARF-NEXT: Length: 0xCC
21-
// DWARF-NEXT: Format: DWARF32
22-
// DWARF-NEXT: Version: 5
23-
// DWARF-NEXT: CU count: 2
24-
// DWARF-NEXT: Local TU count: 0
25-
// DWARF-NEXT: Foreign TU count: 0
26-
// DWARF-NEXT: Bucket count: 5
27-
// DWARF-NEXT: Name count: 5
28-
// DWARF-NEXT: Abbreviations table size: 0x1F
29-
// DWARF-NEXT: Augmentation: ' '
30-
// DWARF: Compilation Unit offsets [
31-
// DWARF-NEXT: CU[0]: 0x00000000
32-
// DWARF-NEXT: CU[1]: 0x0000000c
11+
# DWARF: .debug_names contents:
12+
# DWARF: Name Index @ 0x0 {
13+
# DWARF-NEXT: Header {
14+
# DWARF-NEXT: Length: 0xC0
15+
# DWARF-NEXT: Format: DWARF32
16+
# DWARF-NEXT: Version: 5
17+
# DWARF-NEXT: CU count: 2
18+
# DWARF-NEXT: Local TU count: 0
19+
# DWARF-NEXT: Foreign TU count: 0
20+
# DWARF-NEXT: Bucket count: 5
21+
# DWARF-NEXT: Name count: 5
22+
# DWARF-NEXT: Abbreviations table size: 0x1F
23+
# DWARF-NEXT: Augmentation: ''
24+
# DWARF: Compilation Unit offsets [
25+
# DWARF-NEXT: CU[0]: 0x00000000
26+
# DWARF-NEXT: CU[1]: 0x0000000c
3327

34-
#--- debug-names-bad-aug-string.s
28+
#--- bad-aug-string.s
3529
.text
3630
.globl _Z2f12t1 # -- Begin function _Z2f12t1
3731
.p2align 4, 0x90
@@ -159,19 +153,19 @@ _Z2f12t1: # @_Z2f12t1
159153
.section .debug_line,"",@progbits
160154
.Lline_table_start0:
161155

162-
#--- debug-names-2.s
163-
// input file: debug-names-2.cpp
164-
// Generated with:
165-
// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
166-
// -S debug-names-2.cpp -o debug-names-2.s
156+
#--- b.s
157+
# input file: debug-names-2.cpp
158+
# Generated with:
159+
# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
160+
# -S debug-names-2.cpp -o b.s
167161

168-
// debug-names-2.cpp contents:
162+
# debug-names-2.cpp contents:
169163

170-
// struct t1 { };
171-
// int main() {
172-
// t1 v1;
173-
// }
174-
//
164+
# struct t1 { };
165+
# int main() {
166+
# t1 v1;
167+
# }
168+
#
175169
.text
176170
.globl main # -- Begin function main
177171
.p2align 4, 0x90

lld/test/ELF/debug-names-bad-die-idx-sizes.s

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
// This file was generated by first compiling main.cpp:
2-
// clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
3-
// main.cpp
4-
// Then manually edit the .debug_names section. In the entries, change the
5-
// size of the DW_IDX_die_offset from '.long' to '.byte'.
1+
# This file was generated by first compiling main.cpp:
2+
# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
3+
# main.cpp
4+
# Then manually edit the .debug_names section. In the entries, change the
5+
# size of the DW_IDX_die_offset from '.long' to '.byte'.
66

7-
// Contents of main.cpp:
8-
// int main (int argc, char **argv) { }
7+
# Contents of main.cpp:
8+
# int main (int argc, char **argv) { }
99

10-
// REQUIRES: x86
11-
// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
10+
# REQUIRES: x86
11+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
12+
# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
13+
# RUN: | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
1214

13-
// RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
14-
// RUN: | FileCheck -DFILE=%t1.o %s
15-
16-
// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
15+
# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
1716

1817
.text
1918
.globl main # -- Begin function main

lld/test/ELF/debug-names-bad-name-count.s

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
// REQUIRES: x86
2-
// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
33

4-
// RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
5-
// RUN: FileCheck -DFILE=%t1.o %s
4+
# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
5+
# RUN: FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
66

7-
// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
8-
// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
9-
// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
10-
// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
7+
# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
8+
# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
9+
# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
10+
# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
1111

12-
// This file was generated by first compiling main.cpp:
13-
// clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
14-
// main.cpp
12+
# This file was generated by first compiling main.cpp:
13+
# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
14+
# main.cpp
1515

16-
// Then manually edit .debug_names section: change value for
17-
// 'Header: name count' from 3 to 4.
16+
# Then manually edit .debug_names section: change value for
17+
# 'Header: name count' from 3 to 4.
1818

19-
// Contents of main.cpp:
20-
// int main (int argc, char **argv) { }
19+
# Contents of main.cpp:
20+
# int main (int argc, char **argv) { }
2121

2222
.text
2323
.globl main # -- Begin function main

0 commit comments

Comments
 (0)