mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-24 17:01:07 +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,
|
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.
|
/// Convert the internal value for a section kind to an on-disk value.
|
||||||
///
|
///
|
||||||
/// The conversion depends on the version of the index section.
|
/// The conversion depends on the version of the index section.
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
|
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
|
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
||||||
|
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -156,6 +157,10 @@ private:
|
|||||||
unsigned verifyUnitSection(const DWARFSection &S);
|
unsigned verifyUnitSection(const DWARFSection &S);
|
||||||
unsigned verifyUnits(const DWARFUnitVector &Units);
|
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
|
/// Verifies that a call site entry is nested within a subprogram with a
|
||||||
/// DW_AT_call attribute.
|
/// DW_AT_call attribute.
|
||||||
///
|
///
|
||||||
@ -300,6 +305,24 @@ public:
|
|||||||
/// \returns true if all sections verify successfully, false otherwise.
|
/// \returns true if all sections verify successfully, false otherwise.
|
||||||
bool handleDebugInfo();
|
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.
|
/// Verify the information in the .debug_line section.
|
||||||
///
|
///
|
||||||
/// Any errors are reported to the stream that was this object was
|
/// 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);
|
DWARFVerifier verifier(OS, *this, DumpOpts);
|
||||||
|
|
||||||
Success &= verifier.handleDebugAbbrev();
|
Success &= verifier.handleDebugAbbrev();
|
||||||
|
if (DumpOpts.DumpType & DIDT_DebugCUIndex)
|
||||||
|
Success &= verifier.handleDebugCUIndex();
|
||||||
|
if (DumpOpts.DumpType & DIDT_DebugTUIndex)
|
||||||
|
Success &= verifier.handleDebugTUIndex();
|
||||||
if (DumpOpts.DumpType & DIDT_DebugInfo)
|
if (DumpOpts.DumpType & DIDT_DebugInfo)
|
||||||
Success &= verifier.handleDebugInfo();
|
Success &= verifier.handleDebugInfo();
|
||||||
if (DumpOpts.DumpType & DIDT_DebugLine)
|
if (DumpOpts.DumpType & DIDT_DebugLine)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
|
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
|
||||||
|
#include "llvm/ADT/IntervalMap.h"
|
||||||
#include "llvm/ADT/SmallSet.h"
|
#include "llvm/ADT/SmallSet.h"
|
||||||
#include "llvm/BinaryFormat/Dwarf.h"
|
#include "llvm/BinaryFormat/Dwarf.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
||||||
@ -395,6 +396,57 @@ unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S) {
|
|||||||
return NumDebugInfoErrors;
|
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() {
|
bool DWARFVerifier::handleDebugInfo() {
|
||||||
const DWARFObject &DObj = DCtx.getDWARFObj();
|
const DWARFObject &DObj = DCtx.getDWARFObj();
|
||||||
unsigned NumErrors = 0;
|
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