Index: include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -238,6 +238,34 @@ 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) { Index: include/llvm/DebugInfo/DWARF/DWARFVerifier.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -21,6 +21,7 @@ class DWARFDie; class DWARFUnit; class DWARFAcceleratorTable; +class DWARFDataExtractor; /// A class that verifies DWARF debug information given a DWARF Context. class DWARFVerifier { @@ -34,6 +35,10 @@ uint32_t NumDebugLineErrors = 0; uint32_t NumAppleNamesErrors = 0; + bool isUnitDWARF64 = false; + + bool verifyUnit(const DWARFDataExtractor DebugInfoData, uint32_t *Offset, + unsigned UnitIndex); /// Verifies the attribute's DWARF attribute and its value. /// /// This function currently checks for: @@ -78,6 +83,14 @@ 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 Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -414,6 +414,8 @@ 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; Index: lib/DebugInfo/DWARF/DWARFVerifier.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -24,6 +24,95 @@ using namespace dwarf; using namespace object; +bool DWARFVerifier::verifyUnit(const DWARFDataExtractor DebugInfoData, + uint32_t *Offset, unsigned UnitIndex) { + 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"; + bool Success = true; + DWARFDataExtractor DebugInfoData(DCtx.getInfoSection(), DCtx.isLittleEndian(), + 0); + uint32_t OffsetStart, Offset = 0, UnitIdx = 0; + bool hasDIE = DebugInfoData.isValidOffset(Offset); + while (hasDIE) { + OffsetStart = Offset; + if (!verifyUnit(DebugInfoData, &Offset, UnitIdx)) { + 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; Index: test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s =================================================================== --- /dev/null +++ test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s @@ -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: