[DWARF] Introduce verification for the unit header chain in .debug_info section to llvm-dwarfdump.

This patch adds verification checks for the unit header chain in the .debug_info section.
Specifically, for each unit in the .debug_info section, the verifier checks that:

The unit length is valid (i.e. the unit can actually fit in the .debug_info section)
The dwarf version of the unit is valid
The address size is valid (4 or 8)
The unit type (if the unit is in dwarf5) is valid
The debug_abbrev_offset is valid

llvm-svn: 307975
This commit is contained in:
Spyridoula Gravani 2017-07-13 23:25:24 +00:00
parent 3b4317cbc2
commit 890eedc4e4
5 changed files with 235 additions and 0 deletions

View File

@ -238,6 +238,34 @@ public:
uint8_t getUnitType() const { return UnitType; }
static bool isValidUnitType(uint8_t UnitType) {
return UnitType == dwarf::DW_UT_compile || UnitType == dwarf::DW_UT_type ||
UnitType == dwarf::DW_UT_partial ||
UnitType == dwarf::DW_UT_skeleton ||
UnitType == dwarf::DW_UT_split_compile ||
UnitType == dwarf::DW_UT_split_type;
}
/// \brief Return the number of bytes for the header of a unit of
/// UnitType type.
///
/// This function must be called with a valid unit type which in
/// DWARF5 is defined as one of the following six types.
static uint32_t getDWARF5HeaderSize(uint8_t UnitType) {
switch (UnitType) {
case dwarf::DW_UT_compile:
case dwarf::DW_UT_partial:
return 12;
case dwarf::DW_UT_skeleton:
case dwarf::DW_UT_split_compile:
return 20;
case dwarf::DW_UT_type:
case dwarf::DW_UT_split_type:
return 24;
}
llvm_unreachable("Invalid UnitType.");
}
uint64_t getBaseAddress() const { return BaseAddr; }
void setBaseAddress(uint64_t base_addr) {

View File

@ -21,6 +21,7 @@ class DWARFContext;
class DWARFDie;
class DWARFUnit;
class DWARFAcceleratorTable;
class DWARFDataExtractor;
/// A class that verifies DWARF debug information given a DWARF Context.
class DWARFVerifier {
@ -34,6 +35,29 @@ class DWARFVerifier {
uint32_t NumDebugLineErrors = 0;
uint32_t NumAppleNamesErrors = 0;
/// Verifies the header of a unit in the .debug_info section.
///
/// This function currently checks for:
/// - Unit is in 32-bit DWARF format. The function can be modified to
/// support 64-bit format.
/// - The DWARF version is valid
/// - The unit type is valid (if unit is in version >=5)
/// - The unit doesn't extend beyond .debug_info section
/// - The address size is valid
/// - The offset in the .debug_abbrev section is valid
///
/// \param DebugInfoData The .debug_info section data
/// \param Offset A reference to the offset start of the unit. The offset will
/// be updated to point to the next unit in .debug_info
/// \param UnitIndex The index of the unit to be verified
/// \param isUnitDWARF64 A reference to a flag that shows whether the unit is
/// in 64-bit format.
///
/// \returns true if the header is verified successfully, false otherwise.
bool verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
uint32_t *Offset, unsigned UnitIndex,
bool &isUnitDWARF64);
/// Verifies the attribute's DWARF attribute and its value.
///
/// This function currently checks for:
@ -78,6 +102,14 @@ class DWARFVerifier {
public:
DWARFVerifier(raw_ostream &S, DWARFContext &D)
: OS(S), DCtx(D) {}
/// Verify the unit header chain in the .debug_info section.
///
/// Any errors are reported to the stream that this object was
/// constructed with.
///
/// \returns true if the unit header chain verifies successfully, false
/// otherwise.
bool handleDebugInfoUnitHeaderChain();
/// Verify the information in the .debug_info section.
///
/// Any errors are reported to the stream that was this object was

View File

@ -414,6 +414,8 @@ DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) {
bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
bool Success = true;
DWARFVerifier verifier(OS, *this);
if (!verifier.handleDebugInfoUnitHeaderChain())
Success = false;
if (DumpType == DIDT_All || DumpType == DIDT_Info) {
if (!verifier.handleDebugInfo())
Success = false;

View File

@ -24,6 +24,98 @@ using namespace llvm;
using namespace dwarf;
using namespace object;
bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
uint32_t *Offset, unsigned UnitIndex,
bool &isUnitDWARF64) {
uint32_t AbbrOffset, Length;
uint8_t AddrSize = 0, UnitType = 0;
uint16_t Version;
bool Success = true;
uint32_t HeaderSize =
11; // means that we have only compile units in .debug_info
bool ValidLength = false;
bool ValidVersion = false;
bool ValidAddrSize = false;
bool ValidType = true;
bool ValidAbbrevOffset = true;
uint32_t OffsetStart = *Offset;
Length = DebugInfoData.getU32(Offset);
if (Length == UINT32_MAX) {
isUnitDWARF64 = true;
OS << format(
"Unit[%d] is in 64-bit DWARF format; cannot verify from this point.\n",
UnitIndex);
return false;
}
Version = DebugInfoData.getU16(Offset);
if (Version >= 5) {
UnitType = DebugInfoData.getU8(Offset);
AddrSize = DebugInfoData.getU8(Offset);
AbbrOffset = DebugInfoData.getU32(Offset);
ValidType = DWARFUnit::isValidUnitType(UnitType);
if (ValidType)
HeaderSize = DWARFUnit::getDWARF5HeaderSize(UnitType);
} else {
AbbrOffset = DebugInfoData.getU32(Offset);
AddrSize = DebugInfoData.getU8(Offset);
}
if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset))
ValidAbbrevOffset = false;
ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3);
ValidVersion = DWARFContext::isSupportedVersion(Version);
ValidAddrSize = AddrSize == 4 || AddrSize == 8;
if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
!ValidType) {
Success = false;
OS << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, OffsetStart);
if (!ValidLength)
OS << "\tError: The length for this unit is too "
"large for the .debug_info provided.\n";
if (!ValidVersion)
OS << "\tError: The 16 bit unit header version is not valid.\n";
if (!ValidType)
OS << "\tError: The unit type encoding is not valid.\n";
if (!ValidAbbrevOffset)
OS << "\tError: The offset into the .debug_abbrev section is "
"not valid.\n";
if (!ValidAddrSize)
OS << "\tError: The address size is unsupported.\n";
}
*Offset = OffsetStart + Length + 4;
return Success;
}
bool DWARFVerifier::handleDebugInfoUnitHeaderChain() {
OS << "Verifying .debug_info Unit Header Chain...\n";
DWARFDataExtractor DebugInfoData(DCtx.getInfoSection(), DCtx.isLittleEndian(),
0);
uint32_t OffsetStart, Offset = 0, UnitIdx = 0;
bool isUnitDWARF64 = false;
bool Success = true;
bool hasDIE = DebugInfoData.isValidOffset(Offset);
while (hasDIE) {
OffsetStart = Offset;
if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, isUnitDWARF64)) {
Success = false;
if (isUnitDWARF64)
break;
}
hasDIE = DebugInfoData.isValidOffset(Offset);
++UnitIdx;
}
if (UnitIdx == 0 && !hasDIE) {
OS << "Warning: .debug_info is empty.\n";
Success = true;
}
return Success;
}
void DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
DWARFAttribute &AttrValue) {
const auto Attr = AttrValue.Attr;

View File

@ -0,0 +1,81 @@
# RUN: llvm-mc %s -filetype obj -triple x86_64-apple-darwin -o - \
# RUN: | not llvm-dwarfdump -verify - \
# RUN: | FileCheck %s
# CHECK: Verifying .debug_info Unit Header Chain...
# CHECK-NEXT: Units[1] - start offset: 0x0000000d
# CHECK-NEXT: Error: The unit type encoding is not valid.
# CHECK-NEXT: Error: The address size is unsupported.
# CHECK-NEXT: Units[2] - start offset: 0x00000026
# CHECK-NEXT: Error: The 16 bit unit header version is not valid.
# CHECK-NEXT: Error: The offset into the .debug_abbrev section is not valid.
# CHECK-NEXT: Units[4] - start offset: 0x00000041
# CHECK-NEXT: Error: The length for this unit is too large for the .debug_info provided.
.section __TEXT,__text,regular,pure_instructions
.file 1 "basic.c"
.comm _i,4,2 ## @i
.comm _j,4,2 ## @j
.section __DWARF,__debug_str,regular,debug
Linfo_string:
.asciz "clang version 5.0.0 (trunk 307232) (llvm/trunk 307042)" ## string offset=0
.asciz "basic.c" ## string offset=55
.asciz "/Users/sgravani/Development/tests" ## string offset=63
.asciz "i" ## string offset=97
.asciz "int" ## string offset=99
.asciz "j" ## string offset=103
.section __DWARF,__debug_abbrev,regular,debug
Lsection_abbrev:
.byte 1 ## Abbreviation Code
.byte 17 ## DW_TAG_compile_unit
.byte 0 ## EOM(1)
.byte 0 ## EOM(2)
.byte 0 ## EOM(3)
.section __DWARF,__debug_info,regular,debug
Lsection_info:
Lcu_begin0:
.long 9 ## Length of Unit
.short 4 ## DWARF version number
Lset0 = Lsection_abbrev-Lsection_abbrev ## Offset Into Abbrev. Section
.long Lset0
.byte 4 ## Address Size (in bytes)
.byte 1 ## Abbrev [1] 0xc:0x45 DW_TAG_compile_unit
.byte 0 ## End Of Children Mark
Ltu_begin0:
.long 21 ## Length of Unit
.short 5 ## DWARF version number
.byte 0 ## DWARF Unit Type -- Error: The unit type encoding is not valid.
.byte 3 ## Address Size (in bytes) -- Error: The address size is unsupported.
.long 0
.quad 0
.long 0
.byte 0
Lcu_begin1:
.long 10 ## Length of Unit
.short 6 ## DWARF version number -- Error: The 16 bit unit header version is not valid.
.byte 1 ## DWARF Unit Type
.byte 4 ## Address Size (in bytes) -- The offset into the .debug_abbrev section is not valid.
.long Lline_table_start0
.byte 1 ## Abbrev [1] 0xc:0x45 DW_TAG_compile_unit
.byte 0 ## End Of Children Mark
Lcu_begin2:
.long 9 ## Length of Unit
.short 5 ## DWARF version number
.byte 1 ## DWARF Unit Type
.byte 4 ## Address Size (in bytes)
.long 0 ## Abbrev offset
.byte 0
Ltu_begin1:
.long 26 ## Length of Unit -- Error: The length for this unit is too large for the .debug_info provided.
.short 5 ## DWARF version number
.byte 2 ## DWARF Unit Type
.byte 4 ## Address Size (in bytes)
.long 0
.quad 0
.long 0
.byte 0
.subsections_via_symbols
.section __DWARF,__debug_line,regular,debug
Lsection_line:
Lline_table_start0: