[llvm] r302062 - Break verification down into smaller functions to keep code clean.

Greg Clayton via llvm-commits llvm-commits at lists.llvm.org
Wed May 3 11:25:46 PDT 2017


Author: gclayton
Date: Wed May  3 13:25:46 2017
New Revision: 302062

URL: http://llvm.org/viewvc/llvm-project?rev=302062&view=rev
Log:
Break verification down into smaller functions to keep code clean.

Adrian requested that we break things down to make things clean in the DWARFVerifier. This patch breaks everything down into nice individual functions and cleans up the code quite a bit and prepares us for the next round of verifiers.

Differential Revision: https://reviews.llvm.org/D32812

Modified:
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
    llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFVerifier.h?rev=302062&r1=302061&r2=302062&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFVerifier.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFVerifier.h Wed May  3 13:25:46 2017
@@ -11,19 +11,68 @@
 #define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
 
 #include <cstdint>
+#include <map>
+#include <set>
 
 namespace llvm {
 class raw_ostream;
+struct DWARFAttribute;
 class DWARFContext;
+class DWARFDie;
 class DWARFUnit;
 
 /// A class that verifies DWARF debug information given a DWARF Context.
 class DWARFVerifier {
   raw_ostream &OS;
   DWARFContext &DCtx;
+  /// A map that tracks all references (converted absolute references) so we
+  /// can verify each reference points to a valid DIE and not an offset that
+  /// lies between to valid DIEs.
+  std::map<uint64_t, std::set<uint32_t>> ReferenceToDIEOffsets;
   uint32_t NumDebugInfoErrors;
   uint32_t NumDebugLineErrors;
 
+  /// Verifies the attribute's DWARF attribute and its value.
+  ///
+  /// This function currently checks for:
+  /// - DW_AT_ranges values is a valid .debug_ranges offset
+  /// - DW_AT_stmt_list is a valid .debug_line offset
+  ///
+  /// @param Die          The DWARF DIE that owns the attribute value
+  /// @param AttrValue    The DWARF attribute value to check
+  void verifyDebugInfoAttribute(DWARFDie &Die, DWARFAttribute &AttrValue);
+
+  /// Verifies the attribute's DWARF form.
+  ///
+  /// This function currently checks for:
+  /// - All DW_FORM_ref values that are CU relative have valid CU offsets
+  /// - All DW_FORM_ref_addr values have valid .debug_info offsets
+  /// - All DW_FORM_strp values have valid .debug_str offsets
+  ///
+  /// @param Die          The DWARF DIE that owns the attribute value
+  /// @param AttrValue    The DWARF attribute value to check
+  void verifyDebugInfoForm(DWARFDie &Die, DWARFAttribute &AttrValue);
+
+  /// Verifies the all valid references that were found when iterating through
+  /// all of the DIE attributes.
+  ///
+  /// This function will verify that all references point to DIEs whose DIE
+  /// offset matches. This helps to ensure if a DWARF link phase moved things
+  /// around, that it doesn't create invalid references by failing to relocate
+  /// CU relative and absolute references.
+  void veifyDebugInfoReferences();
+
+  /// Verify the the DW_AT_stmt_list encoding and value and ensure that no
+  /// compile units that have the same DW_AT_stmt_list value.
+  void verifyDebugLineStmtOffsets();
+
+  /// Verify that all of the rows in the line table are valid.
+  ///
+  /// This function currently checks for:
+  /// - addresses within a sequence that decrease in value
+  /// - invalid file indexes
+  void verifyDebugLineRows();
+
 public:
   DWARFVerifier(raw_ostream &S, DWARFContext &D)
       : OS(S), DCtx(D), NumDebugInfoErrors(0), NumDebugLineErrors(0) {}

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp?rev=302062&r1=302061&r2=302062&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp Wed May  3 13:25:46 2017
@@ -23,132 +23,120 @@ using namespace llvm;
 using namespace dwarf;
 using namespace object;
 
-bool DWARFVerifier::handleDebugInfo() {
+void DWARFVerifier::verifyDebugInfoAttribute(DWARFDie &Die,
+                                             DWARFAttribute &AttrValue) {
+  const auto Attr = AttrValue.Attr;
+  switch (Attr) {
+  case DW_AT_ranges:
+    // Make sure the offset in the DW_AT_ranges attribute is valid.
+    if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
+      if (*SectionOffset >= DCtx.getRangeSection().Data.size()) {
+        ++NumDebugInfoErrors;
+        OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
+              "bounds:\n";
+        Die.dump(OS, 0);
+        OS << "\n";
+      }
+    } else {
+      ++NumDebugInfoErrors;
+      OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
+      Die.dump(OS, 0);
+      OS << "\n";
+    }
+    break;
+  case DW_AT_stmt_list:
+    // Make sure the offset in the DW_AT_stmt_list attribute is valid.
+    if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
+      if (*SectionOffset >= DCtx.getLineSection().Data.size()) {
+        ++NumDebugInfoErrors;
+        OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
+              "bounds: "
+           << format("0x%08" PRIx32, *SectionOffset) << "\n";
+        Die.dump(OS, 0);
+        OS << "\n";
+      }
+    } else {
+      ++NumDebugInfoErrors;
+      OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
+      Die.dump(OS, 0);
+      OS << "\n";
+    }
+    break;
 
-  NumDebugInfoErrors = 0;
-  // A map that tracks all references (converted absolute references) so we
-  // can verify each reference points to a valid DIE and not an offset that
-  // lies between to valid DIEs.
-  std::map<uint64_t, std::set<uint32_t>> ReferenceToDIEOffsets;
+  default:
+    break;
+  }
+}
 
-  OS << "Verifying .debug_info...\n";
-  for (const auto &CU : DCtx.compile_units()) {
-    unsigned NumDies = CU->getNumDIEs();
-    for (unsigned I = 0; I < NumDies; ++I) {
-      auto Die = CU->getDIEAtIndex(I);
-      const auto Tag = Die.getTag();
-      if (Tag == DW_TAG_null)
-        continue;
-      for (auto AttrValue : Die.attributes()) {
-        const auto Attr = AttrValue.Attr;
-        const auto Form = AttrValue.Value.getForm();
-        switch (Attr) {
-        case DW_AT_ranges:
-          // Make sure the offset in the DW_AT_ranges attribute is valid.
-          if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
-            if (*SectionOffset >= DCtx.getRangeSection().Data.size()) {
-              ++NumDebugInfoErrors;
-              OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
-                    "bounds:\n";
-              Die.dump(OS, 0);
-              OS << "\n";
-            }
-          } else {
-            ++NumDebugInfoErrors;
-            OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
-            Die.dump(OS, 0);
-            OS << "\n";
-          }
-          break;
-        case DW_AT_stmt_list:
-          // Make sure the offset in the DW_AT_stmt_list attribute is valid.
-          if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
-            if (*SectionOffset >= DCtx.getLineSection().Data.size()) {
-              ++NumDebugInfoErrors;
-              OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
-                    "bounds: "
-                 << format("0x%08" PRIx32, *SectionOffset) << "\n";
-              CU->getUnitDIE().dump(OS, 0);
-              OS << "\n";
-            }
-          } else {
-            ++NumDebugInfoErrors;
-            OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
-            Die.dump(OS, 0);
-            OS << "\n";
-          }
-          break;
-
-        default:
-          break;
-        }
-        switch (Form) {
-        case DW_FORM_ref1:
-        case DW_FORM_ref2:
-        case DW_FORM_ref4:
-        case DW_FORM_ref8:
-        case DW_FORM_ref_udata: {
-          // Verify all CU relative references are valid CU offsets.
-          Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
-          assert(RefVal);
-          if (RefVal) {
-            auto DieCU = Die.getDwarfUnit();
-            auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
-            auto CUOffset = AttrValue.Value.getRawUValue();
-            if (CUOffset >= CUSize) {
-              ++NumDebugInfoErrors;
-              OS << "error: " << FormEncodingString(Form) << " CU offset "
-                 << format("0x%08" PRIx32, CUOffset)
-                 << " is invalid (must be less than CU size of "
-                 << format("0x%08" PRIx32, CUSize) << "):\n";
-              Die.dump(OS, 0);
-              OS << "\n";
-            } else {
-              // Valid reference, but we will verify it points to an actual
-              // DIE later.
-              ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
-            }
-          }
-          break;
-        }
-        case DW_FORM_ref_addr: {
-          // Verify all absolute DIE references have valid offsets in the
-          // .debug_info section.
-          Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
-          assert(RefVal);
-          if (RefVal) {
-            if (*RefVal >= DCtx.getInfoSection().Data.size()) {
-              ++NumDebugInfoErrors;
-              OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
-                    "bounds:\n";
-              Die.dump(OS, 0);
-              OS << "\n";
-            } else {
-              // Valid reference, but we will verify it points to an actual
-              // DIE later.
-              ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
-            }
-          }
-          break;
-        }
-        case DW_FORM_strp: {
-          auto SecOffset = AttrValue.Value.getAsSectionOffset();
-          assert(SecOffset); // DW_FORM_strp is a section offset.
-          if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) {
-            ++NumDebugInfoErrors;
-            OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
-            Die.dump(OS, 0);
-            OS << "\n";
-          }
-          break;
-        }
-        default:
-          break;
-        }
+void DWARFVerifier::verifyDebugInfoForm(DWARFDie &Die,
+                                        DWARFAttribute &AttrValue) {
+  const auto Form = AttrValue.Value.getForm();
+  switch (Form) {
+  case DW_FORM_ref1:
+  case DW_FORM_ref2:
+  case DW_FORM_ref4:
+  case DW_FORM_ref8:
+  case DW_FORM_ref_udata: {
+    // Verify all CU relative references are valid CU offsets.
+    Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
+    assert(RefVal);
+    if (RefVal) {
+      auto DieCU = Die.getDwarfUnit();
+      auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
+      auto CUOffset = AttrValue.Value.getRawUValue();
+      if (CUOffset >= CUSize) {
+        ++NumDebugInfoErrors;
+        OS << "error: " << FormEncodingString(Form) << " CU offset "
+           << format("0x%08" PRIx32, CUOffset)
+           << " is invalid (must be less than CU size of "
+           << format("0x%08" PRIx32, CUSize) << "):\n";
+        Die.dump(OS, 0);
+        OS << "\n";
+      } else {
+        // Valid reference, but we will verify it points to an actual
+        // DIE later.
+        ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
+      }
+    }
+    break;
+  }
+  case DW_FORM_ref_addr: {
+    // Verify all absolute DIE references have valid offsets in the
+    // .debug_info section.
+    Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
+    assert(RefVal);
+    if (RefVal) {
+      if (*RefVal >= DCtx.getInfoSection().Data.size()) {
+        ++NumDebugInfoErrors;
+        OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
+              "bounds:\n";
+        Die.dump(OS, 0);
+        OS << "\n";
+      } else {
+        // Valid reference, but we will verify it points to an actual
+        // DIE later.
+        ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
       }
     }
+    break;
+  }
+  case DW_FORM_strp: {
+    auto SecOffset = AttrValue.Value.getAsSectionOffset();
+    assert(SecOffset); // DW_FORM_strp is a section offset.
+    if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) {
+      ++NumDebugInfoErrors;
+      OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
+      Die.dump(OS, 0);
+      OS << "\n";
+    }
+    break;
   }
+  default:
+    break;
+  }
+}
 
+void DWARFVerifier::veifyDebugInfoReferences() {
   // Take all references and make sure they point to an actual DIE by
   // getting the DIE by offset and emitting an error
   OS << "Verifying .debug_info references...\n";
@@ -166,62 +154,90 @@ bool DWARFVerifier::handleDebugInfo() {
     }
     OS << "\n";
   }
+}
+
+bool DWARFVerifier::handleDebugInfo() {
+  NumDebugInfoErrors = 0;
+  OS << "Verifying .debug_info...\n";
+  for (const auto &CU : DCtx.compile_units()) {
+    unsigned NumDies = CU->getNumDIEs();
+    for (unsigned I = 0; I < NumDies; ++I) {
+      auto Die = CU->getDIEAtIndex(I);
+      const auto Tag = Die.getTag();
+      if (Tag == DW_TAG_null)
+        continue;
+      for (auto AttrValue : Die.attributes()) {
+        verifyDebugInfoAttribute(Die, AttrValue);
+        verifyDebugInfoForm(Die, AttrValue);
+      }
+    }
+  }
+  veifyDebugInfoReferences();
   return NumDebugInfoErrors == 0;
 }
 
-bool DWARFVerifier::handleDebugLine() {
+void DWARFVerifier::verifyDebugLineStmtOffsets() {
   std::map<uint64_t, DWARFDie> StmtListToDie;
-  NumDebugLineErrors = 0;
-  OS << "Verifying .debug_line...\n";
   for (const auto &CU : DCtx.compile_units()) {
-    auto CUDie = CU->getUnitDIE();
+    auto Die = CU->getUnitDIE();
     // Get the attribute value as a section offset. No need to produce an
     // error here if the encoding isn't correct because we validate this in
     // the .debug_info verifier.
-    auto StmtSectionOffset = toSectionOffset(CUDie.find(DW_AT_stmt_list));
+    auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
     if (!StmtSectionOffset)
       continue;
     const uint32_t LineTableOffset = *StmtSectionOffset;
-    if (LineTableOffset >= DCtx.getLineSection().Data.size()) {
-      // Make sure we don't get a valid line table back if the offset
-      // is wrong.
-      assert(DCtx.getLineTableForUnit(CU.get()) == nullptr);
+    auto LineTable = DCtx.getLineTableForUnit(CU.get());
+    if (LineTableOffset < DCtx.getLineSection().Data.size()) {
+      if (!LineTable) {
+        ++NumDebugLineErrors;
+        OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
+           << "] was not able to be parsed for CU:\n";
+        Die.dump(OS, 0);
+        OS << '\n';
+        continue;
+      }
+    } else {
+      // Make sure we don't get a valid line table back if the offset is wrong.
+      assert(LineTable == nullptr);
       // Skip this line table as it isn't valid. No need to create an error
       // here because we validate this in the .debug_info verifier.
       continue;
     }
-
     auto Iter = StmtListToDie.find(LineTableOffset);
     if (Iter != StmtListToDie.end()) {
       ++NumDebugLineErrors;
       OS << "error: two compile unit DIEs, "
          << format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
-         << format("0x%08" PRIx32, CUDie.getOffset())
+         << format("0x%08" PRIx32, Die.getOffset())
          << ", have the same DW_AT_stmt_list section offset:\n";
       Iter->second.dump(OS, 0);
-      CUDie.dump(OS, 0);
+      Die.dump(OS, 0);
       OS << '\n';
       // Already verified this line table before, no need to do it again.
       continue;
     }
-    StmtListToDie[LineTableOffset] = CUDie;
+    StmtListToDie[LineTableOffset] = Die;
+  }
+}
 
+void DWARFVerifier::verifyDebugLineRows() {
+  for (const auto &CU : DCtx.compile_units()) {
+    auto Die = CU->getUnitDIE();
     auto LineTable = DCtx.getLineTableForUnit(CU.get());
-    if (!LineTable) {
-      ++NumDebugLineErrors;
-      OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
-         << "] was not able to be parsed for CU:\n";
-      CUDie.dump(OS, 0);
-      OS << '\n';
+    // If there is no line table we will have created an error in the
+    // .debug_info verifier or in verifyDebugLineStmtOffsets().
+    if (!LineTable)
       continue;
-    }
     uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
     uint64_t PrevAddress = 0;
     uint32_t RowIndex = 0;
     for (const auto &Row : LineTable->Rows) {
       if (Row.Address < PrevAddress) {
         ++NumDebugLineErrors;
-        OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
+        OS << "error: .debug_line["
+           << format("0x%08" PRIx32,
+                     *toSectionOffset(Die.find(DW_AT_stmt_list)))
            << "] row[" << RowIndex
            << "] decreases in address from previous row:\n";
 
@@ -234,7 +250,9 @@ bool DWARFVerifier::handleDebugLine() {
 
       if (Row.File > MaxFileIndex) {
         ++NumDebugLineErrors;
-        OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
+        OS << "error: .debug_line["
+           << format("0x%08" PRIx32,
+                     *toSectionOffset(Die.find(DW_AT_stmt_list)))
            << "][" << RowIndex << "] has invalid file index " << Row.File
            << " (valid values are [1," << MaxFileIndex << "]):\n";
         DWARFDebugLine::Row::dumpTableHeader(OS);
@@ -248,5 +266,12 @@ bool DWARFVerifier::handleDebugLine() {
       ++RowIndex;
     }
   }
+}
+
+bool DWARFVerifier::handleDebugLine() {
+  NumDebugLineErrors = 0;
+  OS << "Verifying .debug_line...\n";
+  verifyDebugLineStmtOffsets();
+  verifyDebugLineRows();
   return NumDebugLineErrors == 0;
 }




More information about the llvm-commits mailing list