From 9fb72f1b5607e6a57e230f075438ae58a9ca0147 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 6 Oct 2017 22:27:31 +0000 Subject: [PATCH] [dwarfdump] Verify that unit type matches root DIE This patch adds two new verifiers: - It checks that the root DIE of a CU is actually a valid unit DIE. (based on its tag) - For DWARF5 which contains a unit type int he CU header, it checks that this matches the type of the unit DIE. Differential revision: https://reviews.llvm.org/D38453 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@315121 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/BinaryFormat/Dwarf.h | 27 ++++++++++++++++ include/llvm/DebugInfo/DWARF/DWARFUnit.h | 21 ++++++++---- include/llvm/DebugInfo/DWARF/DWARFVerifier.h | 18 +++++++++-- lib/DebugInfo/DWARF/DWARFVerifier.cpp | 32 ++++++++++++++----- test/DebugInfo/dwarfdump-header.test | 1 + test/tools/llvm-dwarfdump/X86/empty-CU.s | 2 +- .../llvm-dwarfdump/X86/verify_debug_info.s | 2 ++ .../X86/verify_unit_header_chain.s | 2 ++ 8 files changed, 88 insertions(+), 17 deletions(-) diff --git a/include/llvm/BinaryFormat/Dwarf.h b/include/llvm/BinaryFormat/Dwarf.h index 8f7d055e271..a89adbee298 100644 --- a/include/llvm/BinaryFormat/Dwarf.h +++ b/include/llvm/BinaryFormat/Dwarf.h @@ -325,6 +325,33 @@ enum UnitType : unsigned char { DW_UT_hi_user = 0xff }; +inline bool isUnitType(uint8_t UnitType) { + switch (UnitType) { + case DW_UT_compile: + case DW_UT_type: + case DW_UT_partial: + case DW_UT_skeleton: + case DW_UT_split_compile: + case DW_UT_split_type: + return true; + default: + return false; + } +} + +inline bool isUnitType(dwarf::Tag T) { + switch (T) { + case DW_TAG_compile_unit: + case DW_TAG_type_unit: + case DW_TAG_partial_unit: + case DW_TAG_skeleton_unit: + case DW_TAG_imported_unit: + return true; + default: + return false; + } +} + // Constants for the DWARF v5 Accelerator Table Proposal enum AcceleratorTable { // Data layout descriptors. diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h index 0df5c16e4a2..78f873e9840 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -285,12 +285,21 @@ 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; + static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) { + switch (UnitType) { + case dwarf::DW_UT_compile: + return Tag == dwarf::DW_TAG_compile_unit; + case dwarf::DW_UT_type: + return Tag == dwarf::DW_TAG_type_unit; + case dwarf::DW_UT_partial: + return Tag == dwarf::DW_TAG_partial_unit; + case dwarf::DW_UT_skeleton: + return Tag == dwarf::DW_TAG_skeleton_unit; + case dwarf::DW_UT_split_compile: + case dwarf::DW_UT_split_type: + return dwarf::isUnitType(Tag); + } + return false; } /// \brief Return the number of bytes for the header of a unit of diff --git a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h index 0429c26e81d..0d920abe323 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -136,8 +136,22 @@ private: uint32_t *Offset, unsigned UnitIndex, uint8_t &UnitType, bool &isUnitDWARF64); - - bool verifyUnitContents(DWARFUnit Unit); + /// Verifies the header of a unit in the .debug_info section. + /// + /// This function currently verifies: + /// - The debug info attributes. + /// - The debug info form=s. + /// - The presence of a root DIE. + /// - That the root DIE is a unit DIE. + /// - If a unit type is provided, that the unit DIE matches the unit type. + /// - The DIE ranges. + /// + /// \param Unit The DWARF Unit to verifiy. + /// \param UnitType An optional unit type which will be used to verify the + /// type of the unit DIE. + /// + /// \returns true if the content is verified successfully, false otherwise. + bool verifyUnitContents(DWARFUnit Unit, uint8_t UnitType = 0); /// Verify that all Die ranges are valid. /// diff --git a/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/lib/DebugInfo/DWARF/DWARFVerifier.cpp index 27e6a05e6dd..bec6e922ceb 100644 --- a/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -134,7 +134,7 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, UnitType = DebugInfoData.getU8(Offset); AddrSize = DebugInfoData.getU8(Offset); AbbrOffset = DebugInfoData.getU32(Offset); - ValidType = DWARFUnit::isValidUnitType(UnitType); + ValidType = dwarf::isUnitType(UnitType); } else { UnitType = 0; AbbrOffset = DebugInfoData.getU32(Offset); @@ -169,7 +169,7 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, return Success; } -bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) { +bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit, uint8_t UnitType) { uint32_t NumUnitErrors = 0; unsigned NumDies = Unit.getNumDIEs(); for (unsigned I = 0; I < NumDies; ++I) { @@ -182,14 +182,30 @@ bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) { } } - if (DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false)) { - DieRangeInfo RI; - NumUnitErrors += verifyDieRanges(Die, RI); - } else { - error() << "Compilation unit without unit DIE.\n"; + DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false); + if (!Die) { + error() << "Compilation unit without DIE.\n"; + NumUnitErrors++; + return NumUnitErrors == 0; + } + + if (!dwarf::isUnitType(Die.getTag())) { + error() << "Compilation unit root DIE is not a unit DIE: " + << dwarf::TagString(Die.getTag()) << ".\n"; NumUnitErrors++; } + if (UnitType != 0 && + !DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) { + error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType) + << ") and root DIE (" << dwarf::TagString(Die.getTag()) + << ") do not match.\n"; + NumUnitErrors++; + } + + DieRangeInfo RI; + NumUnitErrors += verifyDieRanges(Die, RI); + return NumUnitErrors == 0; } @@ -286,7 +302,7 @@ bool DWARFVerifier::handleDebugInfo() { default: { llvm_unreachable("Invalid UnitType."); } } Unit->extract(DebugInfoData, &OffsetStart); - if (!verifyUnitContents(*Unit)) + if (!verifyUnitContents(*Unit, UnitType)) ++NumDebugInfoErrors; } hasDIE = DebugInfoData.isValidOffset(Offset); diff --git a/test/DebugInfo/dwarfdump-header.test b/test/DebugInfo/dwarfdump-header.test index 5a7be988edb..375f7043c9f 100644 --- a/test/DebugInfo/dwarfdump-header.test +++ b/test/DebugInfo/dwarfdump-header.test @@ -1,4 +1,5 @@ RUN: llvm-dwarfdump -v %p/Inputs/dwarfdump-header.elf-x86-64 | FileCheck %s +RUN: llvm-dwarfdump -v --verify %p/Inputs/dwarfdump-header.elf-x86-64 The input file is hand-coded assembler to generate all the units, so we're willing to make exact checks for offsets and such. diff --git a/test/tools/llvm-dwarfdump/X86/empty-CU.s b/test/tools/llvm-dwarfdump/X86/empty-CU.s index 14ff75836f4..a01fc16e0d7 100644 --- a/test/tools/llvm-dwarfdump/X86/empty-CU.s +++ b/test/tools/llvm-dwarfdump/X86/empty-CU.s @@ -1,7 +1,7 @@ # RUN: llvm-mc %s -filetype obj -triple x86_64-apple-darwin -o - \ # RUN: | not llvm-dwarfdump --verify --debug-info - \ # RUN: | FileCheck %s -# CHECK: error: Compilation unit without unit DIE. +# CHECK: error: Compilation unit without DIE. .section __DWARF,__debug_info,regular,debug .long 8 # CU length diff --git a/test/tools/llvm-dwarfdump/X86/verify_debug_info.s b/test/tools/llvm-dwarfdump/X86/verify_debug_info.s index b87db731a75..af947afb30e 100644 --- a/test/tools/llvm-dwarfdump/X86/verify_debug_info.s +++ b/test/tools/llvm-dwarfdump/X86/verify_debug_info.s @@ -11,6 +11,8 @@ # CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x0000003f] = "/Users/sgravani/Development/tests") # CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) # CHECK-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000016){{[[:space:]]}} +# CHECK-NEXT: error: Compilation unit root DIE is not a unit DIE: DW_TAG_null. +# CHECK-NEXT: error: Compilation unit type (DW_UT_compile) and root DIE (DW_TAG_null) do not match. # CHECK-NEXT: error: Units[2] - start offset: 0x00000068 # CHECK-NEXT: note: The length for this unit is too large for the .debug_info provided. # CHECK-NEXT: note: The unit type encoding is not valid. diff --git a/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s b/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s index baee5d86a24..046e7b7b6a2 100644 --- a/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s +++ b/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s @@ -9,6 +9,8 @@ # CHECK-NEXT: error: Units[2] - start offset: 0x00000026 # CHECK-NEXT: note: The 16 bit unit header version is not valid. # CHECK-NEXT: note: The offset into the .debug_abbrev section is not valid. +# CHECK-NEXT: error: Compilation unit root DIE is not a unit DIE: DW_TAG_null. +# CHECK-NEXT: error: Compilation unit type (DW_UT_compile) and root DIE (DW_TAG_null) do not match. # CHECK-NEXT: error: Units[4] - start offset: 0x00000041 # CHECK-NEXT: note: The length for this unit is too large for the .debug_info provided. -- 2.50.1