blob: 04530c44d87abe2fdd4ad6cc5696506a9e3c4e22 [file] [log] [blame]
Greg Claytonb8c162b2017-05-03 16:02:29 +00001//===- DWARFVerifier.cpp --------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
11#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
12#include "llvm/DebugInfo/DWARF/DWARFContext.h"
13#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
14#include "llvm/DebugInfo/DWARF/DWARFDie.h"
15#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
16#include "llvm/DebugInfo/DWARF/DWARFSection.h"
Spyridoula Gravanie41823b2017-06-14 00:17:55 +000017#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
Greg Claytonb8c162b2017-05-03 16:02:29 +000018#include "llvm/Support/raw_ostream.h"
19#include <map>
20#include <set>
21#include <vector>
22
23using namespace llvm;
24using namespace dwarf;
25using namespace object;
26
Jonas Devlieghere58910602017-09-14 11:33:42 +000027DWARFVerifier::DieRangeInfo::address_range_iterator
28DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) {
29 auto Begin = Ranges.begin();
30 auto End = Ranges.end();
31 auto Pos = std::lower_bound(Begin, End, R);
32
33 if (Pos != End) {
34 if (Pos->intersects(R))
35 return Pos;
36 if (Pos != Begin) {
37 auto Iter = Pos - 1;
38 if (Iter->intersects(R))
39 return Iter;
40 }
41 }
42
43 Ranges.insert(Pos, R);
44 return Ranges.end();
45}
46
47DWARFVerifier::DieRangeInfo::die_range_info_iterator
48DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) {
49 auto End = Children.end();
50 auto Iter = Children.begin();
51 while (Iter != End) {
52 if (Iter->intersects(RI))
53 return Iter;
54 ++Iter;
55 }
56 Children.insert(RI);
57 return Children.end();
58}
59
60bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const {
61 // Both list of ranges are sorted so we can make this fast.
62
63 if (Ranges.empty() || RHS.Ranges.empty())
64 return false;
65
66 // Since the ranges are sorted we can advance where we start searching with
67 // this object's ranges as we traverse RHS.Ranges.
68 auto End = Ranges.end();
69 auto Iter = findRange(RHS.Ranges.front());
70
71 // Now linearly walk the ranges in this object and see if they contain each
72 // ranges from RHS.Ranges.
73 for (const auto &R : RHS.Ranges) {
74 while (Iter != End) {
75 if (Iter->contains(R))
76 break;
77 ++Iter;
78 }
79 if (Iter == End)
80 return false;
81 }
82 return true;
83}
84
85bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const {
86 if (Ranges.empty() || RHS.Ranges.empty())
87 return false;
88
89 auto End = Ranges.end();
90 auto Iter = findRange(RHS.Ranges.front());
91 for (const auto &R : RHS.Ranges) {
92 if (R.HighPC <= Iter->LowPC)
93 continue;
94 while (Iter != End) {
95 if (Iter->intersects(R))
96 return true;
97 ++Iter;
98 }
99 }
100
101 return false;
102}
103
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000104bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000105 uint32_t *Offset, unsigned UnitIndex,
106 uint8_t &UnitType, bool &isUnitDWARF64) {
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000107 uint32_t AbbrOffset, Length;
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000108 uint8_t AddrSize = 0;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000109 uint16_t Version;
110 bool Success = true;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000111
112 bool ValidLength = false;
113 bool ValidVersion = false;
114 bool ValidAddrSize = false;
115 bool ValidType = true;
116 bool ValidAbbrevOffset = true;
117
118 uint32_t OffsetStart = *Offset;
119 Length = DebugInfoData.getU32(Offset);
120 if (Length == UINT32_MAX) {
121 isUnitDWARF64 = true;
122 OS << format(
123 "Unit[%d] is in 64-bit DWARF format; cannot verify from this point.\n",
124 UnitIndex);
125 return false;
126 }
127 Version = DebugInfoData.getU16(Offset);
128
129 if (Version >= 5) {
130 UnitType = DebugInfoData.getU8(Offset);
131 AddrSize = DebugInfoData.getU8(Offset);
132 AbbrOffset = DebugInfoData.getU32(Offset);
133 ValidType = DWARFUnit::isValidUnitType(UnitType);
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000134 } else {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000135 UnitType = 0;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000136 AbbrOffset = DebugInfoData.getU32(Offset);
137 AddrSize = DebugInfoData.getU8(Offset);
138 }
139
140 if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset))
141 ValidAbbrevOffset = false;
142
143 ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3);
144 ValidVersion = DWARFContext::isSupportedVersion(Version);
145 ValidAddrSize = AddrSize == 4 || AddrSize == 8;
146 if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
147 !ValidType) {
148 Success = false;
149 OS << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, OffsetStart);
150 if (!ValidLength)
151 OS << "\tError: The length for this unit is too "
152 "large for the .debug_info provided.\n";
153 if (!ValidVersion)
154 OS << "\tError: The 16 bit unit header version is not valid.\n";
155 if (!ValidType)
156 OS << "\tError: The unit type encoding is not valid.\n";
157 if (!ValidAbbrevOffset)
158 OS << "\tError: The offset into the .debug_abbrev section is "
159 "not valid.\n";
160 if (!ValidAddrSize)
161 OS << "\tError: The address size is unsupported.\n";
162 }
163 *Offset = OffsetStart + Length + 4;
164 return Success;
165}
166
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000167bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) {
168 uint32_t NumUnitErrors = 0;
169 unsigned NumDies = Unit.getNumDIEs();
170 for (unsigned I = 0; I < NumDies; ++I) {
171 auto Die = Unit.getDIEAtIndex(I);
172 if (Die.getTag() == DW_TAG_null)
173 continue;
174 for (auto AttrValue : Die.attributes()) {
175 NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
176 NumUnitErrors += verifyDebugInfoForm(Die, AttrValue);
177 }
178 }
Jonas Devlieghere58910602017-09-14 11:33:42 +0000179
180 DieRangeInfo RI;
181 DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
182 NumUnitErrors += verifyDieRanges(Die, RI);
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000183 return NumUnitErrors == 0;
184}
185
Spyridoula Gravanic6ef9872017-07-21 00:51:32 +0000186unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
Spyridoula Gravani364b5352017-07-20 02:06:52 +0000187 unsigned NumErrors = 0;
Spyridoula Gravani364b5352017-07-20 02:06:52 +0000188 if (Abbrev) {
189 const DWARFAbbreviationDeclarationSet *AbbrDecls =
190 Abbrev->getAbbreviationDeclarationSet(0);
191 for (auto AbbrDecl : *AbbrDecls) {
192 SmallDenseSet<uint16_t> AttributeSet;
193 for (auto Attribute : AbbrDecl.attributes()) {
194 auto Result = AttributeSet.insert(Attribute.Attr);
195 if (!Result.second) {
Spyridoula Gravanic6ef9872017-07-21 00:51:32 +0000196 OS << "Error: Abbreviation declaration contains multiple "
197 << AttributeString(Attribute.Attr) << " attributes.\n";
198 AbbrDecl.dump(OS);
Spyridoula Gravani364b5352017-07-20 02:06:52 +0000199 ++NumErrors;
200 }
201 }
202 }
203 }
Spyridoula Gravanic6ef9872017-07-21 00:51:32 +0000204 return NumErrors;
205}
206
207bool DWARFVerifier::handleDebugAbbrev() {
208 OS << "Verifying .debug_abbrev...\n";
209
210 const DWARFObject &DObj = DCtx.getDWARFObj();
211 bool noDebugAbbrev = DObj.getAbbrevSection().empty();
212 bool noDebugAbbrevDWO = DObj.getAbbrevDWOSection().empty();
213
214 if (noDebugAbbrev && noDebugAbbrevDWO) {
215 return true;
216 }
217
218 unsigned NumErrors = 0;
219 if (!noDebugAbbrev)
220 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
221
222 if (!noDebugAbbrevDWO)
223 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
Spyridoula Gravani364b5352017-07-20 02:06:52 +0000224 return NumErrors == 0;
225}
226
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000227bool DWARFVerifier::handleDebugInfo() {
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000228 OS << "Verifying .debug_info Unit Header Chain...\n";
229
Rafael Espindolac398e672017-07-19 22:27:28 +0000230 const DWARFObject &DObj = DCtx.getDWARFObj();
231 DWARFDataExtractor DebugInfoData(DObj, DObj.getInfoSection(),
232 DCtx.isLittleEndian(), 0);
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000233 uint32_t NumDebugInfoErrors = 0;
234 uint32_t OffsetStart = 0, Offset = 0, UnitIdx = 0;
235 uint8_t UnitType = 0;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000236 bool isUnitDWARF64 = false;
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000237 bool isHeaderChainValid = true;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000238 bool hasDIE = DebugInfoData.isValidOffset(Offset);
239 while (hasDIE) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000240 OffsetStart = Offset;
241 if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType,
242 isUnitDWARF64)) {
243 isHeaderChainValid = false;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000244 if (isUnitDWARF64)
245 break;
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000246 } else {
247 std::unique_ptr<DWARFUnit> Unit;
248 switch (UnitType) {
249 case dwarf::DW_UT_type:
250 case dwarf::DW_UT_split_type: {
251 DWARFUnitSection<DWARFTypeUnit> TUSection{};
252 Unit.reset(new DWARFTypeUnit(
Rafael Espindolac398e672017-07-19 22:27:28 +0000253 DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
254 &DObj.getRangeSection(), DObj.getStringSection(),
255 DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
256 DObj.getLineSection(), DCtx.isLittleEndian(), false, TUSection,
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000257 nullptr));
258 break;
259 }
260 case dwarf::DW_UT_skeleton:
261 case dwarf::DW_UT_split_compile:
262 case dwarf::DW_UT_compile:
263 case dwarf::DW_UT_partial:
264 // UnitType = 0 means that we are
265 // verifying a compile unit in DWARF v4.
266 case 0: {
267 DWARFUnitSection<DWARFCompileUnit> CUSection{};
268 Unit.reset(new DWARFCompileUnit(
Rafael Espindolac398e672017-07-19 22:27:28 +0000269 DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
270 &DObj.getRangeSection(), DObj.getStringSection(),
271 DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
272 DObj.getLineSection(), DCtx.isLittleEndian(), false, CUSection,
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000273 nullptr));
274 break;
275 }
276 default: { llvm_unreachable("Invalid UnitType."); }
277 }
278 Unit->extract(DebugInfoData, &OffsetStart);
279 if (!verifyUnitContents(*Unit))
280 ++NumDebugInfoErrors;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000281 }
282 hasDIE = DebugInfoData.isValidOffset(Offset);
283 ++UnitIdx;
284 }
285 if (UnitIdx == 0 && !hasDIE) {
286 OS << "Warning: .debug_info is empty.\n";
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000287 isHeaderChainValid = true;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000288 }
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000289 NumDebugInfoErrors += verifyDebugInfoReferences();
290 return (isHeaderChainValid && NumDebugInfoErrors == 0);
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000291}
292
Jonas Devlieghere58910602017-09-14 11:33:42 +0000293unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
294 DieRangeInfo &ParentRI) {
Spyridoula Gravanie0ba4152017-07-24 21:04:11 +0000295 unsigned NumErrors = 0;
Jonas Devlieghere58910602017-09-14 11:33:42 +0000296
297 if (!Die.isValid())
298 return NumErrors;
299
300 DWARFAddressRangesVector Ranges = Die.getAddressRanges();
301
302 // Build RI for this DIE and check that ranges within this DIE do not
303 // overlap.
304 DieRangeInfo RI(Die);
305 for (auto Range : Ranges) {
306 if (!Range.valid()) {
Spyridoula Gravanie0ba4152017-07-24 21:04:11 +0000307 ++NumErrors;
NAKAMURA Takumi7ddaf3c2017-07-25 05:03:17 +0000308 OS << format("error: Invalid address range [0x%08" PRIx64
309 " - 0x%08" PRIx64 "].\n",
Spyridoula Gravanie0ba4152017-07-24 21:04:11 +0000310 Range.LowPC, Range.HighPC);
Jonas Devlieghere58910602017-09-14 11:33:42 +0000311 continue;
312 }
313
314 // Verify that ranges don't intersect.
315 const auto IntersectingRange = RI.insert(Range);
316 if (IntersectingRange != RI.Ranges.end()) {
317 ++NumErrors;
318 OS << format("error: DIE has overlapping address ranges: [0x%08" PRIx64
319 " - 0x%08" PRIx64 "] and [0x%08" PRIx64 " - 0x%08" PRIx64
320 "].\n",
321 Range.LowPC, Range.HighPC, IntersectingRange->LowPC,
322 IntersectingRange->HighPC);
323 break;
Spyridoula Gravanie0ba4152017-07-24 21:04:11 +0000324 }
325 }
Jonas Devlieghere58910602017-09-14 11:33:42 +0000326
327 // Verify that children don't intersect.
328 const auto IntersectingChild = ParentRI.insert(RI);
329 if (IntersectingChild != ParentRI.Children.end()) {
330 ++NumErrors;
331 OS << "error: DIEs have overlapping address ranges:";
332 Die.dump(OS, 0);
333 IntersectingChild->Die.dump(OS, 0);
334 OS << "\n";
335 }
336
337 // Verify that ranges are contained within their parent.
338 bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() &&
339 !(Die.getTag() == DW_TAG_subprogram &&
340 ParentRI.Die.getTag() == DW_TAG_subprogram);
341 if (ShouldBeContained && !ParentRI.contains(RI)) {
342 ++NumErrors;
343 OS << "error: DIE address ranges are not "
344 "contained in its parent's ranges:";
345 Die.dump(OS, 0);
346 ParentRI.Die.dump(OS, 0);
347 OS << "\n";
348 }
349
350 // Recursively check children.
351 for (DWARFDie Child : Die)
352 NumErrors += verifyDieRanges(Child, RI);
353
Spyridoula Gravanie0ba4152017-07-24 21:04:11 +0000354 return NumErrors;
355}
356
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000357unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
358 DWARFAttribute &AttrValue) {
Rafael Espindolac398e672017-07-19 22:27:28 +0000359 const DWARFObject &DObj = DCtx.getDWARFObj();
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000360 unsigned NumErrors = 0;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000361 const auto Attr = AttrValue.Attr;
362 switch (Attr) {
363 case DW_AT_ranges:
364 // Make sure the offset in the DW_AT_ranges attribute is valid.
365 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
Rafael Espindolac398e672017-07-19 22:27:28 +0000366 if (*SectionOffset >= DObj.getRangeSection().Data.size()) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000367 ++NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000368 OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
369 "bounds:\n";
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000370 Die.dump(OS, 0, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000371 OS << "\n";
372 }
373 } else {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000374 ++NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000375 OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000376 Die.dump(OS, 0, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000377 OS << "\n";
378 }
379 break;
380 case DW_AT_stmt_list:
381 // Make sure the offset in the DW_AT_stmt_list attribute is valid.
382 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
Rafael Espindolac398e672017-07-19 22:27:28 +0000383 if (*SectionOffset >= DObj.getLineSection().Data.size()) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000384 ++NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000385 OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
386 "bounds: "
Simon Dardis02d99452017-08-07 15:37:57 +0000387 << format("0x%08" PRIx64, *SectionOffset) << "\n";
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000388 Die.dump(OS, 0, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000389 OS << "\n";
390 }
391 } else {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000392 ++NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000393 OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000394 Die.dump(OS, 0, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000395 OS << "\n";
396 }
397 break;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000398
Greg Claytonc5b2d562017-05-03 18:25:46 +0000399 default:
400 break;
401 }
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000402 return NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000403}
Greg Claytonb8c162b2017-05-03 16:02:29 +0000404
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000405unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
406 DWARFAttribute &AttrValue) {
Rafael Espindolac398e672017-07-19 22:27:28 +0000407 const DWARFObject &DObj = DCtx.getDWARFObj();
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000408 unsigned NumErrors = 0;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000409 const auto Form = AttrValue.Value.getForm();
410 switch (Form) {
411 case DW_FORM_ref1:
412 case DW_FORM_ref2:
413 case DW_FORM_ref4:
414 case DW_FORM_ref8:
415 case DW_FORM_ref_udata: {
416 // Verify all CU relative references are valid CU offsets.
417 Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
418 assert(RefVal);
419 if (RefVal) {
420 auto DieCU = Die.getDwarfUnit();
421 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
422 auto CUOffset = AttrValue.Value.getRawUValue();
423 if (CUOffset >= CUSize) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000424 ++NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000425 OS << "error: " << FormEncodingString(Form) << " CU offset "
Simon Dardis02d99452017-08-07 15:37:57 +0000426 << format("0x%08" PRIx64, CUOffset)
Greg Claytonc5b2d562017-05-03 18:25:46 +0000427 << " is invalid (must be less than CU size of "
428 << format("0x%08" PRIx32, CUSize) << "):\n";
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000429 Die.dump(OS, 0, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000430 OS << "\n";
431 } else {
432 // Valid reference, but we will verify it points to an actual
433 // DIE later.
434 ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
Greg Claytonb8c162b2017-05-03 16:02:29 +0000435 }
436 }
Greg Claytonc5b2d562017-05-03 18:25:46 +0000437 break;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000438 }
Greg Claytonc5b2d562017-05-03 18:25:46 +0000439 case DW_FORM_ref_addr: {
440 // Verify all absolute DIE references have valid offsets in the
441 // .debug_info section.
442 Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
443 assert(RefVal);
444 if (RefVal) {
Rafael Espindolac398e672017-07-19 22:27:28 +0000445 if (*RefVal >= DObj.getInfoSection().Data.size()) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000446 ++NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000447 OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
448 "bounds:\n";
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000449 Die.dump(OS, 0, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000450 OS << "\n";
451 } else {
452 // Valid reference, but we will verify it points to an actual
453 // DIE later.
454 ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
455 }
456 }
457 break;
458 }
459 case DW_FORM_strp: {
460 auto SecOffset = AttrValue.Value.getAsSectionOffset();
461 assert(SecOffset); // DW_FORM_strp is a section offset.
Rafael Espindolac398e672017-07-19 22:27:28 +0000462 if (SecOffset && *SecOffset >= DObj.getStringSection().size()) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000463 ++NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000464 OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000465 Die.dump(OS, 0, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000466 OS << "\n";
467 }
468 break;
469 }
470 default:
471 break;
472 }
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000473 return NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000474}
Greg Claytonb8c162b2017-05-03 16:02:29 +0000475
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000476unsigned DWARFVerifier::verifyDebugInfoReferences() {
Greg Claytonb8c162b2017-05-03 16:02:29 +0000477 // Take all references and make sure they point to an actual DIE by
478 // getting the DIE by offset and emitting an error
479 OS << "Verifying .debug_info references...\n";
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000480 unsigned NumErrors = 0;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000481 for (auto Pair : ReferenceToDIEOffsets) {
482 auto Die = DCtx.getDIEForOffset(Pair.first);
483 if (Die)
484 continue;
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000485 ++NumErrors;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000486 OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
487 << ". Offset is in between DIEs:\n";
488 for (auto Offset : Pair.second) {
489 auto ReferencingDie = DCtx.getDIEForOffset(Offset);
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000490 ReferencingDie.dump(OS, 0, 0, DumpOpts);
Greg Claytonb8c162b2017-05-03 16:02:29 +0000491 OS << "\n";
492 }
493 OS << "\n";
494 }
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000495 return NumErrors;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000496}
497
Greg Claytonc5b2d562017-05-03 18:25:46 +0000498void DWARFVerifier::verifyDebugLineStmtOffsets() {
Greg Claytonb8c162b2017-05-03 16:02:29 +0000499 std::map<uint64_t, DWARFDie> StmtListToDie;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000500 for (const auto &CU : DCtx.compile_units()) {
Greg Claytonc5b2d562017-05-03 18:25:46 +0000501 auto Die = CU->getUnitDIE();
Greg Claytonb8c162b2017-05-03 16:02:29 +0000502 // Get the attribute value as a section offset. No need to produce an
503 // error here if the encoding isn't correct because we validate this in
504 // the .debug_info verifier.
Greg Claytonc5b2d562017-05-03 18:25:46 +0000505 auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
Greg Claytonb8c162b2017-05-03 16:02:29 +0000506 if (!StmtSectionOffset)
507 continue;
508 const uint32_t LineTableOffset = *StmtSectionOffset;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000509 auto LineTable = DCtx.getLineTableForUnit(CU.get());
Rafael Espindolac398e672017-07-19 22:27:28 +0000510 if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
Greg Claytonc5b2d562017-05-03 18:25:46 +0000511 if (!LineTable) {
512 ++NumDebugLineErrors;
513 OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
514 << "] was not able to be parsed for CU:\n";
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000515 Die.dump(OS, 0, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000516 OS << '\n';
517 continue;
518 }
519 } else {
520 // Make sure we don't get a valid line table back if the offset is wrong.
521 assert(LineTable == nullptr);
Greg Claytonb8c162b2017-05-03 16:02:29 +0000522 // Skip this line table as it isn't valid. No need to create an error
523 // here because we validate this in the .debug_info verifier.
524 continue;
525 }
Greg Claytonb8c162b2017-05-03 16:02:29 +0000526 auto Iter = StmtListToDie.find(LineTableOffset);
527 if (Iter != StmtListToDie.end()) {
528 ++NumDebugLineErrors;
529 OS << "error: two compile unit DIEs, "
530 << format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
Greg Claytonc5b2d562017-05-03 18:25:46 +0000531 << format("0x%08" PRIx32, Die.getOffset())
Greg Claytonb8c162b2017-05-03 16:02:29 +0000532 << ", have the same DW_AT_stmt_list section offset:\n";
Jonas Devlieghere27476ce2017-09-13 09:43:05 +0000533 Iter->second.dump(OS, 0, 0, DumpOpts);
534 Die.dump(OS, 0, 0, DumpOpts);
Greg Claytonb8c162b2017-05-03 16:02:29 +0000535 OS << '\n';
536 // Already verified this line table before, no need to do it again.
537 continue;
538 }
Greg Claytonc5b2d562017-05-03 18:25:46 +0000539 StmtListToDie[LineTableOffset] = Die;
540 }
541}
Greg Claytonb8c162b2017-05-03 16:02:29 +0000542
Greg Claytonc5b2d562017-05-03 18:25:46 +0000543void DWARFVerifier::verifyDebugLineRows() {
544 for (const auto &CU : DCtx.compile_units()) {
545 auto Die = CU->getUnitDIE();
Greg Claytonb8c162b2017-05-03 16:02:29 +0000546 auto LineTable = DCtx.getLineTableForUnit(CU.get());
Greg Claytonc5b2d562017-05-03 18:25:46 +0000547 // If there is no line table we will have created an error in the
548 // .debug_info verifier or in verifyDebugLineStmtOffsets().
549 if (!LineTable)
Greg Claytonb8c162b2017-05-03 16:02:29 +0000550 continue;
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000551
552 // Verify prologue.
Greg Claytonb8c162b2017-05-03 16:02:29 +0000553 uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000554 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
555 uint32_t FileIndex = 1;
556 StringMap<uint16_t> FullPathMap;
557 for (const auto &FileName : LineTable->Prologue.FileNames) {
558 // Verify directory index.
559 if (FileName.DirIdx > MaxDirIndex) {
560 ++NumDebugLineErrors;
561 OS << "error: .debug_line["
562 << format("0x%08" PRIx64,
563 *toSectionOffset(Die.find(DW_AT_stmt_list)))
564 << "].prologue.file_names[" << FileIndex
565 << "].dir_idx contains an invalid index: " << FileName.DirIdx
566 << "\n";
567 }
568
569 // Check file paths for duplicates.
570 std::string FullPath;
571 const bool HasFullPath = LineTable->getFileNameByIndex(
572 FileIndex, CU->getCompilationDir(),
573 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath);
574 assert(HasFullPath && "Invalid index?");
575 (void)HasFullPath;
576 auto It = FullPathMap.find(FullPath);
577 if (It == FullPathMap.end())
578 FullPathMap[FullPath] = FileIndex;
579 else if (It->second != FileIndex) {
580 OS << "warning: .debug_line["
581 << format("0x%08" PRIx64,
582 *toSectionOffset(Die.find(DW_AT_stmt_list)))
583 << "].prologue.file_names[" << FileIndex
584 << "] is a duplicate of file_names[" << It->second << "]\n";
585 }
586
587 FileIndex++;
588 }
589
590 // Verify rows.
Greg Claytonb8c162b2017-05-03 16:02:29 +0000591 uint64_t PrevAddress = 0;
592 uint32_t RowIndex = 0;
593 for (const auto &Row : LineTable->Rows) {
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000594 // Verify row address.
Greg Claytonb8c162b2017-05-03 16:02:29 +0000595 if (Row.Address < PrevAddress) {
596 ++NumDebugLineErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000597 OS << "error: .debug_line["
Simon Dardis02d99452017-08-07 15:37:57 +0000598 << format("0x%08" PRIx64,
Greg Claytonc5b2d562017-05-03 18:25:46 +0000599 *toSectionOffset(Die.find(DW_AT_stmt_list)))
Greg Claytonb8c162b2017-05-03 16:02:29 +0000600 << "] row[" << RowIndex
601 << "] decreases in address from previous row:\n";
602
603 DWARFDebugLine::Row::dumpTableHeader(OS);
604 if (RowIndex > 0)
605 LineTable->Rows[RowIndex - 1].dump(OS);
606 Row.dump(OS);
607 OS << '\n';
608 }
609
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000610 // Verify file index.
Greg Claytonb8c162b2017-05-03 16:02:29 +0000611 if (Row.File > MaxFileIndex) {
612 ++NumDebugLineErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000613 OS << "error: .debug_line["
Simon Dardis02d99452017-08-07 15:37:57 +0000614 << format("0x%08" PRIx64,
Greg Claytonc5b2d562017-05-03 18:25:46 +0000615 *toSectionOffset(Die.find(DW_AT_stmt_list)))
Greg Claytonb8c162b2017-05-03 16:02:29 +0000616 << "][" << RowIndex << "] has invalid file index " << Row.File
617 << " (valid values are [1," << MaxFileIndex << "]):\n";
618 DWARFDebugLine::Row::dumpTableHeader(OS);
619 Row.dump(OS);
620 OS << '\n';
621 }
622 if (Row.EndSequence)
623 PrevAddress = 0;
624 else
625 PrevAddress = Row.Address;
626 ++RowIndex;
627 }
628 }
Greg Claytonc5b2d562017-05-03 18:25:46 +0000629}
630
631bool DWARFVerifier::handleDebugLine() {
632 NumDebugLineErrors = 0;
633 OS << "Verifying .debug_line...\n";
634 verifyDebugLineStmtOffsets();
635 verifyDebugLineRows();
Greg Claytonb8c162b2017-05-03 16:02:29 +0000636 return NumDebugLineErrors == 0;
637}
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000638
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000639unsigned DWARFVerifier::verifyAccelTable(const DWARFSection *AccelSection,
640 DataExtractor *StrData,
641 const char *SectionName) {
642 unsigned NumErrors = 0;
643 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
644 DCtx.isLittleEndian(), 0);
645 DWARFAcceleratorTable AccelTable(AccelSectionData, *StrData);
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000646
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000647 OS << "Verifying " << SectionName << "...\n";
648 // Verify that the fixed part of the header is not too short.
649
650 if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {
651 OS << "\terror: Section is too small to fit a section header.\n";
652 return 1;
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000653 }
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000654 // Verify that the section is not too short.
655 if (!AccelTable.extract()) {
656 OS << "\terror: Section is smaller than size described in section header.\n";
657 return 1;
658 }
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000659 // Verify that all buckets have a valid hash index or are empty.
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000660 uint32_t NumBuckets = AccelTable.getNumBuckets();
661 uint32_t NumHashes = AccelTable.getNumHashes();
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000662
663 uint32_t BucketsOffset =
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000664 AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000665 uint32_t HashesBase = BucketsOffset + NumBuckets * 4;
666 uint32_t OffsetsBase = HashesBase + NumHashes * 4;
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000667 for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000668 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000669 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000670 OS << format("\terror: Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000671 HashIdx);
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000672 ++NumErrors;
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000673 }
674 }
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000675 uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000676 if (NumAtoms == 0) {
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000677 OS << "\terror: no atoms; failed to read HashData.\n";
678 return 1;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000679 }
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000680 if (!AccelTable.validateForms()) {
681 OS << "\terror: unsupported form; failed to read HashData.\n";
682 return 1;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000683 }
684
685 for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
686 uint32_t HashOffset = HashesBase + 4 * HashIdx;
687 uint32_t DataOffset = OffsetsBase + 4 * HashIdx;
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000688 uint32_t Hash = AccelSectionData.getU32(&HashOffset);
689 uint32_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
690 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
691 sizeof(uint64_t))) {
692 OS << format("\terror: Hash[%d] has invalid HashData offset: 0x%08x.\n",
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000693 HashIdx, HashDataOffset);
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000694 ++NumErrors;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000695 }
696
697 uint32_t StrpOffset;
698 uint32_t StringOffset;
699 uint32_t StringCount = 0;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000700 unsigned Offset;
701 unsigned Tag;
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000702 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000703 const uint32_t NumHashDataObjects =
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000704 AccelSectionData.getU32(&HashDataOffset);
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000705 for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
706 ++HashDataIdx) {
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000707 std::tie(Offset, Tag) = AccelTable.readAtoms(HashDataOffset);
708 auto Die = DCtx.getDIEForOffset(Offset);
709 if (!Die) {
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000710 const uint32_t BucketIdx =
711 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
712 StringOffset = StrpOffset;
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000713 const char *Name = StrData->getCStr(&StringOffset);
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000714 if (!Name)
715 Name = "<NULL>";
716
717 OS << format(
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000718 "\terror: %s Bucket[%d] Hash[%d] = 0x%08x "
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000719 "Str[%u] = 0x%08x "
720 "DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n",
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000721 SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000722 HashDataIdx, Offset, Name);
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000723
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000724 ++NumErrors;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000725 continue;
726 }
727 if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {
728 OS << "\terror: Tag " << dwarf::TagString(Tag)
729 << " in accelerator table does not match Tag "
730 << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx
731 << "].\n";
732 ++NumErrors;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000733 }
734 }
735 ++StringCount;
736 }
737 }
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000738 return NumErrors;
739}
740
741bool DWARFVerifier::handleAccelTables() {
742 const DWARFObject &D = DCtx.getDWARFObj();
743 DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0);
744 unsigned NumErrors = 0;
745 if (!D.getAppleNamesSection().Data.empty())
746 NumErrors +=
747 verifyAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names");
748 if (!D.getAppleTypesSection().Data.empty())
749 NumErrors +=
750 verifyAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types");
751 if (!D.getAppleNamespacesSection().Data.empty())
752 NumErrors += verifyAccelTable(&D.getAppleNamespacesSection(), &StrData,
753 ".apple_namespaces");
754 if (!D.getAppleObjCSection().Data.empty())
755 NumErrors +=
756 verifyAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc");
757 return NumErrors == 0;
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000758}