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/ErrorHandling.h"
13 #include "llvm/Support/Format.h"
14 #include "llvm/Support/raw_ostream.h"
22 enum class DWARFSectionKindV2
{
28 DW_SECT_STR_OFFSETS
= 6,
35 // Return true if the section identifier is defined in the DWARFv5 standard.
36 constexpr bool isKnownV5SectionID(uint32_t ID
) {
37 return ID
>= DW_SECT_INFO
&& ID
<= DW_SECT_RNGLISTS
&&
38 ID
!= DW_SECT_EXT_TYPES
;
41 uint32_t llvm::serializeSectionKind(DWARFSectionKind Kind
,
42 unsigned IndexVersion
) {
43 if (IndexVersion
== 5) {
44 assert(isKnownV5SectionID(Kind
));
45 return static_cast<uint32_t>(Kind
);
47 assert(IndexVersion
== 2);
51 return static_cast<uint32_t>(DWARFSectionKindV2::DW_SECT_##T)
53 CASE(EXT_TYPES
, TYPES
);
57 CASE(STR_OFFSETS
, STR_OFFSETS
);
58 CASE(EXT_MACINFO
, MACINFO
);
62 // All other section kinds have no corresponding values in v2 indexes.
63 llvm_unreachable("Invalid DWARFSectionKind");
67 DWARFSectionKind
llvm::deserializeSectionKind(uint32_t Value
,
68 unsigned IndexVersion
) {
69 if (IndexVersion
== 5)
70 return isKnownV5SectionID(Value
)
71 ? static_cast<DWARFSectionKind
>(Value
)
72 : DW_SECT_EXT_unknown
;
73 assert(IndexVersion
== 2);
74 switch (static_cast<DWARFSectionKindV2
>(Value
)) {
76 case DWARFSectionKindV2::DW_SECT_##S: \
79 CASE(TYPES
, EXT_TYPES
);
83 CASE(STR_OFFSETS
, STR_OFFSETS
);
84 CASE(MACINFO
, EXT_MACINFO
);
88 return DW_SECT_EXT_unknown
;
91 bool DWARFUnitIndex::Header::parse(DataExtractor IndexData
,
92 uint64_t *OffsetPtr
) {
93 const uint64_t BeginOffset
= *OffsetPtr
;
94 if (!IndexData
.isValidOffsetForDataOfSize(*OffsetPtr
, 16))
96 // GCC Debug Fission defines the version as an unsigned 32-bit field
97 // with value of 2, https://gcc.gnu.org/wiki/DebugFissionDWP.
98 // DWARFv5 defines the same space as an uhalf version field with value of 5
99 // and a 2 bytes long padding, see Section 7.3.5.3.
100 Version
= IndexData
.getU32(OffsetPtr
);
102 *OffsetPtr
= BeginOffset
;
103 Version
= IndexData
.getU16(OffsetPtr
);
106 *OffsetPtr
+= 2; // Skip padding.
108 NumColumns
= IndexData
.getU32(OffsetPtr
);
109 NumUnits
= IndexData
.getU32(OffsetPtr
);
110 NumBuckets
= IndexData
.getU32(OffsetPtr
);
114 void DWARFUnitIndex::Header::dump(raw_ostream
&OS
) const {
115 OS
<< format("version = %u, units = %u, slots = %u\n\n", Version
, NumUnits
, NumBuckets
);
118 bool DWARFUnitIndex::parse(DataExtractor IndexData
) {
119 bool b
= parseImpl(IndexData
);
121 // Make sure we don't try to dump anything
122 Header
.NumBuckets
= 0;
123 // Release any partially initialized data.
130 bool DWARFUnitIndex::parseImpl(DataExtractor IndexData
) {
132 if (!Header
.parse(IndexData
, &Offset
))
135 // Fix InfoColumnKind: in DWARFv5, type units are in .debug_info.dwo.
136 if (Header
.Version
== 5)
137 InfoColumnKind
= DW_SECT_INFO
;
139 if (!IndexData
.isValidOffsetForDataOfSize(
140 Offset
, Header
.NumBuckets
* (8 + 4) +
141 (2 * Header
.NumUnits
+ 1) * 4 * Header
.NumColumns
))
144 Rows
= std::make_unique
<Entry
[]>(Header
.NumBuckets
);
146 std::make_unique
<Entry::SectionContribution
*[]>(Header
.NumUnits
);
147 ColumnKinds
= std::make_unique
<DWARFSectionKind
[]>(Header
.NumColumns
);
148 RawSectionIds
= std::make_unique
<uint32_t[]>(Header
.NumColumns
);
150 // Read Hash Table of Signatures
151 for (unsigned i
= 0; i
!= Header
.NumBuckets
; ++i
)
152 Rows
[i
].Signature
= IndexData
.getU64(&Offset
);
154 // Read Parallel Table of Indexes
155 for (unsigned i
= 0; i
!= Header
.NumBuckets
; ++i
) {
156 auto Index
= IndexData
.getU32(&Offset
);
159 Rows
[i
].Index
= this;
160 Rows
[i
].Contributions
=
161 std::make_unique
<Entry::SectionContribution
[]>(Header
.NumColumns
);
162 Contribs
[Index
- 1] = Rows
[i
].Contributions
.get();
165 // Read the Column Headers
166 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
) {
167 RawSectionIds
[i
] = IndexData
.getU32(&Offset
);
168 ColumnKinds
[i
] = deserializeSectionKind(RawSectionIds
[i
], Header
.Version
);
169 if (ColumnKinds
[i
] == InfoColumnKind
) {
170 if (InfoColumn
!= -1)
176 if (InfoColumn
== -1)
179 // Read Table of Section Offsets
180 for (unsigned i
= 0; i
!= Header
.NumUnits
; ++i
) {
181 auto *Contrib
= Contribs
[i
];
182 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
)
183 Contrib
[i
].Offset
= IndexData
.getU32(&Offset
);
186 // Read Table of Section Sizes
187 for (unsigned i
= 0; i
!= Header
.NumUnits
; ++i
) {
188 auto *Contrib
= Contribs
[i
];
189 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
)
190 Contrib
[i
].Length
= IndexData
.getU32(&Offset
);
196 StringRef
DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS
) {
198 #define HANDLE_DW_SECT(ID, NAME) \
199 case DW_SECT_##NAME: \
201 #include "llvm/BinaryFormat/Dwarf.def"
202 case DW_SECT_EXT_TYPES
:
204 case DW_SECT_EXT_LOC
:
206 case DW_SECT_EXT_MACINFO
:
208 case DW_SECT_EXT_unknown
:
211 llvm_unreachable("Unknown DWARFSectionKind");
214 void DWARFUnitIndex::dump(raw_ostream
&OS
) const {
219 OS
<< "Index Signature ";
220 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
) {
221 DWARFSectionKind Kind
= ColumnKinds
[i
];
222 StringRef Name
= getColumnHeader(Kind
);
224 OS
<< ' ' << left_justify(Name
, 24);
226 OS
<< format(" Unknown: %-15" PRIu32
, RawSectionIds
[i
]);
228 OS
<< "\n----- ------------------";
229 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
)
230 OS
<< " ------------------------";
232 for (unsigned i
= 0; i
!= Header
.NumBuckets
; ++i
) {
234 if (auto *Contribs
= Row
.Contributions
.get()) {
235 OS
<< format("%5u 0x%016" PRIx64
" ", i
+ 1, Row
.Signature
);
236 for (unsigned i
= 0; i
!= Header
.NumColumns
; ++i
) {
237 auto &Contrib
= Contribs
[i
];
238 OS
<< format("[0x%08x, 0x%08x) ", Contrib
.Offset
,
239 Contrib
.Offset
+ Contrib
.Length
);
246 const DWARFUnitIndex::Entry::SectionContribution
*
247 DWARFUnitIndex::Entry::getContribution(DWARFSectionKind Sec
) const {
249 for (; i
!= Index
->Header
.NumColumns
; ++i
)
250 if (Index
->ColumnKinds
[i
] == Sec
)
251 return &Contributions
[i
];
255 const DWARFUnitIndex::Entry::SectionContribution
*
256 DWARFUnitIndex::Entry::getContribution() const {
257 return &Contributions
[Index
->InfoColumn
];
260 const DWARFUnitIndex::Entry
*
261 DWARFUnitIndex::getFromOffset(uint32_t Offset
) const {
262 if (OffsetLookup
.empty()) {
263 for (uint32_t i
= 0; i
!= Header
.NumBuckets
; ++i
)
264 if (Rows
[i
].Contributions
)
265 OffsetLookup
.push_back(&Rows
[i
]);
266 llvm::sort(OffsetLookup
, [&](Entry
*E1
, Entry
*E2
) {
267 return E1
->Contributions
[InfoColumn
].Offset
<
268 E2
->Contributions
[InfoColumn
].Offset
;
271 auto I
= partition_point(OffsetLookup
, [&](Entry
*E2
) {
272 return E2
->Contributions
[InfoColumn
].Offset
<= Offset
;
274 if (I
== OffsetLookup
.begin())
278 const auto &InfoContrib
= E
->Contributions
[InfoColumn
];
279 if ((InfoContrib
.Offset
+ InfoContrib
.Length
) <= Offset
)
284 const DWARFUnitIndex::Entry
*DWARFUnitIndex::getFromHash(uint64_t S
) const {
285 uint64_t Mask
= Header
.NumBuckets
- 1;
288 auto HP
= ((S
>> 32) & Mask
) | 1;
289 // The spec says "while 0 is a valid hash value, the row index in a used slot
290 // will always be non-zero". Loop until we find a match or an empty slot.
291 while (Rows
[H
].getSignature() != S
&& Rows
[H
].Index
!= nullptr)
294 // If the slot is empty, we don't care whether the signature matches (it could
295 // be zero and still match the zeros in the empty slot).
296 if (Rows
[H
].Index
== nullptr)