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