Skip to content

Commit 8223e75

Browse files
committed
Refactor GDBIndex into new file
Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D58156977
1 parent 8423337 commit 8223e75

File tree

3 files changed

+243
-0
lines changed

3 files changed

+243
-0
lines changed

bolt/include/bolt/Core/GDBIndex.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===-- bolt/Core/GDBIndex.h - GDB Index 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+
/// .gdb_index section.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef BOLT_CORE_GDB_INDEX_H
15+
#define BOLT_CORE_GDB_INDEX_H
16+
17+
#include "bolt/Core/BinaryContext.h"
18+
#include <vector>
19+
20+
namespace llvm {
21+
namespace bolt {
22+
23+
class GDBIndex {
24+
public:
25+
/// Contains information about TU so we can write out correct entries in GDB
26+
/// index.
27+
struct GDBIndexTUEntry {
28+
uint64_t UnitOffset;
29+
uint64_t TypeHash;
30+
uint64_t TypeDIERelativeOffset;
31+
};
32+
33+
private:
34+
BinaryContext &BC;
35+
36+
/// Entries for GDB Index Types CU List
37+
using GDBIndexTUEntryType = std::vector<GDBIndexTUEntry>;
38+
GDBIndexTUEntryType GDBIndexTUEntryVector;
39+
40+
public:
41+
GDBIndex(BinaryContext &BC) : BC(BC) {}
42+
43+
/// Adds an GDBIndexTUEntry if .gdb_index section exists.
44+
void addGDBTypeUnitEntry(const GDBIndexTUEntry &Entry);
45+
46+
/// Rewrite .gdb_index section if present.
47+
void updateGdbIndexSection(
48+
CUOffsetMap &CUMap, uint32_t NumCUs,
49+
std::unique_ptr<DebugARangesSectionWriter> &ARangesSectionWriter);
50+
51+
/// Returns all entries needed for Types CU list
52+
const GDBIndexTUEntryType &getGDBIndexTUEntryVector() const {
53+
return GDBIndexTUEntryVector;
54+
}
55+
};
56+
57+
} // namespace bolt
58+
} // namespace llvm
59+
60+
#endif

bolt/lib/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_llvm_library(LLVMBOLTCore
2525
DynoStats.cpp
2626
Exceptions.cpp
2727
FunctionLayout.cpp
28+
GDBIndex.cpp
2829
HashUtilities.cpp
2930
JumpTable.cpp
3031
MCPlusBuilder.cpp

bolt/lib/Core/GDBIndex.cpp

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
//===- bolt/Rewrite/GDBIndex.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/GDBIndex.h"
10+
11+
using namespace llvm::bolt;
12+
using namespace llvm::support::endian;
13+
14+
void GDBIndex::addGDBTypeUnitEntry(const GDBIndexTUEntry &Entry) {
15+
GDBIndexTUEntryVector.push_back(Entry);
16+
}
17+
18+
void GDBIndex::updateGdbIndexSection(
19+
CUOffsetMap &CUMap, uint32_t NumCUs,
20+
std::unique_ptr<DebugARangesSectionWriter> &ARangesSectionWriter) {
21+
if (!BC.getGdbIndexSection())
22+
return;
23+
24+
// See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html
25+
// for .gdb_index section format.
26+
27+
StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents();
28+
29+
const char *Data = GdbIndexContents.data();
30+
31+
// Parse the header.
32+
const uint32_t Version = read32le(Data);
33+
if (Version != 7 && Version != 8) {
34+
errs() << "BOLT-ERROR: can only process .gdb_index versions 7 and 8\n";
35+
exit(1);
36+
}
37+
38+
// Some .gdb_index generators use file offsets while others use section
39+
// offsets. Hence we can only rely on offsets relative to each other,
40+
// and ignore their absolute values.
41+
const uint32_t CUListOffset = read32le(Data + 4);
42+
const uint32_t CUTypesOffset = read32le(Data + 8);
43+
const uint32_t AddressTableOffset = read32le(Data + 12);
44+
const uint32_t SymbolTableOffset = read32le(Data + 16);
45+
const uint32_t ConstantPoolOffset = read32le(Data + 20);
46+
Data += 24;
47+
48+
// Map CUs offsets to indices and verify existing index table.
49+
std::map<uint32_t, uint32_t> OffsetToIndexMap;
50+
const uint32_t CUListSize = CUTypesOffset - CUListOffset;
51+
const uint32_t TUListSize = AddressTableOffset - CUTypesOffset;
52+
const unsigned NUmCUsEncoded = CUListSize / 16;
53+
unsigned MaxDWARFVersion = BC.DwCtx->getMaxVersion();
54+
unsigned NumDWARF5TUs =
55+
getGDBIndexTUEntryVector().size() - BC.DwCtx->getNumTypeUnits();
56+
bool SkipTypeUnits = false;
57+
// For DWARF5 Types are in .debug_info.
58+
// LLD doesn't generate Types CU List, and in CU list offset
59+
// only includes CUs.
60+
// GDB 11+ includes only CUs in CU list and generates Types
61+
// list.
62+
// GDB 9 includes CUs and TUs in CU list and generates TYpes
63+
// list. The NumCUs is CUs + TUs, so need to modify the check.
64+
// For split-dwarf
65+
// GDB-11, DWARF5: TU units from dwo are not included.
66+
// GDB-11, DWARF4: TU units from dwo are included.
67+
if (MaxDWARFVersion >= 5)
68+
SkipTypeUnits = !TUListSize ? true
69+
: ((NUmCUsEncoded + NumDWARF5TUs) ==
70+
BC.DwCtx->getNumCompileUnits());
71+
72+
if (!((CUListSize == NumCUs * 16) ||
73+
(CUListSize == (NumCUs + NumDWARF5TUs) * 16))) {
74+
errs() << "BOLT-ERROR: .gdb_index: CU count mismatch\n";
75+
exit(1);
76+
}
77+
DenseSet<uint64_t> OriginalOffsets;
78+
for (unsigned Index = 0, Units = BC.DwCtx->getNumCompileUnits();
79+
Index < Units; ++Index) {
80+
const DWARFUnit *CU = BC.DwCtx->getUnitAtIndex(Index);
81+
if (SkipTypeUnits && CU->isTypeUnit())
82+
continue;
83+
const uint64_t Offset = read64le(Data);
84+
Data += 16;
85+
if (CU->getOffset() != Offset) {
86+
errs() << "BOLT-ERROR: .gdb_index CU offset mismatch\n";
87+
exit(1);
88+
}
89+
90+
OriginalOffsets.insert(Offset);
91+
OffsetToIndexMap[Offset] = Index;
92+
}
93+
94+
// Ignore old address table.
95+
const uint32_t OldAddressTableSize = SymbolTableOffset - AddressTableOffset;
96+
// Move Data to the beginning of symbol table.
97+
Data += SymbolTableOffset - CUTypesOffset;
98+
99+
// Calculate the size of the new address table.
100+
uint32_t NewAddressTableSize = 0;
101+
for (const auto &CURangesPair : ARangesSectionWriter->getCUAddressRanges()) {
102+
const SmallVector<DebugAddressRange, 2> &Ranges = CURangesPair.second;
103+
NewAddressTableSize += Ranges.size() * 20;
104+
}
105+
106+
// Difference between old and new table (and section) sizes.
107+
// Could be negative.
108+
int32_t Delta = NewAddressTableSize - OldAddressTableSize;
109+
110+
size_t NewGdbIndexSize = GdbIndexContents.size() + Delta;
111+
112+
// Free'd by ExecutableFileMemoryManager.
113+
auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize];
114+
uint8_t *Buffer = NewGdbIndexContents;
115+
116+
write32le(Buffer, Version);
117+
write32le(Buffer + 4, CUListOffset);
118+
write32le(Buffer + 8, CUTypesOffset);
119+
write32le(Buffer + 12, AddressTableOffset);
120+
write32le(Buffer + 16, SymbolTableOffset + Delta);
121+
write32le(Buffer + 20, ConstantPoolOffset + Delta);
122+
Buffer += 24;
123+
124+
using MapEntry = std::pair<uint32_t, CUInfo>;
125+
std::vector<MapEntry> CUVector(CUMap.begin(), CUMap.end());
126+
// Need to sort since we write out all of TUs in .debug_info before CUs.
127+
std::sort(CUVector.begin(), CUVector.end(),
128+
[](const MapEntry &E1, const MapEntry &E2) -> bool {
129+
return E1.second.Offset < E2.second.Offset;
130+
});
131+
// Writing out CU List <Offset, Size>
132+
for (auto &CUInfo : CUVector) {
133+
// Skipping TU for DWARF5 when they are not included in CU list.
134+
if (!OriginalOffsets.count(CUInfo.first))
135+
continue;
136+
write64le(Buffer, CUInfo.second.Offset);
137+
// Length encoded in CU doesn't contain first 4 bytes that encode length.
138+
write64le(Buffer + 8, CUInfo.second.Length + 4);
139+
Buffer += 16;
140+
}
141+
142+
// Rewrite TU CU List, since abbrevs can be different.
143+
// Entry example:
144+
// 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature =
145+
// 0x418503b8111e9a7b Spec says " triplet, the first value is the CU offset,
146+
// the second value is the type offset in the CU, and the third value is the
147+
// type signature" Looking at what is being generated by gdb-add-index. The
148+
// first entry is TU offset, second entry is offset from it, and third entry
149+
// is the type signature.
150+
if (TUListSize)
151+
for (const GDBIndexTUEntry &Entry : getGDBIndexTUEntryVector()) {
152+
write64le(Buffer, Entry.UnitOffset);
153+
write64le(Buffer + 8, Entry.TypeDIERelativeOffset);
154+
write64le(Buffer + 16, Entry.TypeHash);
155+
Buffer += sizeof(GDBIndexTUEntry);
156+
}
157+
158+
// Generate new address table.
159+
for (const std::pair<const uint64_t, DebugAddressRangesVector> &CURangesPair :
160+
ARangesSectionWriter->getCUAddressRanges()) {
161+
const uint32_t CUIndex = OffsetToIndexMap[CURangesPair.first];
162+
const DebugAddressRangesVector &Ranges = CURangesPair.second;
163+
for (const DebugAddressRange &Range : Ranges) {
164+
write64le(Buffer, Range.LowPC);
165+
write64le(Buffer + 8, Range.HighPC);
166+
write32le(Buffer + 16, CUIndex);
167+
Buffer += 20;
168+
}
169+
}
170+
171+
const size_t TrailingSize =
172+
GdbIndexContents.data() + GdbIndexContents.size() - Data;
173+
assert(Buffer + TrailingSize == NewGdbIndexContents + NewGdbIndexSize &&
174+
"size calculation error");
175+
176+
// Copy over the rest of the original data.
177+
memcpy(Buffer, Data, TrailingSize);
178+
179+
// Register the new section.
180+
BC.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents,
181+
NewGdbIndexSize);
182+
}

0 commit comments

Comments
 (0)