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) {
class DWARFDie;
class DWARFUnit;
class DWARFAcceleratorTable;
+class DWARFDataExtractor;
/// A class that verifies DWARF debug information given a DWARF Context.
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:
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
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;
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;
--- /dev/null
+# 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: