]> granicus.if.org Git - llvm/commitdiff
[DWARF] Generalized verification of .apple_names accelerator table to be applicable...
authorSpyridoula Gravani <sgravani@apple.com>
Wed, 26 Jul 2017 00:52:31 +0000 (00:52 +0000)
committerSpyridoula Gravani <sgravani@apple.com>
Wed, 26 Jul 2017 00:52:31 +0000 (00:52 +0000)
Differential Revision: https://reviews.llvm.org/D35853

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

include/llvm/DebugInfo/DWARF/DWARFVerifier.h
lib/DebugInfo/DWARF/DWARFContext.cpp
lib/DebugInfo/DWARF/DWARFVerifier.cpp
test/DebugInfo/dwarfdump-accel.test
test/tools/llvm-dwarfdump/X86/apple_names_verify_data.s
test/tools/llvm-dwarfdump/X86/apple_names_verify_form.s
test/tools/llvm-dwarfdump/X86/apple_names_verify_num_atoms.s

index 55b2895c62b13f08259c6e18e09efd3ef761e4bd..3fe182155e3bf7233e06cdb0adcdc9baa6b2ea41 100644 (file)
@@ -23,6 +23,8 @@ class DWARFUnit;
 class DWARFAcceleratorTable;
 class DWARFDataExtractor;
 class DWARFDebugAbbrev;
+class DataExtractor;
+struct DWARFSection;
 
 /// A class that verifies DWARF debug information given a DWARF Context.
 class DWARFVerifier {
@@ -33,7 +35,6 @@ class DWARFVerifier {
   /// lies between to valid DIEs.
   std::map<uint64_t, std::set<uint32_t>> ReferenceToDIEOffsets;
   uint32_t NumDebugLineErrors = 0;
-  uint32_t NumAppleNamesErrors = 0;
 
   /// Verifies the abbreviations section.
   ///
@@ -133,6 +134,25 @@ class DWARFVerifier {
   /// - invalid file indexes
   void verifyDebugLineRows();
 
+  /// Verify that an Apple-style accelerator table is valid.
+  ///
+  /// This function currently checks that:
+  /// - The fixed part of the header fits in the section
+  /// - The size of the section is as large as what the header describes
+  /// - There is at least one atom
+  /// - The form for each atom is valid
+  /// - The buckets have a valid index, or they are empty
+  /// - Each hashdata offset is valid
+  /// - Each DIE is valid
+  /// 
+  /// \param AccelSection pointer to the section containing the acceleration table
+  /// \param StrData pointer to the string section
+  /// \param SectionName the name of the table we're verifying
+  ///
+  /// \returns The number of errors occured during verification
+  unsigned verifyAccelTable(const DWARFSection *AccelSection,
+                            DataExtractor *StrData, const char *SectionName);
+
 public:
   DWARFVerifier(raw_ostream &S, DWARFContext &D)
       : OS(S), DCtx(D) {}
@@ -162,13 +182,14 @@ public:
   /// \returns true if the .debug_line verifies successfully, false otherwise.
   bool handleDebugLine();
 
-  /// Verify the information in the .apple_names accelerator table.
+  /// Verify the information in accelerator tables, if they exist.
   ///
   /// Any errors are reported to the stream that was this object was
   /// constructed with.
   ///
-  /// \returns true if the .apple_names verifies successfully, false otherwise.
-  bool handleAppleNames();
+  /// \returns true if the existing Apple-style accelerator tables verify
+  /// successfully, false otherwise.
+  bool handleAccelTables();
 };
 
 } // end namespace llvm
index 654fc0c10c409d5680b76ce2e15b4b1d83d6906c..b8bee0c449d1052d10fcd0a65e4d8a5907a2016b 100644 (file)
@@ -427,10 +427,7 @@ bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
     if (!verifier.handleDebugLine())
       Success = false;
   }
-  if (DumpType == DIDT_All || DumpType == DIDT_AppleNames) {
-    if (!verifier.handleAppleNames())
-      Success = false;
-  }
+  Success &= verifier.handleAccelTables();
   return Success;
 }
 
index c76336482f2c95b3bd16afbd0fe3c8c9b3f0845a..c5dc723d8298cb5ba59bfd254fb8617bebb43d70 100644 (file)
@@ -464,61 +464,62 @@ bool DWARFVerifier::handleDebugLine() {
   return NumDebugLineErrors == 0;
 }
 
-bool DWARFVerifier::handleAppleNames() {
-  NumAppleNamesErrors = 0;
-  const DWARFObject &D = DCtx.getDWARFObj();
-  DWARFDataExtractor AppleNamesSection(D, D.getAppleNamesSection(),
-                                       DCtx.isLittleEndian(), 0);
-  DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0);
-  DWARFAcceleratorTable AppleNames(AppleNamesSection, StrData);
-
-  if (!AppleNames.extract()) {
-    return true;
-  }
+unsigned DWARFVerifier::verifyAccelTable(const DWARFSection *AccelSection,
+                                         DataExtractor *StrData,
+                                         const char *SectionName) {
+  unsigned NumErrors = 0;
+  DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
+                                      DCtx.isLittleEndian(), 0);
+  DWARFAcceleratorTable AccelTable(AccelSectionData, *StrData);
 
-  OS << "Verifying .apple_names...\n";
+  OS << "Verifying " << SectionName << "...\n";
+  // Verify that the fixed part of the header is not too short.
 
+  if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {
+    OS << "\terror: Section is too small to fit a section header.\n";
+    return 1;
+  }
+  // Verify that the section is not too short.
+  if (!AccelTable.extract()) {
+    OS << "\terror: Section is smaller than size described in section header.\n";
+    return 1;
+  }
   // Verify that all buckets have a valid hash index or are empty.
-  uint32_t NumBuckets = AppleNames.getNumBuckets();
-  uint32_t NumHashes = AppleNames.getNumHashes();
+  uint32_t NumBuckets = AccelTable.getNumBuckets();
+  uint32_t NumHashes = AccelTable.getNumHashes();
 
   uint32_t BucketsOffset =
-      AppleNames.getSizeHdr() + AppleNames.getHeaderDataLength();
+      AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
   uint32_t HashesBase = BucketsOffset + NumBuckets * 4;
   uint32_t OffsetsBase = HashesBase + NumHashes * 4;
-
   for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
-    uint32_t HashIdx = AppleNamesSection.getU32(&BucketsOffset);
+    uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
     if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
-      OS << format("error: Bucket[%d] has invalid hash index: %u\n", BucketIdx,
+      OS << format("\terror: Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
                    HashIdx);
-      ++NumAppleNamesErrors;
+      ++NumErrors;
     }
   }
-
-  uint32_t NumAtoms = AppleNames.getAtomsDesc().size();
+  uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
   if (NumAtoms == 0) {
-    OS << "error: no atoms; failed to read HashData\n";
-    ++NumAppleNamesErrors;
-    return false;
+    OS << "\terror: no atoms; failed to read HashData.\n";
+    return 1;
   }
-
-  if (!AppleNames.validateForms()) {
-    OS << "error: unsupported form; failed to read HashData\n";
-    ++NumAppleNamesErrors;
-    return false;
+  if (!AccelTable.validateForms()) {
+    OS << "\terror: unsupported form; failed to read HashData.\n";
+    return 1;
   }
 
   for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
     uint32_t HashOffset = HashesBase + 4 * HashIdx;
     uint32_t DataOffset = OffsetsBase + 4 * HashIdx;
-    uint32_t Hash = AppleNamesSection.getU32(&HashOffset);
-    uint32_t HashDataOffset = AppleNamesSection.getU32(&DataOffset);
-    if (!AppleNamesSection.isValidOffsetForDataOfSize(HashDataOffset,
-                                                      sizeof(uint64_t))) {
-      OS << format("error: Hash[%d] has invalid HashData offset: 0x%08x\n",
+    uint32_t Hash = AccelSectionData.getU32(&HashOffset);
+    uint32_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
+    if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
+                                                     sizeof(uint64_t))) {
+      OS << format("\terror: Hash[%d] has invalid HashData offset: 0x%08x.\n",
                    HashIdx, HashDataOffset);
-      ++NumAppleNamesErrors;
+      ++NumErrors;
     }
 
     uint32_t StrpOffset;
@@ -526,32 +527,51 @@ bool DWARFVerifier::handleAppleNames() {
     uint32_t StringCount = 0;
     uint32_t DieOffset = dwarf::DW_INVALID_OFFSET;
 
-    while ((StrpOffset = AppleNamesSection.getU32(&HashDataOffset)) != 0) {
+    while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
       const uint32_t NumHashDataObjects =
-          AppleNamesSection.getU32(&HashDataOffset);
+          AccelSectionData.getU32(&HashDataOffset);
       for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
            ++HashDataIdx) {
-        DieOffset = AppleNames.readAtoms(HashDataOffset);
+        DieOffset = AccelTable.readAtoms(HashDataOffset);
         if (!DCtx.getDIEForOffset(DieOffset)) {
           const uint32_t BucketIdx =
               NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
           StringOffset = StrpOffset;
-          const char *Name = StrData.getCStr(&StringOffset);
+          const char *Name = StrData->getCStr(&StringOffset);
           if (!Name)
             Name = "<NULL>";
 
           OS << format(
-              "error: .apple_names Bucket[%d] Hash[%d] = 0x%08x "
+              "\terror: %s Bucket[%d] Hash[%d] = 0x%08x "
               "Str[%u] = 0x%08x "
               "DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n",
-              BucketIdx, HashIdx, Hash, StringCount, StrpOffset, HashDataIdx,
-              DieOffset, Name);
+              SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
+              HashDataIdx, DieOffset, Name);
 
-          ++NumAppleNamesErrors;
+          ++NumErrors;
         }
       }
       ++StringCount;
     }
   }
-  return NumAppleNamesErrors == 0;
+  return NumErrors;
+}
+
+bool DWARFVerifier::handleAccelTables() {
+  const DWARFObject &D = DCtx.getDWARFObj();
+  DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0);
+  unsigned NumErrors = 0;
+  if (!D.getAppleNamesSection().Data.empty())
+    NumErrors +=
+        verifyAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names");
+  if (!D.getAppleTypesSection().Data.empty())
+    NumErrors +=
+        verifyAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types");
+  if (!D.getAppleNamespacesSection().Data.empty())
+    NumErrors += verifyAccelTable(&D.getAppleNamespacesSection(), &StrData,
+                                  ".apple_namespaces");
+  if (!D.getAppleObjCSection().Data.empty())
+    NumErrors +=
+        verifyAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc");
+  return NumErrors == 0;
 }
index a49d024992c2692996c11e67456d2e96f15f59a8..e73b086ddd5a724666e023f3ee130b42aee1e993 100644 (file)
@@ -1,5 +1,5 @@
 RUN: llvm-dwarfdump %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s
-RUN: llvm-dwarfdump -verify %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s --check-prefix=VERIFY
+RUN: not llvm-dwarfdump -verify %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s --check-prefix=VERIFY
 
 Gather some DIE indexes to verify the accelerator table contents.
 CHECK: .debug_info contents
@@ -66,5 +66,9 @@ CHECK:     {Atom[0]: [[ASSIGN]]}
 CHECK:     {Atom[0]: [[SETASSIGN]]}
 
 Verify the debug info in the apple_names accelerator table.
-VERIFY: Verifying .apple_names
-VERIFY-NEXT: No errors.
+VERIFY: Verifying .apple_names...
+VERIFY-NEXT: Verifying .apple_types...
+VERIFY-NEXT: Verifying .apple_namespaces...
+VERIFY-NEXT: error: Section is smaller than size described in section header.
+VERIFY-NEXT: Verifying .apple_objc...
+VERIFY-NEXT: Errors detected.
index 6d548543e4b9a8f598a253da04738af9015d1c52..280ceaed6b13f725b136510226023a421b5f5865 100644 (file)
@@ -3,9 +3,9 @@
 # RUN: | FileCheck %s
 
 # CHECK: Verifying .apple_names...
-# CHECK-NEXT: error: Bucket[0] has invalid hash index: 4294967294
-# CHECK-NEXT: error: Hash[0] has invalid HashData offset: 0x000000b4
-# CHECK-NEXT: error: .apple_names Bucket[1] Hash[1] = 0x0002b60f Str[0] = 0x0000005a DIE[0] = 0x00000001 is not a valid DIE offset for "j".
+# CHECK-NEXT:  error: Bucket[0] has invalid hash index: 4294967294.
+# CHECK-NEXT:  error: Hash[0] has invalid HashData offset: 0x000000b4.
+# CHECK-NEXT:  error: .apple_names Bucket[1] Hash[1] = 0x0002b60f Str[0] = 0x0000005a DIE[0] = 0x00000001 is not a valid DIE offset for "j".
 
 # This test is meant to verify that the -verify option 
 # in llvm-dwarfdump, correctly identifies
@@ -41,11 +41,11 @@ Lnames_begin:
        .long   1                       ## HeaderData Atom Count
        .short  1                       ## DW_ATOM_die_offset
        .short  25                       ## DW_FORM_data4 -- error: .apple_names Bucket[1] Hash[1] = 0x0002b60f Str[0] = 0x0000005a DIE[0] = 0x00000001 is not a valid DIE offset for "j".
-       .long   -2                      ## Bucket 0 -- error: Bucket[0] has invalid hash index: 4294967294
+       .long   -2                      ## Bucket 0 -- error: Bucket[0] has invalid hash index: 4294967294.
        .long   1                       ## Bucket 1
        .long   177678                  ## Hash in Bucket 0
        .long   177679                  ## Hash in Bucket 1
-       .long   Lsection_line    ## Offset in Bucket 0 -- error: Hash[0] has invalid HashData offset: 0x000000b4
+       .long   Lsection_line    ## Offset in Bucket 0 -- error: Hash[0] has invalid HashData offset: 0x000000b4.
        .long   LNames1-Lnames_begin    ## Offset in Bucket 1
 LNames0:
        .long   84                      ## i
index ed4bf57069cedc32696404c7ba48ba03b0247b8c..1e58de076e9d959f9c3c546709dd34e11cae88c4 100644 (file)
@@ -3,7 +3,7 @@
 # RUN: | FileCheck %s
 
 # CHECK: Verifying .apple_names...
-# CHECK-NEXT: error: unsupported form; failed to read HashData
+# CHECK-NEXT:  error: unsupported form; failed to read HashData.
 
 # This test is meant to verify that the -verify option 
 # in llvm-dwarfdump, correctly identifies that Atom[0].form is unsupported.
@@ -34,7 +34,7 @@ Lnames_begin:
        .long   0                       ## HeaderData Die Offset Base
        .long   1                       ## HeaderData Atom Count
        .short  1                       ## DW_ATOM_die_offset
-       .short  400                     ## DW_FORM_data4 -- error: unsupported form; failed to read HashData
+       .short  400                     ## DW_FORM_data4 -- error: unsupported form; failed to read HashData.
        .long   0                       ## Bucket 0
        .long   1                       ## Bucket 1
        .long   177678                  ## Hash in Bucket 0
index dffb39c20f08556a2fbeacf329c4c2dd670d2c57..6ddb0c910d4d27b190060fb56dae6f1ef1a3ff3b 100644 (file)
@@ -3,7 +3,7 @@
 # RUN: | FileCheck %s
 
 # CHECK: Verifying .apple_names...
-# CHECK-NEXT: error: no atoms; failed to read HashData
+# CHECK-NEXT:  error: no atoms; failed to read HashData.
 
 # This test is meant to verify that the -verify option 
 # in llvm-dwarfdump, correctly identifies that there is not Atom.
@@ -33,7 +33,7 @@ Lnames_begin:
        .long   2                       ## Header Hash Count
        .long   12                      ## Header Data Length
        .long   0                       ## HeaderData Die Offset Base
-       .long   0                       ## HeaderData Atom Count -- error: no atoms; failed to read HashData
+       .long   0                       ## HeaderData Atom Count -- error: no atoms; failed to read HashData.
        .short  1                       ## DW_ATOM_die_offset
        .short  6                       ## DW_FORM_data4
        .long   0                       ## Bucket 0