/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- DWARFVerifier.cpp --------------------------------------------------===// |
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 | | #include "llvm/DebugInfo/DWARF/DWARFVerifier.h" |
9 | | #include "llvm/ADT/SmallSet.h" |
10 | | #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" |
11 | | #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
12 | | #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" |
13 | | #include "llvm/DebugInfo/DWARF/DWARFDie.h" |
14 | | #include "llvm/DebugInfo/DWARF/DWARFExpression.h" |
15 | | #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" |
16 | | #include "llvm/DebugInfo/DWARF/DWARFSection.h" |
17 | | #include "llvm/Support/DJB.h" |
18 | | #include "llvm/Support/FormatVariadic.h" |
19 | | #include "llvm/Support/WithColor.h" |
20 | | #include "llvm/Support/raw_ostream.h" |
21 | | #include <map> |
22 | | #include <set> |
23 | | #include <vector> |
24 | | |
25 | | using namespace llvm; |
26 | | using namespace dwarf; |
27 | | using namespace object; |
28 | | |
29 | | DWARFVerifier::DieRangeInfo::address_range_iterator |
30 | 135 | DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) { |
31 | 135 | auto Begin = Ranges.begin(); |
32 | 135 | auto End = Ranges.end(); |
33 | 135 | auto Pos = std::lower_bound(Begin, End, R); |
34 | 135 | |
35 | 135 | if (Pos != End) { |
36 | 0 | if (Pos->intersects(R)) |
37 | 0 | return Pos; |
38 | 0 | if (Pos != Begin) { |
39 | 0 | auto Iter = Pos - 1; |
40 | 0 | if (Iter->intersects(R)) |
41 | 0 | return Iter; |
42 | 135 | } |
43 | 0 | } |
44 | 135 | |
45 | 135 | Ranges.insert(Pos, R); |
46 | 135 | return Ranges.end(); |
47 | 135 | } |
48 | | |
49 | | DWARFVerifier::DieRangeInfo::die_range_info_iterator |
50 | 579 | DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) { |
51 | 579 | auto End = Children.end(); |
52 | 579 | auto Iter = Children.begin(); |
53 | 1.96k | while (Iter != End) { |
54 | 1.38k | if (Iter->intersects(RI)) |
55 | 2 | return Iter; |
56 | 1.38k | ++Iter; |
57 | 1.38k | } |
58 | 579 | Children.insert(RI); |
59 | 577 | return Children.end(); |
60 | 579 | } |
61 | | |
62 | 80 | bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const { |
63 | 80 | auto I1 = Ranges.begin(), E1 = Ranges.end(); |
64 | 80 | auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); |
65 | 80 | if (I2 == E2) |
66 | 2 | return true; |
67 | 78 | |
68 | 78 | DWARFAddressRange R = *I2; |
69 | 115 | while (I1 != E1) { |
70 | 110 | bool Covered = I1->LowPC <= R.LowPC; |
71 | 110 | if (R.LowPC == R.HighPC || (107 Covered107 && R.HighPC <= I1->HighPC100 )) { |
72 | 81 | if (++I2 == E2) |
73 | 66 | return true; |
74 | 15 | R = *I2; |
75 | 15 | continue; |
76 | 15 | } |
77 | 29 | if (!Covered) |
78 | 7 | return false; |
79 | 22 | if (R.LowPC < I1->HighPC) |
80 | 9 | R.LowPC = I1->HighPC; |
81 | 22 | ++I1; |
82 | 22 | } |
83 | 78 | return false5 ; |
84 | 78 | } |
85 | | |
86 | 1.42k | bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const { |
87 | 1.42k | auto I1 = Ranges.begin(), E1 = Ranges.end(); |
88 | 1.42k | auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); |
89 | 1.69k | while (I1 != E1 && I2 != E2474 ) { |
90 | 298 | if (I1->intersects(*I2)) |
91 | 22 | return true; |
92 | 276 | if (I1->LowPC < I2->LowPC) |
93 | 255 | ++I1; |
94 | 21 | else |
95 | 21 | ++I2; |
96 | 276 | } |
97 | 1.42k | return false1.39k ; |
98 | 1.42k | } |
99 | | |
100 | | bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, |
101 | | uint32_t *Offset, unsigned UnitIndex, |
102 | 113 | uint8_t &UnitType, bool &isUnitDWARF64) { |
103 | 113 | uint64_t AbbrOffset, Length; |
104 | 113 | uint8_t AddrSize = 0; |
105 | 113 | uint16_t Version; |
106 | 113 | bool Success = true; |
107 | 113 | |
108 | 113 | bool ValidLength = false; |
109 | 113 | bool ValidVersion = false; |
110 | 113 | bool ValidAddrSize = false; |
111 | 113 | bool ValidType = true; |
112 | 113 | bool ValidAbbrevOffset = true; |
113 | 113 | |
114 | 113 | uint32_t OffsetStart = *Offset; |
115 | 113 | Length = DebugInfoData.getU32(Offset); |
116 | 113 | if (Length == UINT32_MAX) { |
117 | 1 | Length = DebugInfoData.getU64(Offset); |
118 | 1 | isUnitDWARF64 = true; |
119 | 1 | } |
120 | 113 | Version = DebugInfoData.getU16(Offset); |
121 | 113 | |
122 | 113 | if (Version >= 5) { |
123 | 18 | UnitType = DebugInfoData.getU8(Offset); |
124 | 18 | AddrSize = DebugInfoData.getU8(Offset); |
125 | 18 | AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset)2 : DebugInfoData.getU32(Offset)16 ; |
126 | 18 | ValidType = dwarf::isUnitType(UnitType); |
127 | 95 | } else { |
128 | 95 | UnitType = 0; |
129 | 95 | AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset)0 : DebugInfoData.getU32(Offset); |
130 | 95 | AddrSize = DebugInfoData.getU8(Offset); |
131 | 95 | } |
132 | 113 | |
133 | 113 | if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset)) |
134 | 1 | ValidAbbrevOffset = false; |
135 | 113 | |
136 | 113 | ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3); |
137 | 113 | ValidVersion = DWARFContext::isSupportedVersion(Version); |
138 | 113 | ValidAddrSize = AddrSize == 4 || AddrSize == 8103 ; |
139 | 113 | if (!ValidLength || !ValidVersion110 || !ValidAddrSize109 || !ValidAbbrevOffset108 || |
140 | 113 | !ValidType108 ) { |
141 | 5 | Success = false; |
142 | 5 | error() << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, |
143 | 5 | OffsetStart); |
144 | 5 | if (!ValidLength) |
145 | 3 | note() << "The length for this unit is too " |
146 | 3 | "large for the .debug_info provided.\n"; |
147 | 5 | if (!ValidVersion) |
148 | 2 | note() << "The 16 bit unit header version is not valid.\n"; |
149 | 5 | if (!ValidType) |
150 | 2 | note() << "The unit type encoding is not valid.\n"; |
151 | 5 | if (!ValidAbbrevOffset) |
152 | 1 | note() << "The offset into the .debug_abbrev section is " |
153 | 1 | "not valid.\n"; |
154 | 5 | if (!ValidAddrSize) |
155 | 2 | note() << "The address size is unsupported.\n"; |
156 | 5 | } |
157 | 113 | *Offset = OffsetStart + Length + (isUnitDWARF64 ? 122 : 4111 ); |
158 | 113 | return Success; |
159 | 113 | } |
160 | | |
161 | 108 | unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) { |
162 | 108 | unsigned NumUnitErrors = 0; |
163 | 108 | unsigned NumDies = Unit.getNumDIEs(); |
164 | 863 | for (unsigned I = 0; I < NumDies; ++I755 ) { |
165 | 755 | auto Die = Unit.getDIEAtIndex(I); |
166 | 755 | |
167 | 755 | if (Die.getTag() == DW_TAG_null) |
168 | 177 | continue; |
169 | 578 | |
170 | 2.62k | for (auto AttrValue : Die.attributes())578 { |
171 | 2.62k | NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue); |
172 | 2.62k | NumUnitErrors += verifyDebugInfoForm(Die, AttrValue); |
173 | 2.62k | } |
174 | 578 | |
175 | 578 | NumUnitErrors += verifyDebugInfoCallSite(Die); |
176 | 578 | } |
177 | 108 | |
178 | 108 | DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false); |
179 | 108 | if (!Die) { |
180 | 1 | error() << "Compilation unit without DIE.\n"; |
181 | 1 | NumUnitErrors++; |
182 | 1 | return NumUnitErrors; |
183 | 1 | } |
184 | 107 | |
185 | 107 | if (!dwarf::isUnitType(Die.getTag())) { |
186 | 2 | error() << "Compilation unit root DIE is not a unit DIE: " |
187 | 2 | << dwarf::TagString(Die.getTag()) << ".\n"; |
188 | 2 | NumUnitErrors++; |
189 | 2 | } |
190 | 107 | |
191 | 107 | uint8_t UnitType = Unit.getUnitType(); |
192 | 107 | if (!DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) { |
193 | 2 | error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType) |
194 | 2 | << ") and root DIE (" << dwarf::TagString(Die.getTag()) |
195 | 2 | << ") do not match.\n"; |
196 | 2 | NumUnitErrors++; |
197 | 2 | } |
198 | 107 | |
199 | 107 | DieRangeInfo RI; |
200 | 107 | NumUnitErrors += verifyDieRanges(Die, RI); |
201 | 107 | |
202 | 107 | return NumUnitErrors; |
203 | 107 | } |
204 | | |
205 | 578 | unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) { |
206 | 578 | if (Die.getTag() != DW_TAG_call_site) |
207 | 572 | return 0; |
208 | 6 | |
209 | 6 | DWARFDie Curr = Die.getParent(); |
210 | 6 | for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Die.getParent()0 ) { |
211 | 0 | if (Curr.getTag() == DW_TAG_inlined_subroutine) { |
212 | 0 | error() << "Call site entry nested within inlined subroutine:"; |
213 | 0 | Curr.dump(OS); |
214 | 0 | return 1; |
215 | 0 | } |
216 | 0 | } |
217 | 6 | |
218 | 6 | if (!Curr.isValid()) { |
219 | 0 | error() << "Call site entry not nested within a valid subprogram:"; |
220 | 0 | Die.dump(OS); |
221 | 0 | return 1; |
222 | 0 | } |
223 | 6 | |
224 | 6 | Optional<DWARFFormValue> CallAttr = |
225 | 6 | Curr.find({DW_AT_call_all_calls, DW_AT_call_all_source_calls, |
226 | 6 | DW_AT_call_all_tail_calls}); |
227 | 6 | if (!CallAttr) { |
228 | 1 | error() << "Subprogram with call site entry has no DW_AT_call attribute:"; |
229 | 1 | Curr.dump(OS); |
230 | 1 | Die.dump(OS, /*indent*/ 1); |
231 | 1 | return 1; |
232 | 1 | } |
233 | 5 | |
234 | 5 | return 0; |
235 | 5 | } |
236 | | |
237 | 81 | unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) { |
238 | 81 | unsigned NumErrors = 0; |
239 | 81 | if (Abbrev) { |
240 | 81 | const DWARFAbbreviationDeclarationSet *AbbrDecls = |
241 | 81 | Abbrev->getAbbreviationDeclarationSet(0); |
242 | 376 | for (auto AbbrDecl : *AbbrDecls) { |
243 | 376 | SmallDenseSet<uint16_t> AttributeSet; |
244 | 1.58k | for (auto Attribute : AbbrDecl.attributes()) { |
245 | 1.58k | auto Result = AttributeSet.insert(Attribute.Attr); |
246 | 1.58k | if (!Result.second) { |
247 | 4 | error() << "Abbreviation declaration contains multiple " |
248 | 4 | << AttributeString(Attribute.Attr) << " attributes.\n"; |
249 | 4 | AbbrDecl.dump(OS); |
250 | 4 | ++NumErrors; |
251 | 4 | } |
252 | 1.58k | } |
253 | 376 | } |
254 | 81 | } |
255 | 81 | return NumErrors; |
256 | 81 | } |
257 | | |
258 | 83 | bool DWARFVerifier::handleDebugAbbrev() { |
259 | 83 | OS << "Verifying .debug_abbrev...\n"; |
260 | 83 | |
261 | 83 | const DWARFObject &DObj = DCtx.getDWARFObj(); |
262 | 83 | unsigned NumErrors = 0; |
263 | 83 | if (!DObj.getAbbrevSection().empty()) |
264 | 78 | NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev()); |
265 | 83 | if (!DObj.getAbbrevDWOSection().empty()) |
266 | 3 | NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO()); |
267 | 83 | |
268 | 83 | return NumErrors == 0; |
269 | 83 | } |
270 | | |
271 | | unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S, |
272 | 73 | DWARFSectionKind SectionKind) { |
273 | 73 | const DWARFObject &DObj = DCtx.getDWARFObj(); |
274 | 73 | DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0); |
275 | 73 | unsigned NumDebugInfoErrors = 0; |
276 | 73 | uint32_t OffsetStart = 0, Offset = 0, UnitIdx = 0; |
277 | 73 | uint8_t UnitType = 0; |
278 | 73 | bool isUnitDWARF64 = false; |
279 | 73 | bool isHeaderChainValid = true; |
280 | 73 | bool hasDIE = DebugInfoData.isValidOffset(Offset); |
281 | 73 | DWARFUnitVector TypeUnitVector; |
282 | 73 | DWARFUnitVector CompileUnitVector; |
283 | 186 | while (hasDIE) { |
284 | 113 | OffsetStart = Offset; |
285 | 113 | if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType, |
286 | 113 | isUnitDWARF64)) { |
287 | 5 | isHeaderChainValid = false; |
288 | 5 | if (isUnitDWARF64) |
289 | 0 | break; |
290 | 108 | } else { |
291 | 108 | DWARFUnitHeader Header; |
292 | 108 | Header.extract(DCtx, DebugInfoData, &OffsetStart, SectionKind); |
293 | 108 | DWARFUnit *Unit; |
294 | 108 | switch (UnitType) { |
295 | 108 | case dwarf::DW_UT_type: |
296 | 1 | case dwarf::DW_UT_split_type: { |
297 | 1 | Unit = TypeUnitVector.addUnit(llvm::make_unique<DWARFTypeUnit>( |
298 | 1 | DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangeSection(), |
299 | 1 | &DObj.getLocSection(), DObj.getStringSection(), |
300 | 1 | DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(), |
301 | 1 | DObj.getLineSection(), DCtx.isLittleEndian(), false, |
302 | 1 | TypeUnitVector)); |
303 | 1 | break; |
304 | 1 | } |
305 | 107 | case dwarf::DW_UT_skeleton: |
306 | 107 | case dwarf::DW_UT_split_compile: |
307 | 107 | case dwarf::DW_UT_compile: |
308 | 107 | case dwarf::DW_UT_partial: |
309 | 107 | // UnitType = 0 means that we are verifying a compile unit in DWARF v4. |
310 | 107 | case 0: { |
311 | 107 | Unit = CompileUnitVector.addUnit(llvm::make_unique<DWARFCompileUnit>( |
312 | 107 | DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangeSection(), |
313 | 107 | &DObj.getLocSection(), DObj.getStringSection(), |
314 | 107 | DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(), |
315 | 107 | DObj.getLineSection(), DCtx.isLittleEndian(), false, |
316 | 107 | CompileUnitVector)); |
317 | 107 | break; |
318 | 107 | } |
319 | 107 | default: { 0 llvm_unreachable0 ("Invalid UnitType."); } |
320 | 108 | } |
321 | 108 | NumDebugInfoErrors += verifyUnitContents(*Unit); |
322 | 108 | } |
323 | 113 | hasDIE = DebugInfoData.isValidOffset(Offset); |
324 | 113 | ++UnitIdx; |
325 | 113 | } |
326 | 73 | if (UnitIdx == 0 && !hasDIE4 ) { |
327 | 4 | warn() << "Section is empty.\n"; |
328 | 4 | isHeaderChainValid = true; |
329 | 4 | } |
330 | 73 | if (!isHeaderChainValid) |
331 | 3 | ++NumDebugInfoErrors; |
332 | 73 | NumDebugInfoErrors += verifyDebugInfoReferences(); |
333 | 73 | return NumDebugInfoErrors; |
334 | 73 | } |
335 | | |
336 | 72 | bool DWARFVerifier::handleDebugInfo() { |
337 | 72 | const DWARFObject &DObj = DCtx.getDWARFObj(); |
338 | 72 | unsigned NumErrors = 0; |
339 | 72 | |
340 | 72 | OS << "Verifying .debug_info Unit Header Chain...\n"; |
341 | 72 | DObj.forEachInfoSections([&](const DWARFSection &S) { |
342 | 71 | NumErrors += verifyUnitSection(S, DW_SECT_INFO); |
343 | 71 | }); |
344 | 72 | |
345 | 72 | OS << "Verifying .debug_types Unit Header Chain...\n"; |
346 | 72 | DObj.forEachTypesSections([&](const DWARFSection &S) { |
347 | 2 | NumErrors += verifyUnitSection(S, DW_SECT_TYPES); |
348 | 2 | }); |
349 | 72 | return NumErrors == 0; |
350 | 72 | } |
351 | | |
352 | | unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, |
353 | 580 | DieRangeInfo &ParentRI) { |
354 | 580 | unsigned NumErrors = 0; |
355 | 580 | |
356 | 580 | if (!Die.isValid()) |
357 | 0 | return NumErrors; |
358 | 580 | |
359 | 580 | auto RangesOrError = Die.getAddressRanges(); |
360 | 580 | if (!RangesOrError) { |
361 | 1 | // FIXME: Report the error. |
362 | 1 | ++NumErrors; |
363 | 1 | llvm::consumeError(RangesOrError.takeError()); |
364 | 1 | return NumErrors; |
365 | 1 | } |
366 | 579 | |
367 | 579 | DWARFAddressRangesVector Ranges = RangesOrError.get(); |
368 | 579 | // Build RI for this DIE and check that ranges within this DIE do not |
369 | 579 | // overlap. |
370 | 579 | DieRangeInfo RI(Die); |
371 | 579 | |
372 | 579 | // TODO support object files better |
373 | 579 | // |
374 | 579 | // Some object file formats (i.e. non-MachO) support COMDAT. ELF in |
375 | 579 | // particular does so by placing each function into a section. The DWARF data |
376 | 579 | // for the function at that point uses a section relative DW_FORM_addrp for |
377 | 579 | // the DW_AT_low_pc and a DW_FORM_data4 for the offset as the DW_AT_high_pc. |
378 | 579 | // In such a case, when the Die is the CU, the ranges will overlap, and we |
379 | 579 | // will flag valid conflicting ranges as invalid. |
380 | 579 | // |
381 | 579 | // For such targets, we should read the ranges from the CU and partition them |
382 | 579 | // by the section id. The ranges within a particular section should be |
383 | 579 | // disjoint, although the ranges across sections may overlap. We would map |
384 | 579 | // the child die to the entity that it references and the section with which |
385 | 579 | // it is associated. The child would then be checked against the range |
386 | 579 | // information for the associated section. |
387 | 579 | // |
388 | 579 | // For now, simply elide the range verification for the CU DIEs if we are |
389 | 579 | // processing an object file. |
390 | 579 | |
391 | 579 | if (!IsObjectFile || IsMachOObject267 || Die.getTag() != DW_TAG_compile_unit85 ) { |
392 | 548 | for (auto Range : Ranges) { |
393 | 137 | if (!Range.valid()) { |
394 | 2 | ++NumErrors; |
395 | 2 | error() << "Invalid address range " << Range << "\n"; |
396 | 2 | continue; |
397 | 2 | } |
398 | 135 | |
399 | 135 | // Verify that ranges don't intersect. |
400 | 135 | const auto IntersectingRange = RI.insert(Range); |
401 | 135 | if (IntersectingRange != RI.Ranges.end()) { |
402 | 0 | ++NumErrors; |
403 | 0 | error() << "DIE has overlapping address ranges: " << Range << " and " |
404 | 0 | << *IntersectingRange << "\n"; |
405 | 0 | break; |
406 | 0 | } |
407 | 135 | } |
408 | 548 | } |
409 | 579 | |
410 | 579 | // Verify that children don't intersect. |
411 | 579 | const auto IntersectingChild = ParentRI.insert(RI); |
412 | 579 | if (IntersectingChild != ParentRI.Children.end()) { |
413 | 2 | ++NumErrors; |
414 | 2 | error() << "DIEs have overlapping address ranges:"; |
415 | 2 | dump(Die); |
416 | 2 | dump(IntersectingChild->Die) << '\n'; |
417 | 2 | } |
418 | 579 | |
419 | 579 | // Verify that ranges are contained within their parent. |
420 | 579 | bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty()136 && |
421 | 579 | !(57 Die.getTag() == DW_TAG_subprogram57 && |
422 | 57 | ParentRI.Die.getTag() == DW_TAG_subprogram43 ); |
423 | 579 | if (ShouldBeContained && !ParentRI.contains(RI)56 ) { |
424 | 2 | ++NumErrors; |
425 | 2 | error() << "DIE address ranges are not contained in its parent's ranges:"; |
426 | 2 | dump(ParentRI.Die); |
427 | 2 | dump(Die, 2) << '\n'; |
428 | 2 | } |
429 | 579 | |
430 | 579 | // Recursively check children. |
431 | 579 | for (DWARFDie Child : Die) |
432 | 473 | NumErrors += verifyDieRanges(Child, RI); |
433 | 579 | |
434 | 579 | return NumErrors; |
435 | 579 | } |
436 | | |
437 | | unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, |
438 | 2.62k | DWARFAttribute &AttrValue) { |
439 | 2.62k | unsigned NumErrors = 0; |
440 | 2.62k | auto ReportError = [&](const Twine &TitleMsg) { |
441 | 9 | ++NumErrors; |
442 | 9 | error() << TitleMsg << '\n'; |
443 | 9 | dump(Die) << '\n'; |
444 | 9 | }; |
445 | 2.62k | |
446 | 2.62k | const DWARFObject &DObj = DCtx.getDWARFObj(); |
447 | 2.62k | const auto Attr = AttrValue.Attr; |
448 | 2.62k | switch (Attr) { |
449 | 2.62k | case DW_AT_ranges: |
450 | 6 | // Make sure the offset in the DW_AT_ranges attribute is valid. |
451 | 6 | if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { |
452 | 6 | if (*SectionOffset >= DObj.getRangeSection().Data.size()) |
453 | 1 | ReportError("DW_AT_ranges offset is beyond .debug_ranges bounds:"); |
454 | 6 | break; |
455 | 6 | } |
456 | 0 | ReportError("DIE has invalid DW_AT_ranges encoding:"); |
457 | 0 | break; |
458 | 63 | case DW_AT_stmt_list: |
459 | 63 | // Make sure the offset in the DW_AT_stmt_list attribute is valid. |
460 | 63 | if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { |
461 | 62 | if (*SectionOffset >= DObj.getLineSection().Data.size()) |
462 | 2 | ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " + |
463 | 2 | llvm::formatv("{0:x8}", *SectionOffset)); |
464 | 62 | break; |
465 | 62 | } |
466 | 1 | ReportError("DIE has invalid DW_AT_stmt_list encoding:"); |
467 | 1 | break; |
468 | 150 | case DW_AT_location: { |
469 | 158 | auto VerifyLocationExpr = [&](StringRef D) { |
470 | 158 | DWARFUnit *U = Die.getDwarfUnit(); |
471 | 158 | DataExtractor Data(D, DCtx.isLittleEndian(), 0); |
472 | 158 | DWARFExpression Expression(Data, U->getVersion(), |
473 | 158 | U->getAddressByteSize()); |
474 | 188 | bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) { |
475 | 188 | return Op.isError(); |
476 | 188 | }); |
477 | 158 | if (Error || !Expression.verify(U)157 ) |
478 | 2 | ReportError("DIE contains invalid DWARF expression:"); |
479 | 158 | }; |
480 | 150 | if (Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock()) { |
481 | 137 | // Verify inlined location. |
482 | 137 | VerifyLocationExpr(llvm::toStringRef(*Expr)); |
483 | 137 | } else if (auto 13 LocOffset13 = AttrValue.Value.getAsSectionOffset()) { |
484 | 13 | // Verify location list. |
485 | 13 | if (auto DebugLoc = DCtx.getDebugLoc()) |
486 | 13 | if (auto LocList = DebugLoc->getLocationListAtOffset(*LocOffset)) |
487 | 13 | for (const auto &Entry : LocList->Entries) |
488 | 21 | VerifyLocationExpr({Entry.Loc.data(), Entry.Loc.size()}); |
489 | 13 | } |
490 | 150 | break; |
491 | 1 | } |
492 | 10 | case DW_AT_specification: |
493 | 10 | case DW_AT_abstract_origin: { |
494 | 10 | if (auto ReferencedDie = Die.getAttributeValueAsReferencedDie(Attr)) { |
495 | 10 | auto DieTag = Die.getTag(); |
496 | 10 | auto RefTag = ReferencedDie.getTag(); |
497 | 10 | if (DieTag == RefTag) |
498 | 0 | break; |
499 | 10 | if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram9 ) |
500 | 8 | break; |
501 | 2 | if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member0 ) |
502 | 0 | break; |
503 | 2 | ReportError("DIE with tag " + TagString(DieTag) + " has " + |
504 | 2 | AttributeString(Attr) + |
505 | 2 | " that points to DIE with " |
506 | 2 | "incompatible tag " + |
507 | 2 | TagString(RefTag)); |
508 | 2 | } |
509 | 10 | break2 ; |
510 | 10 | } |
511 | 322 | case DW_AT_type: { |
512 | 322 | DWARFDie TypeDie = Die.getAttributeValueAsReferencedDie(DW_AT_type); |
513 | 322 | if (TypeDie && !isType(TypeDie.getTag())315 ) { |
514 | 1 | ReportError("DIE has " + AttributeString(Attr) + |
515 | 1 | " with incompatible tag " + TagString(TypeDie.getTag())); |
516 | 1 | } |
517 | 322 | break; |
518 | 10 | } |
519 | 2.07k | default: |
520 | 2.07k | break; |
521 | 2.62k | } |
522 | 2.62k | return NumErrors; |
523 | 2.62k | } |
524 | | |
525 | | unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, |
526 | 2.62k | DWARFAttribute &AttrValue) { |
527 | 2.62k | const DWARFObject &DObj = DCtx.getDWARFObj(); |
528 | 2.62k | auto DieCU = Die.getDwarfUnit(); |
529 | 2.62k | unsigned NumErrors = 0; |
530 | 2.62k | const auto Form = AttrValue.Value.getForm(); |
531 | 2.62k | switch (Form) { |
532 | 2.62k | case DW_FORM_ref1: |
533 | 323 | case DW_FORM_ref2: |
534 | 323 | case DW_FORM_ref4: |
535 | 323 | case DW_FORM_ref8: |
536 | 323 | case DW_FORM_ref_udata: { |
537 | 323 | // Verify all CU relative references are valid CU offsets. |
538 | 323 | Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); |
539 | 323 | assert(RefVal); |
540 | 323 | if (RefVal) { |
541 | 323 | auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); |
542 | 323 | auto CUOffset = AttrValue.Value.getRawUValue(); |
543 | 323 | if (CUOffset >= CUSize) { |
544 | 1 | ++NumErrors; |
545 | 1 | error() << FormEncodingString(Form) << " CU offset " |
546 | 1 | << format("0x%08" PRIx64, CUOffset) |
547 | 1 | << " is invalid (must be less than CU size of " |
548 | 1 | << format("0x%08" PRIx32, CUSize) << "):\n"; |
549 | 1 | Die.dump(OS, 0, DumpOpts); |
550 | 1 | dump(Die) << '\n'; |
551 | 322 | } else { |
552 | 322 | // Valid reference, but we will verify it points to an actual |
553 | 322 | // DIE later. |
554 | 322 | ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); |
555 | 322 | } |
556 | 323 | } |
557 | 323 | break; |
558 | 323 | } |
559 | 323 | case DW_FORM_ref_addr: { |
560 | 38 | // Verify all absolute DIE references have valid offsets in the |
561 | 38 | // .debug_info section. |
562 | 38 | Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); |
563 | 38 | assert(RefVal); |
564 | 38 | if (RefVal) { |
565 | 38 | if (*RefVal >= DieCU->getInfoSection().Data.size()) { |
566 | 1 | ++NumErrors; |
567 | 1 | error() << "DW_FORM_ref_addr offset beyond .debug_info " |
568 | 1 | "bounds:\n"; |
569 | 1 | dump(Die) << '\n'; |
570 | 37 | } else { |
571 | 37 | // Valid reference, but we will verify it points to an actual |
572 | 37 | // DIE later. |
573 | 37 | ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); |
574 | 37 | } |
575 | 38 | } |
576 | 38 | break; |
577 | 323 | } |
578 | 593 | case DW_FORM_strp: { |
579 | 593 | auto SecOffset = AttrValue.Value.getAsSectionOffset(); |
580 | 593 | assert(SecOffset); // DW_FORM_strp is a section offset. |
581 | 593 | if (SecOffset && *SecOffset >= DObj.getStringSection().size()) { |
582 | 1 | ++NumErrors; |
583 | 1 | error() << "DW_FORM_strp offset beyond .debug_str bounds:\n"; |
584 | 1 | dump(Die) << '\n'; |
585 | 1 | } |
586 | 593 | break; |
587 | 323 | } |
588 | 323 | case DW_FORM_strx: |
589 | 35 | case DW_FORM_strx1: |
590 | 35 | case DW_FORM_strx2: |
591 | 35 | case DW_FORM_strx3: |
592 | 35 | case DW_FORM_strx4: { |
593 | 35 | auto Index = AttrValue.Value.getRawUValue(); |
594 | 35 | auto DieCU = Die.getDwarfUnit(); |
595 | 35 | // Check that we have a valid DWARF v5 string offsets table. |
596 | 35 | if (!DieCU->getStringOffsetsTableContribution()) { |
597 | 1 | ++NumErrors; |
598 | 1 | error() << FormEncodingString(Form) |
599 | 1 | << " used without a valid string offsets table:\n"; |
600 | 1 | dump(Die) << '\n'; |
601 | 1 | break; |
602 | 1 | } |
603 | 34 | // Check that the index is within the bounds of the section. |
604 | 34 | unsigned ItemSize = DieCU->getDwarfStringOffsetsByteSize(); |
605 | 34 | // Use a 64-bit type to calculate the offset to guard against overflow. |
606 | 34 | uint64_t Offset = |
607 | 34 | (uint64_t)DieCU->getStringOffsetsBase() + Index * ItemSize; |
608 | 34 | if (DObj.getStringOffsetSection().Data.size() < Offset + ItemSize) { |
609 | 1 | ++NumErrors; |
610 | 1 | error() << FormEncodingString(Form) << " uses index " |
611 | 1 | << format("%" PRIu64, Index) << ", which is too large:\n"; |
612 | 1 | dump(Die) << '\n'; |
613 | 1 | break; |
614 | 1 | } |
615 | 33 | // Check that the string offset is valid. |
616 | 33 | uint64_t StringOffset = *DieCU->getStringOffsetSectionItem(Index); |
617 | 33 | if (StringOffset >= DObj.getStringSection().size()) { |
618 | 1 | ++NumErrors; |
619 | 1 | error() << FormEncodingString(Form) << " uses index " |
620 | 1 | << format("%" PRIu64, Index) |
621 | 1 | << ", but the referenced string" |
622 | 1 | " offset is beyond .debug_str bounds:\n"; |
623 | 1 | dump(Die) << '\n'; |
624 | 1 | } |
625 | 33 | break; |
626 | 33 | } |
627 | 1.63k | default: |
628 | 1.63k | break; |
629 | 2.62k | } |
630 | 2.62k | return NumErrors; |
631 | 2.62k | } |
632 | | |
633 | 73 | unsigned DWARFVerifier::verifyDebugInfoReferences() { |
634 | 73 | // Take all references and make sure they point to an actual DIE by |
635 | 73 | // getting the DIE by offset and emitting an error |
636 | 73 | OS << "Verifying .debug_info references...\n"; |
637 | 73 | unsigned NumErrors = 0; |
638 | 73 | for (const std::pair<uint64_t, std::set<uint32_t>> &Pair : |
639 | 163 | ReferenceToDIEOffsets) { |
640 | 163 | if (DCtx.getDIEForOffset(Pair.first)) |
641 | 162 | continue; |
642 | 1 | ++NumErrors; |
643 | 1 | error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first) |
644 | 1 | << ". Offset is in between DIEs:\n"; |
645 | 1 | for (auto Offset : Pair.second) |
646 | 1 | dump(DCtx.getDIEForOffset(Offset)) << '\n'; |
647 | 1 | OS << "\n"; |
648 | 1 | } |
649 | 73 | return NumErrors; |
650 | 73 | } |
651 | | |
652 | 35 | void DWARFVerifier::verifyDebugLineStmtOffsets() { |
653 | 35 | std::map<uint64_t, DWARFDie> StmtListToDie; |
654 | 55 | for (const auto &CU : DCtx.compile_units()) { |
655 | 55 | auto Die = CU->getUnitDIE(); |
656 | 55 | // Get the attribute value as a section offset. No need to produce an |
657 | 55 | // error here if the encoding isn't correct because we validate this in |
658 | 55 | // the .debug_info verifier. |
659 | 55 | auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list)); |
660 | 55 | if (!StmtSectionOffset) |
661 | 15 | continue; |
662 | 40 | const uint32_t LineTableOffset = *StmtSectionOffset; |
663 | 40 | auto LineTable = DCtx.getLineTableForUnit(CU.get()); |
664 | 40 | if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) { |
665 | 39 | if (!LineTable) { |
666 | 0 | ++NumDebugLineErrors; |
667 | 0 | error() << ".debug_line[" << format("0x%08" PRIx32, LineTableOffset) |
668 | 0 | << "] was not able to be parsed for CU:\n"; |
669 | 0 | dump(Die) << '\n'; |
670 | 0 | continue; |
671 | 0 | } |
672 | 1 | } else { |
673 | 1 | // Make sure we don't get a valid line table back if the offset is wrong. |
674 | 1 | assert(LineTable == nullptr); |
675 | 1 | // Skip this line table as it isn't valid. No need to create an error |
676 | 1 | // here because we validate this in the .debug_info verifier. |
677 | 1 | continue; |
678 | 1 | } |
679 | 39 | auto Iter = StmtListToDie.find(LineTableOffset); |
680 | 39 | if (Iter != StmtListToDie.end()) { |
681 | 1 | ++NumDebugLineErrors; |
682 | 1 | error() << "two compile unit DIEs, " |
683 | 1 | << format("0x%08" PRIx32, Iter->second.getOffset()) << " and " |
684 | 1 | << format("0x%08" PRIx32, Die.getOffset()) |
685 | 1 | << ", have the same DW_AT_stmt_list section offset:\n"; |
686 | 1 | dump(Iter->second); |
687 | 1 | dump(Die) << '\n'; |
688 | 1 | // Already verified this line table before, no need to do it again. |
689 | 1 | continue; |
690 | 1 | } |
691 | 38 | StmtListToDie[LineTableOffset] = Die; |
692 | 38 | } |
693 | 35 | } |
694 | | |
695 | 35 | void DWARFVerifier::verifyDebugLineRows() { |
696 | 55 | for (const auto &CU : DCtx.compile_units()) { |
697 | 55 | auto Die = CU->getUnitDIE(); |
698 | 55 | auto LineTable = DCtx.getLineTableForUnit(CU.get()); |
699 | 55 | // If there is no line table we will have created an error in the |
700 | 55 | // .debug_info verifier or in verifyDebugLineStmtOffsets(). |
701 | 55 | if (!LineTable) |
702 | 16 | continue; |
703 | 39 | |
704 | 39 | // Verify prologue. |
705 | 39 | uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size(); |
706 | 39 | uint32_t FileIndex = 1; |
707 | 39 | StringMap<uint16_t> FullPathMap; |
708 | 48 | for (const auto &FileName : LineTable->Prologue.FileNames) { |
709 | 48 | // Verify directory index. |
710 | 48 | if (FileName.DirIdx > MaxDirIndex) { |
711 | 1 | ++NumDebugLineErrors; |
712 | 1 | error() << ".debug_line[" |
713 | 1 | << format("0x%08" PRIx64, |
714 | 1 | *toSectionOffset(Die.find(DW_AT_stmt_list))) |
715 | 1 | << "].prologue.file_names[" << FileIndex |
716 | 1 | << "].dir_idx contains an invalid index: " << FileName.DirIdx |
717 | 1 | << "\n"; |
718 | 1 | } |
719 | 48 | |
720 | 48 | // Check file paths for duplicates. |
721 | 48 | std::string FullPath; |
722 | 48 | const bool HasFullPath = LineTable->getFileNameByIndex( |
723 | 48 | FileIndex, CU->getCompilationDir(), |
724 | 48 | DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath); |
725 | 48 | assert(HasFullPath && "Invalid index?"); |
726 | 48 | (void)HasFullPath; |
727 | 48 | auto It = FullPathMap.find(FullPath); |
728 | 48 | if (It == FullPathMap.end()) |
729 | 47 | FullPathMap[FullPath] = FileIndex; |
730 | 1 | else if (It->second != FileIndex) { |
731 | 1 | warn() << ".debug_line[" |
732 | 1 | << format("0x%08" PRIx64, |
733 | 1 | *toSectionOffset(Die.find(DW_AT_stmt_list))) |
734 | 1 | << "].prologue.file_names[" << FileIndex |
735 | 1 | << "] is a duplicate of file_names[" << It->second << "]\n"; |
736 | 1 | } |
737 | 48 | |
738 | 48 | FileIndex++; |
739 | 48 | } |
740 | 39 | |
741 | 39 | // Verify rows. |
742 | 39 | uint64_t PrevAddress = 0; |
743 | 39 | uint32_t RowIndex = 0; |
744 | 197 | for (const auto &Row : LineTable->Rows) { |
745 | 197 | // Verify row address. |
746 | 197 | if (Row.Address.Address < PrevAddress) { |
747 | 1 | ++NumDebugLineErrors; |
748 | 1 | error() << ".debug_line[" |
749 | 1 | << format("0x%08" PRIx64, |
750 | 1 | *toSectionOffset(Die.find(DW_AT_stmt_list))) |
751 | 1 | << "] row[" << RowIndex |
752 | 1 | << "] decreases in address from previous row:\n"; |
753 | 1 | |
754 | 1 | DWARFDebugLine::Row::dumpTableHeader(OS); |
755 | 1 | if (RowIndex > 0) |
756 | 1 | LineTable->Rows[RowIndex - 1].dump(OS); |
757 | 1 | Row.dump(OS); |
758 | 1 | OS << '\n'; |
759 | 1 | } |
760 | 197 | |
761 | 197 | // Verify file index. |
762 | 197 | if (!LineTable->hasFileAtIndex(Row.File)) { |
763 | 1 | ++NumDebugLineErrors; |
764 | 1 | bool isDWARF5 = LineTable->Prologue.getVersion() >= 5; |
765 | 1 | error() << ".debug_line[" |
766 | 1 | << format("0x%08" PRIx64, |
767 | 1 | *toSectionOffset(Die.find(DW_AT_stmt_list))) |
768 | 1 | << "][" << RowIndex << "] has invalid file index " << Row.File |
769 | 1 | << " (valid values are [" << (isDWARF5 ? "0,"0 : "1,") |
770 | 1 | << LineTable->Prologue.FileNames.size() |
771 | 1 | << (isDWARF5 ? ")"0 : "]") << "):\n"; |
772 | 1 | DWARFDebugLine::Row::dumpTableHeader(OS); |
773 | 1 | Row.dump(OS); |
774 | 1 | OS << '\n'; |
775 | 1 | } |
776 | 197 | if (Row.EndSequence) |
777 | 49 | PrevAddress = 0; |
778 | 148 | else |
779 | 148 | PrevAddress = Row.Address.Address; |
780 | 197 | ++RowIndex; |
781 | 197 | } |
782 | 39 | } |
783 | 35 | } |
784 | | |
785 | | DWARFVerifier::DWARFVerifier(raw_ostream &S, DWARFContext &D, |
786 | | DIDumpOptions DumpOpts) |
787 | | : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)), IsObjectFile(false), |
788 | 83 | IsMachOObject(false) { |
789 | 83 | if (const auto *F = DCtx.getDWARFObj().getFile()) { |
790 | 65 | IsObjectFile = F->isRelocatableObject(); |
791 | 65 | IsMachOObject = F->isMachO(); |
792 | 65 | } |
793 | 83 | } |
794 | | |
795 | 35 | bool DWARFVerifier::handleDebugLine() { |
796 | 35 | NumDebugLineErrors = 0; |
797 | 35 | OS << "Verifying .debug_line...\n"; |
798 | 35 | verifyDebugLineStmtOffsets(); |
799 | 35 | verifyDebugLineRows(); |
800 | 35 | return NumDebugLineErrors == 0; |
801 | 35 | } |
802 | | |
803 | | unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection, |
804 | | DataExtractor *StrData, |
805 | 76 | const char *SectionName) { |
806 | 76 | unsigned NumErrors = 0; |
807 | 76 | DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection, |
808 | 76 | DCtx.isLittleEndian(), 0); |
809 | 76 | AppleAcceleratorTable AccelTable(AccelSectionData, *StrData); |
810 | 76 | |
811 | 76 | OS << "Verifying " << SectionName << "...\n"; |
812 | 76 | |
813 | 76 | // Verify that the fixed part of the header is not too short. |
814 | 76 | if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) { |
815 | 0 | error() << "Section is too small to fit a section header.\n"; |
816 | 0 | return 1; |
817 | 0 | } |
818 | 76 | |
819 | 76 | // Verify that the section is not too short. |
820 | 76 | if (Error E = AccelTable.extract()) { |
821 | 1 | error() << toString(std::move(E)) << '\n'; |
822 | 1 | return 1; |
823 | 1 | } |
824 | 75 | |
825 | 75 | // Verify that all buckets have a valid hash index or are empty. |
826 | 75 | uint32_t NumBuckets = AccelTable.getNumBuckets(); |
827 | 75 | uint32_t NumHashes = AccelTable.getNumHashes(); |
828 | 75 | |
829 | 75 | uint32_t BucketsOffset = |
830 | 75 | AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength(); |
831 | 75 | uint32_t HashesBase = BucketsOffset + NumBuckets * 4; |
832 | 75 | uint32_t OffsetsBase = HashesBase + NumHashes * 4; |
833 | 261 | for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx186 ) { |
834 | 186 | uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset); |
835 | 186 | if (HashIdx >= NumHashes && HashIdx != UINT32_MAX67 ) { |
836 | 1 | error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx, |
837 | 1 | HashIdx); |
838 | 1 | ++NumErrors; |
839 | 1 | } |
840 | 186 | } |
841 | 75 | uint32_t NumAtoms = AccelTable.getAtomsDesc().size(); |
842 | 75 | if (NumAtoms == 0) { |
843 | 1 | error() << "No atoms: failed to read HashData.\n"; |
844 | 1 | return 1; |
845 | 1 | } |
846 | 74 | if (!AccelTable.validateForms()) { |
847 | 1 | error() << "Unsupported form: failed to read HashData.\n"; |
848 | 1 | return 1; |
849 | 1 | } |
850 | 73 | |
851 | 242 | for (uint32_t HashIdx = 0; 73 HashIdx < NumHashes; ++HashIdx169 ) { |
852 | 169 | uint32_t HashOffset = HashesBase + 4 * HashIdx; |
853 | 169 | uint32_t DataOffset = OffsetsBase + 4 * HashIdx; |
854 | 169 | uint32_t Hash = AccelSectionData.getU32(&HashOffset); |
855 | 169 | uint32_t HashDataOffset = AccelSectionData.getU32(&DataOffset); |
856 | 169 | if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset, |
857 | 169 | sizeof(uint64_t))) { |
858 | 1 | error() << format("Hash[%d] has invalid HashData offset: 0x%08x.\n", |
859 | 1 | HashIdx, HashDataOffset); |
860 | 1 | ++NumErrors; |
861 | 1 | } |
862 | 169 | |
863 | 169 | uint32_t StrpOffset; |
864 | 169 | uint32_t StringOffset; |
865 | 169 | uint32_t StringCount = 0; |
866 | 169 | unsigned Offset; |
867 | 169 | unsigned Tag; |
868 | 338 | while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) { |
869 | 169 | const uint32_t NumHashDataObjects = |
870 | 169 | AccelSectionData.getU32(&HashDataOffset); |
871 | 382 | for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects; |
872 | 213 | ++HashDataIdx) { |
873 | 213 | std::tie(Offset, Tag) = AccelTable.readAtoms(HashDataOffset); |
874 | 213 | auto Die = DCtx.getDIEForOffset(Offset); |
875 | 213 | if (!Die) { |
876 | 1 | const uint32_t BucketIdx = |
877 | 1 | NumBuckets ? (Hash % NumBuckets) : UINT32_MAX; |
878 | 1 | StringOffset = StrpOffset; |
879 | 1 | const char *Name = StrData->getCStr(&StringOffset); |
880 | 1 | if (!Name) |
881 | 0 | Name = "<NULL>"; |
882 | 1 | |
883 | 1 | error() << format( |
884 | 1 | "%s Bucket[%d] Hash[%d] = 0x%08x " |
885 | 1 | "Str[%u] = 0x%08x " |
886 | 1 | "DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n", |
887 | 1 | SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset, |
888 | 1 | HashDataIdx, Offset, Name); |
889 | 1 | |
890 | 1 | ++NumErrors; |
891 | 1 | continue; |
892 | 1 | } |
893 | 212 | if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)57 ) { |
894 | 1 | error() << "Tag " << dwarf::TagString(Tag) |
895 | 1 | << " in accelerator table does not match Tag " |
896 | 1 | << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx |
897 | 1 | << "].\n"; |
898 | 1 | ++NumErrors; |
899 | 1 | } |
900 | 212 | } |
901 | 169 | ++StringCount; |
902 | 169 | } |
903 | 169 | } |
904 | 73 | return NumErrors; |
905 | 73 | } |
906 | | |
907 | | unsigned |
908 | 23 | DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) { |
909 | 23 | // A map from CU offset to the (first) Name Index offset which claims to index |
910 | 23 | // this CU. |
911 | 23 | DenseMap<uint32_t, uint32_t> CUMap; |
912 | 23 | const uint32_t NotIndexed = std::numeric_limits<uint32_t>::max(); |
913 | 23 | |
914 | 23 | CUMap.reserve(DCtx.getNumCompileUnits()); |
915 | 23 | for (const auto &CU : DCtx.compile_units()) |
916 | 288 | CUMap[CU->getOffset()] = NotIndexed; |
917 | 23 | |
918 | 23 | unsigned NumErrors = 0; |
919 | 26 | for (const DWARFDebugNames::NameIndex &NI : AccelTable) { |
920 | 26 | if (NI.getCUCount() == 0) { |
921 | 1 | error() << formatv("Name Index @ {0:x} does not index any CU\n", |
922 | 1 | NI.getUnitOffset()); |
923 | 1 | ++NumErrors; |
924 | 1 | continue; |
925 | 1 | } |
926 | 314 | for (uint32_t CU = 0, End = NI.getCUCount(); 25 CU < End; ++CU289 ) { |
927 | 289 | uint32_t Offset = NI.getCUOffset(CU); |
928 | 289 | auto Iter = CUMap.find(Offset); |
929 | 289 | |
930 | 289 | if (Iter == CUMap.end()) { |
931 | 1 | error() << formatv( |
932 | 1 | "Name Index @ {0:x} references a non-existing CU @ {1:x}\n", |
933 | 1 | NI.getUnitOffset(), Offset); |
934 | 1 | ++NumErrors; |
935 | 1 | continue; |
936 | 1 | } |
937 | 288 | |
938 | 288 | if (Iter->second != NotIndexed) { |
939 | 1 | error() << formatv("Name Index @ {0:x} references a CU @ {1:x}, but " |
940 | 1 | "this CU is already indexed by Name Index @ {2:x}\n", |
941 | 1 | NI.getUnitOffset(), Offset, Iter->second); |
942 | 1 | continue; |
943 | 1 | } |
944 | 287 | Iter->second = NI.getUnitOffset(); |
945 | 287 | } |
946 | 25 | } |
947 | 23 | |
948 | 288 | for (const auto &KV : CUMap) { |
949 | 288 | if (KV.second == NotIndexed) |
950 | 1 | warn() << formatv("CU @ {0:x} not covered by any Name Index\n", KV.first); |
951 | 288 | } |
952 | 23 | |
953 | 23 | return NumErrors; |
954 | 23 | } |
955 | | |
956 | | unsigned |
957 | | DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI, |
958 | 26 | const DataExtractor &StrData) { |
959 | 26 | struct BucketInfo { |
960 | 26 | uint32_t Bucket; |
961 | 26 | uint32_t Index; |
962 | 26 | |
963 | 26 | constexpr BucketInfo(uint32_t Bucket, uint32_t Index) |
964 | 197 | : Bucket(Bucket), Index(Index) {} |
965 | 368 | bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; }; |
966 | 26 | }; |
967 | 26 | |
968 | 26 | uint32_t NumErrors = 0; |
969 | 26 | if (NI.getBucketCount() == 0) { |
970 | 8 | warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n", |
971 | 8 | NI.getUnitOffset()); |
972 | 8 | return NumErrors; |
973 | 8 | } |
974 | 18 | |
975 | 18 | // Build up a list of (Bucket, Index) pairs. We use this later to verify that |
976 | 18 | // each Name is reachable from the appropriate bucket. |
977 | 18 | std::vector<BucketInfo> BucketStarts; |
978 | 18 | BucketStarts.reserve(NI.getBucketCount() + 1); |
979 | 230 | for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket212 ) { |
980 | 212 | uint32_t Index = NI.getBucketArrayEntry(Bucket); |
981 | 212 | if (Index > NI.getNameCount()) { |
982 | 1 | error() << formatv("Bucket {0} of Name Index @ {1:x} contains invalid " |
983 | 1 | "value {2}. Valid range is [0, {3}].\n", |
984 | 1 | Bucket, NI.getUnitOffset(), Index, NI.getNameCount()); |
985 | 1 | ++NumErrors; |
986 | 1 | continue; |
987 | 1 | } |
988 | 211 | if (Index > 0) |
989 | 180 | BucketStarts.emplace_back(Bucket, Index); |
990 | 211 | } |
991 | 18 | |
992 | 18 | // If there were any buckets with invalid values, skip further checks as they |
993 | 18 | // will likely produce many errors which will only confuse the actual root |
994 | 18 | // problem. |
995 | 18 | if (NumErrors > 0) |
996 | 1 | return NumErrors; |
997 | 17 | |
998 | 17 | // Sort the list in the order of increasing "Index" entries. |
999 | 17 | array_pod_sort(BucketStarts.begin(), BucketStarts.end()); |
1000 | 17 | |
1001 | 17 | // Insert a sentinel entry at the end, so we can check that the end of the |
1002 | 17 | // table is covered in the loop below. |
1003 | 17 | BucketStarts.emplace_back(NI.getBucketCount(), NI.getNameCount() + 1); |
1004 | 17 | |
1005 | 17 | // Loop invariant: NextUncovered is the (1-based) index of the first Name |
1006 | 17 | // which is not reachable by any of the buckets we processed so far (and |
1007 | 17 | // hasn't been reported as uncovered). |
1008 | 17 | uint32_t NextUncovered = 1; |
1009 | 196 | for (const BucketInfo &B : BucketStarts) { |
1010 | 196 | // Under normal circumstances B.Index be equal to NextUncovered, but it can |
1011 | 196 | // be less if a bucket points to names which are already known to be in some |
1012 | 196 | // bucket we processed earlier. In that case, we won't trigger this error, |
1013 | 196 | // but report the mismatched hash value error instead. (We know the hash |
1014 | 196 | // will not match because we have already verified that the name's hash |
1015 | 196 | // puts it into the previous bucket.) |
1016 | 196 | if (B.Index > NextUncovered) { |
1017 | 2 | error() << formatv("Name Index @ {0:x}: Name table entries [{1}, {2}] " |
1018 | 2 | "are not covered by the hash table.\n", |
1019 | 2 | NI.getUnitOffset(), NextUncovered, B.Index - 1); |
1020 | 2 | ++NumErrors; |
1021 | 2 | } |
1022 | 196 | uint32_t Idx = B.Index; |
1023 | 196 | |
1024 | 196 | // The rest of the checks apply only to non-sentinel entries. |
1025 | 196 | if (B.Bucket == NI.getBucketCount()) |
1026 | 17 | break; |
1027 | 179 | |
1028 | 179 | // This triggers if a non-empty bucket points to a name with a mismatched |
1029 | 179 | // hash. Clients are likely to interpret this as an empty bucket, because a |
1030 | 179 | // mismatched hash signals the end of a bucket, but if this is indeed an |
1031 | 179 | // empty bucket, the producer should have signalled this by marking the |
1032 | 179 | // bucket as empty. |
1033 | 179 | uint32_t FirstHash = NI.getHashArrayEntry(Idx); |
1034 | 179 | if (FirstHash % NI.getBucketCount() != B.Bucket) { |
1035 | 1 | error() << formatv( |
1036 | 1 | "Name Index @ {0:x}: Bucket {1} is not empty but points to a " |
1037 | 1 | "mismatched hash value {2:x} (belonging to bucket {3}).\n", |
1038 | 1 | NI.getUnitOffset(), B.Bucket, FirstHash, |
1039 | 1 | FirstHash % NI.getBucketCount()); |
1040 | 1 | ++NumErrors; |
1041 | 1 | } |
1042 | 179 | |
1043 | 179 | // This find the end of this bucket and also verifies that all the hashes in |
1044 | 179 | // this bucket are correct by comparing the stored hashes to the ones we |
1045 | 179 | // compute ourselves. |
1046 | 523 | while (Idx <= NI.getNameCount()) { |
1047 | 508 | uint32_t Hash = NI.getHashArrayEntry(Idx); |
1048 | 508 | if (Hash % NI.getBucketCount() != B.Bucket) |
1049 | 164 | break; |
1050 | 344 | |
1051 | 344 | const char *Str = NI.getNameTableEntry(Idx).getString(); |
1052 | 344 | if (caseFoldingDjbHash(Str) != Hash) { |
1053 | 1 | error() << formatv("Name Index @ {0:x}: String ({1}) at index {2} " |
1054 | 1 | "hashes to {3:x}, but " |
1055 | 1 | "the Name Index hash is {4:x}\n", |
1056 | 1 | NI.getUnitOffset(), Str, Idx, |
1057 | 1 | caseFoldingDjbHash(Str), Hash); |
1058 | 1 | ++NumErrors; |
1059 | 1 | } |
1060 | 344 | |
1061 | 344 | ++Idx; |
1062 | 344 | } |
1063 | 179 | NextUncovered = std::max(NextUncovered, Idx); |
1064 | 179 | } |
1065 | 17 | return NumErrors; |
1066 | 17 | } |
1067 | | |
1068 | | unsigned DWARFVerifier::verifyNameIndexAttribute( |
1069 | | const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr, |
1070 | 62 | DWARFDebugNames::AttributeEncoding AttrEnc) { |
1071 | 62 | StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form); |
1072 | 62 | if (FormName.empty()) { |
1073 | 1 | error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " |
1074 | 1 | "unknown form: {3}.\n", |
1075 | 1 | NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, |
1076 | 1 | AttrEnc.Form); |
1077 | 1 | return 1; |
1078 | 1 | } |
1079 | 61 | |
1080 | 61 | if (AttrEnc.Index == DW_IDX_type_hash) { |
1081 | 1 | if (AttrEnc.Form != dwarf::DW_FORM_data8) { |
1082 | 1 | error() << formatv( |
1083 | 1 | "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash " |
1084 | 1 | "uses an unexpected form {2} (should be {3}).\n", |
1085 | 1 | NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8); |
1086 | 1 | return 1; |
1087 | 1 | } |
1088 | 60 | } |
1089 | 60 | |
1090 | 60 | // A list of known index attributes and their expected form classes. |
1091 | 60 | // DW_IDX_type_hash is handled specially in the check above, as it has a |
1092 | 60 | // specific form (not just a form class) we should expect. |
1093 | 60 | struct FormClassTable { |
1094 | 60 | dwarf::Index Index; |
1095 | 60 | DWARFFormValue::FormClass Class; |
1096 | 60 | StringLiteral ClassName; |
1097 | 60 | }; |
1098 | 60 | static constexpr FormClassTable Table[] = { |
1099 | 60 | {dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}}, |
1100 | 60 | {dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}}, |
1101 | 60 | {dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}}, |
1102 | 60 | {dwarf::DW_IDX_parent, DWARFFormValue::FC_Constant, {"constant"}}, |
1103 | 60 | }; |
1104 | 60 | |
1105 | 60 | ArrayRef<FormClassTable> TableRef(Table); |
1106 | 157 | auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) { |
1107 | 157 | return T.Index == AttrEnc.Index; |
1108 | 157 | }); |
1109 | 60 | if (Iter == TableRef.end()) { |
1110 | 1 | warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an " |
1111 | 1 | "unknown index attribute: {2}.\n", |
1112 | 1 | NI.getUnitOffset(), Abbr.Code, AttrEnc.Index); |
1113 | 1 | return 0; |
1114 | 1 | } |
1115 | 59 | |
1116 | 59 | if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) { |
1117 | 2 | error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " |
1118 | 2 | "unexpected form {3} (expected form class {4}).\n", |
1119 | 2 | NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, |
1120 | 2 | AttrEnc.Form, Iter->ClassName); |
1121 | 2 | return 1; |
1122 | 2 | } |
1123 | 57 | return 0; |
1124 | 57 | } |
1125 | | |
1126 | | unsigned |
1127 | 26 | DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) { |
1128 | 26 | if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) { |
1129 | 0 | warn() << formatv("Name Index @ {0:x}: Verifying indexes of type units is " |
1130 | 0 | "not currently supported.\n", |
1131 | 0 | NI.getUnitOffset()); |
1132 | 0 | return 0; |
1133 | 0 | } |
1134 | 26 | |
1135 | 26 | unsigned NumErrors = 0; |
1136 | 48 | for (const auto &Abbrev : NI.getAbbrevs()) { |
1137 | 48 | StringRef TagName = dwarf::TagString(Abbrev.Tag); |
1138 | 48 | if (TagName.empty()) { |
1139 | 1 | warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an " |
1140 | 1 | "unknown tag: {2}.\n", |
1141 | 1 | NI.getUnitOffset(), Abbrev.Code, Abbrev.Tag); |
1142 | 1 | } |
1143 | 48 | SmallSet<unsigned, 5> Attributes; |
1144 | 64 | for (const auto &AttrEnc : Abbrev.Attributes) { |
1145 | 64 | if (!Attributes.insert(AttrEnc.Index).second) { |
1146 | 2 | error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains " |
1147 | 2 | "multiple {2} attributes.\n", |
1148 | 2 | NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index); |
1149 | 2 | ++NumErrors; |
1150 | 2 | continue; |
1151 | 2 | } |
1152 | 62 | NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc); |
1153 | 62 | } |
1154 | 48 | |
1155 | 48 | if (NI.getCUCount() > 1 && !Attributes.count(dwarf::DW_IDX_compile_unit)12 ) { |
1156 | 1 | error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units " |
1157 | 1 | "and abbreviation {1:x} has no {2} attribute.\n", |
1158 | 1 | NI.getUnitOffset(), Abbrev.Code, |
1159 | 1 | dwarf::DW_IDX_compile_unit); |
1160 | 1 | ++NumErrors; |
1161 | 1 | } |
1162 | 48 | if (!Attributes.count(dwarf::DW_IDX_die_offset)) { |
1163 | 2 | error() << formatv( |
1164 | 2 | "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n", |
1165 | 2 | NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset); |
1166 | 2 | ++NumErrors; |
1167 | 2 | } |
1168 | 48 | } |
1169 | 26 | return NumErrors; |
1170 | 26 | } |
1171 | | |
1172 | | static SmallVector<StringRef, 2> getNames(const DWARFDie &DIE, |
1173 | 1.34k | bool IncludeLinkageName = true) { |
1174 | 1.34k | SmallVector<StringRef, 2> Result; |
1175 | 1.34k | if (const char *Str = DIE.getName(DINameKind::ShortName)) |
1176 | 1.00k | Result.emplace_back(Str); |
1177 | 343 | else if (DIE.getTag() == dwarf::DW_TAG_namespace) |
1178 | 2 | Result.emplace_back("(anonymous namespace)"); |
1179 | 1.34k | |
1180 | 1.34k | if (IncludeLinkageName) { |
1181 | 391 | if (const char *Str = DIE.getName(DINameKind::LinkageName)) { |
1182 | 390 | if (Result.empty() || Result[0] != Str386 ) |
1183 | 53 | Result.emplace_back(Str); |
1184 | 390 | } |
1185 | 391 | } |
1186 | 1.34k | |
1187 | 1.34k | return Result; |
1188 | 1.34k | } |
1189 | | |
1190 | | unsigned DWARFVerifier::verifyNameIndexEntries( |
1191 | | const DWARFDebugNames::NameIndex &NI, |
1192 | 345 | const DWARFDebugNames::NameTableEntry &NTE) { |
1193 | 345 | // Verifying type unit indexes not supported. |
1194 | 345 | if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) |
1195 | 0 | return 0; |
1196 | 345 | |
1197 | 345 | const char *CStr = NTE.getString(); |
1198 | 345 | if (!CStr) { |
1199 | 1 | error() << formatv( |
1200 | 1 | "Name Index @ {0:x}: Unable to get string associated with name {1}.\n", |
1201 | 1 | NI.getUnitOffset(), NTE.getIndex()); |
1202 | 1 | return 1; |
1203 | 1 | } |
1204 | 344 | StringRef Str(CStr); |
1205 | 344 | |
1206 | 344 | unsigned NumErrors = 0; |
1207 | 344 | unsigned NumEntries = 0; |
1208 | 344 | uint32_t EntryID = NTE.getEntryOffset(); |
1209 | 344 | uint32_t NextEntryID = EntryID; |
1210 | 344 | Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&NextEntryID); |
1211 | 705 | for (; EntryOr; ++NumEntries, EntryID = NextEntryID, |
1212 | 361 | EntryOr = NI.getEntry(&NextEntryID)) { |
1213 | 361 | uint32_t CUIndex = *EntryOr->getCUIndex(); |
1214 | 361 | if (CUIndex > NI.getCUCount()) { |
1215 | 1 | error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an " |
1216 | 1 | "invalid CU index ({2}).\n", |
1217 | 1 | NI.getUnitOffset(), EntryID, CUIndex); |
1218 | 1 | ++NumErrors; |
1219 | 1 | continue; |
1220 | 1 | } |
1221 | 360 | uint32_t CUOffset = NI.getCUOffset(CUIndex); |
1222 | 360 | uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset(); |
1223 | 360 | DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset); |
1224 | 360 | if (!DIE) { |
1225 | 1 | error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a " |
1226 | 1 | "non-existing DIE @ {2:x}.\n", |
1227 | 1 | NI.getUnitOffset(), EntryID, DIEOffset); |
1228 | 1 | ++NumErrors; |
1229 | 1 | continue; |
1230 | 1 | } |
1231 | 359 | if (DIE.getDwarfUnit()->getOffset() != CUOffset) { |
1232 | 1 | error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of " |
1233 | 1 | "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n", |
1234 | 1 | NI.getUnitOffset(), EntryID, DIEOffset, CUOffset, |
1235 | 1 | DIE.getDwarfUnit()->getOffset()); |
1236 | 1 | ++NumErrors; |
1237 | 1 | } |
1238 | 359 | if (DIE.getTag() != EntryOr->tag()) { |
1239 | 1 | error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of " |
1240 | 1 | "DIE @ {2:x}: index - {3}; debug_info - {4}.\n", |
1241 | 1 | NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(), |
1242 | 1 | DIE.getTag()); |
1243 | 1 | ++NumErrors; |
1244 | 1 | } |
1245 | 359 | |
1246 | 359 | auto EntryNames = getNames(DIE); |
1247 | 359 | if (!is_contained(EntryNames, Str)) { |
1248 | 2 | error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name " |
1249 | 2 | "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n", |
1250 | 2 | NI.getUnitOffset(), EntryID, DIEOffset, Str, |
1251 | 2 | make_range(EntryNames.begin(), EntryNames.end())); |
1252 | 2 | ++NumErrors; |
1253 | 2 | } |
1254 | 359 | } |
1255 | 344 | handleAllErrors(EntryOr.takeError(), |
1256 | 344 | [&](const DWARFDebugNames::SentinelError &) { |
1257 | 343 | if (NumEntries > 0) |
1258 | 342 | return; |
1259 | 1 | error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is " |
1260 | 1 | "not associated with any entries.\n", |
1261 | 1 | NI.getUnitOffset(), NTE.getIndex(), Str); |
1262 | 1 | ++NumErrors; |
1263 | 1 | }, |
1264 | 344 | [&](const ErrorInfoBase &Info) { |
1265 | 1 | error() |
1266 | 1 | << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n", |
1267 | 1 | NI.getUnitOffset(), NTE.getIndex(), Str, |
1268 | 1 | Info.message()); |
1269 | 1 | ++NumErrors; |
1270 | 1 | }); |
1271 | 344 | return NumErrors; |
1272 | 344 | } |
1273 | | |
1274 | 283 | static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) { |
1275 | 283 | Optional<DWARFFormValue> Location = Die.findRecursively(DW_AT_location); |
1276 | 283 | if (!Location) |
1277 | 1 | return false; |
1278 | 282 | |
1279 | 282 | auto ContainsInterestingOperators = [&](StringRef D) { |
1280 | 282 | DWARFUnit *U = Die.getDwarfUnit(); |
1281 | 282 | DataExtractor Data(D, DCtx.isLittleEndian(), U->getAddressByteSize()); |
1282 | 282 | DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize()); |
1283 | 282 | return any_of(Expression, [](DWARFExpression::Operation &Op) { |
1284 | 282 | return !Op.isError() && (Op.getCode() == DW_OP_addr || |
1285 | 282 | Op.getCode() == DW_OP_form_tls_address3 || |
1286 | 282 | Op.getCode() == DW_OP_GNU_push_tls_address2 ); |
1287 | 282 | }); |
1288 | 282 | }; |
1289 | 282 | |
1290 | 282 | if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) { |
1291 | 281 | // Inlined location. |
1292 | 281 | if (ContainsInterestingOperators(toStringRef(*Expr))) |
1293 | 280 | return true; |
1294 | 1 | } else if (Optional<uint64_t> Offset = Location->getAsSectionOffset()) { |
1295 | 1 | // Location list. |
1296 | 1 | if (const DWARFDebugLoc *DebugLoc = DCtx.getDebugLoc()) { |
1297 | 1 | if (const DWARFDebugLoc::LocationList *LocList = |
1298 | 1 | DebugLoc->getLocationListAtOffset(*Offset)) { |
1299 | 1 | if (any_of(LocList->Entries, [&](const DWARFDebugLoc::Entry &E) { |
1300 | 1 | return ContainsInterestingOperators({E.Loc.data(), E.Loc.size()}); |
1301 | 1 | })) |
1302 | 1 | return true; |
1303 | 1 | } |
1304 | 1 | } |
1305 | 1 | } |
1306 | 1 | return false; |
1307 | 1 | } |
1308 | | |
1309 | | unsigned DWARFVerifier::verifyNameIndexCompleteness( |
1310 | 987 | const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) { |
1311 | 987 | |
1312 | 987 | // First check, if the Die should be indexed. The code follows the DWARF v5 |
1313 | 987 | // wording as closely as possible. |
1314 | 987 | |
1315 | 987 | // "All non-defining declarations (that is, debugging information entries |
1316 | 987 | // with a DW_AT_declaration attribute) are excluded." |
1317 | 987 | if (Die.find(DW_AT_declaration)) |
1318 | 0 | return 0; |
1319 | 987 | |
1320 | 987 | // "DW_TAG_namespace debugging information entries without a DW_AT_name |
1321 | 987 | // attribute are included with the name “(anonymous namespace)”. |
1322 | 987 | // All other debugging information entries without a DW_AT_name attribute |
1323 | 987 | // are excluded." |
1324 | 987 | // "If a subprogram or inlined subroutine is included, and has a |
1325 | 987 | // DW_AT_linkage_name attribute, there will be an additional index entry for |
1326 | 987 | // the linkage name." |
1327 | 987 | auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram || |
1328 | 987 | Die.getTag() == DW_TAG_inlined_subroutine958 ; |
1329 | 987 | auto EntryNames = getNames(Die, IncludeLinkageName); |
1330 | 987 | if (EntryNames.empty()) |
1331 | 337 | return 0; |
1332 | 650 | |
1333 | 650 | // We deviate from the specification here, which says: |
1334 | 650 | // "The name index must contain an entry for each debugging information entry |
1335 | 650 | // that defines a named subprogram, label, variable, type, or namespace, |
1336 | 650 | // subject to ..." |
1337 | 650 | // Instead whitelisting all TAGs representing a "type" or a "subprogram", to |
1338 | 650 | // make sure we catch any missing items, we instead blacklist all TAGs that we |
1339 | 650 | // know shouldn't be indexed. |
1340 | 650 | switch (Die.getTag()) { |
1341 | 650 | // Compile units and modules have names but shouldn't be indexed. |
1342 | 650 | case DW_TAG_compile_unit: |
1343 | 280 | case DW_TAG_module: |
1344 | 280 | return 0; |
1345 | 280 | |
1346 | 280 | // Function and template parameters are not globally visible, so we shouldn't |
1347 | 280 | // index them. |
1348 | 280 | case DW_TAG_formal_parameter: |
1349 | 19 | case DW_TAG_template_value_parameter: |
1350 | 19 | case DW_TAG_template_type_parameter: |
1351 | 19 | case DW_TAG_GNU_template_parameter_pack: |
1352 | 19 | case DW_TAG_GNU_template_template_param: |
1353 | 19 | return 0; |
1354 | 19 | |
1355 | 19 | // Object members aren't globally visible. |
1356 | 19 | case DW_TAG_member: |
1357 | 0 | return 0; |
1358 | 19 | |
1359 | 19 | // According to a strict reading of the specification, enumerators should not |
1360 | 19 | // be indexed (and LLVM currently does not do that). However, this causes |
1361 | 19 | // problems for the debuggers, so we may need to reconsider this. |
1362 | 19 | case DW_TAG_enumerator: |
1363 | 0 | return 0; |
1364 | 19 | |
1365 | 19 | // Imported declarations should not be indexed according to the specification |
1366 | 19 | // and LLVM currently does not do that. |
1367 | 19 | case DW_TAG_imported_declaration: |
1368 | 0 | return 0; |
1369 | 19 | |
1370 | 19 | // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging |
1371 | 19 | // information entries without an address attribute (DW_AT_low_pc, |
1372 | 19 | // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded." |
1373 | 33 | case DW_TAG_subprogram: |
1374 | 33 | case DW_TAG_inlined_subroutine: |
1375 | 33 | case DW_TAG_label: |
1376 | 33 | if (Die.findRecursively( |
1377 | 33 | {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc})) |
1378 | 30 | break; |
1379 | 3 | return 0; |
1380 | 3 | |
1381 | 3 | // "DW_TAG_variable debugging information entries with a DW_AT_location |
1382 | 3 | // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are |
1383 | 3 | // included; otherwise, they are excluded." |
1384 | 3 | // |
1385 | 3 | // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list. |
1386 | 283 | case DW_TAG_variable: |
1387 | 283 | if (isVariableIndexable(Die, DCtx)) |
1388 | 281 | break; |
1389 | 2 | return 0; |
1390 | 2 | |
1391 | 35 | default: |
1392 | 35 | break; |
1393 | 346 | } |
1394 | 346 | |
1395 | 346 | // Now we know that our Die should be present in the Index. Let's check if |
1396 | 346 | // that's the case. |
1397 | 346 | unsigned NumErrors = 0; |
1398 | 346 | uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset(); |
1399 | 358 | for (StringRef Name : EntryNames) { |
1400 | 366 | if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) 358 { |
1401 | 366 | return E.getDIEUnitOffset() == DieUnitOffset; |
1402 | 366 | })) { |
1403 | 10 | error() << formatv("Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with " |
1404 | 10 | "name {3} missing.\n", |
1405 | 10 | NI.getUnitOffset(), Die.getOffset(), Die.getTag(), |
1406 | 10 | Name); |
1407 | 10 | ++NumErrors; |
1408 | 10 | } |
1409 | 358 | } |
1410 | 346 | return NumErrors; |
1411 | 346 | } |
1412 | | |
1413 | | unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection, |
1414 | 28 | const DataExtractor &StrData) { |
1415 | 28 | unsigned NumErrors = 0; |
1416 | 28 | DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection, |
1417 | 28 | DCtx.isLittleEndian(), 0); |
1418 | 28 | DWARFDebugNames AccelTable(AccelSectionData, StrData); |
1419 | 28 | |
1420 | 28 | OS << "Verifying .debug_names...\n"; |
1421 | 28 | |
1422 | 28 | // This verifies that we can read individual name indices and their |
1423 | 28 | // abbreviation tables. |
1424 | 28 | if (Error E = AccelTable.extract()) { |
1425 | 5 | error() << toString(std::move(E)) << '\n'; |
1426 | 5 | return 1; |
1427 | 5 | } |
1428 | 23 | |
1429 | 23 | NumErrors += verifyDebugNamesCULists(AccelTable); |
1430 | 23 | for (const auto &NI : AccelTable) |
1431 | 26 | NumErrors += verifyNameIndexBuckets(NI, StrData); |
1432 | 23 | for (const auto &NI : AccelTable) |
1433 | 26 | NumErrors += verifyNameIndexAbbrevs(NI); |
1434 | 23 | |
1435 | 23 | // Don't attempt Entry validation if any of the previous checks found errors |
1436 | 23 | if (NumErrors > 0) |
1437 | 5 | return NumErrors; |
1438 | 18 | for (const auto &NI : AccelTable) |
1439 | 18 | for (DWARFDebugNames::NameTableEntry NTE : NI) |
1440 | 345 | NumErrors += verifyNameIndexEntries(NI, NTE); |
1441 | 18 | |
1442 | 18 | if (NumErrors > 0) |
1443 | 1 | return NumErrors; |
1444 | 17 | |
1445 | 278 | for (const std::unique_ptr<DWARFUnit> &U : DCtx.compile_units())17 { |
1446 | 278 | if (const DWARFDebugNames::NameIndex *NI = |
1447 | 278 | AccelTable.getCUNameIndex(U->getOffset())) { |
1448 | 278 | auto *CU = cast<DWARFCompileUnit>(U.get()); |
1449 | 278 | for (const DWARFDebugInfoEntry &Die : CU->dies()) |
1450 | 987 | NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI); |
1451 | 278 | } |
1452 | 278 | } |
1453 | 17 | return NumErrors; |
1454 | 17 | } |
1455 | | |
1456 | 83 | bool DWARFVerifier::handleAccelTables() { |
1457 | 83 | const DWARFObject &D = DCtx.getDWARFObj(); |
1458 | 83 | DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0); |
1459 | 83 | unsigned NumErrors = 0; |
1460 | 83 | if (!D.getAppleNamesSection().Data.empty()) |
1461 | 21 | NumErrors += verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData, |
1462 | 21 | ".apple_names"); |
1463 | 83 | if (!D.getAppleTypesSection().Data.empty()) |
1464 | 19 | NumErrors += verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData, |
1465 | 19 | ".apple_types"); |
1466 | 83 | if (!D.getAppleNamespacesSection().Data.empty()) |
1467 | 18 | NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData, |
1468 | 18 | ".apple_namespaces"); |
1469 | 83 | if (!D.getAppleObjCSection().Data.empty()) |
1470 | 18 | NumErrors += verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData, |
1471 | 18 | ".apple_objc"); |
1472 | 83 | |
1473 | 83 | if (!D.getDebugNamesSection().Data.empty()) |
1474 | 28 | NumErrors += verifyDebugNames(D.getDebugNamesSection(), StrData); |
1475 | 83 | return NumErrors == 0; |
1476 | 83 | } |
1477 | | |
1478 | 89 | raw_ostream &DWARFVerifier::error() const { return WithColor::error(OS); } |
1479 | | |
1480 | 16 | raw_ostream &DWARFVerifier::warn() const { return WithColor::warning(OS); } |
1481 | | |
1482 | 10 | raw_ostream &DWARFVerifier::note() const { return WithColor::note(OS); } |
1483 | | |
1484 | 26 | raw_ostream &DWARFVerifier::dump(const DWARFDie &Die, unsigned indent) const { |
1485 | 26 | Die.dump(OS, indent, DumpOpts); |
1486 | 26 | return OS; |
1487 | 26 | } |