mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-24 00:29:25 +00:00
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.
This commit is contained in:
parent
18fd09ab64
commit
0d8cb8b399
@ -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.
|
||||
|
@ -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 @@ private:
|
||||
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 @@ public:
|
||||
/// \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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
100
llvm/test/DebugInfo/X86/debug-cu-index-overlap.s
Normal file
100
llvm/test/DebugInfo/X86/debug-cu-index-overlap.s
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user