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())
26 // See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html
27 // for .gdb_index section format.
29 StringRef GdbIndexContents
= BC
.getGdbIndexSection()->getContents();
31 const char *Data
= GdbIndexContents
.data();
34 const uint32_t Version
= read32le(Data
);
35 if (Version
!= 7 && Version
!= 8) {
36 errs() << "BOLT-ERROR: can only process .gdb_index versions 7 and 8\n";
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(Data
+ 4);
44 const uint32_t CUTypesOffset
= read32le(Data
+ 8);
45 const uint32_t AddressTableOffset
= read32le(Data
+ 12);
46 const uint32_t SymbolTableOffset
= read32le(Data
+ 16);
47 const uint32_t ConstantPoolOffset
= read32le(Data
+ 20);
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
62 // GDB 11+ includes only CUs in CU list and generates Types
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.
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());
74 if (!((CUListSize
== NumCUs
* 16) ||
75 (CUListSize
== (NumCUs
+ NumDWARF5TUs
) * 16))) {
76 errs() << "BOLT-ERROR: .gdb_index: CU count mismatch\n";
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
);
83 if (SkipTypeUnits
&& CU
->isTypeUnit())
85 const uint64_t Offset
= read64le(Data
);
87 if (CU
->getOffset() != Offset
) {
88 errs() << "BOLT-ERROR: .gdb_index CU offset mismatch\n";
92 OriginalOffsets
.insert(Offset
);
93 OffsetToIndexMap
[Offset
] = Index
;
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
;
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;
108 // Difference between old and new table (and section) sizes.
109 // Could be negative.
110 int32_t Delta
= NewAddressTableSize
- OldAddressTableSize
;
112 size_t NewGdbIndexSize
= GdbIndexContents
.size() + Delta
;
114 // Free'd by ExecutableFileMemoryManager.
115 auto *NewGdbIndexContents
= new uint8_t[NewGdbIndexSize
];
116 uint8_t *Buffer
= NewGdbIndexContents
;
118 write32le(Buffer
, Version
);
119 write32le(Buffer
+ 4, CUListOffset
);
120 write32le(Buffer
+ 8, CUTypesOffset
);
121 write32le(Buffer
+ 12, AddressTableOffset
);
122 write32le(Buffer
+ 16, SymbolTableOffset
+ Delta
);
123 write32le(Buffer
+ 20, ConstantPoolOffset
+ Delta
);
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(CUVector
.begin(), CUVector
.end(),
130 [](const MapEntry
&E1
, const MapEntry
&E2
) -> bool {
131 return E1
.second
.Offset
< E2
.second
.Offset
;
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(CUInfo
.first
))
138 write64le(Buffer
, CUInfo
.second
.Offset
);
139 // Length encoded in CU doesn't contain first 4 bytes that encode length.
140 write64le(Buffer
+ 8, CUInfo
.second
.Length
+ 4);
143 sortGDBIndexTUEntryVector();
144 // Rewrite TU CU List, since abbrevs can be different.
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.
153 for (const GDBIndexTUEntry
&Entry
: getGDBIndexTUEntryVector()) {
154 write64le(Buffer
, Entry
.UnitOffset
);
155 write64le(Buffer
+ 8, Entry
.TypeDIERelativeOffset
);
156 write64le(Buffer
+ 16, Entry
.TypeHash
);
157 Buffer
+= sizeof(GDBIndexTUEntry
);
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(Buffer
, Range
.LowPC
);
167 write64le(Buffer
+ 8, Range
.HighPC
);
168 write32le(Buffer
+ 16, CUIndex
);
173 const size_t TrailingSize
=
174 GdbIndexContents
.data() + GdbIndexContents
.size() - Data
;
175 assert(Buffer
+ TrailingSize
== NewGdbIndexContents
+ NewGdbIndexSize
&&
176 "size calculation error");
178 // Copy over the rest of the original data.
179 memcpy(Buffer
, Data
, TrailingSize
);
181 // Register the new section.
182 BC
.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents
,