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 validateUnitType(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 computeDWARF5HeaderSize(uint8_t UnitType) { + switch (UnitType) { + 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; + case dwarf::DW_UT_compile: + case dwarf::DW_UT_partial: + default: + return 12; + } + } + 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,11 +21,22 @@ class DWARFDie; class DWARFUnit; class DWARFAcceleratorTable; +class DWARFDataExtractor; + +struct VerifyFlags { + bool ValidLength = false; + bool ValidVersion = false; + bool ValidAddrSize = false; + bool ValidType = true; + bool ValidAbbrevOffset = true; + bool isDWARF64 = false; +}; /// A class that verifies DWARF debug information given a DWARF Context. class DWARFVerifier { raw_ostream &OS; DWARFContext &DCtx; + VerifyFlags HeaderFlags; /// A map that tracks all references (converted absolute references) so we /// can verify each reference points to a valid DIE and not an offset that /// lies between to valid DIEs. @@ -34,6 +45,8 @@ uint32_t NumDebugLineErrors = 0; uint32_t NumAppleNamesErrors = 0; + bool verifyUnit(const DWARFDataExtractor DebugInfoData, + uint32_t *Offset); /// Verifies the attribute's DWARF attribute and its value. /// /// This function currently checks for: @@ -78,6 +91,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,90 @@ using namespace dwarf; using namespace object; +bool DWARFVerifier::verifyUnit(const DWARFDataExtractor DebugInfoData, + uint32_t *Offset) { + uint32_t AbbrOffset, Length; + uint8_t AddrSize = 0, UnitType = 0; + uint16_t Version; + bool Success = true; + uint32_t HeaderSize; + + uint32_t OffsetStart = *Offset; + Length = DebugInfoData.getU32(Offset); + if (Length == UINT32_MAX) { + HeaderFlags.isDWARF64 = true; + return false; + } + Version = DebugInfoData.getU16(Offset); + + if (Version >= 5) { + UnitType = DebugInfoData.getU8(Offset); + AddrSize = DebugInfoData.getU8(Offset); + AbbrOffset = DebugInfoData.getU32(Offset); + HeaderFlags.ValidType = DWARFUnit::validateUnitType(UnitType); + HeaderSize = DWARFUnit::computeDWARF5HeaderSize(UnitType); + } else { + AbbrOffset = DebugInfoData.getU32(Offset); + AddrSize = DebugInfoData.getU8(Offset); + HeaderSize = 11; // means that we have only compile units in .debug_info + } + + if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset)) + HeaderFlags.ValidAbbrevOffset = false; + + HeaderFlags.ValidLength = + DebugInfoData.isValidOffset(OffsetStart + Length + 3); + HeaderFlags.ValidVersion = DWARFContext::isSupportedVersion(Version); + HeaderFlags.ValidAddrSize = AddrSize == 4 || AddrSize == 8; + if (!HeaderFlags.ValidLength || !HeaderFlags.ValidVersion || + !HeaderFlags.ValidAddrSize || !HeaderFlags.ValidAbbrevOffset || + !HeaderFlags.ValidType) + Success = false; + + *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, CUIndex = 0; + bool hasDIE = DebugInfoData.isValidOffset(Offset); + while (hasDIE) { + OffsetStart = Offset; + if (!verifyUnit(DebugInfoData, &Offset)) { + Success = false; + OS << format("Units[%d] - start offset: 0x%08x \n", CUIndex, OffsetStart); + if (HeaderFlags.isDWARF64) { + OS << "Unit is in 64-bit DWARF format; cannot verify.\n"; + return true; + } + if (!HeaderFlags.ValidLength) + OS << "\tError: The length for this unit is too " + "large for the .debug_info provided.\n"; + if (!HeaderFlags.ValidVersion) + OS << "\tError: The 16 bit unit header version is not valid.\n"; + if (!HeaderFlags.ValidType) + OS << "\tError: The unit type encoding is not valid.\n"; + if (!HeaderFlags.ValidAbbrevOffset) + OS << "\tError: The offset into the .debug_abbrev section is " + "not valid.\n"; + if (!HeaderFlags.ValidAddrSize) + OS << "\tError: The address size is unsupported.\n"; + } + hasDIE = DebugInfoData.isValidOffset(Offset); + ++CUIndex; + } + if (Success && !hasDIE) { + OS << format("Warning: .debug_info is empty.\n", CUIndex); + Success = true; + } + OS << "\n"; + 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,84 @@ +# 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[3] - start offset: 0x00000034 +# 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. +# CHECK-NEXT: Error: The offset into the .debug_abbrev section is not valid. + + .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 + .byte 3 ## Address Size (in bytes) + .long 0 + .quad 0 + .long 0 + .byte 0 +Lcu_begin1: + .long 10 ## Length of Unit + .short 6 ## DWARF version number + .byte 1 ## DWARF Unit Type + .byte 4 ## Address Size (in bytes) + .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 + .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: