diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h index c0291a83ed97..a7564780cc23 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -114,6 +114,13 @@ class DWARFVerifier { public: DWARFVerifier(raw_ostream &S, DWARFContext &D) : OS(S), DCtx(D) {} + /// Verify the information in the .debug_abbrev section. + /// + /// Currently, we check that no Abbreviation Declaration has more than one + /// attributes with the same name. + /// + /// \returns true if the .debug_abbrev verifies successfully, false otherwise. + bool handleDebugAbbrev(); /// Verify the information in the .debug_info section. /// /// Any errors are reported to the stream that was this object was diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index 88efcd8f49c4..1b45ca9e20df 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -418,6 +418,7 @@ DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) { bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) { bool Success = true; DWARFVerifier verifier(OS, *this); + Success &= verifier.handleDebugAbbrev(); if (DumpType == DIDT_All || DumpType == DIDT_Info) { if (!verifier.handleDebugInfo()) Success = false; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index 50fc45a9e376..d683642af023 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -102,6 +102,37 @@ bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) { return NumUnitErrors == 0; } +bool DWARFVerifier::handleDebugAbbrev() { + OS << "Verifying .debug_abbrev...\n"; + + const DWARFObject &DObj = DCtx.getDWARFObj(); + if (DObj.getAbbrevSection().empty()) { + OS << "Warning: .debug_abbrev is empty.\n"; + return true; + } + + unsigned NumErrors = 0; + const DWARFDebugAbbrev *Abbrev = DCtx.getDebugAbbrev(); + if (Abbrev) { + const DWARFAbbreviationDeclarationSet *AbbrDecls = + Abbrev->getAbbreviationDeclarationSet(0); + for (auto AbbrDecl : *AbbrDecls) { + SmallDenseSet AttributeSet; + for (auto Attribute : AbbrDecl.attributes()) { + auto Result = AttributeSet.insert(Attribute.Attr); + if (!Result.second) { + OS << format("Error: Abbreviation declaration with code %d ", + AbbrDecl.getCode()); + OS << "contains multiple " << AttributeString(Attribute.Attr) + << " attributes.\n"; + ++NumErrors; + } + } + } + } + return NumErrors == 0; +} + bool DWARFVerifier::handleDebugInfo() { OS << "Verifying .debug_info Unit Header Chain...\n"; diff --git a/llvm/test/tools/llvm-dwarfdump/X86/verify_debug_info.s b/llvm/test/tools/llvm-dwarfdump/X86/verify_debug_info.s index 90733eda278f..3268bb91d6f0 100644 --- a/llvm/test/tools/llvm-dwarfdump/X86/verify_debug_info.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/verify_debug_info.s @@ -2,7 +2,9 @@ # RUN: | not llvm-dwarfdump -verify - \ # RUN: | FileCheck %s -# CHECK: Verifying .debug_info Unit Header Chain... +# CHECK: Verifying .debug_abbrev... +# CHECK-NEXT: Error: Abbreviation declaration with code 2 contains multiple DW_AT_low_pc attributes. +# CHECK-NEXT: Verifying .debug_info Unit Header Chain... # CHECK-NEXT: error: DIE has invalid DW_AT_stmt_list encoding:{{[[:space:]]}} # CHECK-NEXT: 0x0000000c: DW_TAG_compile_unit [1] * # CHECK-NEXT: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000000] = "clang version 5.0.0 (trunk 308185) (llvm/trunk 308186)") @@ -80,7 +82,7 @@ Lsection_abbrev: .byte 1 ## DW_CHILDREN_yes .byte 17 ## DW_AT_low_pc .byte 1 ## DW_FORM_addr - .byte 18 ## DW_AT_high_pc + .byte 17 ## DW_AT_low_pc -- Error: Die at offset 0x0000002b contains multiple DW_AT_low_pc attributes. .byte 6 ## DW_FORM_data4 .byte 64 ## DW_AT_frame_base .byte 24 ## DW_FORM_exprloc