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/IntervalMap.h" 10 #include "llvm/ADT/STLExtras.h" 11 #include "llvm/ADT/SmallSet.h" 12 #include "llvm/BinaryFormat/Dwarf.h" 13 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" 14 #include "llvm/DebugInfo/DWARF/DWARFAttribute.h" 15 #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" 16 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 17 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" 18 #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" 19 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" 20 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" 21 #include "llvm/DebugInfo/DWARF/DWARFDie.h" 22 #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 23 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" 24 #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" 25 #include "llvm/DebugInfo/DWARF/DWARFObject.h" 26 #include "llvm/DebugInfo/DWARF/DWARFSection.h" 27 #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" 28 #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 29 #include "llvm/Object/Error.h" 30 #include "llvm/Support/DJB.h" 31 #include "llvm/Support/Error.h" 32 #include "llvm/Support/ErrorHandling.h" 33 #include "llvm/Support/FileSystem.h" 34 #include "llvm/Support/FormatVariadic.h" 35 #include "llvm/Support/JSON.h" 36 #include "llvm/Support/WithColor.h" 37 #include "llvm/Support/raw_ostream.h" 38 #include <map> 39 #include <set> 40 #include <vector> 41 42 using namespace llvm; 43 using namespace dwarf; 44 using namespace object; 45 46 namespace llvm { 47 class DWARFDebugInfoEntry; 48 } 49 50 std::optional<DWARFAddressRange> 51 DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) { 52 auto Begin = Ranges.begin(); 53 auto End = Ranges.end(); 54 auto Pos = std::lower_bound(Begin, End, R); 55 56 // Check for exact duplicates which is an allowed special case 57 if (Pos != End && *Pos == R) { 58 return std::nullopt; 59 } 60 61 if (Pos != End) { 62 DWARFAddressRange Range(*Pos); 63 if (Pos->merge(R)) 64 return Range; 65 } 66 if (Pos != Begin) { 67 auto Iter = Pos - 1; 68 DWARFAddressRange Range(*Iter); 69 if (Iter->merge(R)) 70 return Range; 71 } 72 73 Ranges.insert(Pos, R); 74 return std::nullopt; 75 } 76 77 DWARFVerifier::DieRangeInfo::die_range_info_iterator 78 DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) { 79 if (RI.Ranges.empty()) 80 return Children.end(); 81 82 auto End = Children.end(); 83 auto Iter = Children.begin(); 84 while (Iter != End) { 85 if (Iter->intersects(RI)) 86 return Iter; 87 ++Iter; 88 } 89 Children.insert(RI); 90 return Children.end(); 91 } 92 93 bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const { 94 auto I1 = Ranges.begin(), E1 = Ranges.end(); 95 auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); 96 if (I2 == E2) 97 return true; 98 99 DWARFAddressRange R = *I2; 100 while (I1 != E1) { 101 bool Covered = I1->LowPC <= R.LowPC; 102 if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) { 103 if (++I2 == E2) 104 return true; 105 R = *I2; 106 continue; 107 } 108 if (!Covered) 109 return false; 110 if (R.LowPC < I1->HighPC) 111 R.LowPC = I1->HighPC; 112 ++I1; 113 } 114 return false; 115 } 116 117 bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const { 118 auto I1 = Ranges.begin(), E1 = Ranges.end(); 119 auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); 120 while (I1 != E1 && I2 != E2) { 121 if (I1->intersects(*I2)) { 122 // Exact duplicates are allowed 123 if (!(*I1 == *I2)) 124 return true; 125 } 126 if (I1->LowPC < I2->LowPC) 127 ++I1; 128 else 129 ++I2; 130 } 131 return false; 132 } 133 134 bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, 135 uint64_t *Offset, unsigned UnitIndex, 136 uint8_t &UnitType, bool &isUnitDWARF64) { 137 uint64_t AbbrOffset, Length; 138 uint8_t AddrSize = 0; 139 uint16_t Version; 140 bool Success = true; 141 142 bool ValidLength = false; 143 bool ValidVersion = false; 144 bool ValidAddrSize = false; 145 bool ValidType = true; 146 bool ValidAbbrevOffset = true; 147 148 uint64_t OffsetStart = *Offset; 149 DwarfFormat Format; 150 std::tie(Length, Format) = DebugInfoData.getInitialLength(Offset); 151 isUnitDWARF64 = Format == DWARF64; 152 Version = DebugInfoData.getU16(Offset); 153 154 if (Version >= 5) { 155 UnitType = DebugInfoData.getU8(Offset); 156 AddrSize = DebugInfoData.getU8(Offset); 157 AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); 158 ValidType = dwarf::isUnitType(UnitType); 159 } else { 160 UnitType = 0; 161 AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); 162 AddrSize = DebugInfoData.getU8(Offset); 163 } 164 165 Expected<const DWARFAbbreviationDeclarationSet *> AbbrevSetOrErr = 166 DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset); 167 if (!AbbrevSetOrErr) { 168 ValidAbbrevOffset = false; 169 // FIXME: A problematic debug_abbrev section is reported below in the form 170 // of a `note:`. We should propagate this error there (or elsewhere) to 171 // avoid losing the specific problem with the debug_abbrev section. 172 consumeError(AbbrevSetOrErr.takeError()); 173 } 174 175 ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3); 176 ValidVersion = DWARFContext::isSupportedVersion(Version); 177 ValidAddrSize = DWARFContext::isAddressSizeSupported(AddrSize); 178 if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset || 179 !ValidType) { 180 Success = false; 181 bool HeaderShown = false; 182 auto ShowHeaderOnce = [&]() { 183 if (!HeaderShown) { 184 error() << format("Units[%d] - start offset: 0x%08" PRIx64 " \n", 185 UnitIndex, OffsetStart); 186 HeaderShown = true; 187 } 188 }; 189 if (!ValidLength) 190 ErrorCategory.Report( 191 "Unit Header Length: Unit too large for .debug_info provided", [&]() { 192 ShowHeaderOnce(); 193 note() << "The length for this unit is too " 194 "large for the .debug_info provided.\n"; 195 }); 196 if (!ValidVersion) 197 ErrorCategory.Report( 198 "Unit Header Length: 16 bit unit header version is not valid", [&]() { 199 ShowHeaderOnce(); 200 note() << "The 16 bit unit header version is not valid.\n"; 201 }); 202 if (!ValidType) 203 ErrorCategory.Report( 204 "Unit Header Length: Unit type encoding is not valid", [&]() { 205 ShowHeaderOnce(); 206 note() << "The unit type encoding is not valid.\n"; 207 }); 208 if (!ValidAbbrevOffset) 209 ErrorCategory.Report( 210 "Unit Header Length: Offset into the .debug_abbrev section is not " 211 "valid", 212 [&]() { 213 ShowHeaderOnce(); 214 note() << "The offset into the .debug_abbrev section is " 215 "not valid.\n"; 216 }); 217 if (!ValidAddrSize) 218 ErrorCategory.Report("Unit Header Length: Address size is unsupported", 219 [&]() { 220 ShowHeaderOnce(); 221 note() << "The address size is unsupported.\n"; 222 }); 223 } 224 *Offset = OffsetStart + Length + (isUnitDWARF64 ? 12 : 4); 225 return Success; 226 } 227 228 bool DWARFVerifier::verifyName(const DWARFDie &Die) { 229 // FIXME Add some kind of record of which DIE names have already failed and 230 // don't bother checking a DIE that uses an already failed DIE. 231 232 std::string ReconstructedName; 233 raw_string_ostream OS(ReconstructedName); 234 std::string OriginalFullName; 235 Die.getFullName(OS, &OriginalFullName); 236 OS.flush(); 237 if (OriginalFullName.empty() || OriginalFullName == ReconstructedName) 238 return false; 239 240 ErrorCategory.Report( 241 "Simplified template DW_AT_name could not be reconstituted", [&]() { 242 error() 243 << "Simplified template DW_AT_name could not be reconstituted:\n" 244 << formatv(" original: {0}\n" 245 " reconstituted: {1}\n", 246 OriginalFullName, ReconstructedName); 247 dump(Die) << '\n'; 248 dump(Die.getDwarfUnit()->getUnitDIE()) << '\n'; 249 }); 250 return true; 251 } 252 253 unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit, 254 ReferenceMap &UnitLocalReferences, 255 ReferenceMap &CrossUnitReferences) { 256 unsigned NumUnitErrors = 0; 257 unsigned NumDies = Unit.getNumDIEs(); 258 for (unsigned I = 0; I < NumDies; ++I) { 259 auto Die = Unit.getDIEAtIndex(I); 260 261 if (Die.getTag() == DW_TAG_null) 262 continue; 263 264 for (auto AttrValue : Die.attributes()) { 265 NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue); 266 NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences, 267 CrossUnitReferences); 268 } 269 270 NumUnitErrors += verifyName(Die); 271 272 if (Die.hasChildren()) { 273 if (Die.getFirstChild().isValid() && 274 Die.getFirstChild().getTag() == DW_TAG_null) { 275 warn() << dwarf::TagString(Die.getTag()) 276 << " has DW_CHILDREN_yes but DIE has no children: "; 277 Die.dump(OS); 278 } 279 } 280 281 NumUnitErrors += verifyDebugInfoCallSite(Die); 282 } 283 284 DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false); 285 if (!Die) { 286 ErrorCategory.Report("Compilation unit missing DIE", [&]() { 287 error() << "Compilation unit without DIE.\n"; 288 }); 289 NumUnitErrors++; 290 return NumUnitErrors; 291 } 292 293 if (!dwarf::isUnitType(Die.getTag())) { 294 ErrorCategory.Report("Compilation unit root DIE is not a unit DIE", [&]() { 295 error() << "Compilation unit root DIE is not a unit DIE: " 296 << dwarf::TagString(Die.getTag()) << ".\n"; 297 }); 298 NumUnitErrors++; 299 } 300 301 uint8_t UnitType = Unit.getUnitType(); 302 if (!DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) { 303 ErrorCategory.Report("Mismatched unit type", [&]() { 304 error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType) 305 << ") and root DIE (" << dwarf::TagString(Die.getTag()) 306 << ") do not match.\n"; 307 }); 308 NumUnitErrors++; 309 } 310 311 // According to DWARF Debugging Information Format Version 5, 312 // 3.1.2 Skeleton Compilation Unit Entries: 313 // "A skeleton compilation unit has no children." 314 if (Die.getTag() == dwarf::DW_TAG_skeleton_unit && Die.hasChildren()) { 315 ErrorCategory.Report("Skeleton CU has children", [&]() { 316 error() << "Skeleton compilation unit has children.\n"; 317 }); 318 NumUnitErrors++; 319 } 320 321 DieRangeInfo RI; 322 NumUnitErrors += verifyDieRanges(Die, RI); 323 324 return NumUnitErrors; 325 } 326 327 unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) { 328 if (Die.getTag() != DW_TAG_call_site && Die.getTag() != DW_TAG_GNU_call_site) 329 return 0; 330 331 DWARFDie Curr = Die.getParent(); 332 for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Die.getParent()) { 333 if (Curr.getTag() == DW_TAG_inlined_subroutine) { 334 ErrorCategory.Report( 335 "Call site nested entry within inlined subroutine", [&]() { 336 error() << "Call site entry nested within inlined subroutine:"; 337 Curr.dump(OS); 338 }); 339 return 1; 340 } 341 } 342 343 if (!Curr.isValid()) { 344 ErrorCategory.Report( 345 "Call site entry not nested within valid subprogram", [&]() { 346 error() << "Call site entry not nested within a valid subprogram:"; 347 Die.dump(OS); 348 }); 349 return 1; 350 } 351 352 std::optional<DWARFFormValue> CallAttr = Curr.find( 353 {DW_AT_call_all_calls, DW_AT_call_all_source_calls, 354 DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites, 355 DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites}); 356 if (!CallAttr) { 357 ErrorCategory.Report( 358 "Subprogram with call site entry has no DW_AT_call attribute", [&]() { 359 error() 360 << "Subprogram with call site entry has no DW_AT_call attribute:"; 361 Curr.dump(OS); 362 Die.dump(OS, /*indent*/ 1); 363 }); 364 return 1; 365 } 366 367 return 0; 368 } 369 370 unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) { 371 if (!Abbrev) 372 return 0; 373 374 Expected<const DWARFAbbreviationDeclarationSet *> AbbrDeclsOrErr = 375 Abbrev->getAbbreviationDeclarationSet(0); 376 if (!AbbrDeclsOrErr) { 377 std::string ErrMsg = toString(AbbrDeclsOrErr.takeError()); 378 ErrorCategory.Report("Abbreviation Declaration error", 379 [&]() { error() << ErrMsg << "\n"; }); 380 return 1; 381 } 382 383 const auto *AbbrDecls = *AbbrDeclsOrErr; 384 unsigned NumErrors = 0; 385 for (auto AbbrDecl : *AbbrDecls) { 386 SmallDenseSet<uint16_t> AttributeSet; 387 for (auto Attribute : AbbrDecl.attributes()) { 388 auto Result = AttributeSet.insert(Attribute.Attr); 389 if (!Result.second) { 390 ErrorCategory.Report( 391 "Abbreviation declartion contains multiple attributes", [&]() { 392 error() << "Abbreviation declaration contains multiple " 393 << AttributeString(Attribute.Attr) << " attributes.\n"; 394 AbbrDecl.dump(OS); 395 }); 396 ++NumErrors; 397 } 398 } 399 } 400 return NumErrors; 401 } 402 403 bool DWARFVerifier::handleDebugAbbrev() { 404 OS << "Verifying .debug_abbrev...\n"; 405 406 const DWARFObject &DObj = DCtx.getDWARFObj(); 407 unsigned NumErrors = 0; 408 if (!DObj.getAbbrevSection().empty()) 409 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev()); 410 if (!DObj.getAbbrevDWOSection().empty()) 411 NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO()); 412 413 return NumErrors == 0; 414 } 415 416 unsigned DWARFVerifier::verifyUnits(const DWARFUnitVector &Units) { 417 unsigned NumDebugInfoErrors = 0; 418 ReferenceMap CrossUnitReferences; 419 420 unsigned Index = 1; 421 for (const auto &Unit : Units) { 422 OS << "Verifying unit: " << Index << " / " << Units.getNumUnits(); 423 if (const char* Name = Unit->getUnitDIE(true).getShortName()) 424 OS << ", \"" << Name << '\"'; 425 OS << '\n'; 426 OS.flush(); 427 ReferenceMap UnitLocalReferences; 428 NumDebugInfoErrors += 429 verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences); 430 NumDebugInfoErrors += verifyDebugInfoReferences( 431 UnitLocalReferences, [&](uint64_t Offset) { return Unit.get(); }); 432 ++Index; 433 } 434 435 NumDebugInfoErrors += verifyDebugInfoReferences( 436 CrossUnitReferences, [&](uint64_t Offset) -> DWARFUnit * { 437 if (DWARFUnit *U = Units.getUnitForOffset(Offset)) 438 return U; 439 return nullptr; 440 }); 441 442 return NumDebugInfoErrors; 443 } 444 445 unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S) { 446 const DWARFObject &DObj = DCtx.getDWARFObj(); 447 DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0); 448 unsigned NumDebugInfoErrors = 0; 449 uint64_t Offset = 0, UnitIdx = 0; 450 uint8_t UnitType = 0; 451 bool isUnitDWARF64 = false; 452 bool isHeaderChainValid = true; 453 bool hasDIE = DebugInfoData.isValidOffset(Offset); 454 DWARFUnitVector TypeUnitVector; 455 DWARFUnitVector CompileUnitVector; 456 /// A map that tracks all references (converted absolute references) so we 457 /// can verify each reference points to a valid DIE and not an offset that 458 /// lies between to valid DIEs. 459 ReferenceMap CrossUnitReferences; 460 while (hasDIE) { 461 if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType, 462 isUnitDWARF64)) { 463 isHeaderChainValid = false; 464 if (isUnitDWARF64) 465 break; 466 } 467 hasDIE = DebugInfoData.isValidOffset(Offset); 468 ++UnitIdx; 469 } 470 if (UnitIdx == 0 && !hasDIE) { 471 warn() << "Section is empty.\n"; 472 isHeaderChainValid = true; 473 } 474 if (!isHeaderChainValid) 475 ++NumDebugInfoErrors; 476 return NumDebugInfoErrors; 477 } 478 479 unsigned DWARFVerifier::verifyIndex(StringRef Name, 480 DWARFSectionKind InfoColumnKind, 481 StringRef IndexStr) { 482 if (IndexStr.empty()) 483 return 0; 484 OS << "Verifying " << Name << "...\n"; 485 DWARFUnitIndex Index(InfoColumnKind); 486 DataExtractor D(IndexStr, DCtx.isLittleEndian(), 0); 487 if (!Index.parse(D)) 488 return 1; 489 using MapType = IntervalMap<uint64_t, uint64_t>; 490 MapType::Allocator Alloc; 491 std::vector<std::unique_ptr<MapType>> Sections(Index.getColumnKinds().size()); 492 for (const DWARFUnitIndex::Entry &E : Index.getRows()) { 493 uint64_t Sig = E.getSignature(); 494 if (!E.getContributions()) 495 continue; 496 for (auto E : enumerate( 497 InfoColumnKind == DW_SECT_INFO 498 ? ArrayRef(E.getContributions(), Index.getColumnKinds().size()) 499 : ArrayRef(E.getContribution(), 1))) { 500 const DWARFUnitIndex::Entry::SectionContribution &SC = E.value(); 501 int Col = E.index(); 502 if (SC.getLength() == 0) 503 continue; 504 if (!Sections[Col]) 505 Sections[Col] = std::make_unique<MapType>(Alloc); 506 auto &M = *Sections[Col]; 507 auto I = M.find(SC.getOffset()); 508 if (I != M.end() && I.start() < (SC.getOffset() + SC.getLength())) { 509 StringRef Category = InfoColumnKind == DWARFSectionKind::DW_SECT_INFO 510 ? "Overlapping CU index entries" 511 : "Overlapping TU index entries"; 512 ErrorCategory.Report(Category, [&]() { 513 error() << llvm::formatv( 514 "overlapping index entries for entries {0:x16} " 515 "and {1:x16} for column {2}\n", 516 *I, Sig, toString(Index.getColumnKinds()[Col])); 517 }); 518 return 1; 519 } 520 M.insert(SC.getOffset(), SC.getOffset() + SC.getLength() - 1, Sig); 521 } 522 } 523 524 return 0; 525 } 526 527 bool DWARFVerifier::handleDebugCUIndex() { 528 return verifyIndex(".debug_cu_index", DWARFSectionKind::DW_SECT_INFO, 529 DCtx.getDWARFObj().getCUIndexSection()) == 0; 530 } 531 532 bool DWARFVerifier::handleDebugTUIndex() { 533 return verifyIndex(".debug_tu_index", DWARFSectionKind::DW_SECT_EXT_TYPES, 534 DCtx.getDWARFObj().getTUIndexSection()) == 0; 535 } 536 537 bool DWARFVerifier::handleDebugInfo() { 538 const DWARFObject &DObj = DCtx.getDWARFObj(); 539 unsigned NumErrors = 0; 540 541 OS << "Verifying .debug_info Unit Header Chain...\n"; 542 DObj.forEachInfoSections([&](const DWARFSection &S) { 543 NumErrors += verifyUnitSection(S); 544 }); 545 546 OS << "Verifying .debug_types Unit Header Chain...\n"; 547 DObj.forEachTypesSections([&](const DWARFSection &S) { 548 NumErrors += verifyUnitSection(S); 549 }); 550 551 OS << "Verifying non-dwo Units...\n"; 552 NumErrors += verifyUnits(DCtx.getNormalUnitsVector()); 553 554 OS << "Verifying dwo Units...\n"; 555 NumErrors += verifyUnits(DCtx.getDWOUnitsVector()); 556 return NumErrors == 0; 557 } 558 559 unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, 560 DieRangeInfo &ParentRI) { 561 unsigned NumErrors = 0; 562 563 if (!Die.isValid()) 564 return NumErrors; 565 566 DWARFUnit *Unit = Die.getDwarfUnit(); 567 568 auto RangesOrError = Die.getAddressRanges(); 569 if (!RangesOrError) { 570 // FIXME: Report the error. 571 if (!Unit->isDWOUnit()) 572 ++NumErrors; 573 llvm::consumeError(RangesOrError.takeError()); 574 return NumErrors; 575 } 576 577 const DWARFAddressRangesVector &Ranges = RangesOrError.get(); 578 // Build RI for this DIE and check that ranges within this DIE do not 579 // overlap. 580 DieRangeInfo RI(Die); 581 582 // TODO support object files better 583 // 584 // Some object file formats (i.e. non-MachO) support COMDAT. ELF in 585 // particular does so by placing each function into a section. The DWARF data 586 // for the function at that point uses a section relative DW_FORM_addrp for 587 // the DW_AT_low_pc and a DW_FORM_data4 for the offset as the DW_AT_high_pc. 588 // In such a case, when the Die is the CU, the ranges will overlap, and we 589 // will flag valid conflicting ranges as invalid. 590 // 591 // For such targets, we should read the ranges from the CU and partition them 592 // by the section id. The ranges within a particular section should be 593 // disjoint, although the ranges across sections may overlap. We would map 594 // the child die to the entity that it references and the section with which 595 // it is associated. The child would then be checked against the range 596 // information for the associated section. 597 // 598 // For now, simply elide the range verification for the CU DIEs if we are 599 // processing an object file. 600 601 if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) { 602 bool DumpDieAfterError = false; 603 for (const auto &Range : Ranges) { 604 if (!Range.valid()) { 605 ++NumErrors; 606 ErrorCategory.Report("Invalid address range", [&]() { 607 error() << "Invalid address range " << Range << "\n"; 608 DumpDieAfterError = true; 609 }); 610 continue; 611 } 612 613 // Verify that ranges don't intersect and also build up the DieRangeInfo 614 // address ranges. Don't break out of the loop below early, or we will 615 // think this DIE doesn't have all of the address ranges it is supposed 616 // to have. Compile units often have DW_AT_ranges that can contain one or 617 // more dead stripped address ranges which tend to all be at the same 618 // address: 0 or -1. 619 if (auto PrevRange = RI.insert(Range)) { 620 ++NumErrors; 621 ErrorCategory.Report("DIE has overlapping DW_AT_ranges", [&]() { 622 error() << "DIE has overlapping ranges in DW_AT_ranges attribute: " 623 << *PrevRange << " and " << Range << '\n'; 624 DumpDieAfterError = true; 625 }); 626 } 627 } 628 if (DumpDieAfterError) 629 dump(Die, 2) << '\n'; 630 } 631 632 // Verify that children don't intersect. 633 const auto IntersectingChild = ParentRI.insert(RI); 634 if (IntersectingChild != ParentRI.Children.end()) { 635 ++NumErrors; 636 ErrorCategory.Report("DIEs have overlapping address ranges", [&]() { 637 error() << "DIEs have overlapping address ranges:"; 638 dump(Die); 639 dump(IntersectingChild->Die) << '\n'; 640 }); 641 } 642 643 // Verify that ranges are contained within their parent. 644 bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() && 645 !(Die.getTag() == DW_TAG_subprogram && 646 ParentRI.Die.getTag() == DW_TAG_subprogram); 647 if (ShouldBeContained && !ParentRI.contains(RI)) { 648 ++NumErrors; 649 ErrorCategory.Report( 650 "DIE address ranges are not contained by parent ranges", [&]() { 651 error() 652 << "DIE address ranges are not contained in its parent's ranges:"; 653 dump(ParentRI.Die); 654 dump(Die, 2) << '\n'; 655 }); 656 } 657 658 // Recursively check children. 659 for (DWARFDie Child : Die) 660 NumErrors += verifyDieRanges(Child, RI); 661 662 return NumErrors; 663 } 664 665 unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, 666 DWARFAttribute &AttrValue) { 667 unsigned NumErrors = 0; 668 auto ReportError = [&](StringRef category, const Twine &TitleMsg) { 669 ++NumErrors; 670 ErrorCategory.Report(category, [&]() { 671 error() << TitleMsg << '\n'; 672 dump(Die) << '\n'; 673 }); 674 }; 675 676 const DWARFObject &DObj = DCtx.getDWARFObj(); 677 DWARFUnit *U = Die.getDwarfUnit(); 678 const auto Attr = AttrValue.Attr; 679 switch (Attr) { 680 case DW_AT_ranges: 681 // Make sure the offset in the DW_AT_ranges attribute is valid. 682 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { 683 unsigned DwarfVersion = U->getVersion(); 684 const DWARFSection &RangeSection = DwarfVersion < 5 685 ? DObj.getRangesSection() 686 : DObj.getRnglistsSection(); 687 if (U->isDWOUnit() && RangeSection.Data.empty()) 688 break; 689 if (*SectionOffset >= RangeSection.Data.size()) 690 ReportError("DW_AT_ranges offset out of bounds", 691 "DW_AT_ranges offset is beyond " + 692 StringRef(DwarfVersion < 5 ? ".debug_ranges" 693 : ".debug_rnglists") + 694 " bounds: " + llvm::formatv("{0:x8}", *SectionOffset)); 695 break; 696 } 697 ReportError("Invalid DW_AT_ranges encoding", 698 "DIE has invalid DW_AT_ranges encoding:"); 699 break; 700 case DW_AT_stmt_list: 701 // Make sure the offset in the DW_AT_stmt_list attribute is valid. 702 if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { 703 if (*SectionOffset >= U->getLineSection().Data.size()) 704 ReportError("DW_AT_stmt_list offset out of bounds", 705 "DW_AT_stmt_list offset is beyond .debug_line bounds: " + 706 llvm::formatv("{0:x8}", *SectionOffset)); 707 break; 708 } 709 ReportError("Invalid DW_AT_stmt_list encoding", 710 "DIE has invalid DW_AT_stmt_list encoding:"); 711 break; 712 case DW_AT_location: { 713 // FIXME: It might be nice if there's a way to walk location expressions 714 // without trying to resolve the address ranges - it'd be a more efficient 715 // API (since the API is currently unnecessarily resolving addresses for 716 // this use case which only wants to validate the expressions themselves) & 717 // then the expressions could be validated even if the addresses can't be 718 // resolved. 719 // That sort of API would probably look like a callback "for each 720 // expression" with some way to lazily resolve the address ranges when 721 // needed (& then the existing API used here could be built on top of that - 722 // using the callback API to build the data structure and return it). 723 if (Expected<std::vector<DWARFLocationExpression>> Loc = 724 Die.getLocations(DW_AT_location)) { 725 for (const auto &Entry : *Loc) { 726 DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0); 727 DWARFExpression Expression(Data, U->getAddressByteSize(), 728 U->getFormParams().Format); 729 bool Error = 730 any_of(Expression, [](const DWARFExpression::Operation &Op) { 731 return Op.isError(); 732 }); 733 if (Error || !Expression.verify(U)) 734 ReportError("Invalid DWARF expressions", 735 "DIE contains invalid DWARF expression:"); 736 } 737 } else if (Error Err = handleErrors( 738 Loc.takeError(), [&](std::unique_ptr<ResolverError> E) { 739 return U->isDWOUnit() ? Error::success() 740 : Error(std::move(E)); 741 })) 742 ReportError("Invalid DW_AT_location", toString(std::move(Err))); 743 break; 744 } 745 case DW_AT_specification: 746 case DW_AT_abstract_origin: { 747 if (auto ReferencedDie = Die.getAttributeValueAsReferencedDie(Attr)) { 748 auto DieTag = Die.getTag(); 749 auto RefTag = ReferencedDie.getTag(); 750 if (DieTag == RefTag) 751 break; 752 if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram) 753 break; 754 if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member) 755 break; 756 // This might be reference to a function declaration. 757 if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram) 758 break; 759 ReportError("Incompatible DW_AT_abstract_origin tag reference", 760 "DIE with tag " + TagString(DieTag) + " has " + 761 AttributeString(Attr) + 762 " that points to DIE with " 763 "incompatible tag " + 764 TagString(RefTag)); 765 } 766 break; 767 } 768 case DW_AT_type: { 769 DWARFDie TypeDie = Die.getAttributeValueAsReferencedDie(DW_AT_type); 770 if (TypeDie && !isType(TypeDie.getTag())) { 771 ReportError("Incompatible DW_AT_type attribute tag", 772 "DIE has " + AttributeString(Attr) + 773 " with incompatible tag " + TagString(TypeDie.getTag())); 774 } 775 break; 776 } 777 case DW_AT_call_file: 778 case DW_AT_decl_file: { 779 if (auto FileIdx = AttrValue.Value.getAsUnsignedConstant()) { 780 if (U->isDWOUnit() && !U->isTypeUnit()) 781 break; 782 const auto *LT = U->getContext().getLineTableForUnit(U); 783 if (LT) { 784 if (!LT->hasFileAtIndex(*FileIdx)) { 785 bool IsZeroIndexed = LT->Prologue.getVersion() >= 5; 786 if (std::optional<uint64_t> LastFileIdx = 787 LT->getLastValidFileIndex()) { 788 ReportError("Invalid file index in DW_AT_decl_file", 789 "DIE has " + AttributeString(Attr) + 790 " with an invalid file index " + 791 llvm::formatv("{0}", *FileIdx) + 792 " (valid values are [" + 793 (IsZeroIndexed ? "0-" : "1-") + 794 llvm::formatv("{0}", *LastFileIdx) + "])"); 795 } else { 796 ReportError("Invalid file index in DW_AT_decl_file", 797 "DIE has " + AttributeString(Attr) + 798 " with an invalid file index " + 799 llvm::formatv("{0}", *FileIdx) + 800 " (the file table in the prologue is empty)"); 801 } 802 } 803 } else { 804 ReportError( 805 "File index in DW_AT_decl_file reference CU with no line table", 806 "DIE has " + AttributeString(Attr) + 807 " that references a file with index " + 808 llvm::formatv("{0}", *FileIdx) + 809 " and the compile unit has no line table"); 810 } 811 } else { 812 ReportError("Invalid encoding in DW_AT_decl_file", 813 "DIE has " + AttributeString(Attr) + 814 " with invalid encoding"); 815 } 816 break; 817 } 818 case DW_AT_call_line: 819 case DW_AT_decl_line: { 820 if (!AttrValue.Value.getAsUnsignedConstant()) { 821 ReportError( 822 Attr == DW_AT_call_line ? "Invalid file index in DW_AT_decl_line" 823 : "Invalid file index in DW_AT_call_line", 824 "DIE has " + AttributeString(Attr) + " with invalid encoding"); 825 } 826 break; 827 } 828 default: 829 break; 830 } 831 return NumErrors; 832 } 833 834 unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, 835 DWARFAttribute &AttrValue, 836 ReferenceMap &LocalReferences, 837 ReferenceMap &CrossUnitReferences) { 838 auto DieCU = Die.getDwarfUnit(); 839 unsigned NumErrors = 0; 840 const auto Form = AttrValue.Value.getForm(); 841 switch (Form) { 842 case DW_FORM_ref1: 843 case DW_FORM_ref2: 844 case DW_FORM_ref4: 845 case DW_FORM_ref8: 846 case DW_FORM_ref_udata: { 847 // Verify all CU relative references are valid CU offsets. 848 std::optional<uint64_t> RefVal = AttrValue.Value.getAsRelativeReference(); 849 assert(RefVal); 850 if (RefVal) { 851 auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); 852 auto CUOffset = AttrValue.Value.getRawUValue(); 853 if (CUOffset >= CUSize) { 854 ++NumErrors; 855 ErrorCategory.Report("Invalid CU offset", [&]() { 856 error() << FormEncodingString(Form) << " CU offset " 857 << format("0x%08" PRIx64, CUOffset) 858 << " is invalid (must be less than CU size of " 859 << format("0x%08" PRIx64, CUSize) << "):\n"; 860 Die.dump(OS, 0, DumpOpts); 861 dump(Die) << '\n'; 862 }); 863 } else { 864 // Valid reference, but we will verify it points to an actual 865 // DIE later. 866 LocalReferences[AttrValue.Value.getUnit()->getOffset() + *RefVal] 867 .insert(Die.getOffset()); 868 } 869 } 870 break; 871 } 872 case DW_FORM_ref_addr: { 873 // Verify all absolute DIE references have valid offsets in the 874 // .debug_info section. 875 std::optional<uint64_t> RefVal = AttrValue.Value.getAsDebugInfoReference(); 876 assert(RefVal); 877 if (RefVal) { 878 if (*RefVal >= DieCU->getInfoSection().Data.size()) { 879 ++NumErrors; 880 ErrorCategory.Report("DW_FORM_ref_addr offset out of bounds", [&]() { 881 error() << "DW_FORM_ref_addr offset beyond .debug_info " 882 "bounds:\n"; 883 dump(Die) << '\n'; 884 }); 885 } else { 886 // Valid reference, but we will verify it points to an actual 887 // DIE later. 888 CrossUnitReferences[*RefVal].insert(Die.getOffset()); 889 } 890 } 891 break; 892 } 893 case DW_FORM_strp: 894 case DW_FORM_strx: 895 case DW_FORM_strx1: 896 case DW_FORM_strx2: 897 case DW_FORM_strx3: 898 case DW_FORM_strx4: 899 case DW_FORM_line_strp: { 900 if (Error E = AttrValue.Value.getAsCString().takeError()) { 901 ++NumErrors; 902 std::string ErrMsg = toString(std::move(E)); 903 ErrorCategory.Report("Invalid DW_FORM attribute", [&]() { 904 error() << ErrMsg << ":\n"; 905 dump(Die) << '\n'; 906 }); 907 } 908 break; 909 } 910 default: 911 break; 912 } 913 return NumErrors; 914 } 915 916 unsigned DWARFVerifier::verifyDebugInfoReferences( 917 const ReferenceMap &References, 918 llvm::function_ref<DWARFUnit *(uint64_t)> GetUnitForOffset) { 919 auto GetDIEForOffset = [&](uint64_t Offset) { 920 if (DWARFUnit *U = GetUnitForOffset(Offset)) 921 return U->getDIEForOffset(Offset); 922 return DWARFDie(); 923 }; 924 unsigned NumErrors = 0; 925 for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair : 926 References) { 927 if (GetDIEForOffset(Pair.first)) 928 continue; 929 ++NumErrors; 930 ErrorCategory.Report("Invalid DIE reference", [&]() { 931 error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first) 932 << ". Offset is in between DIEs:\n"; 933 for (auto Offset : Pair.second) 934 dump(GetDIEForOffset(Offset)) << '\n'; 935 OS << "\n"; 936 }); 937 } 938 return NumErrors; 939 } 940 941 void DWARFVerifier::verifyDebugLineStmtOffsets() { 942 std::map<uint64_t, DWARFDie> StmtListToDie; 943 for (const auto &CU : DCtx.compile_units()) { 944 auto Die = CU->getUnitDIE(); 945 // Get the attribute value as a section offset. No need to produce an 946 // error here if the encoding isn't correct because we validate this in 947 // the .debug_info verifier. 948 auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list)); 949 if (!StmtSectionOffset) 950 continue; 951 const uint64_t LineTableOffset = *StmtSectionOffset; 952 auto LineTable = DCtx.getLineTableForUnit(CU.get()); 953 if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) { 954 if (!LineTable) { 955 ++NumDebugLineErrors; 956 ErrorCategory.Report("Unparsable .debug_line entry", [&]() { 957 error() << ".debug_line[" << format("0x%08" PRIx64, LineTableOffset) 958 << "] was not able to be parsed for CU:\n"; 959 dump(Die) << '\n'; 960 }); 961 continue; 962 } 963 } else { 964 // Make sure we don't get a valid line table back if the offset is wrong. 965 assert(LineTable == nullptr); 966 // Skip this line table as it isn't valid. No need to create an error 967 // here because we validate this in the .debug_info verifier. 968 continue; 969 } 970 auto Iter = StmtListToDie.find(LineTableOffset); 971 if (Iter != StmtListToDie.end()) { 972 ++NumDebugLineErrors; 973 ErrorCategory.Report("Identical DW_AT_stmt_list section offset", [&]() { 974 error() << "two compile unit DIEs, " 975 << format("0x%08" PRIx64, Iter->second.getOffset()) << " and " 976 << format("0x%08" PRIx64, Die.getOffset()) 977 << ", have the same DW_AT_stmt_list section offset:\n"; 978 dump(Iter->second); 979 dump(Die) << '\n'; 980 }); 981 // Already verified this line table before, no need to do it again. 982 continue; 983 } 984 StmtListToDie[LineTableOffset] = Die; 985 } 986 } 987 988 void DWARFVerifier::verifyDebugLineRows() { 989 for (const auto &CU : DCtx.compile_units()) { 990 auto Die = CU->getUnitDIE(); 991 auto LineTable = DCtx.getLineTableForUnit(CU.get()); 992 // If there is no line table we will have created an error in the 993 // .debug_info verifier or in verifyDebugLineStmtOffsets(). 994 if (!LineTable) 995 continue; 996 997 // Verify prologue. 998 bool isDWARF5 = LineTable->Prologue.getVersion() >= 5; 999 uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size(); 1000 uint32_t MinFileIndex = isDWARF5 ? 0 : 1; 1001 uint32_t FileIndex = MinFileIndex; 1002 StringMap<uint16_t> FullPathMap; 1003 for (const auto &FileName : LineTable->Prologue.FileNames) { 1004 // Verify directory index. 1005 if (FileName.DirIdx > MaxDirIndex) { 1006 ++NumDebugLineErrors; 1007 ErrorCategory.Report( 1008 "Invalid index in .debug_line->prologue.file_names->dir_idx", 1009 [&]() { 1010 error() << ".debug_line[" 1011 << format("0x%08" PRIx64, 1012 *toSectionOffset(Die.find(DW_AT_stmt_list))) 1013 << "].prologue.file_names[" << FileIndex 1014 << "].dir_idx contains an invalid index: " 1015 << FileName.DirIdx << "\n"; 1016 }); 1017 } 1018 1019 // Check file paths for duplicates. 1020 std::string FullPath; 1021 const bool HasFullPath = LineTable->getFileNameByIndex( 1022 FileIndex, CU->getCompilationDir(), 1023 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath); 1024 assert(HasFullPath && "Invalid index?"); 1025 (void)HasFullPath; 1026 auto [It, Inserted] = FullPathMap.try_emplace(FullPath, FileIndex); 1027 if (!Inserted && It->second != FileIndex && DumpOpts.Verbose) { 1028 warn() << ".debug_line[" 1029 << format("0x%08" PRIx64, 1030 *toSectionOffset(Die.find(DW_AT_stmt_list))) 1031 << "].prologue.file_names[" << FileIndex 1032 << "] is a duplicate of file_names[" << It->second << "]\n"; 1033 } 1034 1035 FileIndex++; 1036 } 1037 1038 // Nothing to verify in a line table with a single row containing the end 1039 // sequence. 1040 if (LineTable->Rows.size() == 1 && LineTable->Rows.front().EndSequence) 1041 continue; 1042 1043 // Verify rows. 1044 uint64_t PrevAddress = 0; 1045 uint32_t RowIndex = 0; 1046 for (const auto &Row : LineTable->Rows) { 1047 // Verify row address. 1048 if (Row.Address.Address < PrevAddress) { 1049 ++NumDebugLineErrors; 1050 ErrorCategory.Report( 1051 "decreasing address between debug_line rows", [&]() { 1052 error() << ".debug_line[" 1053 << format("0x%08" PRIx64, 1054 *toSectionOffset(Die.find(DW_AT_stmt_list))) 1055 << "] row[" << RowIndex 1056 << "] decreases in address from previous row:\n"; 1057 1058 DWARFDebugLine::Row::dumpTableHeader(OS, 0); 1059 if (RowIndex > 0) 1060 LineTable->Rows[RowIndex - 1].dump(OS); 1061 Row.dump(OS); 1062 OS << '\n'; 1063 }); 1064 } 1065 1066 if (!LineTable->hasFileAtIndex(Row.File)) { 1067 ++NumDebugLineErrors; 1068 ErrorCategory.Report("Invalid file index in debug_line", [&]() { 1069 error() << ".debug_line[" 1070 << format("0x%08" PRIx64, 1071 *toSectionOffset(Die.find(DW_AT_stmt_list))) 1072 << "][" << RowIndex << "] has invalid file index " << Row.File 1073 << " (valid values are [" << MinFileIndex << ',' 1074 << LineTable->Prologue.FileNames.size() 1075 << (isDWARF5 ? ")" : "]") << "):\n"; 1076 DWARFDebugLine::Row::dumpTableHeader(OS, 0); 1077 Row.dump(OS); 1078 OS << '\n'; 1079 }); 1080 } 1081 if (Row.EndSequence) 1082 PrevAddress = 0; 1083 else 1084 PrevAddress = Row.Address.Address; 1085 ++RowIndex; 1086 } 1087 } 1088 } 1089 1090 DWARFVerifier::DWARFVerifier(raw_ostream &S, DWARFContext &D, 1091 DIDumpOptions DumpOpts) 1092 : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)), IsObjectFile(false), 1093 IsMachOObject(false) { 1094 ErrorCategory.ShowDetail(this->DumpOpts.Verbose || 1095 !this->DumpOpts.ShowAggregateErrors); 1096 if (const auto *F = DCtx.getDWARFObj().getFile()) { 1097 IsObjectFile = F->isRelocatableObject(); 1098 IsMachOObject = F->isMachO(); 1099 } 1100 } 1101 1102 bool DWARFVerifier::handleDebugLine() { 1103 NumDebugLineErrors = 0; 1104 OS << "Verifying .debug_line...\n"; 1105 verifyDebugLineStmtOffsets(); 1106 verifyDebugLineRows(); 1107 return NumDebugLineErrors == 0; 1108 } 1109 1110 unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection, 1111 DataExtractor *StrData, 1112 const char *SectionName) { 1113 unsigned NumErrors = 0; 1114 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection, 1115 DCtx.isLittleEndian(), 0); 1116 AppleAcceleratorTable AccelTable(AccelSectionData, *StrData); 1117 1118 OS << "Verifying " << SectionName << "...\n"; 1119 1120 // Verify that the fixed part of the header is not too short. 1121 if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) { 1122 ErrorCategory.Report("Section is too small to fit a section header", [&]() { 1123 error() << "Section is too small to fit a section header.\n"; 1124 }); 1125 return 1; 1126 } 1127 1128 // Verify that the section is not too short. 1129 if (Error E = AccelTable.extract()) { 1130 std::string Msg = toString(std::move(E)); 1131 ErrorCategory.Report("Section is too small to fit a section header", 1132 [&]() { error() << Msg << '\n'; }); 1133 return 1; 1134 } 1135 1136 // Verify that all buckets have a valid hash index or are empty. 1137 uint32_t NumBuckets = AccelTable.getNumBuckets(); 1138 uint32_t NumHashes = AccelTable.getNumHashes(); 1139 1140 uint64_t BucketsOffset = 1141 AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength(); 1142 uint64_t HashesBase = BucketsOffset + NumBuckets * 4; 1143 uint64_t OffsetsBase = HashesBase + NumHashes * 4; 1144 for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) { 1145 uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset); 1146 if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) { 1147 ErrorCategory.Report("Invalid hash index", [&]() { 1148 error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx, 1149 HashIdx); 1150 }); 1151 ++NumErrors; 1152 } 1153 } 1154 uint32_t NumAtoms = AccelTable.getAtomsDesc().size(); 1155 if (NumAtoms == 0) { 1156 ErrorCategory.Report("No atoms", [&]() { 1157 error() << "No atoms: failed to read HashData.\n"; 1158 }); 1159 return 1; 1160 } 1161 if (!AccelTable.validateForms()) { 1162 ErrorCategory.Report("Unsupported form", [&]() { 1163 error() << "Unsupported form: failed to read HashData.\n"; 1164 }); 1165 return 1; 1166 } 1167 1168 for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) { 1169 uint64_t HashOffset = HashesBase + 4 * HashIdx; 1170 uint64_t DataOffset = OffsetsBase + 4 * HashIdx; 1171 uint32_t Hash = AccelSectionData.getU32(&HashOffset); 1172 uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset); 1173 if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset, 1174 sizeof(uint64_t))) { 1175 ErrorCategory.Report("Invalid HashData offset", [&]() { 1176 error() << format("Hash[%d] has invalid HashData offset: " 1177 "0x%08" PRIx64 ".\n", 1178 HashIdx, HashDataOffset); 1179 }); 1180 ++NumErrors; 1181 } 1182 1183 uint64_t StrpOffset; 1184 uint64_t StringOffset; 1185 uint32_t StringCount = 0; 1186 uint64_t Offset; 1187 unsigned Tag; 1188 while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) { 1189 const uint32_t NumHashDataObjects = 1190 AccelSectionData.getU32(&HashDataOffset); 1191 for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects; 1192 ++HashDataIdx) { 1193 std::tie(Offset, Tag) = AccelTable.readAtoms(&HashDataOffset); 1194 auto Die = DCtx.getDIEForOffset(Offset); 1195 if (!Die) { 1196 const uint32_t BucketIdx = 1197 NumBuckets ? (Hash % NumBuckets) : UINT32_MAX; 1198 StringOffset = StrpOffset; 1199 const char *Name = StrData->getCStr(&StringOffset); 1200 if (!Name) 1201 Name = "<NULL>"; 1202 1203 ErrorCategory.Report("Invalid DIE offset", [&]() { 1204 error() << format( 1205 "%s Bucket[%d] Hash[%d] = 0x%08x " 1206 "Str[%u] = 0x%08" PRIx64 " DIE[%d] = 0x%08" PRIx64 " " 1207 "is not a valid DIE offset for \"%s\".\n", 1208 SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset, 1209 HashDataIdx, Offset, Name); 1210 }); 1211 1212 ++NumErrors; 1213 continue; 1214 } 1215 if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) { 1216 ErrorCategory.Report("Mismatched Tag in accellerator table", [&]() { 1217 error() << "Tag " << dwarf::TagString(Tag) 1218 << " in accelerator table does not match Tag " 1219 << dwarf::TagString(Die.getTag()) << " of DIE[" 1220 << HashDataIdx << "].\n"; 1221 }); 1222 ++NumErrors; 1223 } 1224 } 1225 ++StringCount; 1226 } 1227 } 1228 return NumErrors; 1229 } 1230 1231 unsigned 1232 DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) { 1233 // A map from CU offset to the (first) Name Index offset which claims to index 1234 // this CU. 1235 DenseMap<uint64_t, uint64_t> CUMap; 1236 const uint64_t NotIndexed = std::numeric_limits<uint64_t>::max(); 1237 1238 CUMap.reserve(DCtx.getNumCompileUnits()); 1239 for (const auto &CU : DCtx.compile_units()) 1240 CUMap[CU->getOffset()] = NotIndexed; 1241 1242 unsigned NumErrors = 0; 1243 for (const DWARFDebugNames::NameIndex &NI : AccelTable) { 1244 if (NI.getCUCount() == 0) { 1245 ErrorCategory.Report("Name Index doesn't index any CU", [&]() { 1246 error() << formatv("Name Index @ {0:x} does not index any CU\n", 1247 NI.getUnitOffset()); 1248 }); 1249 ++NumErrors; 1250 continue; 1251 } 1252 for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) { 1253 uint64_t Offset = NI.getCUOffset(CU); 1254 auto Iter = CUMap.find(Offset); 1255 1256 if (Iter == CUMap.end()) { 1257 ErrorCategory.Report("Name Index references non-existing CU", [&]() { 1258 error() << formatv( 1259 "Name Index @ {0:x} references a non-existing CU @ {1:x}\n", 1260 NI.getUnitOffset(), Offset); 1261 }); 1262 ++NumErrors; 1263 continue; 1264 } 1265 1266 if (Iter->second != NotIndexed) { 1267 ErrorCategory.Report("Duplicate Name Index", [&]() { 1268 error() << formatv( 1269 "Name Index @ {0:x} references a CU @ {1:x}, but " 1270 "this CU is already indexed by Name Index @ {2:x}\n", 1271 NI.getUnitOffset(), Offset, Iter->second); 1272 }); 1273 continue; 1274 } 1275 Iter->second = NI.getUnitOffset(); 1276 } 1277 } 1278 1279 for (const auto &KV : CUMap) { 1280 if (KV.second == NotIndexed) 1281 warn() << formatv("CU @ {0:x} not covered by any Name Index\n", KV.first); 1282 } 1283 1284 return NumErrors; 1285 } 1286 1287 unsigned 1288 DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI, 1289 const DataExtractor &StrData) { 1290 struct BucketInfo { 1291 uint32_t Bucket; 1292 uint32_t Index; 1293 1294 constexpr BucketInfo(uint32_t Bucket, uint32_t Index) 1295 : Bucket(Bucket), Index(Index) {} 1296 bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; } 1297 }; 1298 1299 uint32_t NumErrors = 0; 1300 if (NI.getBucketCount() == 0) { 1301 warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n", 1302 NI.getUnitOffset()); 1303 return NumErrors; 1304 } 1305 1306 // Build up a list of (Bucket, Index) pairs. We use this later to verify that 1307 // each Name is reachable from the appropriate bucket. 1308 std::vector<BucketInfo> BucketStarts; 1309 BucketStarts.reserve(NI.getBucketCount() + 1); 1310 for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) { 1311 uint32_t Index = NI.getBucketArrayEntry(Bucket); 1312 if (Index > NI.getNameCount()) { 1313 ErrorCategory.Report("Name Index Bucket contains invalid value", [&]() { 1314 error() << formatv("Bucket {0} of Name Index @ {1:x} contains invalid " 1315 "value {2}. Valid range is [0, {3}].\n", 1316 Bucket, NI.getUnitOffset(), Index, 1317 NI.getNameCount()); 1318 }); 1319 ++NumErrors; 1320 continue; 1321 } 1322 if (Index > 0) 1323 BucketStarts.emplace_back(Bucket, Index); 1324 } 1325 1326 // If there were any buckets with invalid values, skip further checks as they 1327 // will likely produce many errors which will only confuse the actual root 1328 // problem. 1329 if (NumErrors > 0) 1330 return NumErrors; 1331 1332 // Sort the list in the order of increasing "Index" entries. 1333 array_pod_sort(BucketStarts.begin(), BucketStarts.end()); 1334 1335 // Insert a sentinel entry at the end, so we can check that the end of the 1336 // table is covered in the loop below. 1337 BucketStarts.emplace_back(NI.getBucketCount(), NI.getNameCount() + 1); 1338 1339 // Loop invariant: NextUncovered is the (1-based) index of the first Name 1340 // which is not reachable by any of the buckets we processed so far (and 1341 // hasn't been reported as uncovered). 1342 uint32_t NextUncovered = 1; 1343 for (const BucketInfo &B : BucketStarts) { 1344 // Under normal circumstances B.Index be equal to NextUncovered, but it can 1345 // be less if a bucket points to names which are already known to be in some 1346 // bucket we processed earlier. In that case, we won't trigger this error, 1347 // but report the mismatched hash value error instead. (We know the hash 1348 // will not match because we have already verified that the name's hash 1349 // puts it into the previous bucket.) 1350 if (B.Index > NextUncovered) { 1351 ErrorCategory.Report("Name table entries uncovered by hash table", [&]() { 1352 error() << formatv("Name Index @ {0:x}: Name table entries [{1}, {2}] " 1353 "are not covered by the hash table.\n", 1354 NI.getUnitOffset(), NextUncovered, B.Index - 1); 1355 }); 1356 ++NumErrors; 1357 } 1358 uint32_t Idx = B.Index; 1359 1360 // The rest of the checks apply only to non-sentinel entries. 1361 if (B.Bucket == NI.getBucketCount()) 1362 break; 1363 1364 // This triggers if a non-empty bucket points to a name with a mismatched 1365 // hash. Clients are likely to interpret this as an empty bucket, because a 1366 // mismatched hash signals the end of a bucket, but if this is indeed an 1367 // empty bucket, the producer should have signalled this by marking the 1368 // bucket as empty. 1369 uint32_t FirstHash = NI.getHashArrayEntry(Idx); 1370 if (FirstHash % NI.getBucketCount() != B.Bucket) { 1371 ErrorCategory.Report("Name Index point to mismatched hash value", [&]() { 1372 error() << formatv( 1373 "Name Index @ {0:x}: Bucket {1} is not empty but points to a " 1374 "mismatched hash value {2:x} (belonging to bucket {3}).\n", 1375 NI.getUnitOffset(), B.Bucket, FirstHash, 1376 FirstHash % NI.getBucketCount()); 1377 }); 1378 ++NumErrors; 1379 } 1380 1381 // This find the end of this bucket and also verifies that all the hashes in 1382 // this bucket are correct by comparing the stored hashes to the ones we 1383 // compute ourselves. 1384 while (Idx <= NI.getNameCount()) { 1385 uint32_t Hash = NI.getHashArrayEntry(Idx); 1386 if (Hash % NI.getBucketCount() != B.Bucket) 1387 break; 1388 1389 const char *Str = NI.getNameTableEntry(Idx).getString(); 1390 if (caseFoldingDjbHash(Str) != Hash) { 1391 ErrorCategory.Report( 1392 "String hash doesn't match Name Index hash", [&]() { 1393 error() << formatv( 1394 "Name Index @ {0:x}: String ({1}) at index {2} " 1395 "hashes to {3:x}, but " 1396 "the Name Index hash is {4:x}\n", 1397 NI.getUnitOffset(), Str, Idx, caseFoldingDjbHash(Str), Hash); 1398 }); 1399 ++NumErrors; 1400 } 1401 1402 ++Idx; 1403 } 1404 NextUncovered = std::max(NextUncovered, Idx); 1405 } 1406 return NumErrors; 1407 } 1408 1409 unsigned DWARFVerifier::verifyNameIndexAttribute( 1410 const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr, 1411 DWARFDebugNames::AttributeEncoding AttrEnc) { 1412 StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form); 1413 if (FormName.empty()) { 1414 ErrorCategory.Report("Unknown NameIndex Abbreviation", [&]() { 1415 error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " 1416 "unknown form: {3}.\n", 1417 NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, 1418 AttrEnc.Form); 1419 }); 1420 return 1; 1421 } 1422 1423 if (AttrEnc.Index == DW_IDX_type_hash) { 1424 if (AttrEnc.Form != dwarf::DW_FORM_data8) { 1425 ErrorCategory.Report("Unexpected NameIndex Abbreviation", [&]() { 1426 error() << formatv( 1427 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash " 1428 "uses an unexpected form {2} (should be {3}).\n", 1429 NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8); 1430 }); 1431 return 1; 1432 } 1433 return 0; 1434 } 1435 1436 if (AttrEnc.Index == dwarf::DW_IDX_parent) { 1437 constexpr static auto AllowedForms = {dwarf::Form::DW_FORM_flag_present, 1438 dwarf::Form::DW_FORM_ref4}; 1439 if (!is_contained(AllowedForms, AttrEnc.Form)) { 1440 ErrorCategory.Report("Unexpected NameIndex Abbreviation", [&]() { 1441 error() << formatv( 1442 "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_parent " 1443 "uses an unexpected form {2} (should be " 1444 "DW_FORM_ref4 or DW_FORM_flag_present).\n", 1445 NI.getUnitOffset(), Abbr.Code, AttrEnc.Form); 1446 }); 1447 return 1; 1448 } 1449 return 0; 1450 } 1451 1452 // A list of known index attributes and their expected form classes. 1453 // DW_IDX_type_hash is handled specially in the check above, as it has a 1454 // specific form (not just a form class) we should expect. 1455 struct FormClassTable { 1456 dwarf::Index Index; 1457 DWARFFormValue::FormClass Class; 1458 StringLiteral ClassName; 1459 }; 1460 static constexpr FormClassTable Table[] = { 1461 {dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}}, 1462 {dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}}, 1463 {dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}}, 1464 }; 1465 1466 ArrayRef<FormClassTable> TableRef(Table); 1467 auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) { 1468 return T.Index == AttrEnc.Index; 1469 }); 1470 if (Iter == TableRef.end()) { 1471 warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an " 1472 "unknown index attribute: {2}.\n", 1473 NI.getUnitOffset(), Abbr.Code, AttrEnc.Index); 1474 return 0; 1475 } 1476 1477 if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) { 1478 ErrorCategory.Report("Unexpected NameIndex Abbreviation", [&]() { 1479 error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " 1480 "unexpected form {3} (expected form class {4}).\n", 1481 NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, 1482 AttrEnc.Form, Iter->ClassName); 1483 }); 1484 return 1; 1485 } 1486 return 0; 1487 } 1488 1489 unsigned 1490 DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) { 1491 unsigned NumErrors = 0; 1492 for (const auto &Abbrev : NI.getAbbrevs()) { 1493 StringRef TagName = dwarf::TagString(Abbrev.Tag); 1494 if (TagName.empty()) { 1495 warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an " 1496 "unknown tag: {2}.\n", 1497 NI.getUnitOffset(), Abbrev.Code, Abbrev.Tag); 1498 } 1499 SmallSet<unsigned, 5> Attributes; 1500 for (const auto &AttrEnc : Abbrev.Attributes) { 1501 if (!Attributes.insert(AttrEnc.Index).second) { 1502 ErrorCategory.Report( 1503 "NameIndex Abbreviateion contains multiple attributes", [&]() { 1504 error() << formatv( 1505 "NameIndex @ {0:x}: Abbreviation {1:x} contains " 1506 "multiple {2} attributes.\n", 1507 NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index); 1508 }); 1509 ++NumErrors; 1510 continue; 1511 } 1512 NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc); 1513 } 1514 1515 if (NI.getCUCount() > 1 && !Attributes.count(dwarf::DW_IDX_compile_unit) && 1516 !Attributes.count(dwarf::DW_IDX_type_unit)) { 1517 ErrorCategory.Report("Abbreviation contains no attribute", [&]() { 1518 error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units " 1519 "and abbreviation {1:x} has no DW_IDX_compile_unit " 1520 "or DW_IDX_type_unit attribute.\n", 1521 NI.getUnitOffset(), Abbrev.Code); 1522 }); 1523 ++NumErrors; 1524 } 1525 if (!Attributes.count(dwarf::DW_IDX_die_offset)) { 1526 ErrorCategory.Report("Abbreviate in NameIndex missing attribute", [&]() { 1527 error() << formatv( 1528 "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n", 1529 NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset); 1530 }); 1531 ++NumErrors; 1532 } 1533 } 1534 return NumErrors; 1535 } 1536 1537 static SmallVector<std::string, 3> getNames(const DWARFDie &DIE, 1538 bool IncludeStrippedTemplateNames, 1539 bool IncludeObjCNames = true, 1540 bool IncludeLinkageName = true) { 1541 SmallVector<std::string, 3> Result; 1542 if (const char *Str = DIE.getShortName()) { 1543 StringRef Name(Str); 1544 Result.emplace_back(Name); 1545 if (IncludeStrippedTemplateNames) { 1546 if (std::optional<StringRef> StrippedName = 1547 StripTemplateParameters(Result.back())) 1548 // Convert to std::string and push; emplacing the StringRef may trigger 1549 // a vector resize which may destroy the StringRef memory. 1550 Result.push_back(StrippedName->str()); 1551 } 1552 1553 if (IncludeObjCNames) { 1554 if (std::optional<ObjCSelectorNames> ObjCNames = 1555 getObjCNamesIfSelector(Name)) { 1556 Result.emplace_back(ObjCNames->ClassName); 1557 Result.emplace_back(ObjCNames->Selector); 1558 if (ObjCNames->ClassNameNoCategory) 1559 Result.emplace_back(*ObjCNames->ClassNameNoCategory); 1560 if (ObjCNames->MethodNameNoCategory) 1561 Result.push_back(std::move(*ObjCNames->MethodNameNoCategory)); 1562 } 1563 } 1564 } else if (DIE.getTag() == dwarf::DW_TAG_namespace) 1565 Result.emplace_back("(anonymous namespace)"); 1566 1567 if (IncludeLinkageName) { 1568 if (const char *Str = DIE.getLinkageName()) 1569 Result.emplace_back(Str); 1570 } 1571 1572 return Result; 1573 } 1574 1575 unsigned DWARFVerifier::verifyNameIndexEntries( 1576 const DWARFDebugNames::NameIndex &NI, 1577 const DWARFDebugNames::NameTableEntry &NTE) { 1578 const char *CStr = NTE.getString(); 1579 if (!CStr) { 1580 ErrorCategory.Report("Unable to get string associated with name", [&]() { 1581 error() << formatv("Name Index @ {0:x}: Unable to get string associated " 1582 "with name {1}.\n", 1583 NI.getUnitOffset(), NTE.getIndex()); 1584 }); 1585 return 1; 1586 } 1587 StringRef Str(CStr); 1588 1589 unsigned NumErrors = 0; 1590 unsigned NumEntries = 0; 1591 uint64_t EntryID = NTE.getEntryOffset(); 1592 uint64_t NextEntryID = EntryID; 1593 Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&NextEntryID); 1594 for (; EntryOr; ++NumEntries, EntryID = NextEntryID, 1595 EntryOr = NI.getEntry(&NextEntryID)) { 1596 1597 std::optional<uint64_t> CUIndex = EntryOr->getRelatedCUIndex(); 1598 std::optional<uint64_t> TUIndex = EntryOr->getTUIndex(); 1599 if (CUIndex && *CUIndex >= NI.getCUCount()) { 1600 ErrorCategory.Report("Name Index entry contains invalid CU index", [&]() { 1601 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an " 1602 "invalid CU index ({2}).\n", 1603 NI.getUnitOffset(), EntryID, *CUIndex); 1604 }); 1605 ++NumErrors; 1606 continue; 1607 } 1608 const uint32_t NumLocalTUs = NI.getLocalTUCount(); 1609 const uint32_t NumForeignTUs = NI.getForeignTUCount(); 1610 if (TUIndex && *TUIndex >= (NumLocalTUs + NumForeignTUs)) { 1611 ErrorCategory.Report("Name Index entry contains invalid TU index", [&]() { 1612 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an " 1613 "invalid TU index ({2}).\n", 1614 NI.getUnitOffset(), EntryID, *TUIndex); 1615 }); 1616 ++NumErrors; 1617 continue; 1618 } 1619 std::optional<uint64_t> UnitOffset; 1620 if (TUIndex) { 1621 // We have a local or foreign type unit. 1622 if (*TUIndex >= NumLocalTUs) { 1623 // This is a foreign type unit, we will find the right type unit by 1624 // type unit signature later in this function. 1625 1626 // Foreign type units must have a valid CU index, either from a 1627 // DW_IDX_comp_unit attribute value or from the .debug_names table only 1628 // having a single compile unit. We need the originating compile unit 1629 // because foreign type units can come from any .dwo file, yet only one 1630 // copy of the type unit will end up in the .dwp file. 1631 if (CUIndex) { 1632 // We need the local skeleton unit offset for the code below. 1633 UnitOffset = NI.getCUOffset(*CUIndex); 1634 } else { 1635 ErrorCategory.Report( 1636 "Name Index entry contains foreign TU index with invalid CU " 1637 "index", 1638 [&]() { 1639 error() << formatv( 1640 "Name Index @ {0:x}: Entry @ {1:x} contains an " 1641 "foreign TU index ({2}) with no CU index.\n", 1642 NI.getUnitOffset(), EntryID, *TUIndex); 1643 }); 1644 ++NumErrors; 1645 continue; 1646 } 1647 } else { 1648 // Local type unit, get the DWARF unit offset for the type unit. 1649 UnitOffset = NI.getLocalTUOffset(*TUIndex); 1650 } 1651 } else if (CUIndex) { 1652 // Local CU entry, get the DWARF unit offset for the CU. 1653 UnitOffset = NI.getCUOffset(*CUIndex); 1654 } 1655 1656 // Watch for tombstoned type unit entries. 1657 if (!UnitOffset || UnitOffset == UINT32_MAX) 1658 continue; 1659 // For split DWARF entries we need to make sure we find the non skeleton 1660 // DWARF unit that is needed and use that's DWARF unit offset as the 1661 // DIE offset to add the DW_IDX_die_offset to. 1662 DWARFUnit *DU = DCtx.getUnitForOffset(*UnitOffset); 1663 if (DU == nullptr || DU->getOffset() != *UnitOffset) { 1664 // If we didn't find a DWARF Unit from the UnitOffset, or if the offset 1665 // of the unit doesn't match exactly, report an error. 1666 ErrorCategory.Report( 1667 "Name Index entry contains invalid CU or TU offset", [&]() { 1668 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an " 1669 "invalid CU or TU offset {2:x}.\n", 1670 NI.getUnitOffset(), EntryID, *UnitOffset); 1671 }); 1672 ++NumErrors; 1673 continue; 1674 } 1675 // This function will try to get the non skeleton unit DIE, but if it is 1676 // unable to load the .dwo file from the .dwo or .dwp, it will return the 1677 // unit DIE of the DWARFUnit in "DU". So we need to check if the DWARFUnit 1678 // has a .dwo file, but we couldn't load it. 1679 1680 // FIXME: Need a follow up patch to fix usage of 1681 // DWARFUnit::getNonSkeletonUnitDIE() so that it returns an empty DWARFDie 1682 // if the .dwo file isn't available and clean up other uses of this function 1683 // call to properly deal with it. It isn't clear that getNonSkeletonUnitDIE 1684 // will return the unit DIE of DU if we aren't able to get the .dwo file, 1685 // but that is what the function currently does. 1686 DWARFDie UnitDie = DU->getUnitDIE(); 1687 DWARFDie NonSkeletonUnitDie = DU->getNonSkeletonUnitDIE(); 1688 if (DU->getDWOId() && UnitDie == NonSkeletonUnitDie) { 1689 ErrorCategory.Report("Unable to get load .dwo file", [&]() { 1690 error() << formatv( 1691 "Name Index @ {0:x}: Entry @ {1:x} unable to load " 1692 ".dwo file \"{2}\" for DWARF unit @ {3:x}.\n", 1693 NI.getUnitOffset(), EntryID, 1694 dwarf::toString(UnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name})), 1695 *UnitOffset); 1696 }); 1697 ++NumErrors; 1698 continue; 1699 } 1700 DWARFUnit *NonSkeletonUnit = nullptr; 1701 if (TUIndex && *TUIndex >= NumLocalTUs) { 1702 // We have a foreign TU index, which either means we have a .dwo file 1703 // that has one or more type units, or we have a .dwp file with one or 1704 // more type units. We need to get the type unit from the DWARFContext 1705 // of the .dwo. We got the NonSkeletonUnitDie above that has the .dwo 1706 // or .dwp DWARF context, so we have to get the type unit from that file. 1707 // We have also verified that NonSkeletonUnitDie points to a DWO file 1708 // above, so we know we have the right file. 1709 const uint32_t ForeignTUIdx = *TUIndex - NumLocalTUs; 1710 const uint64_t TypeSig = NI.getForeignTUSignature(ForeignTUIdx); 1711 llvm::DWARFContext &SkeletonDCtx = 1712 NonSkeletonUnitDie.getDwarfUnit()->getContext(); 1713 // Now find the type unit from the type signature and then update the 1714 // NonSkeletonUnitDie to point to the actual type unit in the .dwo/.dwp. 1715 NonSkeletonUnit = 1716 SkeletonDCtx.getTypeUnitForHash(TypeSig, /*IsDWO=*/true); 1717 NonSkeletonUnitDie = NonSkeletonUnit->getUnitDIE(true); 1718 // If we have foreign type unit in a DWP file, then we need to ignore 1719 // any entries from type units that don't match the one that made it into 1720 // the .dwp file. 1721 if (SkeletonDCtx.isDWP()) { 1722 StringRef DUDwoName = dwarf::toStringRef( 1723 UnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name})); 1724 StringRef TUDwoName = dwarf::toStringRef( 1725 NonSkeletonUnitDie.find({DW_AT_dwo_name, DW_AT_GNU_dwo_name})); 1726 if (DUDwoName != TUDwoName) 1727 continue; // Skip this TU, it isn't the one in the .dwp file. 1728 } 1729 } else { 1730 NonSkeletonUnit = NonSkeletonUnitDie.getDwarfUnit(); 1731 } 1732 uint64_t DIEOffset = 1733 NonSkeletonUnit->getOffset() + *EntryOr->getDIEUnitOffset(); 1734 const uint64_t NextUnitOffset = NonSkeletonUnit->getNextUnitOffset(); 1735 // DIE offsets are relative to the specified CU or TU. Make sure the DIE 1736 // offsets is a valid relative offset. 1737 if (DIEOffset >= NextUnitOffset) { 1738 ErrorCategory.Report("NameIndex relative DIE offset too large", [&]() { 1739 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a " 1740 "DIE @ {2:x} when CU or TU ends at {3:x}.\n", 1741 NI.getUnitOffset(), EntryID, DIEOffset, 1742 NextUnitOffset); 1743 }); 1744 continue; 1745 } 1746 DWARFDie DIE = NonSkeletonUnit->getDIEForOffset(DIEOffset); 1747 1748 if (!DIE) { 1749 ErrorCategory.Report("NameIndex references nonexistent DIE", [&]() { 1750 error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a " 1751 "non-existing DIE @ {2:x}.\n", 1752 NI.getUnitOffset(), EntryID, DIEOffset); 1753 }); 1754 ++NumErrors; 1755 continue; 1756 } 1757 // Only compare the DIE we found's DWARFUnit offset if the DIE lives in 1758 // the DWARFUnit from the DW_IDX_comp_unit or DW_IDX_type_unit. If we are 1759 // using split DWARF, then the DIE's DWARFUnit doesn't need to match the 1760 // skeleton unit. 1761 if (DIE.getDwarfUnit() == DU && 1762 DIE.getDwarfUnit()->getOffset() != *UnitOffset) { 1763 ErrorCategory.Report("Name index contains mismatched CU of DIE", [&]() { 1764 error() << formatv( 1765 "Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of " 1766 "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n", 1767 NI.getUnitOffset(), EntryID, DIEOffset, *UnitOffset, 1768 DIE.getDwarfUnit()->getOffset()); 1769 }); 1770 ++NumErrors; 1771 } 1772 if (DIE.getTag() != EntryOr->tag()) { 1773 ErrorCategory.Report("Name Index contains mismatched Tag of DIE", [&]() { 1774 error() << formatv( 1775 "Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of " 1776 "DIE @ {2:x}: index - {3}; debug_info - {4}.\n", 1777 NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(), 1778 DIE.getTag()); 1779 }); 1780 ++NumErrors; 1781 } 1782 1783 // We allow an extra name for functions: their name without any template 1784 // parameters. 1785 auto IncludeStrippedTemplateNames = 1786 DIE.getTag() == DW_TAG_subprogram || 1787 DIE.getTag() == DW_TAG_inlined_subroutine; 1788 auto EntryNames = getNames(DIE, IncludeStrippedTemplateNames); 1789 if (!is_contained(EntryNames, Str)) { 1790 ErrorCategory.Report("Name Index contains mismatched name of DIE", [&]() { 1791 error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name " 1792 "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n", 1793 NI.getUnitOffset(), EntryID, DIEOffset, Str, 1794 make_range(EntryNames.begin(), EntryNames.end())); 1795 }); 1796 ++NumErrors; 1797 } 1798 } 1799 handleAllErrors( 1800 EntryOr.takeError(), 1801 [&](const DWARFDebugNames::SentinelError &) { 1802 if (NumEntries > 0) 1803 return; 1804 ErrorCategory.Report( 1805 "NameIndex Name is not associated with any entries", [&]() { 1806 error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is " 1807 "not associated with any entries.\n", 1808 NI.getUnitOffset(), NTE.getIndex(), Str); 1809 }); 1810 ++NumErrors; 1811 }, 1812 [&](const ErrorInfoBase &Info) { 1813 ErrorCategory.Report("Uncategorized NameIndex error", [&]() { 1814 error() << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n", 1815 NI.getUnitOffset(), NTE.getIndex(), Str, 1816 Info.message()); 1817 }); 1818 ++NumErrors; 1819 }); 1820 return NumErrors; 1821 } 1822 1823 static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) { 1824 Expected<std::vector<DWARFLocationExpression>> Loc = 1825 Die.getLocations(DW_AT_location); 1826 if (!Loc) { 1827 consumeError(Loc.takeError()); 1828 return false; 1829 } 1830 DWARFUnit *U = Die.getDwarfUnit(); 1831 for (const auto &Entry : *Loc) { 1832 DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 1833 U->getAddressByteSize()); 1834 DWARFExpression Expression(Data, U->getAddressByteSize(), 1835 U->getFormParams().Format); 1836 bool IsInteresting = 1837 any_of(Expression, [](const DWARFExpression::Operation &Op) { 1838 return !Op.isError() && (Op.getCode() == DW_OP_addr || 1839 Op.getCode() == DW_OP_form_tls_address || 1840 Op.getCode() == DW_OP_GNU_push_tls_address); 1841 }); 1842 if (IsInteresting) 1843 return true; 1844 } 1845 return false; 1846 } 1847 1848 unsigned DWARFVerifier::verifyNameIndexCompleteness( 1849 const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) { 1850 1851 // First check, if the Die should be indexed. The code follows the DWARF v5 1852 // wording as closely as possible. 1853 1854 // "All non-defining declarations (that is, debugging information entries 1855 // with a DW_AT_declaration attribute) are excluded." 1856 if (Die.find(DW_AT_declaration)) 1857 return 0; 1858 1859 // "DW_TAG_namespace debugging information entries without a DW_AT_name 1860 // attribute are included with the name “(anonymous namespace)”. 1861 // All other debugging information entries without a DW_AT_name attribute 1862 // are excluded." 1863 // "If a subprogram or inlined subroutine is included, and has a 1864 // DW_AT_linkage_name attribute, there will be an additional index entry for 1865 // the linkage name." 1866 auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram || 1867 Die.getTag() == DW_TAG_inlined_subroutine; 1868 // We *allow* stripped template names / ObjectiveC names as extra entries into 1869 // the table, but we don't *require* them to pass the completeness test. 1870 auto IncludeStrippedTemplateNames = false; 1871 auto IncludeObjCNames = false; 1872 auto EntryNames = getNames(Die, IncludeStrippedTemplateNames, 1873 IncludeObjCNames, IncludeLinkageName); 1874 if (EntryNames.empty()) 1875 return 0; 1876 1877 // We deviate from the specification here, which says: 1878 // "The name index must contain an entry for each debugging information entry 1879 // that defines a named subprogram, label, variable, type, or namespace, 1880 // subject to ..." 1881 // Explicitly exclude all TAGs that we know shouldn't be indexed. 1882 switch (Die.getTag()) { 1883 // Compile units and modules have names but shouldn't be indexed. 1884 case DW_TAG_compile_unit: 1885 case DW_TAG_module: 1886 return 0; 1887 1888 // Function and template parameters are not globally visible, so we shouldn't 1889 // index them. 1890 case DW_TAG_formal_parameter: 1891 case DW_TAG_template_value_parameter: 1892 case DW_TAG_template_type_parameter: 1893 case DW_TAG_GNU_template_parameter_pack: 1894 case DW_TAG_GNU_template_template_param: 1895 return 0; 1896 1897 // Object members aren't globally visible. 1898 case DW_TAG_member: 1899 return 0; 1900 1901 // According to a strict reading of the specification, enumerators should not 1902 // be indexed (and LLVM currently does not do that). However, this causes 1903 // problems for the debuggers, so we may need to reconsider this. 1904 case DW_TAG_enumerator: 1905 return 0; 1906 1907 // Imported declarations should not be indexed according to the specification 1908 // and LLVM currently does not do that. 1909 case DW_TAG_imported_declaration: 1910 return 0; 1911 1912 // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging 1913 // information entries without an address attribute (DW_AT_low_pc, 1914 // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded." 1915 case DW_TAG_subprogram: 1916 case DW_TAG_inlined_subroutine: 1917 case DW_TAG_label: 1918 if (Die.findRecursively( 1919 {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc})) 1920 break; 1921 return 0; 1922 1923 // "DW_TAG_variable debugging information entries with a DW_AT_location 1924 // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are 1925 // included; otherwise, they are excluded." 1926 // 1927 // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list. 1928 case DW_TAG_variable: 1929 if (isVariableIndexable(Die, DCtx)) 1930 break; 1931 return 0; 1932 1933 default: 1934 break; 1935 } 1936 1937 // Now we know that our Die should be present in the Index. Let's check if 1938 // that's the case. 1939 unsigned NumErrors = 0; 1940 uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset(); 1941 for (StringRef Name : EntryNames) { 1942 if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) { 1943 return E.getDIEUnitOffset() == DieUnitOffset; 1944 })) { 1945 ErrorCategory.Report("Name Index DIE entry missing name", [&]() { 1946 error() << formatv( 1947 "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with " 1948 "name {3} missing.\n", 1949 NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name); 1950 }); 1951 ++NumErrors; 1952 } 1953 } 1954 return NumErrors; 1955 } 1956 1957 unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection, 1958 const DataExtractor &StrData) { 1959 unsigned NumErrors = 0; 1960 DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection, 1961 DCtx.isLittleEndian(), 0); 1962 DWARFDebugNames AccelTable(AccelSectionData, StrData); 1963 1964 OS << "Verifying .debug_names...\n"; 1965 1966 // This verifies that we can read individual name indices and their 1967 // abbreviation tables. 1968 if (Error E = AccelTable.extract()) { 1969 std::string Msg = toString(std::move(E)); 1970 ErrorCategory.Report("Accelerator Table Error", 1971 [&]() { error() << Msg << '\n'; }); 1972 return 1; 1973 } 1974 1975 NumErrors += verifyDebugNamesCULists(AccelTable); 1976 for (const auto &NI : AccelTable) 1977 NumErrors += verifyNameIndexBuckets(NI, StrData); 1978 for (const auto &NI : AccelTable) 1979 NumErrors += verifyNameIndexAbbrevs(NI); 1980 1981 // Don't attempt Entry validation if any of the previous checks found errors 1982 if (NumErrors > 0) 1983 return NumErrors; 1984 for (const auto &NI : AccelTable) 1985 for (const DWARFDebugNames::NameTableEntry &NTE : NI) 1986 NumErrors += verifyNameIndexEntries(NI, NTE); 1987 1988 for (const std::unique_ptr<DWARFUnit> &U : DCtx.info_section_units()) { 1989 if (const DWARFDebugNames::NameIndex *NI = 1990 AccelTable.getCUOrTUNameIndex(U->getOffset())) { 1991 DWARFCompileUnit *CU = dyn_cast<DWARFCompileUnit>(U.get()); 1992 if (CU) { 1993 if (CU->getDWOId()) { 1994 DWARFDie CUDie = CU->getUnitDIE(true); 1995 DWARFDie NonSkeletonUnitDie = 1996 CUDie.getDwarfUnit()->getNonSkeletonUnitDIE(false); 1997 if (CUDie != NonSkeletonUnitDie) { 1998 for (const DWARFDebugInfoEntry &Die : 1999 NonSkeletonUnitDie.getDwarfUnit()->dies()) 2000 NumErrors += verifyNameIndexCompleteness( 2001 DWARFDie(NonSkeletonUnitDie.getDwarfUnit(), &Die), *NI); 2002 } 2003 } else { 2004 for (const DWARFDebugInfoEntry &Die : CU->dies()) 2005 NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI); 2006 } 2007 } 2008 } 2009 } 2010 return NumErrors; 2011 } 2012 2013 bool DWARFVerifier::handleAccelTables() { 2014 const DWARFObject &D = DCtx.getDWARFObj(); 2015 DataExtractor StrData(D.getStrSection(), DCtx.isLittleEndian(), 0); 2016 unsigned NumErrors = 0; 2017 if (!D.getAppleNamesSection().Data.empty()) 2018 NumErrors += verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData, 2019 ".apple_names"); 2020 if (!D.getAppleTypesSection().Data.empty()) 2021 NumErrors += verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData, 2022 ".apple_types"); 2023 if (!D.getAppleNamespacesSection().Data.empty()) 2024 NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData, 2025 ".apple_namespaces"); 2026 if (!D.getAppleObjCSection().Data.empty()) 2027 NumErrors += verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData, 2028 ".apple_objc"); 2029 2030 if (!D.getNamesSection().Data.empty()) 2031 NumErrors += verifyDebugNames(D.getNamesSection(), StrData); 2032 return NumErrors == 0; 2033 } 2034 2035 bool DWARFVerifier::handleDebugStrOffsets() { 2036 OS << "Verifying .debug_str_offsets...\n"; 2037 const DWARFObject &DObj = DCtx.getDWARFObj(); 2038 bool Success = true; 2039 2040 // dwo sections may contain the legacy debug_str_offsets format (and they 2041 // can't be mixed with dwarf 5's format). This section format contains no 2042 // header. 2043 // As such, check the version from debug_info and, if we are in the legacy 2044 // mode (Dwarf <= 4), extract Dwarf32/Dwarf64. 2045 std::optional<DwarfFormat> DwoLegacyDwarf4Format; 2046 DObj.forEachInfoDWOSections([&](const DWARFSection &S) { 2047 if (DwoLegacyDwarf4Format) 2048 return; 2049 DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0); 2050 uint64_t Offset = 0; 2051 DwarfFormat InfoFormat = DebugInfoData.getInitialLength(&Offset).second; 2052 if (uint16_t InfoVersion = DebugInfoData.getU16(&Offset); InfoVersion <= 4) 2053 DwoLegacyDwarf4Format = InfoFormat; 2054 }); 2055 2056 Success &= verifyDebugStrOffsets( 2057 DwoLegacyDwarf4Format, ".debug_str_offsets.dwo", 2058 DObj.getStrOffsetsDWOSection(), DObj.getStrDWOSection()); 2059 Success &= verifyDebugStrOffsets( 2060 /*LegacyFormat=*/std::nullopt, ".debug_str_offsets", 2061 DObj.getStrOffsetsSection(), DObj.getStrSection()); 2062 return Success; 2063 } 2064 2065 bool DWARFVerifier::verifyDebugStrOffsets( 2066 std::optional<DwarfFormat> LegacyFormat, StringRef SectionName, 2067 const DWARFSection &Section, StringRef StrData) { 2068 const DWARFObject &DObj = DCtx.getDWARFObj(); 2069 2070 DWARFDataExtractor DA(DObj, Section, DCtx.isLittleEndian(), 0); 2071 DataExtractor::Cursor C(0); 2072 uint64_t NextUnit = 0; 2073 bool Success = true; 2074 while (C.seek(NextUnit), C.tell() < DA.getData().size()) { 2075 DwarfFormat Format; 2076 uint64_t Length; 2077 uint64_t StartOffset = C.tell(); 2078 if (LegacyFormat) { 2079 Format = *LegacyFormat; 2080 Length = DA.getData().size(); 2081 NextUnit = C.tell() + Length; 2082 } else { 2083 std::tie(Length, Format) = DA.getInitialLength(C); 2084 if (!C) 2085 break; 2086 if (C.tell() + Length > DA.getData().size()) { 2087 ErrorCategory.Report( 2088 "Section contribution length exceeds available space", [&]() { 2089 error() << formatv( 2090 "{0}: contribution {1:X}: length exceeds available space " 2091 "(contribution " 2092 "offset ({1:X}) + length field space ({2:X}) + length " 2093 "({3:X}) == " 2094 "{4:X} > section size {5:X})\n", 2095 SectionName, StartOffset, C.tell() - StartOffset, Length, 2096 C.tell() + Length, DA.getData().size()); 2097 }); 2098 Success = false; 2099 // Nothing more to do - no other contributions to try. 2100 break; 2101 } 2102 NextUnit = C.tell() + Length; 2103 uint8_t Version = DA.getU16(C); 2104 if (C && Version != 5) { 2105 ErrorCategory.Report("Invalid Section version", [&]() { 2106 error() << formatv("{0}: contribution {1:X}: invalid version {2}\n", 2107 SectionName, StartOffset, Version); 2108 }); 2109 Success = false; 2110 // Can't parse the rest of this contribution, since we don't know the 2111 // version, but we can pick up with the next contribution. 2112 continue; 2113 } 2114 (void)DA.getU16(C); // padding 2115 } 2116 uint64_t OffsetByteSize = getDwarfOffsetByteSize(Format); 2117 DA.setAddressSize(OffsetByteSize); 2118 uint64_t Remainder = (Length - 4) % OffsetByteSize; 2119 if (Remainder != 0) { 2120 ErrorCategory.Report("Invalid section contribution length", [&]() { 2121 error() << formatv( 2122 "{0}: contribution {1:X}: invalid length ((length ({2:X}) " 2123 "- header (0x4)) % offset size {3:X} == {4:X} != 0)\n", 2124 SectionName, StartOffset, Length, OffsetByteSize, Remainder); 2125 }); 2126 Success = false; 2127 } 2128 for (uint64_t Index = 0; C && C.tell() + OffsetByteSize <= NextUnit; ++Index) { 2129 uint64_t OffOff = C.tell(); 2130 uint64_t StrOff = DA.getAddress(C); 2131 // check StrOff refers to the start of a string 2132 if (StrOff == 0) 2133 continue; 2134 if (StrData.size() <= StrOff) { 2135 ErrorCategory.Report( 2136 "String offset out of bounds of string section", [&]() { 2137 error() << formatv( 2138 "{0}: contribution {1:X}: index {2:X}: invalid string " 2139 "offset *{3:X} == {4:X}, is beyond the bounds of the string " 2140 "section of length {5:X}\n", 2141 SectionName, StartOffset, Index, OffOff, StrOff, 2142 StrData.size()); 2143 }); 2144 continue; 2145 } 2146 if (StrData[StrOff - 1] == '\0') 2147 continue; 2148 ErrorCategory.Report( 2149 "Section contribution contains invalid string offset", [&]() { 2150 error() << formatv( 2151 "{0}: contribution {1:X}: index {2:X}: invalid string " 2152 "offset *{3:X} == {4:X}, is neither zero nor " 2153 "immediately following a null character\n", 2154 SectionName, StartOffset, Index, OffOff, StrOff); 2155 }); 2156 Success = false; 2157 } 2158 } 2159 2160 if (Error E = C.takeError()) { 2161 std::string Msg = toString(std::move(E)); 2162 ErrorCategory.Report("String offset error", [&]() { 2163 error() << SectionName << ": " << Msg << '\n'; 2164 return false; 2165 }); 2166 } 2167 return Success; 2168 } 2169 2170 void OutputCategoryAggregator::Report( 2171 StringRef s, std::function<void(void)> detailCallback) { 2172 Aggregation[std::string(s)]++; 2173 if (IncludeDetail) 2174 detailCallback(); 2175 } 2176 2177 void OutputCategoryAggregator::EnumerateResults( 2178 std::function<void(StringRef, unsigned)> handleCounts) { 2179 for (auto &&[name, count] : Aggregation) { 2180 handleCounts(name, count); 2181 } 2182 } 2183 2184 void DWARFVerifier::summarize() { 2185 if (DumpOpts.ShowAggregateErrors && ErrorCategory.GetNumCategories()) { 2186 error() << "Aggregated error counts:\n"; 2187 ErrorCategory.EnumerateResults([&](StringRef s, unsigned count) { 2188 error() << s << " occurred " << count << " time(s).\n"; 2189 }); 2190 } 2191 if (!DumpOpts.JsonErrSummaryFile.empty()) { 2192 std::error_code EC; 2193 raw_fd_ostream JsonStream(DumpOpts.JsonErrSummaryFile, EC, 2194 sys::fs::OF_Text); 2195 if (EC) { 2196 error() << "unable to open json summary file '" 2197 << DumpOpts.JsonErrSummaryFile 2198 << "' for writing: " << EC.message() << '\n'; 2199 return; 2200 } 2201 2202 llvm::json::Object Categories; 2203 uint64_t ErrorCount = 0; 2204 ErrorCategory.EnumerateResults([&](StringRef Category, unsigned Count) { 2205 llvm::json::Object Val; 2206 Val.try_emplace("count", Count); 2207 Categories.try_emplace(Category, std::move(Val)); 2208 ErrorCount += Count; 2209 }); 2210 llvm::json::Object RootNode; 2211 RootNode.try_emplace("error-categories", std::move(Categories)); 2212 RootNode.try_emplace("error-count", ErrorCount); 2213 2214 JsonStream << llvm::json::Value(std::move(RootNode)); 2215 } 2216 } 2217 2218 raw_ostream &DWARFVerifier::error() const { return WithColor::error(OS); } 2219 2220 raw_ostream &DWARFVerifier::warn() const { return WithColor::warning(OS); } 2221 2222 raw_ostream &DWARFVerifier::note() const { return WithColor::note(OS); } 2223 2224 raw_ostream &DWARFVerifier::dump(const DWARFDie &Die, unsigned indent) const { 2225 Die.dump(OS, indent, DumpOpts); 2226 return OS; 2227 } 2228