[llvm] 0d8cb8b - DWARFVerifier: Verify CU/TU index overlap issues

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Thu May 5 11:19:04 PDT 2022


Author: David Blaikie
Date: 2022-05-05T18:18:53Z
New Revision: 0d8cb8b399adcd17e8bf17be7814d030308c8b82

URL: https://github.com/llvm/llvm-project/commit/0d8cb8b399adcd17e8bf17be7814d030308c8b82
DIFF: https://github.com/llvm/llvm-project/commit/0d8cb8b399adcd17e8bf17be7814d030308c8b82.diff

LOG: DWARFVerifier: Verify CU/TU index overlap issues

Discovered in a large object that would need a 64 bit index (but the
cu/tu index format doesn't include a 64 bit offset/length mode in
DWARF64 - a spec bug) but instead binutils dwp overflowed the offsets
causing overlapping regions.

Added: 
    llvm/test/DebugInfo/X86/debug-cu-index-overlap.s

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

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h
index d7e1bc7452552..b5e191ba7def7 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h
@@ -64,6 +64,25 @@ enum DWARFSectionKind {
   DW_SECT_EXT_MACINFO = 10,
 };
 
+inline const char *toString(DWARFSectionKind Kind) {
+  switch (Kind) {
+  case DW_SECT_EXT_unknown:
+    return "Unknown DW_SECT value 0";
+#define STRINGIZE(X) #X
+#define HANDLE_DW_SECT(ID, NAME)                                               \
+  case DW_SECT_##NAME:                                                         \
+    return "DW_SECT_" STRINGIZE(NAME);
+#include "llvm/BinaryFormat/Dwarf.def"
+  case DW_SECT_EXT_TYPES:
+    return "DW_SECT_TYPES";
+  case DW_SECT_EXT_LOC:
+    return "DW_SECT_LOC";
+  case DW_SECT_EXT_MACINFO:
+    return "DW_SECT_MACINFO";
+  }
+  llvm_unreachable("unknown DWARFSectionKind");
+}
+
 /// Convert the internal value for a section kind to an on-disk value.
 ///
 /// The conversion depends on the version of the index section.

diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
index 1f15855067630..1f1ebe943238a 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
@@ -14,6 +14,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
 #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
 #include <cstdint>
 #include <map>
 #include <set>
@@ -156,6 +157,10 @@ class DWARFVerifier {
   unsigned verifyUnitSection(const DWARFSection &S);
   unsigned verifyUnits(const DWARFUnitVector &Units);
 
+  unsigned verifyIndexes(const DWARFObject &DObj);
+  unsigned verifyIndex(StringRef Name, DWARFSectionKind SectionKind,
+                       StringRef Index);
+
   /// Verifies that a call site entry is nested within a subprogram with a
   /// DW_AT_call attribute.
   ///
@@ -300,6 +305,24 @@ class DWARFVerifier {
   /// \returns true if all sections verify successfully, false otherwise.
   bool handleDebugInfo();
 
+  /// Verify the information in the .debug_cu_index section.
+  ///
+  /// Any errors are reported to the stream that was this object was
+  /// constructed with.
+  ///
+  /// \returns true if the .debug_cu_index verifies successfully, false
+  /// otherwise.
+  bool handleDebugCUIndex();
+
+  /// Verify the information in the .debug_tu_index section.
+  ///
+  /// Any errors are reported to the stream that was this object was
+  /// constructed with.
+  ///
+  /// \returns true if the .debug_tu_index verifies successfully, false
+  /// otherwise.
+  bool handleDebugTUIndex();
+
   /// Verify the information in the .debug_line section.
   ///
   /// Any errors are reported to the stream that was this object was

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 7b32a8e3864e1..6c652dd74c804 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -769,6 +769,10 @@ bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) {
   DWARFVerifier verifier(OS, *this, DumpOpts);
 
   Success &= verifier.handleDebugAbbrev();
+  if (DumpOpts.DumpType & DIDT_DebugCUIndex)
+    Success &= verifier.handleDebugCUIndex();
+  if (DumpOpts.DumpType & DIDT_DebugTUIndex)
+    Success &= verifier.handleDebugTUIndex();
   if (DumpOpts.DumpType & DIDT_DebugInfo)
     Success &= verifier.handleDebugInfo();
   if (DumpOpts.DumpType & DIDT_DebugLine)

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 918cd4e277331..1544714053728 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/ADT/IntervalMap.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
@@ -395,6 +396,57 @@ unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S) {
   return NumDebugInfoErrors;
 }
 
+unsigned DWARFVerifier::verifyIndex(StringRef Name,
+                                    DWARFSectionKind InfoColumnKind,
+                                    StringRef IndexStr) {
+  if (IndexStr.empty())
+    return 0;
+  OS << "Verifying " << Name << "...\n";
+  DWARFUnitIndex Index(InfoColumnKind);
+  DataExtractor D(IndexStr, DCtx.isLittleEndian(), 0);
+  if (!Index.parse(D))
+    return 1;
+  IntervalMap<uint32_t, uint64_t>::Allocator Alloc;
+  std::vector<IntervalMap<uint32_t, uint64_t>> Sections(
+      Index.getColumnKinds().size(), IntervalMap<uint32_t, uint64_t>(Alloc));
+  for (const DWARFUnitIndex::Entry &E : Index.getRows()) {
+    uint64_t Sig = E.getSignature();
+    if (!E.getContributions())
+      continue;
+    for (auto E : enumerate(InfoColumnKind == DW_SECT_INFO
+                                ? makeArrayRef(E.getContributions(),
+                                               Index.getColumnKinds().size())
+                                : makeArrayRef(E.getContribution(), 1))) {
+      const DWARFUnitIndex::Entry::SectionContribution &SC = E.value();
+      int Col = E.index();
+      if (SC.Length == 0)
+        continue;
+      auto &M = Sections[Col];
+      auto I = M.find(SC.Offset);
+      if (I != M.end() && I.start() < (SC.Offset + SC.Length)) {
+        error() << llvm::formatv(
+            "overlapping index entries for entries {0:x16} "
+            "and {1:x16} for column {2}\n",
+            *I, Sig, toString(Index.getColumnKinds()[Col]));
+        return 1;
+      }
+      M.insert(SC.Offset, SC.Offset + SC.Length - 1, Sig);
+    }
+  }
+
+  return 0;
+}
+
+bool DWARFVerifier::handleDebugCUIndex() {
+  return verifyIndex(".debug_cu_index", DWARFSectionKind::DW_SECT_INFO,
+                     DCtx.getDWARFObj().getCUIndexSection()) == 0;
+}
+
+bool DWARFVerifier::handleDebugTUIndex() {
+  return verifyIndex(".debug_tu_index", DWARFSectionKind::DW_SECT_EXT_TYPES,
+                     DCtx.getDWARFObj().getTUIndexSection()) == 0;
+}
+
 bool DWARFVerifier::handleDebugInfo() {
   const DWARFObject &DObj = DCtx.getDWARFObj();
   unsigned NumErrors = 0;

diff  --git a/llvm/test/DebugInfo/X86/debug-cu-index-overlap.s b/llvm/test/DebugInfo/X86/debug-cu-index-overlap.s
new file mode 100644
index 0000000000000..66ed6f5a27594
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/debug-cu-index-overlap.s
@@ -0,0 +1,100 @@
+# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o - | \
+# RUN:   not llvm-dwarfdump -debug-cu-index -debug-tu-index --verify - | FileCheck %s
+
+# FIXME: The verifier should probably be handled to verify the hash table
+# itself - in which case this test would need to be updated to have a correct
+# hash table (currently hand crafted with no attempt at correct allocation of
+# hashes to buckets) - and probably to verify that the section ranges apply to
+# sections that exist, which currently they don't
+
+# This tests that an index that describes units as being in overlapping
+# sections is invalid (this was observed in the wild due to overflow due to the
+# 32 bit limit of the indexes (a DWARF spec bug - there should be a 64 bit
+# version of the index format with 64 bit offsets/sizes)) - but Type Units will
+# generally share all the sections other than the info section with each other
+# (and with their originating CU) since the dwo format has no way to describe
+# which part of non-info-section contributions are used by which units, so
+# they're all shared. So demonstrate that the TU index ignores non-info overlap,
+# but the CU index diagnoses such overlap (in the abbrev section, in this case)
+
+# This doesn't currently check for info section overlap between the CU and TU
+# index, but that could be an extension of this work in the future.
+
+# CHECK: Verifying .debug_cu_index... 
+# CHECK: error: overlapping index entries for entries 0x0000000000000001 and 0x0000000000000002 for column DW_SECT_ABBREV
+# CHECK: Verifying .debug_tu_index... 
+# CHECK: error: overlapping index entries for entries 0x0000000000000001 and 0x0000000000000003 for column DW_SECT_INFO
+
+    .section .debug_cu_index, "", @progbits
+## Header:
+    .long 5             # Version
+    .long 2             # Section count
+    .long 3             # Unit count
+    .long 4             # Slot count
+## Hash Table of Signatures:
+    .quad 0x0000000000000001
+    .quad 0x0000000000000002
+    .quad 0x0000000000000003
+    .quad 0
+## Parallel Table of Indexes:
+    .long 1
+    .long 2
+    .long 3
+    .long 0
+## Table of Section Offsets:
+## Row 0:
+    .long 1             # DW_SECT_INFO
+    .long 3             # DW_SECT_ABBREV
+## Row 1:
+    .long 0x1           # Offset in .debug_info.dwo
+    .long 0x1           # Offset in .debug_abbrev.dwo
+## Row 2:
+    .long 0x2           # Offset in .debug_info.dwo
+    .long 0x1           # Offset in .debug_abbrev.dwo
+## Row 3:
+    .long 0x1           # Offset in .debug_info.dwo
+    .long 0x1           # Offset in .debug_abbrev.dwo
+## Table of Section Sizes:
+    .long 0x1          # Size in .debug_info.dwo
+    .long 0x1          # Size in .debug_abbrev.dwo
+    .long 0x1          # Size in .debug_info.dwo
+    .long 0x1          # Size in .debug_abbrev.dwo
+    .long 0x1          # Size in .debug_info.dwo
+    .long 0x1          # Size in .debug_abbrev.dwo
+
+    .section .debug_tu_index, "", @progbits
+## Header:
+    .long 5             # Version
+    .long 2             # Section count
+    .long 3             # Unit count
+    .long 4             # Slot count
+## Hash Table of Signatures:
+    .quad 0x0000000000000001
+    .quad 0x0000000000000002
+    .quad 0x0000000000000003
+    .quad 0
+## Parallel Table of Indexes:
+    .long 1
+    .long 2
+    .long 3
+    .long 0
+## Table of Section Offsets:
+## Row 0:
+    .long 1             # DW_SECT_INFO
+    .long 3             # DW_SECT_ABBREV
+## Row 1:
+    .long 0x1           # Offset in .debug_info.dwo
+    .long 0x1           # Offset in .debug_abbrev.dwo
+## Row 2:
+    .long 0x2           # Offset in .debug_info.dwo
+    .long 0x1           # Offset in .debug_abbrev.dwo
+## Row 3:
+    .long 0x1           # Offset in .debug_info.dwo
+    .long 0x1           # Offset in .debug_abbrev.dwo
+## Table of Section Sizes:
+    .long 0x1          # Size in .debug_info.dwo
+    .long 0x1          # Size in .debug_abbrev.dwo
+    .long 0x1          # Size in .debug_info.dwo
+    .long 0x1          # Size in .debug_abbrev.dwo
+    .long 0x1          # Size in .debug_info.dwo
+    .long 0x1          # Size in .debug_abbrev.dwo


        


More information about the llvm-commits mailing list