[llvm] r328202 - DWARFVerifier: verify debug_names abbreviation table

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 22 07:50:45 PDT 2018


Author: labath
Date: Thu Mar 22 07:50:44 2018
New Revision: 328202

URL: http://llvm.org/viewvc/llvm-project?rev=328202&view=rev
Log:
DWARFVerifier: verify debug_names abbreviation table

Summary:
This commit adds checks of the abbreviation table in a DWARF v5 Name
Index. The most interesting/useful check is the one which checks that
each index attributes is encoded using the correct form class, but it
also checks for the more obvious errors like unknown
forms/tags/attributes and duplicated attributes.

Reviewers: JDevlieghere, aprantl, dblaikie

Subscribers: llvm-commits

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

Added:
    llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-abbrev-forms.s
Modified:
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
    llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
    llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp
    llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-no-buckets.s

Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h?rev=328202&r1=328201&r2=328202&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h Thu Mar 22 07:50:44 2018
@@ -425,6 +425,10 @@ public:
 
     uint32_t getNameCount() const { return Hdr.NameCount; }
 
+    const DenseSet<Abbrev, AbbrevMapInfo> &getAbbrevs() const {
+      return Abbrevs;
+    }
+
     llvm::Error extract();
     uint32_t getUnitOffset() const { return Base; }
     uint32_t getNextUnitOffset() const { return Base + 4 + Hdr.UnitLength; }

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=328202&r1=328201&r2=328202&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFVerifier.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFVerifier.h Thu Mar 22 07:50:44 2018
@@ -236,12 +236,17 @@ private:
   unsigned verifyDebugNamesCULists(const DWARFDebugNames &AccelTable);
   unsigned verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
                                   const DataExtractor &StrData);
+  unsigned verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI);
+  unsigned verifyNameIndexAttribute(const DWARFDebugNames::NameIndex &NI,
+                                    const DWARFDebugNames::Abbrev &Abbr,
+                                    DWARFDebugNames::AttributeEncoding AttrEnc);
 
   /// Verify that the DWARF v5 accelerator table is valid.
   ///
   /// This function currently checks that:
-  /// - Headers and abbreviation tables of individual Name Indices fit into the
-  ///   section and can be parsed.
+  /// - Headers individual Name Indices fit into the section and can be parsed.
+  /// - Abbreviation tables can be parsed and contain valid index attributes
+  ///   with correct form encodings.
   /// - The CU lists reference existing compile units.
   /// - The buckets have a valid index, or they are empty.
   /// - All names are reachable via the hash table (they have the correct hash,

Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp?rev=328202&r1=328201&r2=328202&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFVerifier.cpp Thu Mar 22 07:50:44 2018
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
@@ -939,6 +940,89 @@ DWARFVerifier::verifyNameIndexBuckets(co
   return NumErrors;
 }
 
+unsigned DWARFVerifier::verifyNameIndexAttribute(
+    const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr,
+    DWARFDebugNames::AttributeEncoding AttrEnc) {
+  StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form);
+  if (FormName.empty()) {
+    error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
+                       "unknown form: {3}.\n",
+                       NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
+                       AttrEnc.Form);
+    return 1;
+  }
+
+  if (AttrEnc.Index == DW_IDX_type_hash) {
+    if (AttrEnc.Form != dwarf::DW_FORM_data8) {
+      error() << formatv(
+          "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
+          "uses an unexpected form {2} (should be {3}).\n",
+          NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8);
+      return 1;
+    }
+  }
+
+  // A list of known index attributes and their expected form classes.
+  // DW_IDX_type_hash is handled specially in the check above, as it has a
+  // specific form (not just a form class) we should expect.
+  struct FormClassTable {
+    dwarf::Index Index;
+    DWARFFormValue::FormClass Class;
+    StringLiteral ClassName;
+  };
+  static constexpr FormClassTable Table[] = {
+      {dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}},
+      {dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}},
+      {dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}},
+      {dwarf::DW_IDX_parent, DWARFFormValue::FC_Constant, {"constant"}},
+  };
+
+  ArrayRef<FormClassTable> TableRef(Table);
+  auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) {
+    return T.Index == AttrEnc.Index;
+  });
+  if (Iter == TableRef.end()) {
+    warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an "
+                      "unknown index attribute: {2}.\n",
+                      NI.getUnitOffset(), Abbr.Code, AttrEnc.Index);
+    return 0;
+  }
+
+  if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) {
+    error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
+                       "unexpected form {3} (expected form class {4}).\n",
+                       NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
+                       AttrEnc.Form, Iter->ClassName);
+    return 1;
+  }
+  return 0;
+}
+
+unsigned
+DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
+  unsigned NumErrors = 0;
+  for (const auto &Abbrev : NI.getAbbrevs()) {
+    StringRef TagName = dwarf::TagString(Abbrev.Tag);
+    if (TagName.empty()) {
+      warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an "
+                        "unknown tag: {2}.\n",
+                        NI.getUnitOffset(), Abbrev.Code, Abbrev.Tag);
+    }
+    SmallSet<unsigned, 5> Attributes;
+    for (const auto &AttrEnc : Abbrev.Attributes) {
+      if (!Attributes.insert(AttrEnc.Index).second) {
+        error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains "
+                           "multiple {2} attributes.\n",
+                           NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index);
+        ++NumErrors;
+        continue;
+      }
+      NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
+    }
+  }
+  return NumErrors;
+}
+
 unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,
                                          const DataExtractor &StrData) {
   unsigned NumErrors = 0;
@@ -958,6 +1042,8 @@ unsigned DWARFVerifier::verifyDebugNames
   NumErrors += verifyDebugNamesCULists(AccelTable);
   for (const auto &NI : AccelTable)
     NumErrors += verifyNameIndexBuckets(NI, StrData);
+  for (const auto &NI : AccelTable)
+    NumErrors += verifyNameIndexAbbrevs(NI);
 
   return NumErrors;
 }

Added: llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-abbrev-forms.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-abbrev-forms.s?rev=328202&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-abbrev-forms.s (added)
+++ llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-abbrev-forms.s Thu Mar 22 07:50:44 2018
@@ -0,0 +1,92 @@
+# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj | \
+# RUN:   not llvm-dwarfdump -verify - | FileCheck %s
+
+# CHECK: error: NameIndex @ 0x0: Abbreviation 0x2: DW_IDX_compile_unit uses an unexpected form DW_FORM_ref1 (expected form class constant).
+# CHECK: error: NameIndex @ 0x0: Abbreviation 0x2: DW_IDX_type_unit uses an unexpected form DW_FORM_ref1 (expected form class constant).
+# CHECK: error: NameIndex @ 0x0: Abbreviation 0x2: DW_IDX_type_hash uses an unexpected form DW_FORM_data4 (should be DW_FORM_data8).
+# CHECK: warning: NameIndex @ 0x0: Abbreviation 0x2 contains an unknown index attribute: DW_IDX_unknown_2020.
+# CHECK: error: NameIndex @ 0x0: Abbreviation 0x4 contains multiple DW_IDX_die_offset attributes.
+# CHECK: NameIndex @ 0x0: Abbreviation 0x1: DW_IDX_die_offset uses an unknown form: DW_FORM_unknown_1fff.
+# CHECK: warning: NameIndex @ 0x0: Abbreviation 0x3 references an unknown tag: DW_TAG_unknown_8080.
+
+	.section	.debug_str,"MS", at progbits,1
+.Lstring_producer:
+	.asciz	"Hand-written dwarf"
+
+	.section	.debug_abbrev,"", at progbits
+.Lsection_abbrev:
+	.byte	1                       # Abbreviation Code
+	.byte	17                      # DW_TAG_compile_unit
+	.byte	1                       # DW_CHILDREN_yes
+	.byte	37                      # DW_AT_producer
+	.byte	14                      # DW_FORM_strp
+	.byte	19                      # DW_AT_language
+	.byte	5                       # DW_FORM_data2
+	.byte	0                       # EOM(1)
+	.byte	0                       # EOM(2)
+	.byte	0                       # EOM(3)
+
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Lcu_end0-.Lcu_start0   # Length of Unit
+.Lcu_start0:
+	.short	4                       # DWARF version number
+	.long	.Lsection_abbrev        # Offset Into Abbrev. Section
+	.byte	8                       # Address Size (in bytes)
+	.byte	1                       # Abbrev [1] DW_TAG_compile_unit
+	.long	.Lstring_producer       # DW_AT_producer
+	.short	12                      # DW_AT_language
+	.byte	0                       # End Of Children Mark
+.Lcu_end0:
+
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0 # Header: contribution length
+.Lnames_start0:
+	.short	5                       # Header: version
+	.short	0                       # Header: padding
+	.long	1                       # Header: compilation unit count
+	.long	0                       # Header: local type unit count
+	.long	0                       # Header: foreign type unit count
+	.long	0                       # Header: bucket count
+	.long	0                       # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	0                       # Header: augmentation length
+	.long	.Lcu_begin0             # Compilation unit 0
+.Lnames_abbrev_start0:
+	.byte	1                       # Abbrev code
+	.byte	46                      # DW_TAG_subprogram
+	.byte	3                       # DW_IDX_die_offset
+	.uleb128 0x1fff                 # DW_FORM_unknown_1fff
+	.byte	0                       # End of abbrev
+	.byte	0                       # End of abbrev
+	.byte	2                       # Abbrev code
+	.byte	46                      # DW_TAG_subprogram
+	.byte	1                       # DW_IDX_compile_unit
+	.byte   17                      # DW_FORM_ref1
+	.byte	2                       # DW_IDX_type_unit
+	.byte   17                      # DW_FORM_ref1
+	.byte	2                       # DW_IDX_die_offset
+	.byte   5                       # DW_FORM_data2
+	.byte	5                       # DW_IDX_type_hash
+	.byte   6                       # DW_FORM_data4
+	.uleb128 0x2020                 # DW_IDX_unknown_2020
+	.byte   6                       # DW_FORM_data4
+	.byte	0                       # End of abbrev
+	.byte	0                       # End of abbrev
+	.byte	3                       # Abbrev code
+	.uleb128 0x8080                 # DW_TAG_unknown_8080
+	.byte	3                       # DW_IDX_die_offset
+	.byte   17                      # DW_FORM_ref1
+	.byte	0                       # End of abbrev
+	.byte	0                       # End of abbrev
+	.byte	4                       # Abbrev code
+	.byte	46                      # DW_TAG_subprogram
+	.byte	3                       # DW_IDX_die_offset
+	.byte   17                      # DW_FORM_ref1
+	.byte	3                       # DW_IDX_die_offset
+	.byte   17                      # DW_FORM_ref1
+	.byte	0                       # End of abbrev
+	.byte	0                       # End of abbrev
+	.byte	0                       # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_end0:

Modified: llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-no-buckets.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-no-buckets.s?rev=328202&r1=328201&r2=328202&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-no-buckets.s (original)
+++ llvm/trunk/test/tools/llvm-dwarfdump/X86/debug-names-verify-no-buckets.s Thu Mar 22 07:50:44 2018
@@ -66,7 +66,7 @@
 	.byte	46                      # Abbrev code
 	.byte	46                      # DW_TAG_subprogram
 	.byte	3                       # DW_IDX_die_offset
-	.byte	6                       # DW_FORM_data4
+	.byte	19                      # DW_FORM_ref4
 	.byte	0                       # End of abbrev
 	.byte	0                       # End of abbrev
 	.byte	0                       # End of abbrev list




More information about the llvm-commits mailing list