[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