LCOV - code coverage report
Current view: top level - lib/DebugInfo/DWARF - DWARFVerifier.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 369 394 93.7 %
Date: 2017-09-14 15:23:50 Functions: 14 14 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- DWARFVerifier.cpp --------------------------------------------------===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : 
      10             : #include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
      11             : #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
      12             : #include "llvm/DebugInfo/DWARF/DWARFContext.h"
      13             : #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
      14             : #include "llvm/DebugInfo/DWARF/DWARFDie.h"
      15             : #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
      16             : #include "llvm/DebugInfo/DWARF/DWARFSection.h"
      17             : #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
      18             : #include "llvm/Support/raw_ostream.h"
      19             : #include <map>
      20             : #include <set>
      21             : #include <vector>
      22             : 
      23             : using namespace llvm;
      24             : using namespace dwarf;
      25             : using namespace object;
      26             : 
      27          23 : bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
      28             :                                      uint32_t *Offset, unsigned UnitIndex,
      29             :                                      uint8_t &UnitType, bool &isUnitDWARF64) {
      30             :   uint32_t AbbrOffset, Length;
      31          23 :   uint8_t AddrSize = 0;
      32             :   uint16_t Version;
      33          23 :   bool Success = true;
      34             : 
      35          23 :   bool ValidLength = false;
      36          23 :   bool ValidVersion = false;
      37          23 :   bool ValidAddrSize = false;
      38          23 :   bool ValidType = true;
      39          23 :   bool ValidAbbrevOffset = true;
      40             : 
      41          23 :   uint32_t OffsetStart = *Offset;
      42          23 :   Length = DebugInfoData.getU32(Offset);
      43          23 :   if (Length == UINT32_MAX) {
      44           0 :     isUnitDWARF64 = true;
      45           0 :     OS << format(
      46             :         "Unit[%d] is in 64-bit DWARF format; cannot verify from this point.\n",
      47             :         UnitIndex);
      48           0 :     return false;
      49             :   }
      50          23 :   Version = DebugInfoData.getU16(Offset);
      51             : 
      52          23 :   if (Version >= 5) {
      53           8 :     UnitType = DebugInfoData.getU8(Offset);
      54           8 :     AddrSize = DebugInfoData.getU8(Offset);
      55           8 :     AbbrOffset = DebugInfoData.getU32(Offset);
      56          16 :     ValidType = DWARFUnit::isValidUnitType(UnitType);
      57             :   } else {
      58          15 :     UnitType = 0;
      59          15 :     AbbrOffset = DebugInfoData.getU32(Offset);
      60          15 :     AddrSize = DebugInfoData.getU8(Offset);
      61             :   }
      62             : 
      63          23 :   if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset))
      64           1 :     ValidAbbrevOffset = false;
      65             : 
      66          46 :   ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3);
      67          46 :   ValidVersion = DWARFContext::isSupportedVersion(Version);
      68          23 :   ValidAddrSize = AddrSize == 4 || AddrSize == 8;
      69          23 :   if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
      70             :       !ValidType) {
      71           4 :     Success = false;
      72           8 :     OS << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, OffsetStart);
      73           4 :     if (!ValidLength)
      74           2 :       OS << "\tError: The length for this unit is too "
      75             :             "large for the .debug_info provided.\n";
      76           4 :     if (!ValidVersion)
      77           1 :       OS << "\tError: The 16 bit unit header version is not valid.\n";
      78           4 :     if (!ValidType)
      79           2 :       OS << "\tError: The unit type encoding is not valid.\n";
      80           4 :     if (!ValidAbbrevOffset)
      81           1 :       OS << "\tError: The offset into the .debug_abbrev section is "
      82             :             "not valid.\n";
      83           4 :     if (!ValidAddrSize)
      84           1 :       OS << "\tError: The address size is unsupported.\n";
      85             :   }
      86          23 :   *Offset = OffsetStart + Length + 4;
      87          23 :   return Success;
      88             : }
      89             : 
      90          19 : bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) {
      91          19 :   uint32_t NumUnitErrors = 0;
      92          19 :   unsigned NumDies = Unit.getNumDIEs();
      93         188 :   for (unsigned I = 0; I < NumDies; ++I) {
      94         169 :     auto Die = Unit.getDIEAtIndex(I);
      95         135 :     if (Die.getTag() == DW_TAG_null)
      96          34 :       continue;
      97         135 :     NumUnitErrors += verifyDieRanges(Die);
      98        1675 :     for (auto AttrValue : Die.attributes()) {
      99         635 :       NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
     100         635 :       NumUnitErrors += verifyDebugInfoForm(Die, AttrValue);
     101             :     }
     102             :   }
     103          19 :   return NumUnitErrors == 0;
     104             : }
     105             : 
     106          18 : unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
     107          18 :   unsigned NumErrors = 0;
     108          18 :   if (Abbrev) {
     109             :     const DWARFAbbreviationDeclarationSet *AbbrDecls =
     110          18 :         Abbrev->getAbbreviationDeclarationSet(0);
     111         152 :     for (auto AbbrDecl : *AbbrDecls) {
     112          80 :       SmallDenseSet<uint16_t> AttributeSet;
     113         328 :       for (auto Attribute : AbbrDecl.attributes()) {
     114         288 :         auto Result = AttributeSet.insert(Attribute.Attr);
     115         144 :         if (!Result.second) {
     116           2 :           OS << "Error: Abbreviation declaration contains multiple "
     117           2 :              << AttributeString(Attribute.Attr) << " attributes.\n";
     118           2 :           AbbrDecl.dump(OS);
     119           2 :           ++NumErrors;
     120             :         }
     121             :       }
     122             :     }
     123             :   }
     124          18 :   return NumErrors;
     125             : }
     126             : 
     127          21 : bool DWARFVerifier::handleDebugAbbrev() {
     128          21 :   OS << "Verifying .debug_abbrev...\n";
     129             : 
     130          42 :   const DWARFObject &DObj = DCtx.getDWARFObj();
     131          42 :   bool noDebugAbbrev = DObj.getAbbrevSection().empty();
     132          42 :   bool noDebugAbbrevDWO = DObj.getAbbrevDWOSection().empty();
     133             : 
     134          21 :   if (noDebugAbbrev && noDebugAbbrevDWO) {
     135             :     return true;
     136             :   }
     137             : 
     138          17 :   unsigned NumErrors = 0;
     139          17 :   if (!noDebugAbbrev)
     140          17 :     NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
     141             : 
     142          17 :   if (!noDebugAbbrevDWO)
     143           1 :     NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
     144          17 :   return NumErrors == 0;
     145             : }
     146             : 
     147          21 : bool DWARFVerifier::handleDebugInfo() {
     148          21 :   OS << "Verifying .debug_info Unit Header Chain...\n";
     149             : 
     150          42 :   const DWARFObject &DObj = DCtx.getDWARFObj();
     151          21 :   DWARFDataExtractor DebugInfoData(DObj, DObj.getInfoSection(),
     152          84 :                                    DCtx.isLittleEndian(), 0);
     153          21 :   uint32_t NumDebugInfoErrors = 0;
     154          21 :   uint32_t OffsetStart = 0, Offset = 0, UnitIdx = 0;
     155          21 :   uint8_t UnitType = 0;
     156          21 :   bool isUnitDWARF64 = false;
     157          21 :   bool isHeaderChainValid = true;
     158          42 :   bool hasDIE = DebugInfoData.isValidOffset(Offset);
     159          67 :   while (hasDIE) {
     160          23 :     OffsetStart = Offset;
     161          23 :     if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType,
     162             :                           isUnitDWARF64)) {
     163           4 :       isHeaderChainValid = false;
     164           4 :       if (isUnitDWARF64)
     165             :         break;
     166             :     } else {
     167          38 :       std::unique_ptr<DWARFUnit> Unit;
     168          19 :       switch (UnitType) {
     169           0 :       case dwarf::DW_UT_type:
     170             :       case dwarf::DW_UT_split_type: {
     171           0 :         DWARFUnitSection<DWARFTypeUnit> TUSection{};
     172           0 :         Unit.reset(new DWARFTypeUnit(
     173           0 :             DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
     174           0 :             &DObj.getRangeSection(), DObj.getStringSection(),
     175           0 :             DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
     176           0 :             DObj.getLineSection(), DCtx.isLittleEndian(), false, TUSection,
     177           0 :             nullptr));
     178             :         break;
     179             :       }
     180          19 :       case dwarf::DW_UT_skeleton:
     181             :       case dwarf::DW_UT_split_compile:
     182             :       case dwarf::DW_UT_compile:
     183             :       case dwarf::DW_UT_partial:
     184             :       // UnitType = 0 means that we are
     185             :       // verifying a compile unit in DWARF v4.
     186             :       case 0: {
     187          57 :         DWARFUnitSection<DWARFCompileUnit> CUSection{};
     188          76 :         Unit.reset(new DWARFCompileUnit(
     189          38 :             DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
     190          38 :             &DObj.getRangeSection(), DObj.getStringSection(),
     191          38 :             DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
     192          57 :             DObj.getLineSection(), DCtx.isLittleEndian(), false, CUSection,
     193          38 :             nullptr));
     194             :         break;
     195             :       }
     196           0 :       default: { llvm_unreachable("Invalid UnitType."); }
     197             :       }
     198          19 :       Unit->extract(DebugInfoData, &OffsetStart);
     199          19 :       if (!verifyUnitContents(*Unit))
     200           7 :         ++NumDebugInfoErrors;
     201             :     }
     202          46 :     hasDIE = DebugInfoData.isValidOffset(Offset);
     203          23 :     ++UnitIdx;
     204             :   }
     205          21 :   if (UnitIdx == 0 && !hasDIE) {
     206           5 :     OS << "Warning: .debug_info is empty.\n";
     207           5 :     isHeaderChainValid = true;
     208             :   }
     209          21 :   NumDebugInfoErrors += verifyDebugInfoReferences();
     210          21 :   return (isHeaderChainValid && NumDebugInfoErrors == 0);
     211             : }
     212             : 
     213         135 : unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die) {
     214         135 :   unsigned NumErrors = 0;
     215         700 :   for (auto Range : Die.getAddressRanges()) {
     216          25 :     if (Range.LowPC >= Range.HighPC) {
     217           1 :       ++NumErrors;
     218           2 :       OS << format("error: Invalid address range [0x%08" PRIx64
     219             :                    " - 0x%08" PRIx64 "].\n",
     220             :                    Range.LowPC, Range.HighPC);
     221             :     }
     222             :   }
     223         135 :   return NumErrors;
     224             : }
     225             : 
     226         635 : unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
     227             :                                                  DWARFAttribute &AttrValue) {
     228        1270 :   const DWARFObject &DObj = DCtx.getDWARFObj();
     229         635 :   unsigned NumErrors = 0;
     230         635 :   const auto Attr = AttrValue.Attr;
     231         635 :   switch (Attr) {
     232           1 :   case DW_AT_ranges:
     233             :     // Make sure the offset in the DW_AT_ranges attribute is valid.
     234           2 :     if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
     235           2 :       if (*SectionOffset >= DObj.getRangeSection().Data.size()) {
     236           1 :         ++NumErrors;
     237           1 :         OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
     238             :               "bounds:\n";
     239           1 :         Die.dump(OS, 0, 0, DumpOpts);
     240           1 :         OS << "\n";
     241             :       }
     242             :     } else {
     243           0 :       ++NumErrors;
     244           0 :       OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
     245           0 :       Die.dump(OS, 0, 0, DumpOpts);
     246           0 :       OS << "\n";
     247           1 :     }
     248           1 :     break;
     249          11 :   case DW_AT_stmt_list:
     250             :     // Make sure the offset in the DW_AT_stmt_list attribute is valid.
     251          22 :     if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
     252          20 :       if (*SectionOffset >= DObj.getLineSection().Data.size()) {
     253           1 :         ++NumErrors;
     254           1 :         OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
     255           1 :               "bounds: "
     256           2 :            << format("0x%08" PRIx64, *SectionOffset) << "\n";
     257           1 :         Die.dump(OS, 0, 0, DumpOpts);
     258           1 :         OS << "\n";
     259             :       }
     260             :     } else {
     261           1 :       ++NumErrors;
     262           1 :       OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
     263           1 :       Die.dump(OS, 0, 0, DumpOpts);
     264           1 :       OS << "\n";
     265          11 :     }
     266          11 :     break;
     267             : 
     268             :   default:
     269             :     break;
     270             :   }
     271         635 :   return NumErrors;
     272             : }
     273             : 
     274         635 : unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
     275             :                                             DWARFAttribute &AttrValue) {
     276        1270 :   const DWARFObject &DObj = DCtx.getDWARFObj();
     277         635 :   unsigned NumErrors = 0;
     278         635 :   const auto Form = AttrValue.Value.getForm();
     279         635 :   switch (Form) {
     280         119 :   case DW_FORM_ref1:
     281             :   case DW_FORM_ref2:
     282             :   case DW_FORM_ref4:
     283             :   case DW_FORM_ref8:
     284             :   case DW_FORM_ref_udata: {
     285             :     // Verify all CU relative references are valid CU offsets.
     286         238 :     Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
     287             :     assert(RefVal);
     288         119 :     if (RefVal) {
     289         119 :       auto DieCU = Die.getDwarfUnit();
     290         119 :       auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
     291         119 :       auto CUOffset = AttrValue.Value.getRawUValue();
     292         119 :       if (CUOffset >= CUSize) {
     293           1 :         ++NumErrors;
     294           1 :         OS << "error: " << FormEncodingString(Form) << " CU offset "
     295           3 :            << format("0x%08" PRIx64, CUOffset)
     296           1 :            << " is invalid (must be less than CU size of "
     297           2 :            << format("0x%08" PRIx32, CUSize) << "):\n";
     298           1 :         Die.dump(OS, 0, 0, DumpOpts);
     299           1 :         OS << "\n";
     300             :       } else {
     301             :         // Valid reference, but we will verify it points to an actual
     302             :         // DIE later.
     303         354 :         ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
     304             :       }
     305             :     }
     306             :     break;
     307             :   }
     308           2 :   case DW_FORM_ref_addr: {
     309             :     // Verify all absolute DIE references have valid offsets in the
     310             :     // .debug_info section.
     311           4 :     Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
     312             :     assert(RefVal);
     313           2 :     if (RefVal) {
     314           4 :       if (*RefVal >= DObj.getInfoSection().Data.size()) {
     315           1 :         ++NumErrors;
     316           1 :         OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
     317             :               "bounds:\n";
     318           1 :         Die.dump(OS, 0, 0, DumpOpts);
     319           1 :         OS << "\n";
     320             :       } else {
     321             :         // Valid reference, but we will verify it points to an actual
     322             :         // DIE later.
     323           3 :         ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
     324             :       }
     325             :     }
     326             :     break;
     327             :   }
     328         137 :   case DW_FORM_strp: {
     329         274 :     auto SecOffset = AttrValue.Value.getAsSectionOffset();
     330             :     assert(SecOffset); // DW_FORM_strp is a section offset.
     331         547 :     if (SecOffset && *SecOffset >= DObj.getStringSection().size()) {
     332           1 :       ++NumErrors;
     333           1 :       OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
     334           1 :       Die.dump(OS, 0, 0, DumpOpts);
     335           1 :       OS << "\n";
     336             :     }
     337             :     break;
     338             :   }
     339             :   default:
     340             :     break;
     341             :   }
     342         635 :   return NumErrors;
     343             : }
     344             : 
     345          21 : unsigned DWARFVerifier::verifyDebugInfoReferences() {
     346             :   // Take all references and make sure they point to an actual DIE by
     347             :   // getting the DIE by offset and emitting an error
     348          21 :   OS << "Verifying .debug_info references...\n";
     349          21 :   unsigned NumErrors = 0;
     350         138 :   for (auto Pair : ReferenceToDIEOffsets) {
     351          37 :     auto Die = DCtx.getDIEForOffset(Pair.first);
     352          37 :     if (Die)
     353          36 :       continue;
     354           1 :     ++NumErrors;
     355           3 :     OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
     356           1 :        << ". Offset is in between DIEs:\n";
     357           3 :     for (auto Offset : Pair.second) {
     358           1 :       auto ReferencingDie = DCtx.getDIEForOffset(Offset);
     359           1 :       ReferencingDie.dump(OS, 0, 0, DumpOpts);
     360           1 :       OS << "\n";
     361             :     }
     362           1 :     OS << "\n";
     363             :   }
     364          21 :   return NumErrors;
     365             : }
     366             : 
     367          12 : void DWARFVerifier::verifyDebugLineStmtOffsets() {
     368          24 :   std::map<uint64_t, DWARFDie> StmtListToDie;
     369          38 :   for (const auto &CU : DCtx.compile_units()) {
     370          28 :     auto Die = CU->getUnitDIE();
     371             :     // Get the attribute value as a section offset. No need to produce an
     372             :     // error here if the encoding isn't correct because we validate this in
     373             :     // the .debug_info verifier.
     374          47 :     auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
     375          14 :     if (!StmtSectionOffset)
     376          16 :       continue;
     377           7 :     const uint32_t LineTableOffset = *StmtSectionOffset;
     378          14 :     auto LineTable = DCtx.getLineTableForUnit(CU.get());
     379          22 :     if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
     380           6 :       if (!LineTable) {
     381           0 :         ++NumDebugLineErrors;
     382           0 :         OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
     383           0 :            << "] was not able to be parsed for CU:\n";
     384           0 :         Die.dump(OS, 0, 0, DumpOpts);
     385           0 :         OS << '\n';
     386           0 :         continue;
     387             :       }
     388             :     } else {
     389             :       // Make sure we don't get a valid line table back if the offset is wrong.
     390             :       assert(LineTable == nullptr);
     391             :       // Skip this line table as it isn't valid. No need to create an error
     392             :       // here because we validate this in the .debug_info verifier.
     393           1 :       continue;
     394             :     }
     395          12 :     auto Iter = StmtListToDie.find(LineTableOffset);
     396           7 :     if (Iter != StmtListToDie.end()) {
     397           1 :       ++NumDebugLineErrors;
     398           1 :       OS << "error: two compile unit DIEs, "
     399           4 :          << format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
     400           4 :          << format("0x%08" PRIx32, Die.getOffset())
     401           1 :          << ", have the same DW_AT_stmt_list section offset:\n";
     402           1 :       Iter->second.dump(OS, 0, 0, DumpOpts);
     403           1 :       Die.dump(OS, 0, 0, DumpOpts);
     404           2 :       OS << '\n';
     405             :       // Already verified this line table before, no need to do it again.
     406           1 :       continue;
     407             :     }
     408           5 :     StmtListToDie[LineTableOffset] = Die;
     409             :   }
     410          12 : }
     411             : 
     412          12 : void DWARFVerifier::verifyDebugLineRows() {
     413          38 :   for (const auto &CU : DCtx.compile_units()) {
     414          28 :     auto Die = CU->getUnitDIE();
     415          28 :     auto LineTable = DCtx.getLineTableForUnit(CU.get());
     416             :     // If there is no line table we will have created an error in the
     417             :     // .debug_info verifier or in verifyDebugLineStmtOffsets().
     418          14 :     if (!LineTable)
     419           8 :       continue;
     420             : 
     421             :     // Verify prologue.
     422          12 :     uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
     423          12 :     uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
     424           6 :     uint32_t FileIndex = 1;
     425          12 :     StringMap<uint16_t> FullPathMap;
     426          31 :     for (const auto &FileName : LineTable->Prologue.FileNames) {
     427             :       // Verify directory index.
     428           7 :       if (FileName.DirIdx > MaxDirIndex) {
     429           1 :         ++NumDebugLineErrors;
     430           1 :         OS << "error: .debug_line["
     431           3 :            << format("0x%08" PRIx64,
     432           6 :                      *toSectionOffset(Die.find(DW_AT_stmt_list)))
     433           2 :            << "].prologue.file_names[" << FileIndex
     434           1 :            << "].dir_idx contains an invalid index: " << FileName.DirIdx
     435           1 :            << "\n";
     436             :       }
     437             : 
     438             :       // Check file paths for duplicates.
     439          14 :       std::string FullPath;
     440           7 :       const bool HasFullPath = LineTable->getFileNameByIndex(
     441           7 :           FileIndex, CU->getCompilationDir(),
     442           7 :           DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath);
     443             :       assert(HasFullPath && "Invalid index?");
     444             :       (void)HasFullPath;
     445           7 :       auto It = FullPathMap.find(FullPath);
     446          14 :       if (It == FullPathMap.end())
     447          12 :         FullPathMap[FullPath] = FileIndex;
     448           1 :       else if (It->second != FileIndex) {
     449           1 :         OS << "warning: .debug_line["
     450           3 :            << format("0x%08" PRIx64,
     451           6 :                      *toSectionOffset(Die.find(DW_AT_stmt_list)))
     452           2 :            << "].prologue.file_names[" << FileIndex
     453           3 :            << "] is a duplicate of file_names[" << It->second << "]\n";
     454             :       }
     455             : 
     456           7 :       FileIndex++;
     457             :     }
     458             : 
     459             :     // Verify rows.
     460           6 :     uint64_t PrevAddress = 0;
     461           6 :     uint32_t RowIndex = 0;
     462          36 :     for (const auto &Row : LineTable->Rows) {
     463             :       // Verify row address.
     464          12 :       if (Row.Address < PrevAddress) {
     465           1 :         ++NumDebugLineErrors;
     466           1 :         OS << "error: .debug_line["
     467           3 :            << format("0x%08" PRIx64,
     468           6 :                      *toSectionOffset(Die.find(DW_AT_stmt_list)))
     469           2 :            << "] row[" << RowIndex
     470           1 :            << "] decreases in address from previous row:\n";
     471             : 
     472           1 :         DWARFDebugLine::Row::dumpTableHeader(OS);
     473           1 :         if (RowIndex > 0)
     474           2 :           LineTable->Rows[RowIndex - 1].dump(OS);
     475           1 :         Row.dump(OS);
     476           1 :         OS << '\n';
     477             :       }
     478             : 
     479             :       // Verify file index.
     480          12 :       if (Row.File > MaxFileIndex) {
     481           1 :         ++NumDebugLineErrors;
     482           1 :         OS << "error: .debug_line["
     483           3 :            << format("0x%08" PRIx64,
     484           6 :                      *toSectionOffset(Die.find(DW_AT_stmt_list)))
     485           3 :            << "][" << RowIndex << "] has invalid file index " << Row.File
     486           2 :            << " (valid values are [1," << MaxFileIndex << "]):\n";
     487           1 :         DWARFDebugLine::Row::dumpTableHeader(OS);
     488           1 :         Row.dump(OS);
     489           1 :         OS << '\n';
     490             :       }
     491          12 :       if (Row.EndSequence)
     492             :         PrevAddress = 0;
     493             :       else
     494           6 :         PrevAddress = Row.Address;
     495          12 :       ++RowIndex;
     496             :     }
     497             :   }
     498          12 : }
     499             : 
     500          12 : bool DWARFVerifier::handleDebugLine() {
     501          12 :   NumDebugLineErrors = 0;
     502          12 :   OS << "Verifying .debug_line...\n";
     503          12 :   verifyDebugLineStmtOffsets();
     504          12 :   verifyDebugLineRows();
     505          12 :   return NumDebugLineErrors == 0;
     506             : }
     507             : 
     508           8 : unsigned DWARFVerifier::verifyAccelTable(const DWARFSection *AccelSection,
     509             :                                          DataExtractor *StrData,
     510             :                                          const char *SectionName) {
     511           8 :   unsigned NumErrors = 0;
     512           8 :   DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
     513          32 :                                       DCtx.isLittleEndian(), 0);
     514          16 :   DWARFAcceleratorTable AccelTable(AccelSectionData, *StrData);
     515             : 
     516           8 :   OS << "Verifying " << SectionName << "...\n";
     517             :   // Verify that the fixed part of the header is not too short.
     518             : 
     519          16 :   if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {
     520           0 :     OS << "\terror: Section is too small to fit a section header.\n";
     521           0 :     return 1;
     522             :   }
     523             :   // Verify that the section is not too short.
     524           8 :   if (!AccelTable.extract()) {
     525           1 :     OS << "\terror: Section is smaller than size described in section header.\n";
     526           1 :     return 1;
     527             :   }
     528             :   // Verify that all buckets have a valid hash index or are empty.
     529           7 :   uint32_t NumBuckets = AccelTable.getNumBuckets();
     530           7 :   uint32_t NumHashes = AccelTable.getNumHashes();
     531             : 
     532             :   uint32_t BucketsOffset =
     533           7 :       AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
     534           7 :   uint32_t HashesBase = BucketsOffset + NumBuckets * 4;
     535           7 :   uint32_t OffsetsBase = HashesBase + NumHashes * 4;
     536          42 :   for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
     537          35 :     uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
     538          35 :     if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
     539           2 :       OS << format("\terror: Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
     540             :                    HashIdx);
     541           1 :       ++NumErrors;
     542             :     }
     543             :   }
     544           7 :   uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
     545           7 :   if (NumAtoms == 0) {
     546           1 :     OS << "\terror: no atoms; failed to read HashData.\n";
     547           1 :     return 1;
     548             :   }
     549           6 :   if (!AccelTable.validateForms()) {
     550           1 :     OS << "\terror: unsupported form; failed to read HashData.\n";
     551           1 :     return 1;
     552             :   }
     553             : 
     554         109 :   for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
     555          52 :     uint32_t HashOffset = HashesBase + 4 * HashIdx;
     556          52 :     uint32_t DataOffset = OffsetsBase + 4 * HashIdx;
     557          52 :     uint32_t Hash = AccelSectionData.getU32(&HashOffset);
     558          52 :     uint32_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
     559          52 :     if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
     560             :                                                      sizeof(uint64_t))) {
     561           2 :       OS << format("\terror: Hash[%d] has invalid HashData offset: 0x%08x.\n",
     562             :                    HashIdx, HashDataOffset);
     563           1 :       ++NumErrors;
     564             :     }
     565             : 
     566             :     uint32_t StrpOffset;
     567             :     uint32_t StringOffset;
     568             :     uint32_t StringCount = 0;
     569             :     unsigned Offset;
     570             :     unsigned Tag;
     571         156 :     while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
     572             :       const uint32_t NumHashDataObjects =
     573          52 :           AccelSectionData.getU32(&HashDataOffset);
     574         123 :       for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
     575             :            ++HashDataIdx) {
     576         213 :         std::tie(Offset, Tag) = AccelTable.readAtoms(HashDataOffset);
     577          71 :         auto Die = DCtx.getDIEForOffset(Offset);
     578          71 :         if (!Die) {
     579           1 :           const uint32_t BucketIdx =
     580           2 :               NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
     581           1 :           StringOffset = StrpOffset;
     582           1 :           const char *Name = StrData->getCStr(&StringOffset);
     583           1 :           if (!Name)
     584           0 :             Name = "<NULL>";
     585             : 
     586           2 :           OS << format(
     587             :               "\terror: %s Bucket[%d] Hash[%d] = 0x%08x "
     588             :               "Str[%u] = 0x%08x "
     589             :               "DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n",
     590             :               SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
     591             :               HashDataIdx, Offset, Name);
     592             : 
     593           1 :           ++NumErrors;
     594           1 :           continue;
     595             :         }
     596          77 :         if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {
     597           1 :           OS << "\terror: Tag " << dwarf::TagString(Tag)
     598           1 :              << " in accelerator table does not match Tag "
     599           2 :              << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx
     600           2 :              << "].\n";
     601           1 :           ++NumErrors;
     602             :         }
     603             :       }
     604          52 :       ++StringCount;
     605             :     }
     606             :   }
     607             :   return NumErrors;
     608             : }
     609             : 
     610          21 : bool DWARFVerifier::handleAccelTables() {
     611          42 :   const DWARFObject &D = DCtx.getDWARFObj();
     612          63 :   DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0);
     613          21 :   unsigned NumErrors = 0;
     614          42 :   if (!D.getAppleNamesSection().Data.empty())
     615           4 :     NumErrors +=
     616           4 :         verifyAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names");
     617          42 :   if (!D.getAppleTypesSection().Data.empty())
     618           2 :     NumErrors +=
     619           2 :         verifyAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types");
     620          42 :   if (!D.getAppleNamespacesSection().Data.empty())
     621           1 :     NumErrors += verifyAccelTable(&D.getAppleNamespacesSection(), &StrData,
     622             :                                   ".apple_namespaces");
     623          42 :   if (!D.getAppleObjCSection().Data.empty())
     624           1 :     NumErrors +=
     625           1 :         verifyAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc");
     626          21 :   return NumErrors == 0;
     627             : }

Generated by: LCOV version 1.13