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