1 //===- DWARFUnitIndex.cpp -------------------------------------------------===//
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 "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/Support/DataExtractor.h"
13 #include "llvm/Support/ErrorHandling.h"
14 #include "llvm/Support/Format.h"
15 #include "llvm/Support/raw_ostream.h"
23 enum class DWARFSectionKindV2
{
29 DW_SECT_STR_OFFSETS
= 6,
36 // Return true if the section identifier is defined in the DWARFv5 standard.
37 constexpr bool isKnownV5SectionID(uint32_t ID
) {
38 return ID
>= DW_SECT_INFO
&& ID
<= DW_SECT_RNGLISTS
&&
39 ID
!= DW_SECT_EXT_TYPES
;
42 uint32_t llvm::serializeSectionKind(DWARFSectionKind Kind
,
43 unsigned IndexVersion
) {
44 if (IndexVersion
== 5) {
45 assert(isKnownV5SectionID(Kind
));
46 return static_cast<uint32_t>(Kind
);
48 assert(IndexVersion
== 2);
52 return static_cast<uint32_t>(DWARFSectionKindV2::DW_SECT_##T)
54 CASE(EXT_TYPES
, TYPES
);
58 CASE(STR_OFFSETS
, STR_OFFSETS
);
59 CASE(EXT_MACINFO
, MACINFO
);
63 // All other section kinds have no corresponding values in v2 indexes.
64 llvm_unreachable("Invalid DWARFSectionKind");
68 DWARFSectionKind
llvm::deserializeSectionKind(uint32_t Value
,
69 unsigned IndexVersion
) {
70 if (IndexVersion
== 5)
71 return isKnownV5SectionID(Value
)
72 ? static_cast<DWARFSectionKind
>(Value
)
73 : DW_SECT_EXT_unknown
;
74 assert(IndexVersion
== 2);
75 switch (static_cast<DWARFSectionKindV2
>(Value
)) {
77 case DWARFSectionKindV2::DW_SECT_##S: \
80 CASE(TYPES
, EXT_TYPES
);
84 CASE(STR_OFFSETS
, STR_OFFSETS
);
85 CASE(MACINFO
, EXT_MACINFO
);
89 return DW_SECT_EXT_unknown
;
92 bool DWARFUnitIndex::Header::parse(DataExtractor IndexData
,
93 uint64_t *OffsetPtr
) {
94 const uint64_t BeginOffset
= *OffsetPtr
;
95 if (!IndexData
.isValidOffsetForDataOfSize(*OffsetPtr
, 16))
97 // GCC Debug Fission defines the version as an unsigned 32-bit field
98 // with value of 2, https://gcc.gnu.org/wiki/DebugFissionDWP.
99 // DWARFv5 defines the same space as an uhalf version field with value of 5
100 // and a 2 bytes long padding, see Section 7.3.5.3.
101 Version
= IndexData
.getU32(OffsetPtr
);
103 *OffsetPtr
= BeginOffset
;
104 Version
= IndexData
.getU16(OffsetPtr
);
107 *OffsetPtr
+= 2; // Skip padding.
109 NumColumns
= IndexData
.getU32(OffsetPtr
);
110 NumUnits
= IndexData
.getU32(OffsetPtr
);
111 NumBuckets
= IndexData
.getU32(OffsetPtr
);
115 void DWARFUnitIndex::Header::dump(raw_ostream
&OS
) const {
116 OS
<< format("version = %u, units = %u, slots = %u\n\n", Version
, NumUnits
, NumBuckets
);
119 bool DWARFUnitIndex::parse(DataExtractor IndexData
) {
120 bool b
= parseImpl(IndexData
);
122 // Make sure we don't try to dump anything
123 Header
.NumBuckets
= 0;
124 // Release any partially initialized data.
131 bool DWARFUnitIndex::parseImpl(DataExtractor IndexData
) {
133 if (!Header
.parse(IndexData
, &Offset
))
136 // Fix InfoColumnKind: in DWARFv5, type units are in .debug_info.dwo.
137 if (Header
.Version
== 5)
138 InfoColumnKind
= DW_SECT_INFO
;
140 if (!IndexData
.isValidOffsetForDataOfSize(
141 Offset
, Header
.NumBuckets
* (8 + 4) +
142 (2 * Header
.NumUnits
+ 1) * 4 * Header
.NumColumns
))
145 Rows
= std::make_unique
<Entry
[]>(Header
.NumBuckets
);
147 std::make_unique
<Entry::SectionContribution
*[]>(Header
.NumUnits
);
148 ColumnKinds
= std::make_unique
<DWARFSectionKind
[]>(Header
.NumColumns
);
149 RawSectionIds
= std::make_unique
<uint32_t[]>(Header
.NumColumns
);
151 // Read Hash Table of Signatures
152 for (unsigned i
= 0; i
!= Header
.NumBuckets
; ++i
)
153 Rows
[i
].Signature
= IndexData
.getU64(&Offset
);
155 // Read Parallel Table of Indexes
156 for (unsigned i
= 0; i
!= Header
.NumBuckets
; ++i
) {
157 auto Index
= IndexData
.getU32(&Offset
);
160 Rows
[i
].Index
= this;
161 Rows
[i
].Contributions
=
162 std::make_unique
<Entry::SectionContribution
[]>(Header
.NumColumns
);
163 Contribs
[Index
- 1] = Rows
[i
].Contributions
.get();
166 // Read the Column Headers
167 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
) {
168 RawSectionIds
[i
] = IndexData
.getU32(&Offset
);
169 ColumnKinds
[i
] = deserializeSectionKind(RawSectionIds
[i
], Header
.Version
);
170 if (ColumnKinds
[i
] == InfoColumnKind
) {
171 if (InfoColumn
!= -1)
177 if (InfoColumn
== -1)
180 // Read Table of Section Offsets
181 for (unsigned i
= 0; i
!= Header
.NumUnits
; ++i
) {
182 auto *Contrib
= Contribs
[i
];
183 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
)
184 Contrib
[i
].setOffset(IndexData
.getU32(&Offset
));
187 // Read Table of Section Sizes
188 for (unsigned i
= 0; i
!= Header
.NumUnits
; ++i
) {
189 auto *Contrib
= Contribs
[i
];
190 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
)
191 Contrib
[i
].setLength(IndexData
.getU32(&Offset
));
197 StringRef
DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS
) {
199 #define HANDLE_DW_SECT(ID, NAME) \
200 case DW_SECT_##NAME: \
202 #include "llvm/BinaryFormat/Dwarf.def"
203 case DW_SECT_EXT_TYPES
:
205 case DW_SECT_EXT_LOC
:
207 case DW_SECT_EXT_MACINFO
:
209 case DW_SECT_EXT_unknown
:
212 llvm_unreachable("Unknown DWARFSectionKind");
215 void DWARFUnitIndex::dump(raw_ostream
&OS
) const {
220 OS
<< "Index Signature ";
221 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
) {
222 DWARFSectionKind Kind
= ColumnKinds
[i
];
223 StringRef Name
= getColumnHeader(Kind
);
226 << left_justify(Name
,
227 Kind
== DWARFSectionKind::DW_SECT_INFO
? 40 : 24);
229 OS
<< format(" Unknown: %-15" PRIu32
, RawSectionIds
[i
]);
231 OS
<< "\n----- ------------------";
232 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
) {
233 DWARFSectionKind Kind
= ColumnKinds
[i
];
234 if (Kind
== DWARFSectionKind::DW_SECT_INFO
||
235 Kind
== DWARFSectionKind::DW_SECT_EXT_TYPES
)
236 OS
<< " ----------------------------------------";
238 OS
<< " ------------------------";
241 for (unsigned i
= 0; i
!= Header
.NumBuckets
; ++i
) {
243 if (auto *Contribs
= Row
.Contributions
.get()) {
244 OS
<< format("%5u 0x%016" PRIx64
" ", i
+ 1, Row
.Signature
);
245 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
) {
246 auto &Contrib
= Contribs
[i
];
247 DWARFSectionKind Kind
= ColumnKinds
[i
];
248 if (Kind
== DWARFSectionKind::DW_SECT_INFO
||
249 Kind
== DWARFSectionKind::DW_SECT_EXT_TYPES
)
250 OS
<< format("[0x%016" PRIx64
", 0x%016" PRIx64
") ",
252 Contrib
.getOffset() + Contrib
.getLength());
254 OS
<< format("[0x%08" PRIx32
", 0x%08" PRIx32
") ",
255 Contrib
.getOffset32(),
256 Contrib
.getOffset32() + Contrib
.getLength32());
263 const DWARFUnitIndex::Entry::SectionContribution
*
264 DWARFUnitIndex::Entry::getContribution(DWARFSectionKind Sec
) const {
266 for (; i
!= Index
->Header
.NumColumns
; ++i
)
267 if (Index
->ColumnKinds
[i
] == Sec
)
268 return &Contributions
[i
];
272 DWARFUnitIndex::Entry::SectionContribution
&
273 DWARFUnitIndex::Entry::getContribution() {
274 return Contributions
[Index
->InfoColumn
];
277 const DWARFUnitIndex::Entry::SectionContribution
*
278 DWARFUnitIndex::Entry::getContribution() const {
279 return &Contributions
[Index
->InfoColumn
];
282 const DWARFUnitIndex::Entry
*
283 DWARFUnitIndex::getFromOffset(uint64_t Offset
) const {
284 if (OffsetLookup
.empty()) {
285 for (uint32_t i
= 0; i
!= Header
.NumBuckets
; ++i
)
286 if (Rows
[i
].Contributions
)
287 OffsetLookup
.push_back(&Rows
[i
]);
288 llvm::sort(OffsetLookup
, [&](Entry
*E1
, Entry
*E2
) {
289 return E1
->Contributions
[InfoColumn
].getOffset() <
290 E2
->Contributions
[InfoColumn
].getOffset();
293 auto I
= partition_point(OffsetLookup
, [&](Entry
*E2
) {
294 return E2
->Contributions
[InfoColumn
].getOffset() <= Offset
;
296 if (I
== OffsetLookup
.begin())
300 const auto &InfoContrib
= E
->Contributions
[InfoColumn
];
301 if ((InfoContrib
.getOffset() + InfoContrib
.getLength()) <= Offset
)
306 const DWARFUnitIndex::Entry
*DWARFUnitIndex::getFromHash(uint64_t S
) const {
307 uint64_t Mask
= Header
.NumBuckets
- 1;
310 auto HP
= ((S
>> 32) & Mask
) | 1;
311 // The spec says "while 0 is a valid hash value, the row index in a used slot
312 // will always be non-zero". Loop until we find a match or an empty slot.
313 while (Rows
[H
].getSignature() != S
&& Rows
[H
].Index
!= nullptr)
316 // If the slot is empty, we don't care whether the signature matches (it could
317 // be zero and still match the zeros in the empty slot).
318 if (Rows
[H
].Index
== nullptr)