]> granicus.if.org Git - llvm/commitdiff
[dwarfdump] Verify that unit type matches root DIE
authorJonas Devlieghere <jonas@devlieghere.com>
Fri, 6 Oct 2017 22:27:31 +0000 (22:27 +0000)
committerJonas Devlieghere <jonas@devlieghere.com>
Fri, 6 Oct 2017 22:27:31 +0000 (22:27 +0000)
This patch adds two new verifiers:

  - It checks that the root DIE of a CU is actually a valid unit DIE.
    (based on its tag)
  - For DWARF5 which contains a unit type int he CU header, it checks that
    this matches the type of the unit DIE.

Differential revision: https://reviews.llvm.org/D38453

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@315121 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/BinaryFormat/Dwarf.h
include/llvm/DebugInfo/DWARF/DWARFUnit.h
include/llvm/DebugInfo/DWARF/DWARFVerifier.h
lib/DebugInfo/DWARF/DWARFVerifier.cpp
test/DebugInfo/dwarfdump-header.test
test/tools/llvm-dwarfdump/X86/empty-CU.s
test/tools/llvm-dwarfdump/X86/verify_debug_info.s
test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s

index 8f7d055e27130baea785efc624605f4ed4dabd1c..a89adbee298fc12172eb38c274c55d6bc44c0b5e 100644 (file)
@@ -325,6 +325,33 @@ enum UnitType : unsigned char {
   DW_UT_hi_user = 0xff
 };
 
+inline bool isUnitType(uint8_t UnitType) {
+  switch (UnitType) {
+  case DW_UT_compile:
+  case DW_UT_type:
+  case DW_UT_partial:
+  case DW_UT_skeleton:
+  case DW_UT_split_compile:
+  case DW_UT_split_type:
+    return true;
+  default:
+    return false;
+  }
+}
+
+inline bool isUnitType(dwarf::Tag T) {
+  switch (T) {
+  case DW_TAG_compile_unit:
+  case DW_TAG_type_unit:
+  case DW_TAG_partial_unit:
+  case DW_TAG_skeleton_unit:
+  case DW_TAG_imported_unit:
+    return true;
+  default:
+    return false;
+  }
+}
+
 // Constants for the DWARF v5 Accelerator Table Proposal
 enum AcceleratorTable {
   // Data layout descriptors.
index 0df5c16e4a23f958a9d279176de514aa201c01ab..78f873e9840f5afe85e18c5d37cb574f5d753b01 100644 (file)
@@ -285,12 +285,21 @@ public:
 
   uint8_t getUnitType() const { return UnitType; }
 
-  static bool isValidUnitType(uint8_t UnitType) {
-    return UnitType == dwarf::DW_UT_compile || UnitType == dwarf::DW_UT_type ||
-           UnitType == dwarf::DW_UT_partial ||
-           UnitType == dwarf::DW_UT_skeleton ||
-           UnitType == dwarf::DW_UT_split_compile ||
-           UnitType == dwarf::DW_UT_split_type;
+  static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) {
+    switch (UnitType) {
+    case dwarf::DW_UT_compile:
+      return Tag == dwarf::DW_TAG_compile_unit;
+    case dwarf::DW_UT_type:
+      return Tag == dwarf::DW_TAG_type_unit;
+    case dwarf::DW_UT_partial:
+      return Tag == dwarf::DW_TAG_partial_unit;
+    case dwarf::DW_UT_skeleton:
+      return Tag == dwarf::DW_TAG_skeleton_unit;
+    case dwarf::DW_UT_split_compile:
+    case dwarf::DW_UT_split_type:
+      return dwarf::isUnitType(Tag);
+    }
+    return false;
   }
 
   /// \brief Return the number of bytes for the header of a unit of
index 0429c26e81d63f0e82184fedc1e9516298963593..0d920abe3231574c09bd92ca6cbdf8383cc267ac 100644 (file)
@@ -136,8 +136,22 @@ private:
                         uint32_t *Offset, unsigned UnitIndex, uint8_t &UnitType,
                         bool &isUnitDWARF64);
 
-
-  bool verifyUnitContents(DWARFUnit Unit);
+  /// Verifies the header of a unit in the .debug_info section.
+  ///
+  /// This function currently verifies:
+  ///  - The debug info attributes.
+  ///  - The debug info form=s.
+  ///  - The presence of a root DIE.
+  ///  - That the root DIE is a unit DIE.
+  ///  - If a unit type is provided, that the unit DIE matches the unit type.
+  ///  - The DIE ranges.
+  ///
+  /// \param Unit      The DWARF Unit to verifiy.
+  /// \param UnitType  An optional unit type which will be used to verify the
+  ///                  type of the unit DIE.
+  ///
+  /// \returns true if the content is verified successfully, false otherwise.
+  bool verifyUnitContents(DWARFUnit Unit, uint8_t UnitType = 0);
 
   /// Verify that all Die ranges are valid.
   ///
index 27e6a05e6dd05f8805cec69715e418865d6bb844..bec6e922ceb35a0deaffcca39561246e67ed5241 100644 (file)
@@ -134,7 +134,7 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
     UnitType = DebugInfoData.getU8(Offset);
     AddrSize = DebugInfoData.getU8(Offset);
     AbbrOffset = DebugInfoData.getU32(Offset);
-    ValidType = DWARFUnit::isValidUnitType(UnitType);
+    ValidType = dwarf::isUnitType(UnitType);
   } else {
     UnitType = 0;
     AbbrOffset = DebugInfoData.getU32(Offset);
@@ -169,7 +169,7 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
   return Success;
 }
 
-bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) {
+bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit, uint8_t UnitType) {
   uint32_t NumUnitErrors = 0;
   unsigned NumDies = Unit.getNumDIEs();
   for (unsigned I = 0; I < NumDies; ++I) {
@@ -182,14 +182,30 @@ bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) {
     }
   }
 
-  if (DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false)) {
-    DieRangeInfo RI;
-    NumUnitErrors += verifyDieRanges(Die, RI);
-  } else {
-    error() << "Compilation unit without unit DIE.\n";
+  DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
+  if (!Die) {
+    error() << "Compilation unit without DIE.\n";
+    NumUnitErrors++;
+    return NumUnitErrors == 0;
+  }
+
+  if (!dwarf::isUnitType(Die.getTag())) {
+    error() << "Compilation unit root DIE is not a unit DIE: "
+            << dwarf::TagString(Die.getTag()) << ".\n";
     NumUnitErrors++;
   }
 
+  if (UnitType != 0 &&
+      !DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) {
+    error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType)
+            << ") and root DIE (" << dwarf::TagString(Die.getTag())
+            << ") do not match.\n";
+    NumUnitErrors++;
+  }
+
+  DieRangeInfo RI;
+  NumUnitErrors += verifyDieRanges(Die, RI);
+
   return NumUnitErrors == 0;
 }
 
@@ -286,7 +302,7 @@ bool DWARFVerifier::handleDebugInfo() {
       default: { llvm_unreachable("Invalid UnitType."); }
       }
       Unit->extract(DebugInfoData, &OffsetStart);
-      if (!verifyUnitContents(*Unit))
+      if (!verifyUnitContents(*Unit, UnitType))
         ++NumDebugInfoErrors;
     }
     hasDIE = DebugInfoData.isValidOffset(Offset);
index 5a7be988edb86c2a7cacbf70ef173e42f641fa08..375f7043c9fa30943ffb2953e552f5dd9ed42847 100644 (file)
@@ -1,4 +1,5 @@
 RUN: llvm-dwarfdump -v %p/Inputs/dwarfdump-header.elf-x86-64 | FileCheck %s
+RUN: llvm-dwarfdump -v --verify %p/Inputs/dwarfdump-header.elf-x86-64
 
 The input file is hand-coded assembler to generate all the units,
 so we're willing to make exact checks for offsets and such.
index 14ff75836f4091b99c3fb475d3e6a541a8e2238c..a01fc16e0d7fcbed2efbd1389ef79266f65687de 100644 (file)
@@ -1,7 +1,7 @@
 # RUN: llvm-mc %s -filetype obj -triple x86_64-apple-darwin -o - \
 # RUN: | not llvm-dwarfdump --verify --debug-info - \
 # RUN: | FileCheck %s
-# CHECK: error: Compilation unit without unit DIE.
+# CHECK: error: Compilation unit without DIE.
 
         .section        __DWARF,__debug_info,regular,debug
 .long 8  # CU length
index b87db731a754046542e400ff81b893e0e169421c..af947afb30e894815b1250a030e63eeb971becc9 100644 (file)
@@ -11,6 +11,8 @@
 # CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strp]    ( .debug_str[0x0000003f] = "/Users/sgravani/Development/tests")
 # CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr]      (0x0000000000000000)
 # CHECK-NEXT: DW_AT_high_pc [DW_FORM_data4]    (0x00000016){{[[:space:]]}}
+# CHECK-NEXT: error: Compilation unit root DIE is not a unit DIE: DW_TAG_null.
+# CHECK-NEXT: error: Compilation unit type (DW_UT_compile) and root DIE (DW_TAG_null) do not match.
 # CHECK-NEXT: error: Units[2] - start offset: 0x00000068
 # CHECK-NEXT: note: The length for this unit is too large for the .debug_info provided.
 # CHECK-NEXT: note: The unit type encoding is not valid.
index baee5d86a24edc2f0ce8b86f31e1cedd92dd6aea..046e7b7b6a2d7eda8b824aab6e0848229ad762f4 100644 (file)
@@ -9,6 +9,8 @@
 # CHECK-NEXT: error: Units[2] - start offset: 0x00000026
 # CHECK-NEXT: note: The 16 bit unit header version is not valid.
 # CHECK-NEXT: note: The offset into the .debug_abbrev section is not valid.
+# CHECK-NEXT: error: Compilation unit root DIE is not a unit DIE: DW_TAG_null.
+# CHECK-NEXT: error: Compilation unit type (DW_UT_compile) and root DIE (DW_TAG_null) do not match.
 # CHECK-NEXT: error: Units[4] - start offset: 0x00000041
 # CHECK-NEXT: note: The length for this unit is too large for the .debug_info provided.