blob: f27c849456bffa77b2ad4f2c948b41de5a21662e [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
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +000010#include "SyntaxHighlighting.h"
Greg Claytonb8c162b2017-05-03 16:02:29 +000011#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
12#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
13#include "llvm/DebugInfo/DWARF/DWARFContext.h"
14#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
15#include "llvm/DebugInfo/DWARF/DWARFDie.h"
George Rimar144e4c52017-10-27 10:42:04 +000016#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
Greg Claytonb8c162b2017-05-03 16:02:29 +000017#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
18#include "llvm/DebugInfo/DWARF/DWARFSection.h"
Spyridoula Gravanie41823b2017-06-14 00:17:55 +000019#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
George Rimar144e4c52017-10-27 10:42:04 +000020#include "llvm/Support/FormatVariadic.h"
Greg Claytonb8c162b2017-05-03 16:02:29 +000021#include "llvm/Support/raw_ostream.h"
22#include <map>
23#include <set>
24#include <vector>
25
26using namespace llvm;
27using namespace dwarf;
28using namespace object;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +000029using namespace syntax;
Greg Claytonb8c162b2017-05-03 16:02:29 +000030
Jonas Devlieghere58910602017-09-14 11:33:42 +000031DWARFVerifier::DieRangeInfo::address_range_iterator
32DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) {
33 auto Begin = Ranges.begin();
34 auto End = Ranges.end();
35 auto Pos = std::lower_bound(Begin, End, R);
36
37 if (Pos != End) {
38 if (Pos->intersects(R))
39 return Pos;
40 if (Pos != Begin) {
41 auto Iter = Pos - 1;
42 if (Iter->intersects(R))
43 return Iter;
44 }
45 }
46
47 Ranges.insert(Pos, R);
48 return Ranges.end();
49}
50
51DWARFVerifier::DieRangeInfo::die_range_info_iterator
52DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) {
53 auto End = Children.end();
54 auto Iter = Children.begin();
55 while (Iter != End) {
56 if (Iter->intersects(RI))
57 return Iter;
58 ++Iter;
59 }
60 Children.insert(RI);
61 return Children.end();
62}
63
64bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const {
65 // Both list of ranges are sorted so we can make this fast.
66
67 if (Ranges.empty() || RHS.Ranges.empty())
68 return false;
69
70 // Since the ranges are sorted we can advance where we start searching with
71 // this object's ranges as we traverse RHS.Ranges.
72 auto End = Ranges.end();
73 auto Iter = findRange(RHS.Ranges.front());
74
75 // Now linearly walk the ranges in this object and see if they contain each
76 // ranges from RHS.Ranges.
77 for (const auto &R : RHS.Ranges) {
78 while (Iter != End) {
79 if (Iter->contains(R))
80 break;
81 ++Iter;
82 }
83 if (Iter == End)
84 return false;
85 }
86 return true;
87}
88
89bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const {
90 if (Ranges.empty() || RHS.Ranges.empty())
91 return false;
92
93 auto End = Ranges.end();
94 auto Iter = findRange(RHS.Ranges.front());
95 for (const auto &R : RHS.Ranges) {
Jonas Devlieghered585a202017-09-14 17:46:23 +000096 if(Iter == End)
97 return false;
Jonas Devlieghere58910602017-09-14 11:33:42 +000098 if (R.HighPC <= Iter->LowPC)
99 continue;
100 while (Iter != End) {
101 if (Iter->intersects(R))
102 return true;
103 ++Iter;
104 }
105 }
106
107 return false;
108}
109
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000110bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000111 uint32_t *Offset, unsigned UnitIndex,
112 uint8_t &UnitType, bool &isUnitDWARF64) {
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000113 uint32_t AbbrOffset, Length;
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000114 uint8_t AddrSize = 0;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000115 uint16_t Version;
116 bool Success = true;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000117
118 bool ValidLength = false;
119 bool ValidVersion = false;
120 bool ValidAddrSize = false;
121 bool ValidType = true;
122 bool ValidAbbrevOffset = true;
123
124 uint32_t OffsetStart = *Offset;
125 Length = DebugInfoData.getU32(Offset);
126 if (Length == UINT32_MAX) {
127 isUnitDWARF64 = true;
128 OS << format(
129 "Unit[%d] is in 64-bit DWARF format; cannot verify from this point.\n",
130 UnitIndex);
131 return false;
132 }
133 Version = DebugInfoData.getU16(Offset);
134
135 if (Version >= 5) {
136 UnitType = DebugInfoData.getU8(Offset);
137 AddrSize = DebugInfoData.getU8(Offset);
138 AbbrOffset = DebugInfoData.getU32(Offset);
Jonas Devliegheref2fa9eb2017-10-06 22:27:31 +0000139 ValidType = dwarf::isUnitType(UnitType);
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000140 } else {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000141 UnitType = 0;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000142 AbbrOffset = DebugInfoData.getU32(Offset);
143 AddrSize = DebugInfoData.getU8(Offset);
144 }
145
146 if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset))
147 ValidAbbrevOffset = false;
148
149 ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3);
150 ValidVersion = DWARFContext::isSupportedVersion(Version);
151 ValidAddrSize = AddrSize == 4 || AddrSize == 8;
152 if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
153 !ValidType) {
154 Success = false;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000155 error() << format("Units[%d] - start offset: 0x%08x \n", UnitIndex,
156 OffsetStart);
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000157 if (!ValidLength)
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000158 note() << "The length for this unit is too "
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000159 "large for the .debug_info provided.\n";
160 if (!ValidVersion)
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000161 note() << "The 16 bit unit header version is not valid.\n";
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000162 if (!ValidType)
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000163 note() << "The unit type encoding is not valid.\n";
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000164 if (!ValidAbbrevOffset)
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000165 note() << "The offset into the .debug_abbrev section is "
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000166 "not valid.\n";
167 if (!ValidAddrSize)
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000168 note() << "The address size is unsupported.\n";
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000169 }
170 *Offset = OffsetStart + Length + 4;
171 return Success;
172}
173
Jonas Devliegheref2fa9eb2017-10-06 22:27:31 +0000174bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit, uint8_t UnitType) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000175 uint32_t NumUnitErrors = 0;
176 unsigned NumDies = Unit.getNumDIEs();
177 for (unsigned I = 0; I < NumDies; ++I) {
178 auto Die = Unit.getDIEAtIndex(I);
179 if (Die.getTag() == DW_TAG_null)
180 continue;
181 for (auto AttrValue : Die.attributes()) {
182 NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
183 NumUnitErrors += verifyDebugInfoForm(Die, AttrValue);
184 }
185 }
Jonas Devlieghere58910602017-09-14 11:33:42 +0000186
Jonas Devliegheref2fa9eb2017-10-06 22:27:31 +0000187 DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
188 if (!Die) {
189 error() << "Compilation unit without DIE.\n";
190 NumUnitErrors++;
191 return NumUnitErrors == 0;
192 }
193
194 if (!dwarf::isUnitType(Die.getTag())) {
195 error() << "Compilation unit root DIE is not a unit DIE: "
196 << dwarf::TagString(Die.getTag()) << ".\n";
Jonas Devlieghere35fdaa92017-09-28 15:57:50 +0000197 NumUnitErrors++;
198 }
199
Jonas Devliegheref2fa9eb2017-10-06 22:27:31 +0000200 if (UnitType != 0 &&
201 !DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) {
202 error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType)
203 << ") and root DIE (" << dwarf::TagString(Die.getTag())
204 << ") do not match.\n";
205 NumUnitErrors++;
206 }
207
208 DieRangeInfo RI;
209 NumUnitErrors += verifyDieRanges(Die, RI);
210
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000211 return NumUnitErrors == 0;
212}
213
Spyridoula Gravanic6ef9872017-07-21 00:51:32 +0000214unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
Spyridoula Gravani364b5352017-07-20 02:06:52 +0000215 unsigned NumErrors = 0;
Spyridoula Gravani364b5352017-07-20 02:06:52 +0000216 if (Abbrev) {
217 const DWARFAbbreviationDeclarationSet *AbbrDecls =
218 Abbrev->getAbbreviationDeclarationSet(0);
219 for (auto AbbrDecl : *AbbrDecls) {
220 SmallDenseSet<uint16_t> AttributeSet;
221 for (auto Attribute : AbbrDecl.attributes()) {
222 auto Result = AttributeSet.insert(Attribute.Attr);
223 if (!Result.second) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000224 error() << "Abbreviation declaration contains multiple "
225 << AttributeString(Attribute.Attr) << " attributes.\n";
Spyridoula Gravanic6ef9872017-07-21 00:51:32 +0000226 AbbrDecl.dump(OS);
Spyridoula Gravani364b5352017-07-20 02:06:52 +0000227 ++NumErrors;
228 }
229 }
230 }
231 }
Spyridoula Gravanic6ef9872017-07-21 00:51:32 +0000232 return NumErrors;
233}
234
235bool DWARFVerifier::handleDebugAbbrev() {
236 OS << "Verifying .debug_abbrev...\n";
237
238 const DWARFObject &DObj = DCtx.getDWARFObj();
239 bool noDebugAbbrev = DObj.getAbbrevSection().empty();
240 bool noDebugAbbrevDWO = DObj.getAbbrevDWOSection().empty();
241
242 if (noDebugAbbrev && noDebugAbbrevDWO) {
243 return true;
244 }
245
246 unsigned NumErrors = 0;
247 if (!noDebugAbbrev)
248 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
249
250 if (!noDebugAbbrevDWO)
251 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
Spyridoula Gravani364b5352017-07-20 02:06:52 +0000252 return NumErrors == 0;
253}
254
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000255bool DWARFVerifier::handleDebugInfo() {
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000256 OS << "Verifying .debug_info Unit Header Chain...\n";
257
Rafael Espindolac398e672017-07-19 22:27:28 +0000258 const DWARFObject &DObj = DCtx.getDWARFObj();
259 DWARFDataExtractor DebugInfoData(DObj, DObj.getInfoSection(),
260 DCtx.isLittleEndian(), 0);
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000261 uint32_t NumDebugInfoErrors = 0;
262 uint32_t OffsetStart = 0, Offset = 0, UnitIdx = 0;
263 uint8_t UnitType = 0;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000264 bool isUnitDWARF64 = false;
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000265 bool isHeaderChainValid = true;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000266 bool hasDIE = DebugInfoData.isValidOffset(Offset);
Jonas Devlieghereaa6be822017-10-10 14:15:25 +0000267 DWARFUnitSection<DWARFTypeUnit> TUSection{};
268 DWARFUnitSection<DWARFCompileUnit> CUSection{};
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000269 while (hasDIE) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000270 OffsetStart = Offset;
271 if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType,
272 isUnitDWARF64)) {
273 isHeaderChainValid = false;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000274 if (isUnitDWARF64)
275 break;
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000276 } else {
277 std::unique_ptr<DWARFUnit> Unit;
278 switch (UnitType) {
279 case dwarf::DW_UT_type:
280 case dwarf::DW_UT_split_type: {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000281 Unit.reset(new DWARFTypeUnit(
Rafael Espindolac398e672017-07-19 22:27:28 +0000282 DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
283 &DObj.getRangeSection(), DObj.getStringSection(),
284 DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
285 DObj.getLineSection(), DCtx.isLittleEndian(), false, TUSection,
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000286 nullptr));
287 break;
288 }
289 case dwarf::DW_UT_skeleton:
290 case dwarf::DW_UT_split_compile:
291 case dwarf::DW_UT_compile:
292 case dwarf::DW_UT_partial:
293 // UnitType = 0 means that we are
294 // verifying a compile unit in DWARF v4.
295 case 0: {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000296 Unit.reset(new DWARFCompileUnit(
Rafael Espindolac398e672017-07-19 22:27:28 +0000297 DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
298 &DObj.getRangeSection(), DObj.getStringSection(),
299 DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
300 DObj.getLineSection(), DCtx.isLittleEndian(), false, CUSection,
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000301 nullptr));
302 break;
303 }
304 default: { llvm_unreachable("Invalid UnitType."); }
305 }
306 Unit->extract(DebugInfoData, &OffsetStart);
Jonas Devliegheref2fa9eb2017-10-06 22:27:31 +0000307 if (!verifyUnitContents(*Unit, UnitType))
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000308 ++NumDebugInfoErrors;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000309 }
310 hasDIE = DebugInfoData.isValidOffset(Offset);
311 ++UnitIdx;
312 }
313 if (UnitIdx == 0 && !hasDIE) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000314 warn() << ".debug_info is empty.\n";
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000315 isHeaderChainValid = true;
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000316 }
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000317 NumDebugInfoErrors += verifyDebugInfoReferences();
318 return (isHeaderChainValid && NumDebugInfoErrors == 0);
Spyridoula Gravani890eedc2017-07-13 23:25:24 +0000319}
320
Jonas Devlieghere58910602017-09-14 11:33:42 +0000321unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
322 DieRangeInfo &ParentRI) {
Spyridoula Gravanie0ba4152017-07-24 21:04:11 +0000323 unsigned NumErrors = 0;
Jonas Devlieghere58910602017-09-14 11:33:42 +0000324
325 if (!Die.isValid())
326 return NumErrors;
327
328 DWARFAddressRangesVector Ranges = Die.getAddressRanges();
329
330 // Build RI for this DIE and check that ranges within this DIE do not
331 // overlap.
332 DieRangeInfo RI(Die);
333 for (auto Range : Ranges) {
334 if (!Range.valid()) {
Spyridoula Gravanie0ba4152017-07-24 21:04:11 +0000335 ++NumErrors;
Jonas Devliegherea15f25d32017-09-29 15:41:22 +0000336 error() << "Invalid address range " << Range << "\n";
Jonas Devlieghere58910602017-09-14 11:33:42 +0000337 continue;
338 }
339
340 // Verify that ranges don't intersect.
341 const auto IntersectingRange = RI.insert(Range);
342 if (IntersectingRange != RI.Ranges.end()) {
343 ++NumErrors;
Jonas Devliegherea15f25d32017-09-29 15:41:22 +0000344 error() << "DIE has overlapping address ranges: " << Range << " and "
345 << *IntersectingRange << "\n";
Jonas Devlieghere58910602017-09-14 11:33:42 +0000346 break;
Spyridoula Gravanie0ba4152017-07-24 21:04:11 +0000347 }
348 }
Jonas Devlieghere58910602017-09-14 11:33:42 +0000349
350 // Verify that children don't intersect.
351 const auto IntersectingChild = ParentRI.insert(RI);
352 if (IntersectingChild != ParentRI.Children.end()) {
353 ++NumErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000354 error() << "DIEs have overlapping address ranges:";
Jonas Devlieghere58910602017-09-14 11:33:42 +0000355 Die.dump(OS, 0);
356 IntersectingChild->Die.dump(OS, 0);
357 OS << "\n";
358 }
359
360 // Verify that ranges are contained within their parent.
361 bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() &&
362 !(Die.getTag() == DW_TAG_subprogram &&
363 ParentRI.Die.getTag() == DW_TAG_subprogram);
364 if (ShouldBeContained && !ParentRI.contains(RI)) {
365 ++NumErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000366 error() << "DIE address ranges are not "
367 "contained in its parent's ranges:";
Jonas Devlieghere58910602017-09-14 11:33:42 +0000368 Die.dump(OS, 0);
369 ParentRI.Die.dump(OS, 0);
370 OS << "\n";
371 }
372
373 // Recursively check children.
374 for (DWARFDie Child : Die)
375 NumErrors += verifyDieRanges(Child, RI);
376
Spyridoula Gravanie0ba4152017-07-24 21:04:11 +0000377 return NumErrors;
378}
379
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000380unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
381 DWARFAttribute &AttrValue) {
382 unsigned NumErrors = 0;
George Rimar144e4c52017-10-27 10:42:04 +0000383 auto ReportError = [&](const Twine &TitleMsg) {
384 ++NumErrors;
385 error() << TitleMsg << '\n';
386 Die.dump(OS, 0, DumpOpts);
387 OS << "\n";
388 };
389
390 const DWARFObject &DObj = DCtx.getDWARFObj();
Greg Claytonc5b2d562017-05-03 18:25:46 +0000391 const auto Attr = AttrValue.Attr;
392 switch (Attr) {
393 case DW_AT_ranges:
394 // Make sure the offset in the DW_AT_ranges attribute is valid.
395 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
George Rimar144e4c52017-10-27 10:42:04 +0000396 if (*SectionOffset >= DObj.getRangeSection().Data.size())
397 ReportError("DW_AT_ranges offset is beyond .debug_ranges bounds:");
398 break;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000399 }
George Rimar144e4c52017-10-27 10:42:04 +0000400 ReportError("DIE has invalid DW_AT_ranges encoding:");
Greg Claytonc5b2d562017-05-03 18:25:46 +0000401 break;
402 case DW_AT_stmt_list:
403 // Make sure the offset in the DW_AT_stmt_list attribute is valid.
404 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
George Rimar144e4c52017-10-27 10:42:04 +0000405 if (*SectionOffset >= DObj.getLineSection().Data.size())
406 ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " +
407 llvm::formatv("{0:x16}", *SectionOffset));
408 break;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000409 }
George Rimar144e4c52017-10-27 10:42:04 +0000410 ReportError("DIE has invalid DW_AT_stmt_list encoding:");
Greg Claytonc5b2d562017-05-03 18:25:46 +0000411 break;
George Rimar144e4c52017-10-27 10:42:04 +0000412 case DW_AT_location: {
413 Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock();
414 if (!Expr) {
415 ReportError("DIE has invalid DW_AT_location encoding:");
416 break;
417 }
418
419 DWARFUnit *U = Die.getDwarfUnit();
420 DataExtractor Data(
421 StringRef(reinterpret_cast<const char *>(Expr->data()), Expr->size()),
422 DCtx.isLittleEndian(), 0);
423 DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize());
424 bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
425 return Op.isError();
426 });
427 if (Error)
428 ReportError("DIE contains invalid DWARF expression:");
429 break;
430 }
Greg Claytonb8c162b2017-05-03 16:02:29 +0000431
Greg Claytonc5b2d562017-05-03 18:25:46 +0000432 default:
433 break;
434 }
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000435 return NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000436}
Greg Claytonb8c162b2017-05-03 16:02:29 +0000437
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000438unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
439 DWARFAttribute &AttrValue) {
Rafael Espindolac398e672017-07-19 22:27:28 +0000440 const DWARFObject &DObj = DCtx.getDWARFObj();
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000441 unsigned NumErrors = 0;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000442 const auto Form = AttrValue.Value.getForm();
443 switch (Form) {
444 case DW_FORM_ref1:
445 case DW_FORM_ref2:
446 case DW_FORM_ref4:
447 case DW_FORM_ref8:
448 case DW_FORM_ref_udata: {
449 // Verify all CU relative references are valid CU offsets.
450 Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
451 assert(RefVal);
452 if (RefVal) {
453 auto DieCU = Die.getDwarfUnit();
454 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
455 auto CUOffset = AttrValue.Value.getRawUValue();
456 if (CUOffset >= CUSize) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000457 ++NumErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000458 error() << FormEncodingString(Form) << " CU offset "
459 << format("0x%08" PRIx64, CUOffset)
460 << " is invalid (must be less than CU size of "
461 << format("0x%08" PRIx32, CUSize) << "):\n";
Adrian Prantld3f9f212017-09-20 17:44:00 +0000462 Die.dump(OS, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000463 OS << "\n";
464 } else {
465 // Valid reference, but we will verify it points to an actual
466 // DIE later.
467 ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
Greg Claytonb8c162b2017-05-03 16:02:29 +0000468 }
469 }
Greg Claytonc5b2d562017-05-03 18:25:46 +0000470 break;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000471 }
Greg Claytonc5b2d562017-05-03 18:25:46 +0000472 case DW_FORM_ref_addr: {
473 // Verify all absolute DIE references have valid offsets in the
474 // .debug_info section.
475 Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
476 assert(RefVal);
477 if (RefVal) {
Rafael Espindolac398e672017-07-19 22:27:28 +0000478 if (*RefVal >= DObj.getInfoSection().Data.size()) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000479 ++NumErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000480 error() << "DW_FORM_ref_addr offset beyond .debug_info "
481 "bounds:\n";
Adrian Prantld3f9f212017-09-20 17:44:00 +0000482 Die.dump(OS, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000483 OS << "\n";
484 } else {
485 // Valid reference, but we will verify it points to an actual
486 // DIE later.
487 ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
488 }
489 }
490 break;
491 }
492 case DW_FORM_strp: {
493 auto SecOffset = AttrValue.Value.getAsSectionOffset();
494 assert(SecOffset); // DW_FORM_strp is a section offset.
Rafael Espindolac398e672017-07-19 22:27:28 +0000495 if (SecOffset && *SecOffset >= DObj.getStringSection().size()) {
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000496 ++NumErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000497 error() << "DW_FORM_strp offset beyond .debug_str bounds:\n";
Adrian Prantld3f9f212017-09-20 17:44:00 +0000498 Die.dump(OS, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000499 OS << "\n";
500 }
501 break;
502 }
503 default:
504 break;
505 }
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000506 return NumErrors;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000507}
Greg Claytonb8c162b2017-05-03 16:02:29 +0000508
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000509unsigned DWARFVerifier::verifyDebugInfoReferences() {
Greg Claytonb8c162b2017-05-03 16:02:29 +0000510 // Take all references and make sure they point to an actual DIE by
511 // getting the DIE by offset and emitting an error
512 OS << "Verifying .debug_info references...\n";
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000513 unsigned NumErrors = 0;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000514 for (auto Pair : ReferenceToDIEOffsets) {
515 auto Die = DCtx.getDIEForOffset(Pair.first);
516 if (Die)
517 continue;
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000518 ++NumErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000519 error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
520 << ". Offset is in between DIEs:\n";
Greg Claytonb8c162b2017-05-03 16:02:29 +0000521 for (auto Offset : Pair.second) {
522 auto ReferencingDie = DCtx.getDIEForOffset(Offset);
Adrian Prantld3f9f212017-09-20 17:44:00 +0000523 ReferencingDie.dump(OS, 0, DumpOpts);
Greg Claytonb8c162b2017-05-03 16:02:29 +0000524 OS << "\n";
525 }
526 OS << "\n";
527 }
Spyridoula Gravanif6bd788d2017-07-18 01:00:26 +0000528 return NumErrors;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000529}
530
Greg Claytonc5b2d562017-05-03 18:25:46 +0000531void DWARFVerifier::verifyDebugLineStmtOffsets() {
Greg Claytonb8c162b2017-05-03 16:02:29 +0000532 std::map<uint64_t, DWARFDie> StmtListToDie;
Greg Claytonb8c162b2017-05-03 16:02:29 +0000533 for (const auto &CU : DCtx.compile_units()) {
Greg Claytonc5b2d562017-05-03 18:25:46 +0000534 auto Die = CU->getUnitDIE();
Greg Claytonb8c162b2017-05-03 16:02:29 +0000535 // Get the attribute value as a section offset. No need to produce an
536 // error here if the encoding isn't correct because we validate this in
537 // the .debug_info verifier.
Greg Claytonc5b2d562017-05-03 18:25:46 +0000538 auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
Greg Claytonb8c162b2017-05-03 16:02:29 +0000539 if (!StmtSectionOffset)
540 continue;
541 const uint32_t LineTableOffset = *StmtSectionOffset;
Greg Claytonc5b2d562017-05-03 18:25:46 +0000542 auto LineTable = DCtx.getLineTableForUnit(CU.get());
Rafael Espindolac398e672017-07-19 22:27:28 +0000543 if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
Greg Claytonc5b2d562017-05-03 18:25:46 +0000544 if (!LineTable) {
545 ++NumDebugLineErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000546 error() << ".debug_line[" << format("0x%08" PRIx32, LineTableOffset)
547 << "] was not able to be parsed for CU:\n";
Adrian Prantld3f9f212017-09-20 17:44:00 +0000548 Die.dump(OS, 0, DumpOpts);
Greg Claytonc5b2d562017-05-03 18:25:46 +0000549 OS << '\n';
550 continue;
551 }
552 } else {
553 // Make sure we don't get a valid line table back if the offset is wrong.
554 assert(LineTable == nullptr);
Greg Claytonb8c162b2017-05-03 16:02:29 +0000555 // Skip this line table as it isn't valid. No need to create an error
556 // here because we validate this in the .debug_info verifier.
557 continue;
558 }
Greg Claytonb8c162b2017-05-03 16:02:29 +0000559 auto Iter = StmtListToDie.find(LineTableOffset);
560 if (Iter != StmtListToDie.end()) {
561 ++NumDebugLineErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000562 error() << "two compile unit DIEs, "
563 << format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
564 << format("0x%08" PRIx32, Die.getOffset())
565 << ", have the same DW_AT_stmt_list section offset:\n";
Adrian Prantld3f9f212017-09-20 17:44:00 +0000566 Iter->second.dump(OS, 0, DumpOpts);
567 Die.dump(OS, 0, DumpOpts);
Greg Claytonb8c162b2017-05-03 16:02:29 +0000568 OS << '\n';
569 // Already verified this line table before, no need to do it again.
570 continue;
571 }
Greg Claytonc5b2d562017-05-03 18:25:46 +0000572 StmtListToDie[LineTableOffset] = Die;
573 }
574}
Greg Claytonb8c162b2017-05-03 16:02:29 +0000575
Greg Claytonc5b2d562017-05-03 18:25:46 +0000576void DWARFVerifier::verifyDebugLineRows() {
577 for (const auto &CU : DCtx.compile_units()) {
578 auto Die = CU->getUnitDIE();
Greg Claytonb8c162b2017-05-03 16:02:29 +0000579 auto LineTable = DCtx.getLineTableForUnit(CU.get());
Greg Claytonc5b2d562017-05-03 18:25:46 +0000580 // If there is no line table we will have created an error in the
581 // .debug_info verifier or in verifyDebugLineStmtOffsets().
582 if (!LineTable)
Greg Claytonb8c162b2017-05-03 16:02:29 +0000583 continue;
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000584
585 // Verify prologue.
Greg Claytonb8c162b2017-05-03 16:02:29 +0000586 uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000587 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
588 uint32_t FileIndex = 1;
589 StringMap<uint16_t> FullPathMap;
590 for (const auto &FileName : LineTable->Prologue.FileNames) {
591 // Verify directory index.
592 if (FileName.DirIdx > MaxDirIndex) {
593 ++NumDebugLineErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000594 error() << ".debug_line["
595 << format("0x%08" PRIx64,
596 *toSectionOffset(Die.find(DW_AT_stmt_list)))
597 << "].prologue.file_names[" << FileIndex
598 << "].dir_idx contains an invalid index: " << FileName.DirIdx
599 << "\n";
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000600 }
601
602 // Check file paths for duplicates.
603 std::string FullPath;
604 const bool HasFullPath = LineTable->getFileNameByIndex(
605 FileIndex, CU->getCompilationDir(),
606 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath);
607 assert(HasFullPath && "Invalid index?");
608 (void)HasFullPath;
609 auto It = FullPathMap.find(FullPath);
610 if (It == FullPathMap.end())
611 FullPathMap[FullPath] = FileIndex;
612 else if (It->second != FileIndex) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000613 warn() << ".debug_line["
614 << format("0x%08" PRIx64,
615 *toSectionOffset(Die.find(DW_AT_stmt_list)))
616 << "].prologue.file_names[" << FileIndex
617 << "] is a duplicate of file_names[" << It->second << "]\n";
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000618 }
619
620 FileIndex++;
621 }
622
623 // Verify rows.
Greg Claytonb8c162b2017-05-03 16:02:29 +0000624 uint64_t PrevAddress = 0;
625 uint32_t RowIndex = 0;
626 for (const auto &Row : LineTable->Rows) {
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000627 // Verify row address.
Greg Claytonb8c162b2017-05-03 16:02:29 +0000628 if (Row.Address < PrevAddress) {
629 ++NumDebugLineErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000630 error() << ".debug_line["
631 << format("0x%08" PRIx64,
632 *toSectionOffset(Die.find(DW_AT_stmt_list)))
633 << "] row[" << RowIndex
634 << "] decreases in address from previous row:\n";
Greg Claytonb8c162b2017-05-03 16:02:29 +0000635
636 DWARFDebugLine::Row::dumpTableHeader(OS);
637 if (RowIndex > 0)
638 LineTable->Rows[RowIndex - 1].dump(OS);
639 Row.dump(OS);
640 OS << '\n';
641 }
642
Jonas Devliegheref4ed65d2017-09-08 09:48:51 +0000643 // Verify file index.
Greg Claytonb8c162b2017-05-03 16:02:29 +0000644 if (Row.File > MaxFileIndex) {
645 ++NumDebugLineErrors;
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000646 error() << ".debug_line["
647 << format("0x%08" PRIx64,
648 *toSectionOffset(Die.find(DW_AT_stmt_list)))
649 << "][" << RowIndex << "] has invalid file index " << Row.File
650 << " (valid values are [1," << MaxFileIndex << "]):\n";
Greg Claytonb8c162b2017-05-03 16:02:29 +0000651 DWARFDebugLine::Row::dumpTableHeader(OS);
652 Row.dump(OS);
653 OS << '\n';
654 }
655 if (Row.EndSequence)
656 PrevAddress = 0;
657 else
658 PrevAddress = Row.Address;
659 ++RowIndex;
660 }
661 }
Greg Claytonc5b2d562017-05-03 18:25:46 +0000662}
663
664bool DWARFVerifier::handleDebugLine() {
665 NumDebugLineErrors = 0;
666 OS << "Verifying .debug_line...\n";
667 verifyDebugLineStmtOffsets();
668 verifyDebugLineRows();
Greg Claytonb8c162b2017-05-03 16:02:29 +0000669 return NumDebugLineErrors == 0;
670}
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000671
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000672unsigned DWARFVerifier::verifyAccelTable(const DWARFSection *AccelSection,
673 DataExtractor *StrData,
674 const char *SectionName) {
675 unsigned NumErrors = 0;
676 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
677 DCtx.isLittleEndian(), 0);
678 DWARFAcceleratorTable AccelTable(AccelSectionData, *StrData);
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000679
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000680 OS << "Verifying " << SectionName << "...\n";
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000681
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000682 // Verify that the fixed part of the header is not too short.
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000683 if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000684 error() << "Section is too small to fit a section header.\n";
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000685 return 1;
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000686 }
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000687
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000688 // Verify that the section is not too short.
689 if (!AccelTable.extract()) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000690 error() << "Section is smaller than size described in section header.\n";
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000691 return 1;
692 }
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000693
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000694 // Verify that all buckets have a valid hash index or are empty.
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000695 uint32_t NumBuckets = AccelTable.getNumBuckets();
696 uint32_t NumHashes = AccelTable.getNumHashes();
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000697
698 uint32_t BucketsOffset =
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000699 AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000700 uint32_t HashesBase = BucketsOffset + NumBuckets * 4;
701 uint32_t OffsetsBase = HashesBase + NumHashes * 4;
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000702 for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000703 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000704 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000705 error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
706 HashIdx);
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000707 ++NumErrors;
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000708 }
709 }
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000710 uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000711 if (NumAtoms == 0) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000712 error() << "No atoms: failed to read HashData.\n";
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000713 return 1;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000714 }
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000715 if (!AccelTable.validateForms()) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000716 error() << "Unsupported form: failed to read HashData.\n";
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000717 return 1;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000718 }
719
720 for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
721 uint32_t HashOffset = HashesBase + 4 * HashIdx;
722 uint32_t DataOffset = OffsetsBase + 4 * HashIdx;
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000723 uint32_t Hash = AccelSectionData.getU32(&HashOffset);
724 uint32_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
725 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
726 sizeof(uint64_t))) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000727 error() << format("Hash[%d] has invalid HashData offset: 0x%08x.\n",
728 HashIdx, HashDataOffset);
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000729 ++NumErrors;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000730 }
731
732 uint32_t StrpOffset;
733 uint32_t StringOffset;
734 uint32_t StringCount = 0;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000735 unsigned Offset;
736 unsigned Tag;
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000737 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000738 const uint32_t NumHashDataObjects =
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000739 AccelSectionData.getU32(&HashDataOffset);
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000740 for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
741 ++HashDataIdx) {
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000742 std::tie(Offset, Tag) = AccelTable.readAtoms(HashDataOffset);
743 auto Die = DCtx.getDIEForOffset(Offset);
744 if (!Die) {
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000745 const uint32_t BucketIdx =
746 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
747 StringOffset = StrpOffset;
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000748 const char *Name = StrData->getCStr(&StringOffset);
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000749 if (!Name)
750 Name = "<NULL>";
751
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000752 error() << format(
753 "%s Bucket[%d] Hash[%d] = 0x%08x "
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000754 "Str[%u] = 0x%08x "
755 "DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n",
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000756 SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000757 HashDataIdx, Offset, Name);
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000758
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000759 ++NumErrors;
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000760 continue;
761 }
762 if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000763 error() << "Tag " << dwarf::TagString(Tag)
764 << " in accelerator table does not match Tag "
765 << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx
766 << "].\n";
Spyridoula Gravani70d35e12017-07-31 18:01:16 +0000767 ++NumErrors;
Spyridoula Gravani837c1102017-06-29 20:13:05 +0000768 }
769 }
770 ++StringCount;
771 }
772 }
Spyridoula Gravanidc635f42017-07-26 00:52:31 +0000773 return NumErrors;
774}
775
776bool DWARFVerifier::handleAccelTables() {
777 const DWARFObject &D = DCtx.getDWARFObj();
778 DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0);
779 unsigned NumErrors = 0;
780 if (!D.getAppleNamesSection().Data.empty())
781 NumErrors +=
782 verifyAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names");
783 if (!D.getAppleTypesSection().Data.empty())
784 NumErrors +=
785 verifyAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types");
786 if (!D.getAppleNamespacesSection().Data.empty())
787 NumErrors += verifyAccelTable(&D.getAppleNamespacesSection(), &StrData,
788 ".apple_namespaces");
789 if (!D.getAppleObjCSection().Data.empty())
790 NumErrors +=
791 verifyAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc");
792 return NumErrors == 0;
Spyridoula Gravanie41823b2017-06-14 00:17:55 +0000793}
Jonas Devlieghere19fc4d92017-09-29 09:33:31 +0000794
795raw_ostream &DWARFVerifier::error() const {
796 return WithColor(OS, syntax::Error).get() << "error: ";
797}
798
799raw_ostream &DWARFVerifier::warn() const {
800 return WithColor(OS, syntax::Warning).get() << "warning: ";
801}
802
803raw_ostream &DWARFVerifier::note() const {
804 return WithColor(OS, syntax::Note).get() << "note: ";
805}