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 #include #include @@ -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::Allocator Alloc; + std::vector> Sections( + Index.getColumnKinds().size(), IntervalMap(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