10b57cec5SDimitry Andric //===- DWARFVerifier.cpp --------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFVerifier.h" 981ad6265SDimitry Andric #include "llvm/ADT/IntervalMap.h" 107a6dacacSDimitry Andric #include "llvm/ADT/STLExtras.h" 110b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 12349cc55cSDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 1381ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" 1481ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFAttribute.h" 150b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" 160b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 1781ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" 1881ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" 190b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" 2081ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" 210b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDie.h" 220b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 230b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" 2481ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" 2581ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFObject.h" 260b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFSection.h" 2781ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFUnit.h" 2881ad6265SDimitry Andric #include "llvm/Object/Error.h" 290b57cec5SDimitry Andric #include "llvm/Support/DJB.h" 3081ad6265SDimitry Andric #include "llvm/Support/Error.h" 3181ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h" 32*0fca6ea1SDimitry Andric #include "llvm/Support/FileSystem.h" 330b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h" 34*0fca6ea1SDimitry Andric #include "llvm/Support/JSON.h" 350b57cec5SDimitry Andric #include "llvm/Support/WithColor.h" 360b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 370b57cec5SDimitry Andric #include <map> 380b57cec5SDimitry Andric #include <set> 390b57cec5SDimitry Andric #include <vector> 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric using namespace llvm; 420b57cec5SDimitry Andric using namespace dwarf; 430b57cec5SDimitry Andric using namespace object; 440b57cec5SDimitry Andric 4581ad6265SDimitry Andric namespace llvm { 4681ad6265SDimitry Andric class DWARFDebugInfoEntry; 4781ad6265SDimitry Andric } 4881ad6265SDimitry Andric 49bdd1243dSDimitry Andric std::optional<DWARFAddressRange> 500b57cec5SDimitry Andric DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) { 510b57cec5SDimitry Andric auto Begin = Ranges.begin(); 520b57cec5SDimitry Andric auto End = Ranges.end(); 530b57cec5SDimitry Andric auto Pos = std::lower_bound(Begin, End, R); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric if (Pos != End) { 565ffd83dbSDimitry Andric DWARFAddressRange Range(*Pos); 575ffd83dbSDimitry Andric if (Pos->merge(R)) 585ffd83dbSDimitry Andric return Range; 595ffd83dbSDimitry Andric } 600b57cec5SDimitry Andric if (Pos != Begin) { 610b57cec5SDimitry Andric auto Iter = Pos - 1; 625ffd83dbSDimitry Andric DWARFAddressRange Range(*Iter); 635ffd83dbSDimitry Andric if (Iter->merge(R)) 645ffd83dbSDimitry Andric return Range; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric Ranges.insert(Pos, R); 68bdd1243dSDimitry Andric return std::nullopt; 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric DWARFVerifier::DieRangeInfo::die_range_info_iterator 720b57cec5SDimitry Andric DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) { 73349cc55cSDimitry Andric if (RI.Ranges.empty()) 74349cc55cSDimitry Andric return Children.end(); 75349cc55cSDimitry Andric 760b57cec5SDimitry Andric auto End = Children.end(); 770b57cec5SDimitry Andric auto Iter = Children.begin(); 780b57cec5SDimitry Andric while (Iter != End) { 790b57cec5SDimitry Andric if (Iter->intersects(RI)) 800b57cec5SDimitry Andric return Iter; 810b57cec5SDimitry Andric ++Iter; 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric Children.insert(RI); 840b57cec5SDimitry Andric return Children.end(); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const { 880b57cec5SDimitry Andric auto I1 = Ranges.begin(), E1 = Ranges.end(); 890b57cec5SDimitry Andric auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); 900b57cec5SDimitry Andric if (I2 == E2) 910b57cec5SDimitry Andric return true; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric DWARFAddressRange R = *I2; 940b57cec5SDimitry Andric while (I1 != E1) { 950b57cec5SDimitry Andric bool Covered = I1->LowPC <= R.LowPC; 960b57cec5SDimitry Andric if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) { 970b57cec5SDimitry Andric if (++I2 == E2) 980b57cec5SDimitry Andric return true; 990b57cec5SDimitry Andric R = *I2; 1000b57cec5SDimitry Andric continue; 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric if (!Covered) 1030b57cec5SDimitry Andric return false; 1040b57cec5SDimitry Andric if (R.LowPC < I1->HighPC) 1050b57cec5SDimitry Andric R.LowPC = I1->HighPC; 1060b57cec5SDimitry Andric ++I1; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric return false; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const { 1120b57cec5SDimitry Andric auto I1 = Ranges.begin(), E1 = Ranges.end(); 1130b57cec5SDimitry Andric auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); 1140b57cec5SDimitry Andric while (I1 != E1 && I2 != E2) { 1150b57cec5SDimitry Andric if (I1->intersects(*I2)) 1160b57cec5SDimitry Andric return true; 1170b57cec5SDimitry Andric if (I1->LowPC < I2->LowPC) 1180b57cec5SDimitry Andric ++I1; 1190b57cec5SDimitry Andric else 1200b57cec5SDimitry Andric ++I2; 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric return false; 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, 1268bcb0991SDimitry Andric uint64_t *Offset, unsigned UnitIndex, 1270b57cec5SDimitry Andric uint8_t &UnitType, bool &isUnitDWARF64) { 1280b57cec5SDimitry Andric uint64_t AbbrOffset, Length; 1290b57cec5SDimitry Andric uint8_t AddrSize = 0; 1300b57cec5SDimitry Andric uint16_t Version; 1310b57cec5SDimitry Andric bool Success = true; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric bool ValidLength = false; 1340b57cec5SDimitry Andric bool ValidVersion = false; 1350b57cec5SDimitry Andric bool ValidAddrSize = false; 1360b57cec5SDimitry Andric bool ValidType = true; 1370b57cec5SDimitry Andric bool ValidAbbrevOffset = true; 1380b57cec5SDimitry Andric 1398bcb0991SDimitry Andric uint64_t OffsetStart = *Offset; 1405ffd83dbSDimitry Andric DwarfFormat Format; 1415ffd83dbSDimitry Andric std::tie(Length, Format) = DebugInfoData.getInitialLength(Offset); 1425ffd83dbSDimitry Andric isUnitDWARF64 = Format == DWARF64; 1430b57cec5SDimitry Andric Version = DebugInfoData.getU16(Offset); 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric if (Version >= 5) { 1460b57cec5SDimitry Andric UnitType = DebugInfoData.getU8(Offset); 1470b57cec5SDimitry Andric AddrSize = DebugInfoData.getU8(Offset); 1480b57cec5SDimitry Andric AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); 1490b57cec5SDimitry Andric ValidType = dwarf::isUnitType(UnitType); 1500b57cec5SDimitry Andric } else { 1510b57cec5SDimitry Andric UnitType = 0; 1520b57cec5SDimitry Andric AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); 1530b57cec5SDimitry Andric AddrSize = DebugInfoData.getU8(Offset); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 15606c3fb27SDimitry Andric Expected<const DWARFAbbreviationDeclarationSet *> AbbrevSetOrErr = 15706c3fb27SDimitry Andric DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset); 15806c3fb27SDimitry Andric if (!AbbrevSetOrErr) { 1590b57cec5SDimitry Andric ValidAbbrevOffset = false; 16006c3fb27SDimitry Andric // FIXME: A problematic debug_abbrev section is reported below in the form 16106c3fb27SDimitry Andric // of a `note:`. We should propagate this error there (or elsewhere) to 16206c3fb27SDimitry Andric // avoid losing the specific problem with the debug_abbrev section. 16306c3fb27SDimitry Andric consumeError(AbbrevSetOrErr.takeError()); 16406c3fb27SDimitry Andric } 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3); 1670b57cec5SDimitry Andric ValidVersion = DWARFContext::isSupportedVersion(Version); 1685ffd83dbSDimitry Andric ValidAddrSize = DWARFContext::isAddressSizeSupported(AddrSize); 1690b57cec5SDimitry Andric if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset || 1700b57cec5SDimitry Andric !ValidType) { 1710b57cec5SDimitry Andric Success = false; 172*0fca6ea1SDimitry Andric bool HeaderShown = false; 173*0fca6ea1SDimitry Andric auto ShowHeaderOnce = [&]() { 174*0fca6ea1SDimitry Andric if (!HeaderShown) { 175*0fca6ea1SDimitry Andric error() << format("Units[%d] - start offset: 0x%08" PRIx64 " \n", 176*0fca6ea1SDimitry Andric UnitIndex, OffsetStart); 177*0fca6ea1SDimitry Andric HeaderShown = true; 178*0fca6ea1SDimitry Andric } 179*0fca6ea1SDimitry Andric }; 1800b57cec5SDimitry Andric if (!ValidLength) 181*0fca6ea1SDimitry Andric ErrorCategory.Report( 182*0fca6ea1SDimitry Andric "Unit Header Length: Unit too large for .debug_info provided", [&]() { 183*0fca6ea1SDimitry Andric ShowHeaderOnce(); 1840b57cec5SDimitry Andric note() << "The length for this unit is too " 1850b57cec5SDimitry Andric "large for the .debug_info provided.\n"; 186*0fca6ea1SDimitry Andric }); 1870b57cec5SDimitry Andric if (!ValidVersion) 188*0fca6ea1SDimitry Andric ErrorCategory.Report( 189*0fca6ea1SDimitry Andric "Unit Header Length: 16 bit unit header version is not valid", [&]() { 190*0fca6ea1SDimitry Andric ShowHeaderOnce(); 1910b57cec5SDimitry Andric note() << "The 16 bit unit header version is not valid.\n"; 192*0fca6ea1SDimitry Andric }); 1930b57cec5SDimitry Andric if (!ValidType) 194*0fca6ea1SDimitry Andric ErrorCategory.Report( 195*0fca6ea1SDimitry Andric "Unit Header Length: Unit type encoding is not valid", [&]() { 196*0fca6ea1SDimitry Andric ShowHeaderOnce(); 1970b57cec5SDimitry Andric note() << "The unit type encoding is not valid.\n"; 198*0fca6ea1SDimitry Andric }); 1990b57cec5SDimitry Andric if (!ValidAbbrevOffset) 200*0fca6ea1SDimitry Andric ErrorCategory.Report( 201*0fca6ea1SDimitry Andric "Unit Header Length: Offset into the .debug_abbrev section is not " 202*0fca6ea1SDimitry Andric "valid", 203*0fca6ea1SDimitry Andric [&]() { 204*0fca6ea1SDimitry Andric ShowHeaderOnce(); 2050b57cec5SDimitry Andric note() << "The offset into the .debug_abbrev section is " 2060b57cec5SDimitry Andric "not valid.\n"; 207*0fca6ea1SDimitry Andric }); 2080b57cec5SDimitry Andric if (!ValidAddrSize) 209*0fca6ea1SDimitry Andric ErrorCategory.Report("Unit Header Length: Address size is unsupported", 210*0fca6ea1SDimitry Andric [&]() { 211*0fca6ea1SDimitry Andric ShowHeaderOnce(); 2120b57cec5SDimitry Andric note() << "The address size is unsupported.\n"; 213*0fca6ea1SDimitry Andric }); 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric *Offset = OffsetStart + Length + (isUnitDWARF64 ? 12 : 4); 2160b57cec5SDimitry Andric return Success; 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 219349cc55cSDimitry Andric bool DWARFVerifier::verifyName(const DWARFDie &Die) { 220349cc55cSDimitry Andric // FIXME Add some kind of record of which DIE names have already failed and 221349cc55cSDimitry Andric // don't bother checking a DIE that uses an already failed DIE. 222349cc55cSDimitry Andric 223349cc55cSDimitry Andric std::string ReconstructedName; 224349cc55cSDimitry Andric raw_string_ostream OS(ReconstructedName); 225349cc55cSDimitry Andric std::string OriginalFullName; 226349cc55cSDimitry Andric Die.getFullName(OS, &OriginalFullName); 227349cc55cSDimitry Andric OS.flush(); 228349cc55cSDimitry Andric if (OriginalFullName.empty() || OriginalFullName == ReconstructedName) 22904eeddc0SDimitry Andric return false; 230349cc55cSDimitry Andric 231*0fca6ea1SDimitry Andric ErrorCategory.Report( 232*0fca6ea1SDimitry Andric "Simplified template DW_AT_name could not be reconstituted", [&]() { 233*0fca6ea1SDimitry Andric error() 234*0fca6ea1SDimitry Andric << "Simplified template DW_AT_name could not be reconstituted:\n" 235349cc55cSDimitry Andric << formatv(" original: {0}\n" 236349cc55cSDimitry Andric " reconstituted: {1}\n", 237349cc55cSDimitry Andric OriginalFullName, ReconstructedName); 238349cc55cSDimitry Andric dump(Die) << '\n'; 239349cc55cSDimitry Andric dump(Die.getDwarfUnit()->getUnitDIE()) << '\n'; 240*0fca6ea1SDimitry Andric }); 24104eeddc0SDimitry Andric return true; 242349cc55cSDimitry Andric } 243349cc55cSDimitry Andric 244349cc55cSDimitry Andric unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit, 245349cc55cSDimitry Andric ReferenceMap &UnitLocalReferences, 246349cc55cSDimitry Andric ReferenceMap &CrossUnitReferences) { 2470b57cec5SDimitry Andric unsigned NumUnitErrors = 0; 2480b57cec5SDimitry Andric unsigned NumDies = Unit.getNumDIEs(); 2490b57cec5SDimitry Andric for (unsigned I = 0; I < NumDies; ++I) { 2500b57cec5SDimitry Andric auto Die = Unit.getDIEAtIndex(I); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric if (Die.getTag() == DW_TAG_null) 2530b57cec5SDimitry Andric continue; 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric for (auto AttrValue : Die.attributes()) { 2560b57cec5SDimitry Andric NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue); 257349cc55cSDimitry Andric NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences, 258349cc55cSDimitry Andric CrossUnitReferences); 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric 261349cc55cSDimitry Andric NumUnitErrors += verifyName(Die); 262349cc55cSDimitry Andric 263e8d8bef9SDimitry Andric if (Die.hasChildren()) { 264e8d8bef9SDimitry Andric if (Die.getFirstChild().isValid() && 265e8d8bef9SDimitry Andric Die.getFirstChild().getTag() == DW_TAG_null) { 266e8d8bef9SDimitry Andric warn() << dwarf::TagString(Die.getTag()) 267e8d8bef9SDimitry Andric << " has DW_CHILDREN_yes but DIE has no children: "; 268e8d8bef9SDimitry Andric Die.dump(OS); 269e8d8bef9SDimitry Andric } 270e8d8bef9SDimitry Andric } 271e8d8bef9SDimitry Andric 2720b57cec5SDimitry Andric NumUnitErrors += verifyDebugInfoCallSite(Die); 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false); 2760b57cec5SDimitry Andric if (!Die) { 277*0fca6ea1SDimitry Andric ErrorCategory.Report("Compilation unit missing DIE", [&]() { 2780b57cec5SDimitry Andric error() << "Compilation unit without DIE.\n"; 279*0fca6ea1SDimitry Andric }); 2800b57cec5SDimitry Andric NumUnitErrors++; 2810b57cec5SDimitry Andric return NumUnitErrors; 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric if (!dwarf::isUnitType(Die.getTag())) { 285*0fca6ea1SDimitry Andric ErrorCategory.Report("Compilation unit root DIE is not a unit DIE", [&]() { 2860b57cec5SDimitry Andric error() << "Compilation unit root DIE is not a unit DIE: " 2870b57cec5SDimitry Andric << dwarf::TagString(Die.getTag()) << ".\n"; 288*0fca6ea1SDimitry Andric }); 2890b57cec5SDimitry Andric NumUnitErrors++; 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric 2920b57cec5SDimitry Andric uint8_t UnitType = Unit.getUnitType(); 2930b57cec5SDimitry Andric if (!DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) { 294*0fca6ea1SDimitry Andric ErrorCategory.Report("Mismatched unit type", [&]() { 2950b57cec5SDimitry Andric error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType) 2960b57cec5SDimitry Andric << ") and root DIE (" << dwarf::TagString(Die.getTag()) 2970b57cec5SDimitry Andric << ") do not match.\n"; 298*0fca6ea1SDimitry Andric }); 2990b57cec5SDimitry Andric NumUnitErrors++; 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric 302480093f4SDimitry Andric // According to DWARF Debugging Information Format Version 5, 303480093f4SDimitry Andric // 3.1.2 Skeleton Compilation Unit Entries: 304480093f4SDimitry Andric // "A skeleton compilation unit has no children." 305480093f4SDimitry Andric if (Die.getTag() == dwarf::DW_TAG_skeleton_unit && Die.hasChildren()) { 306*0fca6ea1SDimitry Andric ErrorCategory.Report("Skeleton CU has children", [&]() { 307480093f4SDimitry Andric error() << "Skeleton compilation unit has children.\n"; 308*0fca6ea1SDimitry Andric }); 309480093f4SDimitry Andric NumUnitErrors++; 310480093f4SDimitry Andric } 311480093f4SDimitry Andric 3120b57cec5SDimitry Andric DieRangeInfo RI; 3130b57cec5SDimitry Andric NumUnitErrors += verifyDieRanges(Die, RI); 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric return NumUnitErrors; 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) { 3198bcb0991SDimitry Andric if (Die.getTag() != DW_TAG_call_site && Die.getTag() != DW_TAG_GNU_call_site) 3200b57cec5SDimitry Andric return 0; 3210b57cec5SDimitry Andric 3220b57cec5SDimitry Andric DWARFDie Curr = Die.getParent(); 3230b57cec5SDimitry Andric for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Die.getParent()) { 3240b57cec5SDimitry Andric if (Curr.getTag() == DW_TAG_inlined_subroutine) { 325*0fca6ea1SDimitry Andric ErrorCategory.Report( 326*0fca6ea1SDimitry Andric "Call site nested entry within inlined subroutine", [&]() { 3270b57cec5SDimitry Andric error() << "Call site entry nested within inlined subroutine:"; 3280b57cec5SDimitry Andric Curr.dump(OS); 329*0fca6ea1SDimitry Andric }); 3300b57cec5SDimitry Andric return 1; 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric if (!Curr.isValid()) { 335*0fca6ea1SDimitry Andric ErrorCategory.Report( 336*0fca6ea1SDimitry Andric "Call site entry not nested within valid subprogram", [&]() { 3370b57cec5SDimitry Andric error() << "Call site entry not nested within a valid subprogram:"; 3380b57cec5SDimitry Andric Die.dump(OS); 339*0fca6ea1SDimitry Andric }); 3400b57cec5SDimitry Andric return 1; 3410b57cec5SDimitry Andric } 3420b57cec5SDimitry Andric 343bdd1243dSDimitry Andric std::optional<DWARFFormValue> CallAttr = Curr.find( 344bdd1243dSDimitry Andric {DW_AT_call_all_calls, DW_AT_call_all_source_calls, 3458bcb0991SDimitry Andric DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites, 346bdd1243dSDimitry Andric DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites}); 3470b57cec5SDimitry Andric if (!CallAttr) { 348*0fca6ea1SDimitry Andric ErrorCategory.Report( 349*0fca6ea1SDimitry Andric "Subprogram with call site entry has no DW_AT_call attribute", [&]() { 350*0fca6ea1SDimitry Andric error() 351*0fca6ea1SDimitry Andric << "Subprogram with call site entry has no DW_AT_call attribute:"; 3520b57cec5SDimitry Andric Curr.dump(OS); 3530b57cec5SDimitry Andric Die.dump(OS, /*indent*/ 1); 354*0fca6ea1SDimitry Andric }); 3550b57cec5SDimitry Andric return 1; 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric return 0; 3590b57cec5SDimitry Andric } 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) { 36206c3fb27SDimitry Andric if (!Abbrev) 36306c3fb27SDimitry Andric return 0; 36406c3fb27SDimitry Andric 36506c3fb27SDimitry Andric Expected<const DWARFAbbreviationDeclarationSet *> AbbrDeclsOrErr = 3660b57cec5SDimitry Andric Abbrev->getAbbreviationDeclarationSet(0); 36706c3fb27SDimitry Andric if (!AbbrDeclsOrErr) { 368*0fca6ea1SDimitry Andric std::string ErrMsg = toString(AbbrDeclsOrErr.takeError()); 369*0fca6ea1SDimitry Andric ErrorCategory.Report("Abbreviation Declaration error", 370*0fca6ea1SDimitry Andric [&]() { error() << ErrMsg << "\n"; }); 37106c3fb27SDimitry Andric return 1; 37206c3fb27SDimitry Andric } 37306c3fb27SDimitry Andric 37406c3fb27SDimitry Andric const auto *AbbrDecls = *AbbrDeclsOrErr; 37506c3fb27SDimitry Andric unsigned NumErrors = 0; 3760b57cec5SDimitry Andric for (auto AbbrDecl : *AbbrDecls) { 3770b57cec5SDimitry Andric SmallDenseSet<uint16_t> AttributeSet; 3780b57cec5SDimitry Andric for (auto Attribute : AbbrDecl.attributes()) { 3790b57cec5SDimitry Andric auto Result = AttributeSet.insert(Attribute.Attr); 3800b57cec5SDimitry Andric if (!Result.second) { 381*0fca6ea1SDimitry Andric ErrorCategory.Report( 382*0fca6ea1SDimitry Andric "Abbreviation declartion contains multiple attributes", [&]() { 3830b57cec5SDimitry Andric error() << "Abbreviation declaration contains multiple " 3840b57cec5SDimitry Andric << AttributeString(Attribute.Attr) << " attributes.\n"; 3850b57cec5SDimitry Andric AbbrDecl.dump(OS); 386*0fca6ea1SDimitry Andric }); 3870b57cec5SDimitry Andric ++NumErrors; 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric return NumErrors; 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric bool DWARFVerifier::handleDebugAbbrev() { 3950b57cec5SDimitry Andric OS << "Verifying .debug_abbrev...\n"; 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric const DWARFObject &DObj = DCtx.getDWARFObj(); 3980b57cec5SDimitry Andric unsigned NumErrors = 0; 3990b57cec5SDimitry Andric if (!DObj.getAbbrevSection().empty()) 4000b57cec5SDimitry Andric NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev()); 4010b57cec5SDimitry Andric if (!DObj.getAbbrevDWOSection().empty()) 4020b57cec5SDimitry Andric NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO()); 4030b57cec5SDimitry Andric 4040b57cec5SDimitry Andric return NumErrors == 0; 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric 4074824e7fdSDimitry Andric unsigned DWARFVerifier::verifyUnits(const DWARFUnitVector &Units) { 4084824e7fdSDimitry Andric unsigned NumDebugInfoErrors = 0; 4094824e7fdSDimitry Andric ReferenceMap CrossUnitReferences; 4104824e7fdSDimitry Andric 41104eeddc0SDimitry Andric unsigned Index = 1; 4124824e7fdSDimitry Andric for (const auto &Unit : Units) { 41304eeddc0SDimitry Andric OS << "Verifying unit: " << Index << " / " << Units.getNumUnits(); 41404eeddc0SDimitry Andric if (const char* Name = Unit->getUnitDIE(true).getShortName()) 41504eeddc0SDimitry Andric OS << ", \"" << Name << '\"'; 41604eeddc0SDimitry Andric OS << '\n'; 41704eeddc0SDimitry Andric OS.flush(); 4184824e7fdSDimitry Andric ReferenceMap UnitLocalReferences; 4194824e7fdSDimitry Andric NumDebugInfoErrors += 4204824e7fdSDimitry Andric verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences); 4214824e7fdSDimitry Andric NumDebugInfoErrors += verifyDebugInfoReferences( 4224824e7fdSDimitry Andric UnitLocalReferences, [&](uint64_t Offset) { return Unit.get(); }); 42304eeddc0SDimitry Andric ++Index; 4244824e7fdSDimitry Andric } 4254824e7fdSDimitry Andric 4264824e7fdSDimitry Andric NumDebugInfoErrors += verifyDebugInfoReferences( 4274824e7fdSDimitry Andric CrossUnitReferences, [&](uint64_t Offset) -> DWARFUnit * { 4284824e7fdSDimitry Andric if (DWARFUnit *U = Units.getUnitForOffset(Offset)) 4294824e7fdSDimitry Andric return U; 4304824e7fdSDimitry Andric return nullptr; 4314824e7fdSDimitry Andric }); 4324824e7fdSDimitry Andric 4334824e7fdSDimitry Andric return NumDebugInfoErrors; 4344824e7fdSDimitry Andric } 4354824e7fdSDimitry Andric 4364824e7fdSDimitry Andric unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S) { 4370b57cec5SDimitry Andric const DWARFObject &DObj = DCtx.getDWARFObj(); 4380b57cec5SDimitry Andric DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0); 4390b57cec5SDimitry Andric unsigned NumDebugInfoErrors = 0; 4404824e7fdSDimitry Andric uint64_t Offset = 0, UnitIdx = 0; 4410b57cec5SDimitry Andric uint8_t UnitType = 0; 4420b57cec5SDimitry Andric bool isUnitDWARF64 = false; 4430b57cec5SDimitry Andric bool isHeaderChainValid = true; 4440b57cec5SDimitry Andric bool hasDIE = DebugInfoData.isValidOffset(Offset); 4450b57cec5SDimitry Andric DWARFUnitVector TypeUnitVector; 4460b57cec5SDimitry Andric DWARFUnitVector CompileUnitVector; 447349cc55cSDimitry Andric /// A map that tracks all references (converted absolute references) so we 448349cc55cSDimitry Andric /// can verify each reference points to a valid DIE and not an offset that 449349cc55cSDimitry Andric /// lies between to valid DIEs. 450349cc55cSDimitry Andric ReferenceMap CrossUnitReferences; 4510b57cec5SDimitry Andric while (hasDIE) { 4520b57cec5SDimitry Andric if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType, 4530b57cec5SDimitry Andric isUnitDWARF64)) { 4540b57cec5SDimitry Andric isHeaderChainValid = false; 4550b57cec5SDimitry Andric if (isUnitDWARF64) 4560b57cec5SDimitry Andric break; 4570b57cec5SDimitry Andric } 4580b57cec5SDimitry Andric hasDIE = DebugInfoData.isValidOffset(Offset); 4590b57cec5SDimitry Andric ++UnitIdx; 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric if (UnitIdx == 0 && !hasDIE) { 4620b57cec5SDimitry Andric warn() << "Section is empty.\n"; 4630b57cec5SDimitry Andric isHeaderChainValid = true; 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric if (!isHeaderChainValid) 4660b57cec5SDimitry Andric ++NumDebugInfoErrors; 4670b57cec5SDimitry Andric return NumDebugInfoErrors; 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric 47081ad6265SDimitry Andric unsigned DWARFVerifier::verifyIndex(StringRef Name, 47181ad6265SDimitry Andric DWARFSectionKind InfoColumnKind, 47281ad6265SDimitry Andric StringRef IndexStr) { 47381ad6265SDimitry Andric if (IndexStr.empty()) 47481ad6265SDimitry Andric return 0; 47581ad6265SDimitry Andric OS << "Verifying " << Name << "...\n"; 47681ad6265SDimitry Andric DWARFUnitIndex Index(InfoColumnKind); 47781ad6265SDimitry Andric DataExtractor D(IndexStr, DCtx.isLittleEndian(), 0); 47881ad6265SDimitry Andric if (!Index.parse(D)) 47981ad6265SDimitry Andric return 1; 480bdd1243dSDimitry Andric using MapType = IntervalMap<uint64_t, uint64_t>; 48181ad6265SDimitry Andric MapType::Allocator Alloc; 48281ad6265SDimitry Andric std::vector<std::unique_ptr<MapType>> Sections(Index.getColumnKinds().size()); 48381ad6265SDimitry Andric for (const DWARFUnitIndex::Entry &E : Index.getRows()) { 48481ad6265SDimitry Andric uint64_t Sig = E.getSignature(); 48581ad6265SDimitry Andric if (!E.getContributions()) 48681ad6265SDimitry Andric continue; 487bdd1243dSDimitry Andric for (auto E : enumerate( 488bdd1243dSDimitry Andric InfoColumnKind == DW_SECT_INFO 489bdd1243dSDimitry Andric ? ArrayRef(E.getContributions(), Index.getColumnKinds().size()) 490bdd1243dSDimitry Andric : ArrayRef(E.getContribution(), 1))) { 49181ad6265SDimitry Andric const DWARFUnitIndex::Entry::SectionContribution &SC = E.value(); 49281ad6265SDimitry Andric int Col = E.index(); 493bdd1243dSDimitry Andric if (SC.getLength() == 0) 49481ad6265SDimitry Andric continue; 49581ad6265SDimitry Andric if (!Sections[Col]) 49681ad6265SDimitry Andric Sections[Col] = std::make_unique<MapType>(Alloc); 49781ad6265SDimitry Andric auto &M = *Sections[Col]; 498bdd1243dSDimitry Andric auto I = M.find(SC.getOffset()); 499bdd1243dSDimitry Andric if (I != M.end() && I.start() < (SC.getOffset() + SC.getLength())) { 500*0fca6ea1SDimitry Andric StringRef Category = InfoColumnKind == DWARFSectionKind::DW_SECT_INFO 501*0fca6ea1SDimitry Andric ? "Overlapping CU index entries" 502*0fca6ea1SDimitry Andric : "Overlapping TU index entries"; 503*0fca6ea1SDimitry Andric ErrorCategory.Report(Category, [&]() { 50481ad6265SDimitry Andric error() << llvm::formatv( 50581ad6265SDimitry Andric "overlapping index entries for entries {0:x16} " 50681ad6265SDimitry Andric "and {1:x16} for column {2}\n", 50781ad6265SDimitry Andric *I, Sig, toString(Index.getColumnKinds()[Col])); 508*0fca6ea1SDimitry Andric }); 50981ad6265SDimitry Andric return 1; 51081ad6265SDimitry Andric } 511bdd1243dSDimitry Andric M.insert(SC.getOffset(), SC.getOffset() + SC.getLength() - 1, Sig); 51281ad6265SDimitry Andric } 51381ad6265SDimitry Andric } 51481ad6265SDimitry Andric 51581ad6265SDimitry Andric return 0; 51681ad6265SDimitry Andric } 51781ad6265SDimitry Andric 51881ad6265SDimitry Andric bool DWARFVerifier::handleDebugCUIndex() { 51981ad6265SDimitry Andric return verifyIndex(".debug_cu_index", DWARFSectionKind::DW_SECT_INFO, 52081ad6265SDimitry Andric DCtx.getDWARFObj().getCUIndexSection()) == 0; 52181ad6265SDimitry Andric } 52281ad6265SDimitry Andric 52381ad6265SDimitry Andric bool DWARFVerifier::handleDebugTUIndex() { 52481ad6265SDimitry Andric return verifyIndex(".debug_tu_index", DWARFSectionKind::DW_SECT_EXT_TYPES, 52581ad6265SDimitry Andric DCtx.getDWARFObj().getTUIndexSection()) == 0; 52681ad6265SDimitry Andric } 52781ad6265SDimitry Andric 5280b57cec5SDimitry Andric bool DWARFVerifier::handleDebugInfo() { 5290b57cec5SDimitry Andric const DWARFObject &DObj = DCtx.getDWARFObj(); 5300b57cec5SDimitry Andric unsigned NumErrors = 0; 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric OS << "Verifying .debug_info Unit Header Chain...\n"; 5330b57cec5SDimitry Andric DObj.forEachInfoSections([&](const DWARFSection &S) { 5344824e7fdSDimitry Andric NumErrors += verifyUnitSection(S); 5350b57cec5SDimitry Andric }); 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric OS << "Verifying .debug_types Unit Header Chain...\n"; 5380b57cec5SDimitry Andric DObj.forEachTypesSections([&](const DWARFSection &S) { 5394824e7fdSDimitry Andric NumErrors += verifyUnitSection(S); 5400b57cec5SDimitry Andric }); 5414824e7fdSDimitry Andric 5424824e7fdSDimitry Andric OS << "Verifying non-dwo Units...\n"; 5434824e7fdSDimitry Andric NumErrors += verifyUnits(DCtx.getNormalUnitsVector()); 5440eae32dcSDimitry Andric 5450eae32dcSDimitry Andric OS << "Verifying dwo Units...\n"; 5460eae32dcSDimitry Andric NumErrors += verifyUnits(DCtx.getDWOUnitsVector()); 5470b57cec5SDimitry Andric return NumErrors == 0; 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, 5510b57cec5SDimitry Andric DieRangeInfo &ParentRI) { 5520b57cec5SDimitry Andric unsigned NumErrors = 0; 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric if (!Die.isValid()) 5550b57cec5SDimitry Andric return NumErrors; 5560b57cec5SDimitry Andric 5570eae32dcSDimitry Andric DWARFUnit *Unit = Die.getDwarfUnit(); 5580eae32dcSDimitry Andric 5590b57cec5SDimitry Andric auto RangesOrError = Die.getAddressRanges(); 5600b57cec5SDimitry Andric if (!RangesOrError) { 5610b57cec5SDimitry Andric // FIXME: Report the error. 5620eae32dcSDimitry Andric if (!Unit->isDWOUnit()) 5630b57cec5SDimitry Andric ++NumErrors; 5640b57cec5SDimitry Andric llvm::consumeError(RangesOrError.takeError()); 5650b57cec5SDimitry Andric return NumErrors; 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric 568349cc55cSDimitry Andric const DWARFAddressRangesVector &Ranges = RangesOrError.get(); 5690b57cec5SDimitry Andric // Build RI for this DIE and check that ranges within this DIE do not 5700b57cec5SDimitry Andric // overlap. 5710b57cec5SDimitry Andric DieRangeInfo RI(Die); 5720b57cec5SDimitry Andric 5730b57cec5SDimitry Andric // TODO support object files better 5740b57cec5SDimitry Andric // 5750b57cec5SDimitry Andric // Some object file formats (i.e. non-MachO) support COMDAT. ELF in 5760b57cec5SDimitry Andric // particular does so by placing each function into a section. The DWARF data 5770b57cec5SDimitry Andric // for the function at that point uses a section relative DW_FORM_addrp for 5780b57cec5SDimitry Andric // the DW_AT_low_pc and a DW_FORM_data4 for the offset as the DW_AT_high_pc. 5790b57cec5SDimitry Andric // In such a case, when the Die is the CU, the ranges will overlap, and we 5800b57cec5SDimitry Andric // will flag valid conflicting ranges as invalid. 5810b57cec5SDimitry Andric // 5820b57cec5SDimitry Andric // For such targets, we should read the ranges from the CU and partition them 5830b57cec5SDimitry Andric // by the section id. The ranges within a particular section should be 5840b57cec5SDimitry Andric // disjoint, although the ranges across sections may overlap. We would map 5850b57cec5SDimitry Andric // the child die to the entity that it references and the section with which 5860b57cec5SDimitry Andric // it is associated. The child would then be checked against the range 5870b57cec5SDimitry Andric // information for the associated section. 5880b57cec5SDimitry Andric // 5890b57cec5SDimitry Andric // For now, simply elide the range verification for the CU DIEs if we are 5900b57cec5SDimitry Andric // processing an object file. 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) { 5935ffd83dbSDimitry Andric bool DumpDieAfterError = false; 594349cc55cSDimitry Andric for (const auto &Range : Ranges) { 5950b57cec5SDimitry Andric if (!Range.valid()) { 5960b57cec5SDimitry Andric ++NumErrors; 597*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid address range", [&]() { 5980b57cec5SDimitry Andric error() << "Invalid address range " << Range << "\n"; 5995ffd83dbSDimitry Andric DumpDieAfterError = true; 600*0fca6ea1SDimitry Andric }); 6010b57cec5SDimitry Andric continue; 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric 6045ffd83dbSDimitry Andric // Verify that ranges don't intersect and also build up the DieRangeInfo 6055ffd83dbSDimitry Andric // address ranges. Don't break out of the loop below early, or we will 6065ffd83dbSDimitry Andric // think this DIE doesn't have all of the address ranges it is supposed 6075ffd83dbSDimitry Andric // to have. Compile units often have DW_AT_ranges that can contain one or 6085ffd83dbSDimitry Andric // more dead stripped address ranges which tend to all be at the same 6095ffd83dbSDimitry Andric // address: 0 or -1. 6105ffd83dbSDimitry Andric if (auto PrevRange = RI.insert(Range)) { 6110b57cec5SDimitry Andric ++NumErrors; 612*0fca6ea1SDimitry Andric ErrorCategory.Report("DIE has overlapping DW_AT_ranges", [&]() { 6135ffd83dbSDimitry Andric error() << "DIE has overlapping ranges in DW_AT_ranges attribute: " 6145ffd83dbSDimitry Andric << *PrevRange << " and " << Range << '\n'; 6155ffd83dbSDimitry Andric DumpDieAfterError = true; 616*0fca6ea1SDimitry Andric }); 6170b57cec5SDimitry Andric } 6180b57cec5SDimitry Andric } 6195ffd83dbSDimitry Andric if (DumpDieAfterError) 6205ffd83dbSDimitry Andric dump(Die, 2) << '\n'; 6210b57cec5SDimitry Andric } 6220b57cec5SDimitry Andric 6230b57cec5SDimitry Andric // Verify that children don't intersect. 6240b57cec5SDimitry Andric const auto IntersectingChild = ParentRI.insert(RI); 6250b57cec5SDimitry Andric if (IntersectingChild != ParentRI.Children.end()) { 6260b57cec5SDimitry Andric ++NumErrors; 627*0fca6ea1SDimitry Andric ErrorCategory.Report("DIEs have overlapping address ranges", [&]() { 6280b57cec5SDimitry Andric error() << "DIEs have overlapping address ranges:"; 6290b57cec5SDimitry Andric dump(Die); 6300b57cec5SDimitry Andric dump(IntersectingChild->Die) << '\n'; 631*0fca6ea1SDimitry Andric }); 6320b57cec5SDimitry Andric } 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric // Verify that ranges are contained within their parent. 635349cc55cSDimitry Andric bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() && 6360b57cec5SDimitry Andric !(Die.getTag() == DW_TAG_subprogram && 6370b57cec5SDimitry Andric ParentRI.Die.getTag() == DW_TAG_subprogram); 6380b57cec5SDimitry Andric if (ShouldBeContained && !ParentRI.contains(RI)) { 6390b57cec5SDimitry Andric ++NumErrors; 640*0fca6ea1SDimitry Andric ErrorCategory.Report( 641*0fca6ea1SDimitry Andric "DIE address ranges are not contained by parent ranges", [&]() { 642*0fca6ea1SDimitry Andric error() 643*0fca6ea1SDimitry Andric << "DIE address ranges are not contained in its parent's ranges:"; 6440b57cec5SDimitry Andric dump(ParentRI.Die); 6450b57cec5SDimitry Andric dump(Die, 2) << '\n'; 646*0fca6ea1SDimitry Andric }); 6470b57cec5SDimitry Andric } 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric // Recursively check children. 6500b57cec5SDimitry Andric for (DWARFDie Child : Die) 6510b57cec5SDimitry Andric NumErrors += verifyDieRanges(Child, RI); 6520b57cec5SDimitry Andric 6530b57cec5SDimitry Andric return NumErrors; 6540b57cec5SDimitry Andric } 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, 6570b57cec5SDimitry Andric DWARFAttribute &AttrValue) { 6580b57cec5SDimitry Andric unsigned NumErrors = 0; 659*0fca6ea1SDimitry Andric auto ReportError = [&](StringRef category, const Twine &TitleMsg) { 6600b57cec5SDimitry Andric ++NumErrors; 661*0fca6ea1SDimitry Andric ErrorCategory.Report(category, [&]() { 6620b57cec5SDimitry Andric error() << TitleMsg << '\n'; 6630b57cec5SDimitry Andric dump(Die) << '\n'; 664*0fca6ea1SDimitry Andric }); 6650b57cec5SDimitry Andric }; 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric const DWARFObject &DObj = DCtx.getDWARFObj(); 6680eae32dcSDimitry Andric DWARFUnit *U = Die.getDwarfUnit(); 6690b57cec5SDimitry Andric const auto Attr = AttrValue.Attr; 6700b57cec5SDimitry Andric switch (Attr) { 6710b57cec5SDimitry Andric case DW_AT_ranges: 6720b57cec5SDimitry Andric // Make sure the offset in the DW_AT_ranges attribute is valid. 6730b57cec5SDimitry Andric if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { 6740eae32dcSDimitry Andric unsigned DwarfVersion = U->getVersion(); 6755ffd83dbSDimitry Andric const DWARFSection &RangeSection = DwarfVersion < 5 6765ffd83dbSDimitry Andric ? DObj.getRangesSection() 6775ffd83dbSDimitry Andric : DObj.getRnglistsSection(); 6780eae32dcSDimitry Andric if (U->isDWOUnit() && RangeSection.Data.empty()) 6790eae32dcSDimitry Andric break; 6805ffd83dbSDimitry Andric if (*SectionOffset >= RangeSection.Data.size()) 681*0fca6ea1SDimitry Andric ReportError("DW_AT_ranges offset out of bounds", 6825ffd83dbSDimitry Andric "DW_AT_ranges offset is beyond " + 683*0fca6ea1SDimitry Andric StringRef(DwarfVersion < 5 ? ".debug_ranges" 684*0fca6ea1SDimitry Andric : ".debug_rnglists") + 6855ffd83dbSDimitry Andric " bounds: " + llvm::formatv("{0:x8}", *SectionOffset)); 6860b57cec5SDimitry Andric break; 6870b57cec5SDimitry Andric } 688*0fca6ea1SDimitry Andric ReportError("Invalid DW_AT_ranges encoding", 689*0fca6ea1SDimitry Andric "DIE has invalid DW_AT_ranges encoding:"); 6900b57cec5SDimitry Andric break; 6910b57cec5SDimitry Andric case DW_AT_stmt_list: 6920b57cec5SDimitry Andric // Make sure the offset in the DW_AT_stmt_list attribute is valid. 6930b57cec5SDimitry Andric if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { 6940eae32dcSDimitry Andric if (*SectionOffset >= U->getLineSection().Data.size()) 695*0fca6ea1SDimitry Andric ReportError("DW_AT_stmt_list offset out of bounds", 696*0fca6ea1SDimitry Andric "DW_AT_stmt_list offset is beyond .debug_line bounds: " + 6970b57cec5SDimitry Andric llvm::formatv("{0:x8}", *SectionOffset)); 6980b57cec5SDimitry Andric break; 6990b57cec5SDimitry Andric } 700*0fca6ea1SDimitry Andric ReportError("Invalid DW_AT_stmt_list encoding", 701*0fca6ea1SDimitry Andric "DIE has invalid DW_AT_stmt_list encoding:"); 7020b57cec5SDimitry Andric break; 7030b57cec5SDimitry Andric case DW_AT_location: { 7040eae32dcSDimitry Andric // FIXME: It might be nice if there's a way to walk location expressions 7050eae32dcSDimitry Andric // without trying to resolve the address ranges - it'd be a more efficient 7060eae32dcSDimitry Andric // API (since the API is currently unnecessarily resolving addresses for 7070eae32dcSDimitry Andric // this use case which only wants to validate the expressions themselves) & 7080eae32dcSDimitry Andric // then the expressions could be validated even if the addresses can't be 7090eae32dcSDimitry Andric // resolved. 7100eae32dcSDimitry Andric // That sort of API would probably look like a callback "for each 7110eae32dcSDimitry Andric // expression" with some way to lazily resolve the address ranges when 7120eae32dcSDimitry Andric // needed (& then the existing API used here could be built on top of that - 7130eae32dcSDimitry Andric // using the callback API to build the data structure and return it). 714480093f4SDimitry Andric if (Expected<std::vector<DWARFLocationExpression>> Loc = 715480093f4SDimitry Andric Die.getLocations(DW_AT_location)) { 716480093f4SDimitry Andric for (const auto &Entry : *Loc) { 717480093f4SDimitry Andric DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0); 7185ffd83dbSDimitry Andric DWARFExpression Expression(Data, U->getAddressByteSize(), 7195ffd83dbSDimitry Andric U->getFormParams().Format); 720349cc55cSDimitry Andric bool Error = 721349cc55cSDimitry Andric any_of(Expression, [](const DWARFExpression::Operation &Op) { 7220b57cec5SDimitry Andric return Op.isError(); 7230b57cec5SDimitry Andric }); 7240b57cec5SDimitry Andric if (Error || !Expression.verify(U)) 725*0fca6ea1SDimitry Andric ReportError("Invalid DWARF expressions", 726*0fca6ea1SDimitry Andric "DIE contains invalid DWARF expression:"); 7270b57cec5SDimitry Andric } 7280eae32dcSDimitry Andric } else if (Error Err = handleErrors( 7290eae32dcSDimitry Andric Loc.takeError(), [&](std::unique_ptr<ResolverError> E) { 7300eae32dcSDimitry Andric return U->isDWOUnit() ? Error::success() 7310eae32dcSDimitry Andric : Error(std::move(E)); 7320eae32dcSDimitry Andric })) 733*0fca6ea1SDimitry Andric ReportError("Invalid DW_AT_location", toString(std::move(Err))); 7340b57cec5SDimitry Andric break; 7350b57cec5SDimitry Andric } 7360b57cec5SDimitry Andric case DW_AT_specification: 7370b57cec5SDimitry Andric case DW_AT_abstract_origin: { 7380b57cec5SDimitry Andric if (auto ReferencedDie = Die.getAttributeValueAsReferencedDie(Attr)) { 7390b57cec5SDimitry Andric auto DieTag = Die.getTag(); 7400b57cec5SDimitry Andric auto RefTag = ReferencedDie.getTag(); 7410b57cec5SDimitry Andric if (DieTag == RefTag) 7420b57cec5SDimitry Andric break; 7430b57cec5SDimitry Andric if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram) 7440b57cec5SDimitry Andric break; 7450b57cec5SDimitry Andric if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member) 7460b57cec5SDimitry Andric break; 7478bcb0991SDimitry Andric // This might be reference to a function declaration. 7488bcb0991SDimitry Andric if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram) 7498bcb0991SDimitry Andric break; 750*0fca6ea1SDimitry Andric ReportError("Incompatible DW_AT_abstract_origin tag reference", 751*0fca6ea1SDimitry Andric "DIE with tag " + TagString(DieTag) + " has " + 7520b57cec5SDimitry Andric AttributeString(Attr) + 7530b57cec5SDimitry Andric " that points to DIE with " 7540b57cec5SDimitry Andric "incompatible tag " + 7550b57cec5SDimitry Andric TagString(RefTag)); 7560b57cec5SDimitry Andric } 7570b57cec5SDimitry Andric break; 7580b57cec5SDimitry Andric } 7590b57cec5SDimitry Andric case DW_AT_type: { 7600b57cec5SDimitry Andric DWARFDie TypeDie = Die.getAttributeValueAsReferencedDie(DW_AT_type); 7610b57cec5SDimitry Andric if (TypeDie && !isType(TypeDie.getTag())) { 762*0fca6ea1SDimitry Andric ReportError("Incompatible DW_AT_type attribute tag", 763*0fca6ea1SDimitry Andric "DIE has " + AttributeString(Attr) + 7640b57cec5SDimitry Andric " with incompatible tag " + TagString(TypeDie.getTag())); 7650b57cec5SDimitry Andric } 7660b57cec5SDimitry Andric break; 7670b57cec5SDimitry Andric } 768e8d8bef9SDimitry Andric case DW_AT_call_file: 769e8d8bef9SDimitry Andric case DW_AT_decl_file: { 770e8d8bef9SDimitry Andric if (auto FileIdx = AttrValue.Value.getAsUnsignedConstant()) { 7710eae32dcSDimitry Andric if (U->isDWOUnit() && !U->isTypeUnit()) 7720eae32dcSDimitry Andric break; 773e8d8bef9SDimitry Andric const auto *LT = U->getContext().getLineTableForUnit(U); 774e8d8bef9SDimitry Andric if (LT) { 775e8d8bef9SDimitry Andric if (!LT->hasFileAtIndex(*FileIdx)) { 776e8d8bef9SDimitry Andric bool IsZeroIndexed = LT->Prologue.getVersion() >= 5; 777bdd1243dSDimitry Andric if (std::optional<uint64_t> LastFileIdx = 778bdd1243dSDimitry Andric LT->getLastValidFileIndex()) { 779*0fca6ea1SDimitry Andric ReportError("Invalid file index in DW_AT_decl_file", 780*0fca6ea1SDimitry Andric "DIE has " + AttributeString(Attr) + 781e8d8bef9SDimitry Andric " with an invalid file index " + 782e8d8bef9SDimitry Andric llvm::formatv("{0}", *FileIdx) + 783*0fca6ea1SDimitry Andric " (valid values are [" + 784*0fca6ea1SDimitry Andric (IsZeroIndexed ? "0-" : "1-") + 785e8d8bef9SDimitry Andric llvm::formatv("{0}", *LastFileIdx) + "])"); 786e8d8bef9SDimitry Andric } else { 787*0fca6ea1SDimitry Andric ReportError("Invalid file index in DW_AT_decl_file", 788*0fca6ea1SDimitry Andric "DIE has " + AttributeString(Attr) + 789e8d8bef9SDimitry Andric " with an invalid file index " + 790e8d8bef9SDimitry Andric llvm::formatv("{0}", *FileIdx) + 791e8d8bef9SDimitry Andric " (the file table in the prologue is empty)"); 792e8d8bef9SDimitry Andric } 793e8d8bef9SDimitry Andric } 794e8d8bef9SDimitry Andric } else { 795*0fca6ea1SDimitry Andric ReportError( 796*0fca6ea1SDimitry Andric "File index in DW_AT_decl_file reference CU with no line table", 797*0fca6ea1SDimitry Andric "DIE has " + AttributeString(Attr) + 798e8d8bef9SDimitry Andric " that references a file with index " + 799e8d8bef9SDimitry Andric llvm::formatv("{0}", *FileIdx) + 800e8d8bef9SDimitry Andric " and the compile unit has no line table"); 801e8d8bef9SDimitry Andric } 802e8d8bef9SDimitry Andric } else { 803*0fca6ea1SDimitry Andric ReportError("Invalid encoding in DW_AT_decl_file", 804*0fca6ea1SDimitry Andric "DIE has " + AttributeString(Attr) + 805e8d8bef9SDimitry Andric " with invalid encoding"); 806e8d8bef9SDimitry Andric } 807e8d8bef9SDimitry Andric break; 808e8d8bef9SDimitry Andric } 809753f127fSDimitry Andric case DW_AT_call_line: 810753f127fSDimitry Andric case DW_AT_decl_line: { 811753f127fSDimitry Andric if (!AttrValue.Value.getAsUnsignedConstant()) { 812*0fca6ea1SDimitry Andric ReportError( 813*0fca6ea1SDimitry Andric Attr == DW_AT_call_line ? "Invalid file index in DW_AT_decl_line" 814*0fca6ea1SDimitry Andric : "Invalid file index in DW_AT_call_line", 815*0fca6ea1SDimitry Andric "DIE has " + AttributeString(Attr) + " with invalid encoding"); 816753f127fSDimitry Andric } 817753f127fSDimitry Andric break; 818753f127fSDimitry Andric } 8190b57cec5SDimitry Andric default: 8200b57cec5SDimitry Andric break; 8210b57cec5SDimitry Andric } 8220b57cec5SDimitry Andric return NumErrors; 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, 826349cc55cSDimitry Andric DWARFAttribute &AttrValue, 827349cc55cSDimitry Andric ReferenceMap &LocalReferences, 828349cc55cSDimitry Andric ReferenceMap &CrossUnitReferences) { 8290b57cec5SDimitry Andric auto DieCU = Die.getDwarfUnit(); 8300b57cec5SDimitry Andric unsigned NumErrors = 0; 8310b57cec5SDimitry Andric const auto Form = AttrValue.Value.getForm(); 8320b57cec5SDimitry Andric switch (Form) { 8330b57cec5SDimitry Andric case DW_FORM_ref1: 8340b57cec5SDimitry Andric case DW_FORM_ref2: 8350b57cec5SDimitry Andric case DW_FORM_ref4: 8360b57cec5SDimitry Andric case DW_FORM_ref8: 8370b57cec5SDimitry Andric case DW_FORM_ref_udata: { 8380b57cec5SDimitry Andric // Verify all CU relative references are valid CU offsets. 839*0fca6ea1SDimitry Andric std::optional<uint64_t> RefVal = AttrValue.Value.getAsRelativeReference(); 8400b57cec5SDimitry Andric assert(RefVal); 8410b57cec5SDimitry Andric if (RefVal) { 8420b57cec5SDimitry Andric auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); 8430b57cec5SDimitry Andric auto CUOffset = AttrValue.Value.getRawUValue(); 8440b57cec5SDimitry Andric if (CUOffset >= CUSize) { 8450b57cec5SDimitry Andric ++NumErrors; 846*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid CU offset", [&]() { 8470b57cec5SDimitry Andric error() << FormEncodingString(Form) << " CU offset " 8480b57cec5SDimitry Andric << format("0x%08" PRIx64, CUOffset) 8490b57cec5SDimitry Andric << " is invalid (must be less than CU size of " 8508bcb0991SDimitry Andric << format("0x%08" PRIx64, CUSize) << "):\n"; 8510b57cec5SDimitry Andric Die.dump(OS, 0, DumpOpts); 8520b57cec5SDimitry Andric dump(Die) << '\n'; 853*0fca6ea1SDimitry Andric }); 8540b57cec5SDimitry Andric } else { 8550b57cec5SDimitry Andric // Valid reference, but we will verify it points to an actual 8560b57cec5SDimitry Andric // DIE later. 857*0fca6ea1SDimitry Andric LocalReferences[AttrValue.Value.getUnit()->getOffset() + *RefVal] 858*0fca6ea1SDimitry Andric .insert(Die.getOffset()); 8590b57cec5SDimitry Andric } 8600b57cec5SDimitry Andric } 8610b57cec5SDimitry Andric break; 8620b57cec5SDimitry Andric } 8630b57cec5SDimitry Andric case DW_FORM_ref_addr: { 8640b57cec5SDimitry Andric // Verify all absolute DIE references have valid offsets in the 8650b57cec5SDimitry Andric // .debug_info section. 866*0fca6ea1SDimitry Andric std::optional<uint64_t> RefVal = AttrValue.Value.getAsDebugInfoReference(); 8670b57cec5SDimitry Andric assert(RefVal); 8680b57cec5SDimitry Andric if (RefVal) { 8690b57cec5SDimitry Andric if (*RefVal >= DieCU->getInfoSection().Data.size()) { 8700b57cec5SDimitry Andric ++NumErrors; 871*0fca6ea1SDimitry Andric ErrorCategory.Report("DW_FORM_ref_addr offset out of bounds", [&]() { 8720b57cec5SDimitry Andric error() << "DW_FORM_ref_addr offset beyond .debug_info " 8730b57cec5SDimitry Andric "bounds:\n"; 8740b57cec5SDimitry Andric dump(Die) << '\n'; 875*0fca6ea1SDimitry Andric }); 8760b57cec5SDimitry Andric } else { 8770b57cec5SDimitry Andric // Valid reference, but we will verify it points to an actual 8780b57cec5SDimitry Andric // DIE later. 879349cc55cSDimitry Andric CrossUnitReferences[*RefVal].insert(Die.getOffset()); 8800b57cec5SDimitry Andric } 8810b57cec5SDimitry Andric } 8820b57cec5SDimitry Andric break; 8830b57cec5SDimitry Andric } 8840eae32dcSDimitry Andric case DW_FORM_strp: 8850b57cec5SDimitry Andric case DW_FORM_strx: 8860b57cec5SDimitry Andric case DW_FORM_strx1: 8870b57cec5SDimitry Andric case DW_FORM_strx2: 8880b57cec5SDimitry Andric case DW_FORM_strx3: 88906c3fb27SDimitry Andric case DW_FORM_strx4: 89006c3fb27SDimitry Andric case DW_FORM_line_strp: { 8910eae32dcSDimitry Andric if (Error E = AttrValue.Value.getAsCString().takeError()) { 8920b57cec5SDimitry Andric ++NumErrors; 893*0fca6ea1SDimitry Andric std::string ErrMsg = toString(std::move(E)); 894*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid DW_FORM attribute", [&]() { 895*0fca6ea1SDimitry Andric error() << ErrMsg << ":\n"; 8960b57cec5SDimitry Andric dump(Die) << '\n'; 897*0fca6ea1SDimitry Andric }); 8980b57cec5SDimitry Andric } 8990b57cec5SDimitry Andric break; 9000b57cec5SDimitry Andric } 9010b57cec5SDimitry Andric default: 9020b57cec5SDimitry Andric break; 9030b57cec5SDimitry Andric } 9040b57cec5SDimitry Andric return NumErrors; 9050b57cec5SDimitry Andric } 9060b57cec5SDimitry Andric 907349cc55cSDimitry Andric unsigned DWARFVerifier::verifyDebugInfoReferences( 908349cc55cSDimitry Andric const ReferenceMap &References, 909349cc55cSDimitry Andric llvm::function_ref<DWARFUnit *(uint64_t)> GetUnitForOffset) { 910349cc55cSDimitry Andric auto GetDIEForOffset = [&](uint64_t Offset) { 911349cc55cSDimitry Andric if (DWARFUnit *U = GetUnitForOffset(Offset)) 912349cc55cSDimitry Andric return U->getDIEForOffset(Offset); 913349cc55cSDimitry Andric return DWARFDie(); 914349cc55cSDimitry Andric }; 9150b57cec5SDimitry Andric unsigned NumErrors = 0; 916480093f4SDimitry Andric for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair : 917349cc55cSDimitry Andric References) { 918349cc55cSDimitry Andric if (GetDIEForOffset(Pair.first)) 9190b57cec5SDimitry Andric continue; 9200b57cec5SDimitry Andric ++NumErrors; 921*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid DIE reference", [&]() { 9220b57cec5SDimitry Andric error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first) 9230b57cec5SDimitry Andric << ". Offset is in between DIEs:\n"; 9240b57cec5SDimitry Andric for (auto Offset : Pair.second) 925349cc55cSDimitry Andric dump(GetDIEForOffset(Offset)) << '\n'; 9260b57cec5SDimitry Andric OS << "\n"; 927*0fca6ea1SDimitry Andric }); 9280b57cec5SDimitry Andric } 9290b57cec5SDimitry Andric return NumErrors; 9300b57cec5SDimitry Andric } 9310b57cec5SDimitry Andric 9320b57cec5SDimitry Andric void DWARFVerifier::verifyDebugLineStmtOffsets() { 9330b57cec5SDimitry Andric std::map<uint64_t, DWARFDie> StmtListToDie; 9340b57cec5SDimitry Andric for (const auto &CU : DCtx.compile_units()) { 9350b57cec5SDimitry Andric auto Die = CU->getUnitDIE(); 9360b57cec5SDimitry Andric // Get the attribute value as a section offset. No need to produce an 9370b57cec5SDimitry Andric // error here if the encoding isn't correct because we validate this in 9380b57cec5SDimitry Andric // the .debug_info verifier. 9390b57cec5SDimitry Andric auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list)); 9400b57cec5SDimitry Andric if (!StmtSectionOffset) 9410b57cec5SDimitry Andric continue; 9428bcb0991SDimitry Andric const uint64_t LineTableOffset = *StmtSectionOffset; 9430b57cec5SDimitry Andric auto LineTable = DCtx.getLineTableForUnit(CU.get()); 9440b57cec5SDimitry Andric if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) { 9450b57cec5SDimitry Andric if (!LineTable) { 9460b57cec5SDimitry Andric ++NumDebugLineErrors; 947*0fca6ea1SDimitry Andric ErrorCategory.Report("Unparsable .debug_line entry", [&]() { 9488bcb0991SDimitry Andric error() << ".debug_line[" << format("0x%08" PRIx64, LineTableOffset) 9490b57cec5SDimitry Andric << "] was not able to be parsed for CU:\n"; 9500b57cec5SDimitry Andric dump(Die) << '\n'; 951*0fca6ea1SDimitry Andric }); 9520b57cec5SDimitry Andric continue; 9530b57cec5SDimitry Andric } 9540b57cec5SDimitry Andric } else { 9550b57cec5SDimitry Andric // Make sure we don't get a valid line table back if the offset is wrong. 9560b57cec5SDimitry Andric assert(LineTable == nullptr); 9570b57cec5SDimitry Andric // Skip this line table as it isn't valid. No need to create an error 9580b57cec5SDimitry Andric // here because we validate this in the .debug_info verifier. 9590b57cec5SDimitry Andric continue; 9600b57cec5SDimitry Andric } 9610b57cec5SDimitry Andric auto Iter = StmtListToDie.find(LineTableOffset); 9620b57cec5SDimitry Andric if (Iter != StmtListToDie.end()) { 9630b57cec5SDimitry Andric ++NumDebugLineErrors; 964*0fca6ea1SDimitry Andric ErrorCategory.Report("Identical DW_AT_stmt_list section offset", [&]() { 9650b57cec5SDimitry Andric error() << "two compile unit DIEs, " 9668bcb0991SDimitry Andric << format("0x%08" PRIx64, Iter->second.getOffset()) << " and " 9678bcb0991SDimitry Andric << format("0x%08" PRIx64, Die.getOffset()) 9680b57cec5SDimitry Andric << ", have the same DW_AT_stmt_list section offset:\n"; 9690b57cec5SDimitry Andric dump(Iter->second); 9700b57cec5SDimitry Andric dump(Die) << '\n'; 971*0fca6ea1SDimitry Andric }); 9720b57cec5SDimitry Andric // Already verified this line table before, no need to do it again. 9730b57cec5SDimitry Andric continue; 9740b57cec5SDimitry Andric } 9750b57cec5SDimitry Andric StmtListToDie[LineTableOffset] = Die; 9760b57cec5SDimitry Andric } 9770b57cec5SDimitry Andric } 9780b57cec5SDimitry Andric 9790b57cec5SDimitry Andric void DWARFVerifier::verifyDebugLineRows() { 9800b57cec5SDimitry Andric for (const auto &CU : DCtx.compile_units()) { 9810b57cec5SDimitry Andric auto Die = CU->getUnitDIE(); 9820b57cec5SDimitry Andric auto LineTable = DCtx.getLineTableForUnit(CU.get()); 9830b57cec5SDimitry Andric // If there is no line table we will have created an error in the 9840b57cec5SDimitry Andric // .debug_info verifier or in verifyDebugLineStmtOffsets(). 9850b57cec5SDimitry Andric if (!LineTable) 9860b57cec5SDimitry Andric continue; 9870b57cec5SDimitry Andric 9880b57cec5SDimitry Andric // Verify prologue. 98906c3fb27SDimitry Andric bool isDWARF5 = LineTable->Prologue.getVersion() >= 5; 9900b57cec5SDimitry Andric uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size(); 99106c3fb27SDimitry Andric uint32_t MinFileIndex = isDWARF5 ? 0 : 1; 99206c3fb27SDimitry Andric uint32_t FileIndex = MinFileIndex; 9930b57cec5SDimitry Andric StringMap<uint16_t> FullPathMap; 9940b57cec5SDimitry Andric for (const auto &FileName : LineTable->Prologue.FileNames) { 9950b57cec5SDimitry Andric // Verify directory index. 9960b57cec5SDimitry Andric if (FileName.DirIdx > MaxDirIndex) { 9970b57cec5SDimitry Andric ++NumDebugLineErrors; 998*0fca6ea1SDimitry Andric ErrorCategory.Report( 999*0fca6ea1SDimitry Andric "Invalid index in .debug_line->prologue.file_names->dir_idx", 1000*0fca6ea1SDimitry Andric [&]() { 10010b57cec5SDimitry Andric error() << ".debug_line[" 10020b57cec5SDimitry Andric << format("0x%08" PRIx64, 10030b57cec5SDimitry Andric *toSectionOffset(Die.find(DW_AT_stmt_list))) 10040b57cec5SDimitry Andric << "].prologue.file_names[" << FileIndex 1005*0fca6ea1SDimitry Andric << "].dir_idx contains an invalid index: " 1006*0fca6ea1SDimitry Andric << FileName.DirIdx << "\n"; 1007*0fca6ea1SDimitry Andric }); 10080b57cec5SDimitry Andric } 10090b57cec5SDimitry Andric 10100b57cec5SDimitry Andric // Check file paths for duplicates. 10110b57cec5SDimitry Andric std::string FullPath; 10120b57cec5SDimitry Andric const bool HasFullPath = LineTable->getFileNameByIndex( 10130b57cec5SDimitry Andric FileIndex, CU->getCompilationDir(), 10140b57cec5SDimitry Andric DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath); 10150b57cec5SDimitry Andric assert(HasFullPath && "Invalid index?"); 10160b57cec5SDimitry Andric (void)HasFullPath; 10170b57cec5SDimitry Andric auto It = FullPathMap.find(FullPath); 10180b57cec5SDimitry Andric if (It == FullPathMap.end()) 10190b57cec5SDimitry Andric FullPathMap[FullPath] = FileIndex; 1020*0fca6ea1SDimitry Andric else if (It->second != FileIndex && DumpOpts.Verbose) { 10210b57cec5SDimitry Andric warn() << ".debug_line[" 10220b57cec5SDimitry Andric << format("0x%08" PRIx64, 10230b57cec5SDimitry Andric *toSectionOffset(Die.find(DW_AT_stmt_list))) 10240b57cec5SDimitry Andric << "].prologue.file_names[" << FileIndex 10250b57cec5SDimitry Andric << "] is a duplicate of file_names[" << It->second << "]\n"; 10260b57cec5SDimitry Andric } 10270b57cec5SDimitry Andric 10280b57cec5SDimitry Andric FileIndex++; 10290b57cec5SDimitry Andric } 10300b57cec5SDimitry Andric 1031*0fca6ea1SDimitry Andric // Nothing to verify in a line table with a single row containing the end 1032*0fca6ea1SDimitry Andric // sequence. 1033*0fca6ea1SDimitry Andric if (LineTable->Rows.size() == 1 && LineTable->Rows.front().EndSequence) 1034*0fca6ea1SDimitry Andric continue; 1035*0fca6ea1SDimitry Andric 10360b57cec5SDimitry Andric // Verify rows. 10370b57cec5SDimitry Andric uint64_t PrevAddress = 0; 10380b57cec5SDimitry Andric uint32_t RowIndex = 0; 10390b57cec5SDimitry Andric for (const auto &Row : LineTable->Rows) { 10400b57cec5SDimitry Andric // Verify row address. 10410b57cec5SDimitry Andric if (Row.Address.Address < PrevAddress) { 10420b57cec5SDimitry Andric ++NumDebugLineErrors; 1043*0fca6ea1SDimitry Andric ErrorCategory.Report( 1044*0fca6ea1SDimitry Andric "decreasing address between debug_line rows", [&]() { 10450b57cec5SDimitry Andric error() << ".debug_line[" 10460b57cec5SDimitry Andric << format("0x%08" PRIx64, 10470b57cec5SDimitry Andric *toSectionOffset(Die.find(DW_AT_stmt_list))) 10480b57cec5SDimitry Andric << "] row[" << RowIndex 10490b57cec5SDimitry Andric << "] decreases in address from previous row:\n"; 10500b57cec5SDimitry Andric 10515ffd83dbSDimitry Andric DWARFDebugLine::Row::dumpTableHeader(OS, 0); 10520b57cec5SDimitry Andric if (RowIndex > 0) 10530b57cec5SDimitry Andric LineTable->Rows[RowIndex - 1].dump(OS); 10540b57cec5SDimitry Andric Row.dump(OS); 10550b57cec5SDimitry Andric OS << '\n'; 1056*0fca6ea1SDimitry Andric }); 10570b57cec5SDimitry Andric } 10580b57cec5SDimitry Andric 1059*0fca6ea1SDimitry Andric if (!LineTable->hasFileAtIndex(Row.File)) { 10600b57cec5SDimitry Andric ++NumDebugLineErrors; 1061*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid file index in debug_line", [&]() { 10620b57cec5SDimitry Andric error() << ".debug_line[" 10630b57cec5SDimitry Andric << format("0x%08" PRIx64, 10640b57cec5SDimitry Andric *toSectionOffset(Die.find(DW_AT_stmt_list))) 10650b57cec5SDimitry Andric << "][" << RowIndex << "] has invalid file index " << Row.File 106606c3fb27SDimitry Andric << " (valid values are [" << MinFileIndex << ',' 10670b57cec5SDimitry Andric << LineTable->Prologue.FileNames.size() 10680b57cec5SDimitry Andric << (isDWARF5 ? ")" : "]") << "):\n"; 10695ffd83dbSDimitry Andric DWARFDebugLine::Row::dumpTableHeader(OS, 0); 10700b57cec5SDimitry Andric Row.dump(OS); 10710b57cec5SDimitry Andric OS << '\n'; 1072*0fca6ea1SDimitry Andric }); 10730b57cec5SDimitry Andric } 10740b57cec5SDimitry Andric if (Row.EndSequence) 10750b57cec5SDimitry Andric PrevAddress = 0; 10760b57cec5SDimitry Andric else 10770b57cec5SDimitry Andric PrevAddress = Row.Address.Address; 10780b57cec5SDimitry Andric ++RowIndex; 10790b57cec5SDimitry Andric } 10800b57cec5SDimitry Andric } 10810b57cec5SDimitry Andric } 10820b57cec5SDimitry Andric 10830b57cec5SDimitry Andric DWARFVerifier::DWARFVerifier(raw_ostream &S, DWARFContext &D, 10840b57cec5SDimitry Andric DIDumpOptions DumpOpts) 10850b57cec5SDimitry Andric : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)), IsObjectFile(false), 10860b57cec5SDimitry Andric IsMachOObject(false) { 1087*0fca6ea1SDimitry Andric ErrorCategory.ShowDetail(this->DumpOpts.Verbose || 1088*0fca6ea1SDimitry Andric !this->DumpOpts.ShowAggregateErrors); 10890b57cec5SDimitry Andric if (const auto *F = DCtx.getDWARFObj().getFile()) { 10900b57cec5SDimitry Andric IsObjectFile = F->isRelocatableObject(); 10910b57cec5SDimitry Andric IsMachOObject = F->isMachO(); 10920b57cec5SDimitry Andric } 10930b57cec5SDimitry Andric } 10940b57cec5SDimitry Andric 10950b57cec5SDimitry Andric bool DWARFVerifier::handleDebugLine() { 10960b57cec5SDimitry Andric NumDebugLineErrors = 0; 10970b57cec5SDimitry Andric OS << "Verifying .debug_line...\n"; 10980b57cec5SDimitry Andric verifyDebugLineStmtOffsets(); 10990b57cec5SDimitry Andric verifyDebugLineRows(); 11000b57cec5SDimitry Andric return NumDebugLineErrors == 0; 11010b57cec5SDimitry Andric } 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection, 11040b57cec5SDimitry Andric DataExtractor *StrData, 11050b57cec5SDimitry Andric const char *SectionName) { 11060b57cec5SDimitry Andric unsigned NumErrors = 0; 11070b57cec5SDimitry Andric DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection, 11080b57cec5SDimitry Andric DCtx.isLittleEndian(), 0); 11090b57cec5SDimitry Andric AppleAcceleratorTable AccelTable(AccelSectionData, *StrData); 11100b57cec5SDimitry Andric 11110b57cec5SDimitry Andric OS << "Verifying " << SectionName << "...\n"; 11120b57cec5SDimitry Andric 11130b57cec5SDimitry Andric // Verify that the fixed part of the header is not too short. 11140b57cec5SDimitry Andric if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) { 1115*0fca6ea1SDimitry Andric ErrorCategory.Report("Section is too small to fit a section header", [&]() { 11160b57cec5SDimitry Andric error() << "Section is too small to fit a section header.\n"; 1117*0fca6ea1SDimitry Andric }); 11180b57cec5SDimitry Andric return 1; 11190b57cec5SDimitry Andric } 11200b57cec5SDimitry Andric 11210b57cec5SDimitry Andric // Verify that the section is not too short. 11220b57cec5SDimitry Andric if (Error E = AccelTable.extract()) { 1123*0fca6ea1SDimitry Andric std::string Msg = toString(std::move(E)); 1124*0fca6ea1SDimitry Andric ErrorCategory.Report("Section is too small to fit a section header", 1125*0fca6ea1SDimitry Andric [&]() { error() << Msg << '\n'; }); 11260b57cec5SDimitry Andric return 1; 11270b57cec5SDimitry Andric } 11280b57cec5SDimitry Andric 11290b57cec5SDimitry Andric // Verify that all buckets have a valid hash index or are empty. 11300b57cec5SDimitry Andric uint32_t NumBuckets = AccelTable.getNumBuckets(); 11310b57cec5SDimitry Andric uint32_t NumHashes = AccelTable.getNumHashes(); 11320b57cec5SDimitry Andric 11338bcb0991SDimitry Andric uint64_t BucketsOffset = 11340b57cec5SDimitry Andric AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength(); 11358bcb0991SDimitry Andric uint64_t HashesBase = BucketsOffset + NumBuckets * 4; 11368bcb0991SDimitry Andric uint64_t OffsetsBase = HashesBase + NumHashes * 4; 11370b57cec5SDimitry Andric for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) { 11380b57cec5SDimitry Andric uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset); 11390b57cec5SDimitry Andric if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) { 1140*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid hash index", [&]() { 11410b57cec5SDimitry Andric error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx, 11420b57cec5SDimitry Andric HashIdx); 1143*0fca6ea1SDimitry Andric }); 11440b57cec5SDimitry Andric ++NumErrors; 11450b57cec5SDimitry Andric } 11460b57cec5SDimitry Andric } 11470b57cec5SDimitry Andric uint32_t NumAtoms = AccelTable.getAtomsDesc().size(); 11480b57cec5SDimitry Andric if (NumAtoms == 0) { 1149*0fca6ea1SDimitry Andric ErrorCategory.Report("No atoms", [&]() { 11500b57cec5SDimitry Andric error() << "No atoms: failed to read HashData.\n"; 1151*0fca6ea1SDimitry Andric }); 11520b57cec5SDimitry Andric return 1; 11530b57cec5SDimitry Andric } 11540b57cec5SDimitry Andric if (!AccelTable.validateForms()) { 1155*0fca6ea1SDimitry Andric ErrorCategory.Report("Unsupported form", [&]() { 11560b57cec5SDimitry Andric error() << "Unsupported form: failed to read HashData.\n"; 1157*0fca6ea1SDimitry Andric }); 11580b57cec5SDimitry Andric return 1; 11590b57cec5SDimitry Andric } 11600b57cec5SDimitry Andric 11610b57cec5SDimitry Andric for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) { 11628bcb0991SDimitry Andric uint64_t HashOffset = HashesBase + 4 * HashIdx; 11638bcb0991SDimitry Andric uint64_t DataOffset = OffsetsBase + 4 * HashIdx; 11640b57cec5SDimitry Andric uint32_t Hash = AccelSectionData.getU32(&HashOffset); 11658bcb0991SDimitry Andric uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset); 11660b57cec5SDimitry Andric if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset, 11670b57cec5SDimitry Andric sizeof(uint64_t))) { 1168*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid HashData offset", [&]() { 11698bcb0991SDimitry Andric error() << format("Hash[%d] has invalid HashData offset: " 11708bcb0991SDimitry Andric "0x%08" PRIx64 ".\n", 11710b57cec5SDimitry Andric HashIdx, HashDataOffset); 1172*0fca6ea1SDimitry Andric }); 11730b57cec5SDimitry Andric ++NumErrors; 11740b57cec5SDimitry Andric } 11750b57cec5SDimitry Andric 11768bcb0991SDimitry Andric uint64_t StrpOffset; 11778bcb0991SDimitry Andric uint64_t StringOffset; 11780b57cec5SDimitry Andric uint32_t StringCount = 0; 11798bcb0991SDimitry Andric uint64_t Offset; 11800b57cec5SDimitry Andric unsigned Tag; 11810b57cec5SDimitry Andric while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) { 11820b57cec5SDimitry Andric const uint32_t NumHashDataObjects = 11830b57cec5SDimitry Andric AccelSectionData.getU32(&HashDataOffset); 11840b57cec5SDimitry Andric for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects; 11850b57cec5SDimitry Andric ++HashDataIdx) { 11868bcb0991SDimitry Andric std::tie(Offset, Tag) = AccelTable.readAtoms(&HashDataOffset); 11870b57cec5SDimitry Andric auto Die = DCtx.getDIEForOffset(Offset); 11880b57cec5SDimitry Andric if (!Die) { 11890b57cec5SDimitry Andric const uint32_t BucketIdx = 11900b57cec5SDimitry Andric NumBuckets ? (Hash % NumBuckets) : UINT32_MAX; 11910b57cec5SDimitry Andric StringOffset = StrpOffset; 11920b57cec5SDimitry Andric const char *Name = StrData->getCStr(&StringOffset); 11930b57cec5SDimitry Andric if (!Name) 11940b57cec5SDimitry Andric Name = "<NULL>"; 11950b57cec5SDimitry Andric 1196*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid DIE offset", [&]() { 11970b57cec5SDimitry Andric error() << format( 11980b57cec5SDimitry Andric "%s Bucket[%d] Hash[%d] = 0x%08x " 11998bcb0991SDimitry Andric "Str[%u] = 0x%08" PRIx64 " DIE[%d] = 0x%08" PRIx64 " " 12008bcb0991SDimitry Andric "is not a valid DIE offset for \"%s\".\n", 12010b57cec5SDimitry Andric SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset, 12020b57cec5SDimitry Andric HashDataIdx, Offset, Name); 1203*0fca6ea1SDimitry Andric }); 12040b57cec5SDimitry Andric 12050b57cec5SDimitry Andric ++NumErrors; 12060b57cec5SDimitry Andric continue; 12070b57cec5SDimitry Andric } 12080b57cec5SDimitry Andric if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) { 1209*0fca6ea1SDimitry Andric ErrorCategory.Report("Mismatched Tag in accellerator table", [&]() { 12100b57cec5SDimitry Andric error() << "Tag " << dwarf::TagString(Tag) 12110b57cec5SDimitry Andric << " in accelerator table does not match Tag " 1212*0fca6ea1SDimitry Andric << dwarf::TagString(Die.getTag()) << " of DIE[" 1213*0fca6ea1SDimitry Andric << HashDataIdx << "].\n"; 1214*0fca6ea1SDimitry Andric }); 12150b57cec5SDimitry Andric ++NumErrors; 12160b57cec5SDimitry Andric } 12170b57cec5SDimitry Andric } 12180b57cec5SDimitry Andric ++StringCount; 12190b57cec5SDimitry Andric } 12200b57cec5SDimitry Andric } 12210b57cec5SDimitry Andric return NumErrors; 12220b57cec5SDimitry Andric } 12230b57cec5SDimitry Andric 12240b57cec5SDimitry Andric unsigned 12250b57cec5SDimitry Andric DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) { 12260b57cec5SDimitry Andric // A map from CU offset to the (first) Name Index offset which claims to index 12270b57cec5SDimitry Andric // this CU. 12288bcb0991SDimitry Andric DenseMap<uint64_t, uint64_t> CUMap; 12298bcb0991SDimitry Andric const uint64_t NotIndexed = std::numeric_limits<uint64_t>::max(); 12300b57cec5SDimitry Andric 12310b57cec5SDimitry Andric CUMap.reserve(DCtx.getNumCompileUnits()); 12320b57cec5SDimitry Andric for (const auto &CU : DCtx.compile_units()) 12330b57cec5SDimitry Andric CUMap[CU->getOffset()] = NotIndexed; 12340b57cec5SDimitry Andric 12350b57cec5SDimitry Andric unsigned NumErrors = 0; 12360b57cec5SDimitry Andric for (const DWARFDebugNames::NameIndex &NI : AccelTable) { 12370b57cec5SDimitry Andric if (NI.getCUCount() == 0) { 1238*0fca6ea1SDimitry Andric ErrorCategory.Report("Name Index doesn't index any CU", [&]() { 12390b57cec5SDimitry Andric error() << formatv("Name Index @ {0:x} does not index any CU\n", 12400b57cec5SDimitry Andric NI.getUnitOffset()); 1241*0fca6ea1SDimitry Andric }); 12420b57cec5SDimitry Andric ++NumErrors; 12430b57cec5SDimitry Andric continue; 12440b57cec5SDimitry Andric } 12450b57cec5SDimitry Andric for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) { 12468bcb0991SDimitry Andric uint64_t Offset = NI.getCUOffset(CU); 12470b57cec5SDimitry Andric auto Iter = CUMap.find(Offset); 12480b57cec5SDimitry Andric 12490b57cec5SDimitry Andric if (Iter == CUMap.end()) { 1250*0fca6ea1SDimitry Andric ErrorCategory.Report("Name Index references non-existing CU", [&]() { 12510b57cec5SDimitry Andric error() << formatv( 12520b57cec5SDimitry Andric "Name Index @ {0:x} references a non-existing CU @ {1:x}\n", 12530b57cec5SDimitry Andric NI.getUnitOffset(), Offset); 1254*0fca6ea1SDimitry Andric }); 12550b57cec5SDimitry Andric ++NumErrors; 12560b57cec5SDimitry Andric continue; 12570b57cec5SDimitry Andric } 12580b57cec5SDimitry Andric 12590b57cec5SDimitry Andric if (Iter->second != NotIndexed) { 1260*0fca6ea1SDimitry Andric ErrorCategory.Report("Duplicate Name Index", [&]() { 1261*0fca6ea1SDimitry Andric error() << formatv( 1262*0fca6ea1SDimitry Andric "Name Index @ {0:x} references a CU @ {1:x}, but " 12630b57cec5SDimitry Andric "this CU is already indexed by Name Index @ {2:x}\n", 12640b57cec5SDimitry Andric NI.getUnitOffset(), Offset, Iter->second); 1265*0fca6ea1SDimitry Andric }); 12660b57cec5SDimitry Andric continue; 12670b57cec5SDimitry Andric } 12680b57cec5SDimitry Andric Iter->second = NI.getUnitOffset(); 12690b57cec5SDimitry Andric } 12700b57cec5SDimitry Andric } 12710b57cec5SDimitry Andric 12720b57cec5SDimitry Andric for (const auto &KV : CUMap) { 12730b57cec5SDimitry Andric if (KV.second == NotIndexed) 12740b57cec5SDimitry Andric warn() << formatv("CU @ {0:x} not covered by any Name Index\n", KV.first); 12750b57cec5SDimitry Andric } 12760b57cec5SDimitry Andric 12770b57cec5SDimitry Andric return NumErrors; 12780b57cec5SDimitry Andric } 12790b57cec5SDimitry Andric 12800b57cec5SDimitry Andric unsigned 12810b57cec5SDimitry Andric DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI, 12820b57cec5SDimitry Andric const DataExtractor &StrData) { 12830b57cec5SDimitry Andric struct BucketInfo { 12840b57cec5SDimitry Andric uint32_t Bucket; 12850b57cec5SDimitry Andric uint32_t Index; 12860b57cec5SDimitry Andric 12870b57cec5SDimitry Andric constexpr BucketInfo(uint32_t Bucket, uint32_t Index) 12880b57cec5SDimitry Andric : Bucket(Bucket), Index(Index) {} 1289480093f4SDimitry Andric bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; } 12900b57cec5SDimitry Andric }; 12910b57cec5SDimitry Andric 12920b57cec5SDimitry Andric uint32_t NumErrors = 0; 12930b57cec5SDimitry Andric if (NI.getBucketCount() == 0) { 12940b57cec5SDimitry Andric warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n", 12950b57cec5SDimitry Andric NI.getUnitOffset()); 12960b57cec5SDimitry Andric return NumErrors; 12970b57cec5SDimitry Andric } 12980b57cec5SDimitry Andric 12990b57cec5SDimitry Andric // Build up a list of (Bucket, Index) pairs. We use this later to verify that 13000b57cec5SDimitry Andric // each Name is reachable from the appropriate bucket. 13010b57cec5SDimitry Andric std::vector<BucketInfo> BucketStarts; 13020b57cec5SDimitry Andric BucketStarts.reserve(NI.getBucketCount() + 1); 13030b57cec5SDimitry Andric for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) { 13040b57cec5SDimitry Andric uint32_t Index = NI.getBucketArrayEntry(Bucket); 13050b57cec5SDimitry Andric if (Index > NI.getNameCount()) { 1306*0fca6ea1SDimitry Andric ErrorCategory.Report("Name Index Bucket contains invalid value", [&]() { 13070b57cec5SDimitry Andric error() << formatv("Bucket {0} of Name Index @ {1:x} contains invalid " 13080b57cec5SDimitry Andric "value {2}. Valid range is [0, {3}].\n", 1309*0fca6ea1SDimitry Andric Bucket, NI.getUnitOffset(), Index, 1310*0fca6ea1SDimitry Andric NI.getNameCount()); 1311*0fca6ea1SDimitry Andric }); 13120b57cec5SDimitry Andric ++NumErrors; 13130b57cec5SDimitry Andric continue; 13140b57cec5SDimitry Andric } 13150b57cec5SDimitry Andric if (Index > 0) 13160b57cec5SDimitry Andric BucketStarts.emplace_back(Bucket, Index); 13170b57cec5SDimitry Andric } 13180b57cec5SDimitry Andric 13190b57cec5SDimitry Andric // If there were any buckets with invalid values, skip further checks as they 13200b57cec5SDimitry Andric // will likely produce many errors which will only confuse the actual root 13210b57cec5SDimitry Andric // problem. 13220b57cec5SDimitry Andric if (NumErrors > 0) 13230b57cec5SDimitry Andric return NumErrors; 13240b57cec5SDimitry Andric 13250b57cec5SDimitry Andric // Sort the list in the order of increasing "Index" entries. 13260b57cec5SDimitry Andric array_pod_sort(BucketStarts.begin(), BucketStarts.end()); 13270b57cec5SDimitry Andric 13280b57cec5SDimitry Andric // Insert a sentinel entry at the end, so we can check that the end of the 13290b57cec5SDimitry Andric // table is covered in the loop below. 13300b57cec5SDimitry Andric BucketStarts.emplace_back(NI.getBucketCount(), NI.getNameCount() + 1); 13310b57cec5SDimitry Andric 13320b57cec5SDimitry Andric // Loop invariant: NextUncovered is the (1-based) index of the first Name 13330b57cec5SDimitry Andric // which is not reachable by any of the buckets we processed so far (and 13340b57cec5SDimitry Andric // hasn't been reported as uncovered). 13350b57cec5SDimitry Andric uint32_t NextUncovered = 1; 13360b57cec5SDimitry Andric for (const BucketInfo &B : BucketStarts) { 13370b57cec5SDimitry Andric // Under normal circumstances B.Index be equal to NextUncovered, but it can 13380b57cec5SDimitry Andric // be less if a bucket points to names which are already known to be in some 13390b57cec5SDimitry Andric // bucket we processed earlier. In that case, we won't trigger this error, 13400b57cec5SDimitry Andric // but report the mismatched hash value error instead. (We know the hash 13410b57cec5SDimitry Andric // will not match because we have already verified that the name's hash 13420b57cec5SDimitry Andric // puts it into the previous bucket.) 13430b57cec5SDimitry Andric if (B.Index > NextUncovered) { 1344*0fca6ea1SDimitry Andric ErrorCategory.Report("Name table entries uncovered by hash table", [&]() { 13450b57cec5SDimitry Andric error() << formatv("Name Index @ {0:x}: Name table entries [{1}, {2}] " 13460b57cec5SDimitry Andric "are not covered by the hash table.\n", 13470b57cec5SDimitry Andric NI.getUnitOffset(), NextUncovered, B.Index - 1); 1348*0fca6ea1SDimitry Andric }); 13490b57cec5SDimitry Andric ++NumErrors; 13500b57cec5SDimitry Andric } 13510b57cec5SDimitry Andric uint32_t Idx = B.Index; 13520b57cec5SDimitry Andric 13530b57cec5SDimitry Andric // The rest of the checks apply only to non-sentinel entries. 13540b57cec5SDimitry Andric if (B.Bucket == NI.getBucketCount()) 13550b57cec5SDimitry Andric break; 13560b57cec5SDimitry Andric 13570b57cec5SDimitry Andric // This triggers if a non-empty bucket points to a name with a mismatched 13580b57cec5SDimitry Andric // hash. Clients are likely to interpret this as an empty bucket, because a 13590b57cec5SDimitry Andric // mismatched hash signals the end of a bucket, but if this is indeed an 13600b57cec5SDimitry Andric // empty bucket, the producer should have signalled this by marking the 13610b57cec5SDimitry Andric // bucket as empty. 13620b57cec5SDimitry Andric uint32_t FirstHash = NI.getHashArrayEntry(Idx); 13630b57cec5SDimitry Andric if (FirstHash % NI.getBucketCount() != B.Bucket) { 1364*0fca6ea1SDimitry Andric ErrorCategory.Report("Name Index point to mismatched hash value", [&]() { 13650b57cec5SDimitry Andric error() << formatv( 13660b57cec5SDimitry Andric "Name Index @ {0:x}: Bucket {1} is not empty but points to a " 13670b57cec5SDimitry Andric "mismatched hash value {2:x} (belonging to bucket {3}).\n", 13680b57cec5SDimitry Andric NI.getUnitOffset(), B.Bucket, FirstHash, 13690b57cec5SDimitry Andric FirstHash % NI.getBucketCount()); 1370*0fca6ea1SDimitry Andric }); 13710b57cec5SDimitry Andric ++NumErrors; 13720b57cec5SDimitry Andric } 13730b57cec5SDimitry Andric 13740b57cec5SDimitry Andric // This find the end of this bucket and also verifies that all the hashes in 13750b57cec5SDimitry Andric // this bucket are correct by comparing the stored hashes to the ones we 13760b57cec5SDimitry Andric // compute ourselves. 13770b57cec5SDimitry Andric while (Idx <= NI.getNameCount()) { 13780b57cec5SDimitry Andric uint32_t Hash = NI.getHashArrayEntry(Idx); 13790b57cec5SDimitry Andric if (Hash % NI.getBucketCount() != B.Bucket) 13800b57cec5SDimitry Andric break; 13810b57cec5SDimitry Andric 13820b57cec5SDimitry Andric const char *Str = NI.getNameTableEntry(Idx).getString(); 13830b57cec5SDimitry Andric if (caseFoldingDjbHash(Str) != Hash) { 1384*0fca6ea1SDimitry Andric ErrorCategory.Report( 1385*0fca6ea1SDimitry Andric "String hash doesn't match Name Index hash", [&]() { 1386*0fca6ea1SDimitry Andric error() << formatv( 1387*0fca6ea1SDimitry Andric "Name Index @ {0:x}: String ({1}) at index {2} " 13880b57cec5SDimitry Andric "hashes to {3:x}, but " 13890b57cec5SDimitry Andric "the Name Index hash is {4:x}\n", 1390*0fca6ea1SDimitry Andric NI.getUnitOffset(), Str, Idx, caseFoldingDjbHash(Str), Hash); 1391*0fca6ea1SDimitry Andric }); 13920b57cec5SDimitry Andric ++NumErrors; 13930b57cec5SDimitry Andric } 13940b57cec5SDimitry Andric 13950b57cec5SDimitry Andric ++Idx; 13960b57cec5SDimitry Andric } 13970b57cec5SDimitry Andric NextUncovered = std::max(NextUncovered, Idx); 13980b57cec5SDimitry Andric } 13990b57cec5SDimitry Andric return NumErrors; 14000b57cec5SDimitry Andric } 14010b57cec5SDimitry Andric 14020b57cec5SDimitry Andric unsigned DWARFVerifier::verifyNameIndexAttribute( 14030b57cec5SDimitry Andric const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr, 14040b57cec5SDimitry Andric DWARFDebugNames::AttributeEncoding AttrEnc) { 14050b57cec5SDimitry Andric StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form); 14060b57cec5SDimitry Andric if (FormName.empty()) { 1407*0fca6ea1SDimitry Andric ErrorCategory.Report("Unknown NameIndex Abbreviation", [&]() { 14080b57cec5SDimitry Andric error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " 14090b57cec5SDimitry Andric "unknown form: {3}.\n", 14100b57cec5SDimitry Andric NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, 14110b57cec5SDimitry Andric AttrEnc.Form); 1412*0fca6ea1SDimitry Andric }); 14130b57cec5SDimitry Andric return 1; 14140b57cec5SDimitry Andric } 14150b57cec5SDimitry Andric 14160b57cec5SDimitry Andric if (AttrEnc.Index == DW_IDX_type_hash) { 14170b57cec5SDimitry Andric if (AttrEnc.Form != dwarf::DW_FORM_data8) { 1418*0fca6ea1SDimitry Andric ErrorCategory.Report("Unexpected NameIndex Abbreviation", [&]() { 14190b57cec5SDimitry Andric error() << formatv( 14200b57cec5SDimitry Andric "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash " 14210b57cec5SDimitry Andric "uses an unexpected form {2} (should be {3}).\n", 14220b57cec5SDimitry Andric NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8); 1423*0fca6ea1SDimitry Andric }); 14240b57cec5SDimitry Andric return 1; 14250b57cec5SDimitry Andric } 14267a6dacacSDimitry Andric return 0; 14277a6dacacSDimitry Andric } 14287a6dacacSDimitry Andric 14297a6dacacSDimitry Andric if (AttrEnc.Index == dwarf::DW_IDX_parent) { 14307a6dacacSDimitry Andric constexpr static auto AllowedForms = {dwarf::Form::DW_FORM_flag_present, 14317a6dacacSDimitry Andric dwarf::Form::DW_FORM_ref4}; 14327a6dacacSDimitry Andric if (!is_contained(AllowedForms, AttrEnc.Form)) { 1433*0fca6ea1SDimitry Andric ErrorCategory.Report("Unexpected NameIndex Abbreviation", [&]() { 1434*0fca6ea1SDimitry Andric error() << formatv( 1435*0fca6ea1SDimitry Andric "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_parent " 14367a6dacacSDimitry Andric "uses an unexpected form {2} (should be " 14377a6dacacSDimitry Andric "DW_FORM_ref4 or DW_FORM_flag_present).\n", 14387a6dacacSDimitry Andric NI.getUnitOffset(), Abbr.Code, AttrEnc.Form); 1439*0fca6ea1SDimitry Andric }); 14407a6dacacSDimitry Andric return 1; 14417a6dacacSDimitry Andric } 14427a6dacacSDimitry Andric return 0; 14430b57cec5SDimitry Andric } 14440b57cec5SDimitry Andric 14450b57cec5SDimitry Andric // A list of known index attributes and their expected form classes. 14460b57cec5SDimitry Andric // DW_IDX_type_hash is handled specially in the check above, as it has a 14470b57cec5SDimitry Andric // specific form (not just a form class) we should expect. 14480b57cec5SDimitry Andric struct FormClassTable { 14490b57cec5SDimitry Andric dwarf::Index Index; 14500b57cec5SDimitry Andric DWARFFormValue::FormClass Class; 14510b57cec5SDimitry Andric StringLiteral ClassName; 14520b57cec5SDimitry Andric }; 14530b57cec5SDimitry Andric static constexpr FormClassTable Table[] = { 14540b57cec5SDimitry Andric {dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}}, 14550b57cec5SDimitry Andric {dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}}, 14560b57cec5SDimitry Andric {dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}}, 14570b57cec5SDimitry Andric }; 14580b57cec5SDimitry Andric 14590b57cec5SDimitry Andric ArrayRef<FormClassTable> TableRef(Table); 14600b57cec5SDimitry Andric auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) { 14610b57cec5SDimitry Andric return T.Index == AttrEnc.Index; 14620b57cec5SDimitry Andric }); 14630b57cec5SDimitry Andric if (Iter == TableRef.end()) { 14640b57cec5SDimitry Andric warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an " 14650b57cec5SDimitry Andric "unknown index attribute: {2}.\n", 14660b57cec5SDimitry Andric NI.getUnitOffset(), Abbr.Code, AttrEnc.Index); 14670b57cec5SDimitry Andric return 0; 14680b57cec5SDimitry Andric } 14690b57cec5SDimitry Andric 14700b57cec5SDimitry Andric if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) { 1471*0fca6ea1SDimitry Andric ErrorCategory.Report("Unexpected NameIndex Abbreviation", [&]() { 14720b57cec5SDimitry Andric error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " 14730b57cec5SDimitry Andric "unexpected form {3} (expected form class {4}).\n", 14740b57cec5SDimitry Andric NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, 14750b57cec5SDimitry Andric AttrEnc.Form, Iter->ClassName); 1476*0fca6ea1SDimitry Andric }); 14770b57cec5SDimitry Andric return 1; 14780b57cec5SDimitry Andric } 14790b57cec5SDimitry Andric return 0; 14800b57cec5SDimitry Andric } 14810b57cec5SDimitry Andric 14820b57cec5SDimitry Andric unsigned 14830b57cec5SDimitry Andric DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) { 14840b57cec5SDimitry Andric if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) { 14850b57cec5SDimitry Andric warn() << formatv("Name Index @ {0:x}: Verifying indexes of type units is " 14860b57cec5SDimitry Andric "not currently supported.\n", 14870b57cec5SDimitry Andric NI.getUnitOffset()); 14880b57cec5SDimitry Andric return 0; 14890b57cec5SDimitry Andric } 14900b57cec5SDimitry Andric 14910b57cec5SDimitry Andric unsigned NumErrors = 0; 14920b57cec5SDimitry Andric for (const auto &Abbrev : NI.getAbbrevs()) { 14930b57cec5SDimitry Andric StringRef TagName = dwarf::TagString(Abbrev.Tag); 14940b57cec5SDimitry Andric if (TagName.empty()) { 14950b57cec5SDimitry Andric warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an " 14960b57cec5SDimitry Andric "unknown tag: {2}.\n", 14970b57cec5SDimitry Andric NI.getUnitOffset(), Abbrev.Code, Abbrev.Tag); 14980b57cec5SDimitry Andric } 14990b57cec5SDimitry Andric SmallSet<unsigned, 5> Attributes; 15000b57cec5SDimitry Andric for (const auto &AttrEnc : Abbrev.Attributes) { 15010b57cec5SDimitry Andric if (!Attributes.insert(AttrEnc.Index).second) { 1502*0fca6ea1SDimitry Andric ErrorCategory.Report( 1503*0fca6ea1SDimitry Andric "NameIndex Abbreviateion contains multiple attributes", [&]() { 1504*0fca6ea1SDimitry Andric error() << formatv( 1505*0fca6ea1SDimitry Andric "NameIndex @ {0:x}: Abbreviation {1:x} contains " 15060b57cec5SDimitry Andric "multiple {2} attributes.\n", 15070b57cec5SDimitry Andric NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index); 1508*0fca6ea1SDimitry Andric }); 15090b57cec5SDimitry Andric ++NumErrors; 15100b57cec5SDimitry Andric continue; 15110b57cec5SDimitry Andric } 15120b57cec5SDimitry Andric NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc); 15130b57cec5SDimitry Andric } 15140b57cec5SDimitry Andric 15150b57cec5SDimitry Andric if (NI.getCUCount() > 1 && !Attributes.count(dwarf::DW_IDX_compile_unit)) { 1516*0fca6ea1SDimitry Andric ErrorCategory.Report("Abbreviation contains no attribute", [&]() { 15170b57cec5SDimitry Andric error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units " 15180b57cec5SDimitry Andric "and abbreviation {1:x} has no {2} attribute.\n", 15190b57cec5SDimitry Andric NI.getUnitOffset(), Abbrev.Code, 15200b57cec5SDimitry Andric dwarf::DW_IDX_compile_unit); 1521*0fca6ea1SDimitry Andric }); 15220b57cec5SDimitry Andric ++NumErrors; 15230b57cec5SDimitry Andric } 15240b57cec5SDimitry Andric if (!Attributes.count(dwarf::DW_IDX_die_offset)) { 1525*0fca6ea1SDimitry Andric ErrorCategory.Report("Abbreviate in NameIndex missing attribute", [&]() { 15260b57cec5SDimitry Andric error() << formatv( 15270b57cec5SDimitry Andric "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n", 15280b57cec5SDimitry Andric NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset); 1529*0fca6ea1SDimitry Andric }); 15300b57cec5SDimitry Andric ++NumErrors; 15310b57cec5SDimitry Andric } 15320b57cec5SDimitry Andric } 15330b57cec5SDimitry Andric return NumErrors; 15340b57cec5SDimitry Andric } 15350b57cec5SDimitry Andric 15365f757f3fSDimitry Andric static SmallVector<std::string, 3> getNames(const DWARFDie &DIE, 15375f757f3fSDimitry Andric bool IncludeStrippedTemplateNames, 15385f757f3fSDimitry Andric bool IncludeObjCNames = true, 15390b57cec5SDimitry Andric bool IncludeLinkageName = true) { 15405f757f3fSDimitry Andric SmallVector<std::string, 3> Result; 15415f757f3fSDimitry Andric if (const char *Str = DIE.getShortName()) { 15425f757f3fSDimitry Andric StringRef Name(Str); 15435f757f3fSDimitry Andric Result.emplace_back(Name); 15445f757f3fSDimitry Andric if (IncludeStrippedTemplateNames) { 15455f757f3fSDimitry Andric if (std::optional<StringRef> StrippedName = 15465f757f3fSDimitry Andric StripTemplateParameters(Result.back())) 15475f757f3fSDimitry Andric // Convert to std::string and push; emplacing the StringRef may trigger 15485f757f3fSDimitry Andric // a vector resize which may destroy the StringRef memory. 15495f757f3fSDimitry Andric Result.push_back(StrippedName->str()); 15505f757f3fSDimitry Andric } 15515f757f3fSDimitry Andric 15525f757f3fSDimitry Andric if (IncludeObjCNames) { 15535f757f3fSDimitry Andric if (std::optional<ObjCSelectorNames> ObjCNames = 15545f757f3fSDimitry Andric getObjCNamesIfSelector(Name)) { 15555f757f3fSDimitry Andric Result.emplace_back(ObjCNames->ClassName); 15565f757f3fSDimitry Andric Result.emplace_back(ObjCNames->Selector); 15575f757f3fSDimitry Andric if (ObjCNames->ClassNameNoCategory) 15585f757f3fSDimitry Andric Result.emplace_back(*ObjCNames->ClassNameNoCategory); 15595f757f3fSDimitry Andric if (ObjCNames->MethodNameNoCategory) 15605f757f3fSDimitry Andric Result.push_back(std::move(*ObjCNames->MethodNameNoCategory)); 15615f757f3fSDimitry Andric } 15625f757f3fSDimitry Andric } 15635f757f3fSDimitry Andric } else if (DIE.getTag() == dwarf::DW_TAG_namespace) 15640b57cec5SDimitry Andric Result.emplace_back("(anonymous namespace)"); 15650b57cec5SDimitry Andric 15660b57cec5SDimitry Andric if (IncludeLinkageName) { 15675e801ac6SDimitry Andric if (const char *Str = DIE.getLinkageName()) 15680b57cec5SDimitry Andric Result.emplace_back(Str); 15690b57cec5SDimitry Andric } 15700b57cec5SDimitry Andric 15710b57cec5SDimitry Andric return Result; 15720b57cec5SDimitry Andric } 15730b57cec5SDimitry Andric 15740b57cec5SDimitry Andric unsigned DWARFVerifier::verifyNameIndexEntries( 15750b57cec5SDimitry Andric const DWARFDebugNames::NameIndex &NI, 15760b57cec5SDimitry Andric const DWARFDebugNames::NameTableEntry &NTE) { 15770b57cec5SDimitry Andric // Verifying type unit indexes not supported. 15780b57cec5SDimitry Andric if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) 15790b57cec5SDimitry Andric return 0; 15800b57cec5SDimitry Andric 15810b57cec5SDimitry Andric const char *CStr = NTE.getString(); 15820b57cec5SDimitry Andric if (!CStr) { 1583*0fca6ea1SDimitry Andric ErrorCategory.Report("Unable to get string associated with name", [&]() { 1584*0fca6ea1SDimitry Andric error() << formatv("Name Index @ {0:x}: Unable to get string associated " 1585*0fca6ea1SDimitry Andric "with name {1}.\n", 15860b57cec5SDimitry Andric NI.getUnitOffset(), NTE.getIndex()); 1587*0fca6ea1SDimitry Andric }); 15880b57cec5SDimitry Andric return 1; 15890b57cec5SDimitry Andric } 15900b57cec5SDimitry Andric StringRef Str(CStr); 15910b57cec5SDimitry Andric 15920b57cec5SDimitry Andric unsigned NumErrors = 0; 15930b57cec5SDimitry Andric unsigned NumEntries = 0; 15948bcb0991SDimitry Andric uint64_t EntryID = NTE.getEntryOffset(); 15958bcb0991SDimitry Andric uint64_t NextEntryID = EntryID; 15960b57cec5SDimitry Andric Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&NextEntryID); 15970b57cec5SDimitry Andric for (; EntryOr; ++NumEntries, EntryID = NextEntryID, 15980b57cec5SDimitry Andric EntryOr = NI.getEntry(&NextEntryID)) { 15990b57cec5SDimitry Andric uint32_t CUIndex = *EntryOr->getCUIndex(); 16000b57cec5SDimitry Andric if (CUIndex > NI.getCUCount()) { 1601*0fca6ea1SDimitry Andric ErrorCategory.Report("Name Index entry contains invalid CU index", [&]() { 16020b57cec5SDimitry Andric error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an " 16030b57cec5SDimitry Andric "invalid CU index ({2}).\n", 16040b57cec5SDimitry Andric NI.getUnitOffset(), EntryID, CUIndex); 1605*0fca6ea1SDimitry Andric }); 16060b57cec5SDimitry Andric ++NumErrors; 16070b57cec5SDimitry Andric continue; 16080b57cec5SDimitry Andric } 16098bcb0991SDimitry Andric uint64_t CUOffset = NI.getCUOffset(CUIndex); 16100b57cec5SDimitry Andric uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset(); 16110b57cec5SDimitry Andric DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset); 16120b57cec5SDimitry Andric if (!DIE) { 1613*0fca6ea1SDimitry Andric ErrorCategory.Report("NameIndex references nonexistent DIE", [&]() { 16140b57cec5SDimitry Andric error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a " 16150b57cec5SDimitry Andric "non-existing DIE @ {2:x}.\n", 16160b57cec5SDimitry Andric NI.getUnitOffset(), EntryID, DIEOffset); 1617*0fca6ea1SDimitry Andric }); 16180b57cec5SDimitry Andric ++NumErrors; 16190b57cec5SDimitry Andric continue; 16200b57cec5SDimitry Andric } 16210b57cec5SDimitry Andric if (DIE.getDwarfUnit()->getOffset() != CUOffset) { 1622*0fca6ea1SDimitry Andric ErrorCategory.Report("Name index contains mismatched CU of DIE", [&]() { 1623*0fca6ea1SDimitry Andric error() << formatv( 1624*0fca6ea1SDimitry Andric "Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of " 16250b57cec5SDimitry Andric "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n", 16260b57cec5SDimitry Andric NI.getUnitOffset(), EntryID, DIEOffset, CUOffset, 16270b57cec5SDimitry Andric DIE.getDwarfUnit()->getOffset()); 1628*0fca6ea1SDimitry Andric }); 16290b57cec5SDimitry Andric ++NumErrors; 16300b57cec5SDimitry Andric } 16310b57cec5SDimitry Andric if (DIE.getTag() != EntryOr->tag()) { 1632*0fca6ea1SDimitry Andric ErrorCategory.Report("Name Index contains mismatched Tag of DIE", [&]() { 1633*0fca6ea1SDimitry Andric error() << formatv( 1634*0fca6ea1SDimitry Andric "Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of " 16350b57cec5SDimitry Andric "DIE @ {2:x}: index - {3}; debug_info - {4}.\n", 16360b57cec5SDimitry Andric NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(), 16370b57cec5SDimitry Andric DIE.getTag()); 1638*0fca6ea1SDimitry Andric }); 16390b57cec5SDimitry Andric ++NumErrors; 16400b57cec5SDimitry Andric } 16410b57cec5SDimitry Andric 16425f757f3fSDimitry Andric // We allow an extra name for functions: their name without any template 16435f757f3fSDimitry Andric // parameters. 16445f757f3fSDimitry Andric auto IncludeStrippedTemplateNames = 16455f757f3fSDimitry Andric DIE.getTag() == DW_TAG_subprogram || 16465f757f3fSDimitry Andric DIE.getTag() == DW_TAG_inlined_subroutine; 16475f757f3fSDimitry Andric auto EntryNames = getNames(DIE, IncludeStrippedTemplateNames); 16480b57cec5SDimitry Andric if (!is_contained(EntryNames, Str)) { 1649*0fca6ea1SDimitry Andric ErrorCategory.Report("Name Index contains mismatched name of DIE", [&]() { 16500b57cec5SDimitry Andric error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name " 16510b57cec5SDimitry Andric "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n", 16520b57cec5SDimitry Andric NI.getUnitOffset(), EntryID, DIEOffset, Str, 16530b57cec5SDimitry Andric make_range(EntryNames.begin(), EntryNames.end())); 1654*0fca6ea1SDimitry Andric }); 16550b57cec5SDimitry Andric ++NumErrors; 16560b57cec5SDimitry Andric } 16570b57cec5SDimitry Andric } 1658*0fca6ea1SDimitry Andric handleAllErrors( 1659*0fca6ea1SDimitry Andric EntryOr.takeError(), 16600b57cec5SDimitry Andric [&](const DWARFDebugNames::SentinelError &) { 16610b57cec5SDimitry Andric if (NumEntries > 0) 16620b57cec5SDimitry Andric return; 1663*0fca6ea1SDimitry Andric ErrorCategory.Report( 1664*0fca6ea1SDimitry Andric "NameIndex Name is not associated with any entries", [&]() { 16650b57cec5SDimitry Andric error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is " 16660b57cec5SDimitry Andric "not associated with any entries.\n", 16670b57cec5SDimitry Andric NI.getUnitOffset(), NTE.getIndex(), Str); 1668*0fca6ea1SDimitry Andric }); 16690b57cec5SDimitry Andric ++NumErrors; 16700b57cec5SDimitry Andric }, 16710b57cec5SDimitry Andric [&](const ErrorInfoBase &Info) { 1672*0fca6ea1SDimitry Andric ErrorCategory.Report("Uncategorized NameIndex error", [&]() { 1673*0fca6ea1SDimitry Andric error() << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n", 16740b57cec5SDimitry Andric NI.getUnitOffset(), NTE.getIndex(), Str, 16750b57cec5SDimitry Andric Info.message()); 1676*0fca6ea1SDimitry Andric }); 16770b57cec5SDimitry Andric ++NumErrors; 16780b57cec5SDimitry Andric }); 16790b57cec5SDimitry Andric return NumErrors; 16800b57cec5SDimitry Andric } 16810b57cec5SDimitry Andric 16820b57cec5SDimitry Andric static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) { 1683480093f4SDimitry Andric Expected<std::vector<DWARFLocationExpression>> Loc = 1684480093f4SDimitry Andric Die.getLocations(DW_AT_location); 1685480093f4SDimitry Andric if (!Loc) { 1686480093f4SDimitry Andric consumeError(Loc.takeError()); 16870b57cec5SDimitry Andric return false; 1688480093f4SDimitry Andric } 16890b57cec5SDimitry Andric DWARFUnit *U = Die.getDwarfUnit(); 1690480093f4SDimitry Andric for (const auto &Entry : *Loc) { 1691480093f4SDimitry Andric DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 1692480093f4SDimitry Andric U->getAddressByteSize()); 16935ffd83dbSDimitry Andric DWARFExpression Expression(Data, U->getAddressByteSize(), 16945ffd83dbSDimitry Andric U->getFormParams().Format); 1695349cc55cSDimitry Andric bool IsInteresting = 1696349cc55cSDimitry Andric any_of(Expression, [](const DWARFExpression::Operation &Op) { 16970b57cec5SDimitry Andric return !Op.isError() && (Op.getCode() == DW_OP_addr || 16980b57cec5SDimitry Andric Op.getCode() == DW_OP_form_tls_address || 16990b57cec5SDimitry Andric Op.getCode() == DW_OP_GNU_push_tls_address); 17000b57cec5SDimitry Andric }); 1701480093f4SDimitry Andric if (IsInteresting) 17020b57cec5SDimitry Andric return true; 17030b57cec5SDimitry Andric } 17040b57cec5SDimitry Andric return false; 17050b57cec5SDimitry Andric } 17060b57cec5SDimitry Andric 17070b57cec5SDimitry Andric unsigned DWARFVerifier::verifyNameIndexCompleteness( 17080b57cec5SDimitry Andric const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) { 17090b57cec5SDimitry Andric 17100b57cec5SDimitry Andric // First check, if the Die should be indexed. The code follows the DWARF v5 17110b57cec5SDimitry Andric // wording as closely as possible. 17120b57cec5SDimitry Andric 17130b57cec5SDimitry Andric // "All non-defining declarations (that is, debugging information entries 17140b57cec5SDimitry Andric // with a DW_AT_declaration attribute) are excluded." 17150b57cec5SDimitry Andric if (Die.find(DW_AT_declaration)) 17160b57cec5SDimitry Andric return 0; 17170b57cec5SDimitry Andric 17180b57cec5SDimitry Andric // "DW_TAG_namespace debugging information entries without a DW_AT_name 17190b57cec5SDimitry Andric // attribute are included with the name “(anonymous namespace)”. 17200b57cec5SDimitry Andric // All other debugging information entries without a DW_AT_name attribute 17210b57cec5SDimitry Andric // are excluded." 17220b57cec5SDimitry Andric // "If a subprogram or inlined subroutine is included, and has a 17230b57cec5SDimitry Andric // DW_AT_linkage_name attribute, there will be an additional index entry for 17240b57cec5SDimitry Andric // the linkage name." 17250b57cec5SDimitry Andric auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram || 17260b57cec5SDimitry Andric Die.getTag() == DW_TAG_inlined_subroutine; 17275f757f3fSDimitry Andric // We *allow* stripped template names / ObjectiveC names as extra entries into 17285f757f3fSDimitry Andric // the table, but we don't *require* them to pass the completeness test. 17295f757f3fSDimitry Andric auto IncludeStrippedTemplateNames = false; 17305f757f3fSDimitry Andric auto IncludeObjCNames = false; 17315f757f3fSDimitry Andric auto EntryNames = getNames(Die, IncludeStrippedTemplateNames, 17325f757f3fSDimitry Andric IncludeObjCNames, IncludeLinkageName); 17330b57cec5SDimitry Andric if (EntryNames.empty()) 17340b57cec5SDimitry Andric return 0; 17350b57cec5SDimitry Andric 17360b57cec5SDimitry Andric // We deviate from the specification here, which says: 17370b57cec5SDimitry Andric // "The name index must contain an entry for each debugging information entry 17380b57cec5SDimitry Andric // that defines a named subprogram, label, variable, type, or namespace, 17390b57cec5SDimitry Andric // subject to ..." 17405ffd83dbSDimitry Andric // Explicitly exclude all TAGs that we know shouldn't be indexed. 17410b57cec5SDimitry Andric switch (Die.getTag()) { 17420b57cec5SDimitry Andric // Compile units and modules have names but shouldn't be indexed. 17430b57cec5SDimitry Andric case DW_TAG_compile_unit: 17440b57cec5SDimitry Andric case DW_TAG_module: 17450b57cec5SDimitry Andric return 0; 17460b57cec5SDimitry Andric 17470b57cec5SDimitry Andric // Function and template parameters are not globally visible, so we shouldn't 17480b57cec5SDimitry Andric // index them. 17490b57cec5SDimitry Andric case DW_TAG_formal_parameter: 17500b57cec5SDimitry Andric case DW_TAG_template_value_parameter: 17510b57cec5SDimitry Andric case DW_TAG_template_type_parameter: 17520b57cec5SDimitry Andric case DW_TAG_GNU_template_parameter_pack: 17530b57cec5SDimitry Andric case DW_TAG_GNU_template_template_param: 17540b57cec5SDimitry Andric return 0; 17550b57cec5SDimitry Andric 17560b57cec5SDimitry Andric // Object members aren't globally visible. 17570b57cec5SDimitry Andric case DW_TAG_member: 17580b57cec5SDimitry Andric return 0; 17590b57cec5SDimitry Andric 17600b57cec5SDimitry Andric // According to a strict reading of the specification, enumerators should not 17610b57cec5SDimitry Andric // be indexed (and LLVM currently does not do that). However, this causes 17620b57cec5SDimitry Andric // problems for the debuggers, so we may need to reconsider this. 17630b57cec5SDimitry Andric case DW_TAG_enumerator: 17640b57cec5SDimitry Andric return 0; 17650b57cec5SDimitry Andric 17660b57cec5SDimitry Andric // Imported declarations should not be indexed according to the specification 17670b57cec5SDimitry Andric // and LLVM currently does not do that. 17680b57cec5SDimitry Andric case DW_TAG_imported_declaration: 17690b57cec5SDimitry Andric return 0; 17700b57cec5SDimitry Andric 17710b57cec5SDimitry Andric // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging 17720b57cec5SDimitry Andric // information entries without an address attribute (DW_AT_low_pc, 17730b57cec5SDimitry Andric // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded." 17740b57cec5SDimitry Andric case DW_TAG_subprogram: 17750b57cec5SDimitry Andric case DW_TAG_inlined_subroutine: 17760b57cec5SDimitry Andric case DW_TAG_label: 17770b57cec5SDimitry Andric if (Die.findRecursively( 17780b57cec5SDimitry Andric {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc})) 17790b57cec5SDimitry Andric break; 17800b57cec5SDimitry Andric return 0; 17810b57cec5SDimitry Andric 17820b57cec5SDimitry Andric // "DW_TAG_variable debugging information entries with a DW_AT_location 17830b57cec5SDimitry Andric // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are 17840b57cec5SDimitry Andric // included; otherwise, they are excluded." 17850b57cec5SDimitry Andric // 17860b57cec5SDimitry Andric // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list. 17870b57cec5SDimitry Andric case DW_TAG_variable: 17880b57cec5SDimitry Andric if (isVariableIndexable(Die, DCtx)) 17890b57cec5SDimitry Andric break; 17900b57cec5SDimitry Andric return 0; 17910b57cec5SDimitry Andric 17920b57cec5SDimitry Andric default: 17930b57cec5SDimitry Andric break; 17940b57cec5SDimitry Andric } 17950b57cec5SDimitry Andric 17960b57cec5SDimitry Andric // Now we know that our Die should be present in the Index. Let's check if 17970b57cec5SDimitry Andric // that's the case. 17980b57cec5SDimitry Andric unsigned NumErrors = 0; 17990b57cec5SDimitry Andric uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset(); 18000b57cec5SDimitry Andric for (StringRef Name : EntryNames) { 18010b57cec5SDimitry Andric if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) { 18020b57cec5SDimitry Andric return E.getDIEUnitOffset() == DieUnitOffset; 18030b57cec5SDimitry Andric })) { 1804*0fca6ea1SDimitry Andric ErrorCategory.Report("Name Index DIE entry missing name", [&]() { 1805*0fca6ea1SDimitry Andric error() << formatv( 1806*0fca6ea1SDimitry Andric "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with " 18070b57cec5SDimitry Andric "name {3} missing.\n", 1808*0fca6ea1SDimitry Andric NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name); 1809*0fca6ea1SDimitry Andric }); 18100b57cec5SDimitry Andric ++NumErrors; 18110b57cec5SDimitry Andric } 18120b57cec5SDimitry Andric } 18130b57cec5SDimitry Andric return NumErrors; 18140b57cec5SDimitry Andric } 18150b57cec5SDimitry Andric 18160b57cec5SDimitry Andric unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection, 18170b57cec5SDimitry Andric const DataExtractor &StrData) { 18180b57cec5SDimitry Andric unsigned NumErrors = 0; 18190b57cec5SDimitry Andric DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection, 18200b57cec5SDimitry Andric DCtx.isLittleEndian(), 0); 18210b57cec5SDimitry Andric DWARFDebugNames AccelTable(AccelSectionData, StrData); 18220b57cec5SDimitry Andric 18230b57cec5SDimitry Andric OS << "Verifying .debug_names...\n"; 18240b57cec5SDimitry Andric 18250b57cec5SDimitry Andric // This verifies that we can read individual name indices and their 18260b57cec5SDimitry Andric // abbreviation tables. 18270b57cec5SDimitry Andric if (Error E = AccelTable.extract()) { 1828*0fca6ea1SDimitry Andric std::string Msg = toString(std::move(E)); 1829*0fca6ea1SDimitry Andric ErrorCategory.Report("Accelerator Table Error", 1830*0fca6ea1SDimitry Andric [&]() { error() << Msg << '\n'; }); 18310b57cec5SDimitry Andric return 1; 18320b57cec5SDimitry Andric } 18330b57cec5SDimitry Andric 18340b57cec5SDimitry Andric NumErrors += verifyDebugNamesCULists(AccelTable); 18350b57cec5SDimitry Andric for (const auto &NI : AccelTable) 18360b57cec5SDimitry Andric NumErrors += verifyNameIndexBuckets(NI, StrData); 18370b57cec5SDimitry Andric for (const auto &NI : AccelTable) 18380b57cec5SDimitry Andric NumErrors += verifyNameIndexAbbrevs(NI); 18390b57cec5SDimitry Andric 18400b57cec5SDimitry Andric // Don't attempt Entry validation if any of the previous checks found errors 18410b57cec5SDimitry Andric if (NumErrors > 0) 18420b57cec5SDimitry Andric return NumErrors; 18430b57cec5SDimitry Andric for (const auto &NI : AccelTable) 1844349cc55cSDimitry Andric for (const DWARFDebugNames::NameTableEntry &NTE : NI) 18450b57cec5SDimitry Andric NumErrors += verifyNameIndexEntries(NI, NTE); 18460b57cec5SDimitry Andric 18470b57cec5SDimitry Andric if (NumErrors > 0) 18480b57cec5SDimitry Andric return NumErrors; 18490b57cec5SDimitry Andric 18500b57cec5SDimitry Andric for (const std::unique_ptr<DWARFUnit> &U : DCtx.compile_units()) { 18510b57cec5SDimitry Andric if (const DWARFDebugNames::NameIndex *NI = 18520b57cec5SDimitry Andric AccelTable.getCUNameIndex(U->getOffset())) { 18530b57cec5SDimitry Andric auto *CU = cast<DWARFCompileUnit>(U.get()); 18540b57cec5SDimitry Andric for (const DWARFDebugInfoEntry &Die : CU->dies()) 18550b57cec5SDimitry Andric NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI); 18560b57cec5SDimitry Andric } 18570b57cec5SDimitry Andric } 18580b57cec5SDimitry Andric return NumErrors; 18590b57cec5SDimitry Andric } 18600b57cec5SDimitry Andric 18610b57cec5SDimitry Andric bool DWARFVerifier::handleAccelTables() { 18620b57cec5SDimitry Andric const DWARFObject &D = DCtx.getDWARFObj(); 18638bcb0991SDimitry Andric DataExtractor StrData(D.getStrSection(), DCtx.isLittleEndian(), 0); 18640b57cec5SDimitry Andric unsigned NumErrors = 0; 18650b57cec5SDimitry Andric if (!D.getAppleNamesSection().Data.empty()) 18660b57cec5SDimitry Andric NumErrors += verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData, 18670b57cec5SDimitry Andric ".apple_names"); 18680b57cec5SDimitry Andric if (!D.getAppleTypesSection().Data.empty()) 18690b57cec5SDimitry Andric NumErrors += verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData, 18700b57cec5SDimitry Andric ".apple_types"); 18710b57cec5SDimitry Andric if (!D.getAppleNamespacesSection().Data.empty()) 18720b57cec5SDimitry Andric NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData, 18730b57cec5SDimitry Andric ".apple_namespaces"); 18740b57cec5SDimitry Andric if (!D.getAppleObjCSection().Data.empty()) 18750b57cec5SDimitry Andric NumErrors += verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData, 18760b57cec5SDimitry Andric ".apple_objc"); 18770b57cec5SDimitry Andric 18788bcb0991SDimitry Andric if (!D.getNamesSection().Data.empty()) 18798bcb0991SDimitry Andric NumErrors += verifyDebugNames(D.getNamesSection(), StrData); 18800b57cec5SDimitry Andric return NumErrors == 0; 18810b57cec5SDimitry Andric } 18820b57cec5SDimitry Andric 188306c3fb27SDimitry Andric bool DWARFVerifier::handleDebugStrOffsets() { 188406c3fb27SDimitry Andric OS << "Verifying .debug_str_offsets...\n"; 188506c3fb27SDimitry Andric const DWARFObject &DObj = DCtx.getDWARFObj(); 188606c3fb27SDimitry Andric bool Success = true; 1887*0fca6ea1SDimitry Andric 1888*0fca6ea1SDimitry Andric // dwo sections may contain the legacy debug_str_offsets format (and they 1889*0fca6ea1SDimitry Andric // can't be mixed with dwarf 5's format). This section format contains no 1890*0fca6ea1SDimitry Andric // header. 1891*0fca6ea1SDimitry Andric // As such, check the version from debug_info and, if we are in the legacy 1892*0fca6ea1SDimitry Andric // mode (Dwarf <= 4), extract Dwarf32/Dwarf64. 1893*0fca6ea1SDimitry Andric std::optional<DwarfFormat> DwoLegacyDwarf4Format; 1894*0fca6ea1SDimitry Andric DObj.forEachInfoDWOSections([&](const DWARFSection &S) { 1895*0fca6ea1SDimitry Andric if (DwoLegacyDwarf4Format) 1896*0fca6ea1SDimitry Andric return; 1897*0fca6ea1SDimitry Andric DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0); 1898*0fca6ea1SDimitry Andric uint64_t Offset = 0; 1899*0fca6ea1SDimitry Andric DwarfFormat InfoFormat = DebugInfoData.getInitialLength(&Offset).second; 1900*0fca6ea1SDimitry Andric if (uint16_t InfoVersion = DebugInfoData.getU16(&Offset); InfoVersion <= 4) 1901*0fca6ea1SDimitry Andric DwoLegacyDwarf4Format = InfoFormat; 1902*0fca6ea1SDimitry Andric }); 1903*0fca6ea1SDimitry Andric 190406c3fb27SDimitry Andric Success &= verifyDebugStrOffsets( 1905*0fca6ea1SDimitry Andric DwoLegacyDwarf4Format, ".debug_str_offsets.dwo", 1906*0fca6ea1SDimitry Andric DObj.getStrOffsetsDWOSection(), DObj.getStrDWOSection()); 190706c3fb27SDimitry Andric Success &= verifyDebugStrOffsets( 1908*0fca6ea1SDimitry Andric /*LegacyFormat=*/std::nullopt, ".debug_str_offsets", 1909*0fca6ea1SDimitry Andric DObj.getStrOffsetsSection(), DObj.getStrSection()); 191006c3fb27SDimitry Andric return Success; 191106c3fb27SDimitry Andric } 191206c3fb27SDimitry Andric 191306c3fb27SDimitry Andric bool DWARFVerifier::verifyDebugStrOffsets( 1914*0fca6ea1SDimitry Andric std::optional<DwarfFormat> LegacyFormat, StringRef SectionName, 1915*0fca6ea1SDimitry Andric const DWARFSection &Section, StringRef StrData) { 191606c3fb27SDimitry Andric const DWARFObject &DObj = DCtx.getDWARFObj(); 191706c3fb27SDimitry Andric 191806c3fb27SDimitry Andric DWARFDataExtractor DA(DObj, Section, DCtx.isLittleEndian(), 0); 191906c3fb27SDimitry Andric DataExtractor::Cursor C(0); 192006c3fb27SDimitry Andric uint64_t NextUnit = 0; 192106c3fb27SDimitry Andric bool Success = true; 192206c3fb27SDimitry Andric while (C.seek(NextUnit), C.tell() < DA.getData().size()) { 192306c3fb27SDimitry Andric DwarfFormat Format; 192406c3fb27SDimitry Andric uint64_t Length; 192506c3fb27SDimitry Andric uint64_t StartOffset = C.tell(); 1926*0fca6ea1SDimitry Andric if (LegacyFormat) { 1927*0fca6ea1SDimitry Andric Format = *LegacyFormat; 192806c3fb27SDimitry Andric Length = DA.getData().size(); 192906c3fb27SDimitry Andric NextUnit = C.tell() + Length; 193006c3fb27SDimitry Andric } else { 193106c3fb27SDimitry Andric std::tie(Length, Format) = DA.getInitialLength(C); 193206c3fb27SDimitry Andric if (!C) 193306c3fb27SDimitry Andric break; 193406c3fb27SDimitry Andric if (C.tell() + Length > DA.getData().size()) { 1935*0fca6ea1SDimitry Andric ErrorCategory.Report( 1936*0fca6ea1SDimitry Andric "Section contribution length exceeds available space", [&]() { 193706c3fb27SDimitry Andric error() << formatv( 193806c3fb27SDimitry Andric "{0}: contribution {1:X}: length exceeds available space " 193906c3fb27SDimitry Andric "(contribution " 1940*0fca6ea1SDimitry Andric "offset ({1:X}) + length field space ({2:X}) + length " 1941*0fca6ea1SDimitry Andric "({3:X}) == " 194206c3fb27SDimitry Andric "{4:X} > section size {5:X})\n", 194306c3fb27SDimitry Andric SectionName, StartOffset, C.tell() - StartOffset, Length, 194406c3fb27SDimitry Andric C.tell() + Length, DA.getData().size()); 1945*0fca6ea1SDimitry Andric }); 194606c3fb27SDimitry Andric Success = false; 194706c3fb27SDimitry Andric // Nothing more to do - no other contributions to try. 194806c3fb27SDimitry Andric break; 194906c3fb27SDimitry Andric } 195006c3fb27SDimitry Andric NextUnit = C.tell() + Length; 195106c3fb27SDimitry Andric uint8_t Version = DA.getU16(C); 195206c3fb27SDimitry Andric if (C && Version != 5) { 1953*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid Section version", [&]() { 195406c3fb27SDimitry Andric error() << formatv("{0}: contribution {1:X}: invalid version {2}\n", 195506c3fb27SDimitry Andric SectionName, StartOffset, Version); 1956*0fca6ea1SDimitry Andric }); 195706c3fb27SDimitry Andric Success = false; 195806c3fb27SDimitry Andric // Can't parse the rest of this contribution, since we don't know the 195906c3fb27SDimitry Andric // version, but we can pick up with the next contribution. 196006c3fb27SDimitry Andric continue; 196106c3fb27SDimitry Andric } 196206c3fb27SDimitry Andric (void)DA.getU16(C); // padding 196306c3fb27SDimitry Andric } 196406c3fb27SDimitry Andric uint64_t OffsetByteSize = getDwarfOffsetByteSize(Format); 196506c3fb27SDimitry Andric DA.setAddressSize(OffsetByteSize); 196606c3fb27SDimitry Andric uint64_t Remainder = (Length - 4) % OffsetByteSize; 196706c3fb27SDimitry Andric if (Remainder != 0) { 1968*0fca6ea1SDimitry Andric ErrorCategory.Report("Invalid section contribution length", [&]() { 196906c3fb27SDimitry Andric error() << formatv( 197006c3fb27SDimitry Andric "{0}: contribution {1:X}: invalid length ((length ({2:X}) " 197106c3fb27SDimitry Andric "- header (0x4)) % offset size {3:X} == {4:X} != 0)\n", 197206c3fb27SDimitry Andric SectionName, StartOffset, Length, OffsetByteSize, Remainder); 1973*0fca6ea1SDimitry Andric }); 197406c3fb27SDimitry Andric Success = false; 197506c3fb27SDimitry Andric } 197606c3fb27SDimitry Andric for (uint64_t Index = 0; C && C.tell() + OffsetByteSize <= NextUnit; ++Index) { 197706c3fb27SDimitry Andric uint64_t OffOff = C.tell(); 197806c3fb27SDimitry Andric uint64_t StrOff = DA.getAddress(C); 197906c3fb27SDimitry Andric // check StrOff refers to the start of a string 198006c3fb27SDimitry Andric if (StrOff == 0) 198106c3fb27SDimitry Andric continue; 198206c3fb27SDimitry Andric if (StrData.size() <= StrOff) { 1983*0fca6ea1SDimitry Andric ErrorCategory.Report( 1984*0fca6ea1SDimitry Andric "String offset out of bounds of string section", [&]() { 198506c3fb27SDimitry Andric error() << formatv( 198606c3fb27SDimitry Andric "{0}: contribution {1:X}: index {2:X}: invalid string " 1987*0fca6ea1SDimitry Andric "offset *{3:X} == {4:X}, is beyond the bounds of the string " 1988*0fca6ea1SDimitry Andric "section of length {5:X}\n", 1989*0fca6ea1SDimitry Andric SectionName, StartOffset, Index, OffOff, StrOff, 1990*0fca6ea1SDimitry Andric StrData.size()); 1991*0fca6ea1SDimitry Andric }); 199206c3fb27SDimitry Andric continue; 199306c3fb27SDimitry Andric } 199406c3fb27SDimitry Andric if (StrData[StrOff - 1] == '\0') 199506c3fb27SDimitry Andric continue; 1996*0fca6ea1SDimitry Andric ErrorCategory.Report( 1997*0fca6ea1SDimitry Andric "Section contribution contains invalid string offset", [&]() { 1998*0fca6ea1SDimitry Andric error() << formatv( 1999*0fca6ea1SDimitry Andric "{0}: contribution {1:X}: index {2:X}: invalid string " 200006c3fb27SDimitry Andric "offset *{3:X} == {4:X}, is neither zero nor " 200106c3fb27SDimitry Andric "immediately following a null character\n", 200206c3fb27SDimitry Andric SectionName, StartOffset, Index, OffOff, StrOff); 2003*0fca6ea1SDimitry Andric }); 200406c3fb27SDimitry Andric Success = false; 200506c3fb27SDimitry Andric } 200606c3fb27SDimitry Andric } 200706c3fb27SDimitry Andric 200806c3fb27SDimitry Andric if (Error E = C.takeError()) { 2009*0fca6ea1SDimitry Andric std::string Msg = toString(std::move(E)); 2010*0fca6ea1SDimitry Andric ErrorCategory.Report("String offset error", [&]() { 2011*0fca6ea1SDimitry Andric error() << SectionName << ": " << Msg << '\n'; 201206c3fb27SDimitry Andric return false; 2013*0fca6ea1SDimitry Andric }); 201406c3fb27SDimitry Andric } 201506c3fb27SDimitry Andric return Success; 201606c3fb27SDimitry Andric } 201706c3fb27SDimitry Andric 2018*0fca6ea1SDimitry Andric void OutputCategoryAggregator::Report( 2019*0fca6ea1SDimitry Andric StringRef s, std::function<void(void)> detailCallback) { 2020*0fca6ea1SDimitry Andric Aggregation[std::string(s)]++; 2021*0fca6ea1SDimitry Andric if (IncludeDetail) 2022*0fca6ea1SDimitry Andric detailCallback(); 2023*0fca6ea1SDimitry Andric } 2024*0fca6ea1SDimitry Andric 2025*0fca6ea1SDimitry Andric void OutputCategoryAggregator::EnumerateResults( 2026*0fca6ea1SDimitry Andric std::function<void(StringRef, unsigned)> handleCounts) { 2027*0fca6ea1SDimitry Andric for (auto &&[name, count] : Aggregation) { 2028*0fca6ea1SDimitry Andric handleCounts(name, count); 2029*0fca6ea1SDimitry Andric } 2030*0fca6ea1SDimitry Andric } 2031*0fca6ea1SDimitry Andric 2032*0fca6ea1SDimitry Andric void DWARFVerifier::summarize() { 2033*0fca6ea1SDimitry Andric if (DumpOpts.ShowAggregateErrors && ErrorCategory.GetNumCategories()) { 2034*0fca6ea1SDimitry Andric error() << "Aggregated error counts:\n"; 2035*0fca6ea1SDimitry Andric ErrorCategory.EnumerateResults([&](StringRef s, unsigned count) { 2036*0fca6ea1SDimitry Andric error() << s << " occurred " << count << " time(s).\n"; 2037*0fca6ea1SDimitry Andric }); 2038*0fca6ea1SDimitry Andric } 2039*0fca6ea1SDimitry Andric if (!DumpOpts.JsonErrSummaryFile.empty()) { 2040*0fca6ea1SDimitry Andric std::error_code EC; 2041*0fca6ea1SDimitry Andric raw_fd_ostream JsonStream(DumpOpts.JsonErrSummaryFile, EC, 2042*0fca6ea1SDimitry Andric sys::fs::OF_Text); 2043*0fca6ea1SDimitry Andric if (EC) { 2044*0fca6ea1SDimitry Andric error() << "unable to open json summary file '" 2045*0fca6ea1SDimitry Andric << DumpOpts.JsonErrSummaryFile 2046*0fca6ea1SDimitry Andric << "' for writing: " << EC.message() << '\n'; 2047*0fca6ea1SDimitry Andric return; 2048*0fca6ea1SDimitry Andric } 2049*0fca6ea1SDimitry Andric 2050*0fca6ea1SDimitry Andric llvm::json::Object Categories; 2051*0fca6ea1SDimitry Andric uint64_t ErrorCount = 0; 2052*0fca6ea1SDimitry Andric ErrorCategory.EnumerateResults([&](StringRef Category, unsigned Count) { 2053*0fca6ea1SDimitry Andric llvm::json::Object Val; 2054*0fca6ea1SDimitry Andric Val.try_emplace("count", Count); 2055*0fca6ea1SDimitry Andric Categories.try_emplace(Category, std::move(Val)); 2056*0fca6ea1SDimitry Andric ErrorCount += Count; 2057*0fca6ea1SDimitry Andric }); 2058*0fca6ea1SDimitry Andric llvm::json::Object RootNode; 2059*0fca6ea1SDimitry Andric RootNode.try_emplace("error-categories", std::move(Categories)); 2060*0fca6ea1SDimitry Andric RootNode.try_emplace("error-count", ErrorCount); 2061*0fca6ea1SDimitry Andric 2062*0fca6ea1SDimitry Andric JsonStream << llvm::json::Value(std::move(RootNode)); 2063*0fca6ea1SDimitry Andric } 2064*0fca6ea1SDimitry Andric } 2065*0fca6ea1SDimitry Andric 20660b57cec5SDimitry Andric raw_ostream &DWARFVerifier::error() const { return WithColor::error(OS); } 20670b57cec5SDimitry Andric 20680b57cec5SDimitry Andric raw_ostream &DWARFVerifier::warn() const { return WithColor::warning(OS); } 20690b57cec5SDimitry Andric 20700b57cec5SDimitry Andric raw_ostream &DWARFVerifier::note() const { return WithColor::note(OS); } 20710b57cec5SDimitry Andric 20720b57cec5SDimitry Andric raw_ostream &DWARFVerifier::dump(const DWARFDie &Die, unsigned indent) const { 20730b57cec5SDimitry Andric Die.dump(OS, indent, DumpOpts); 20740b57cec5SDimitry Andric return OS; 20750b57cec5SDimitry Andric } 2076