From 715726429ec4fc4f0f5f0f2e3dc6c3c31ce8f3a6 Mon Sep 17 00:00:00 2001 From: Alex Langford Date: Tue, 23 May 2023 17:13:31 -0700 Subject: [PATCH] [DebugInfo] Add error-handling to DWARFAbbreviationDeclarationSet This commit aims to improve error handling in the DWARFAbbreviationDeclarationSet class. Specifically, we change the return type of DWARFAbbreviationDeclarationSet::extract to an llvm::Error. In doing so, we propagate the error from DWARFAbbreviationDeclaration::extract another layer upward. I have built on the previous unittest for DWARFDebugAbbrev that I wrote a few days prior. Namely, I am verifying that the following should give an error: - An invalid tag following a non-null code - An invalid attribute with a valid form - A valid attribute with an invalid form - An incorrectly terminated DWARFAbbreviationDeclaration Additionally, I uncovered some invalid DWARF in an unrelated dsymutil test. Namely the last Abbreviation Decl was missing a code. This test has been updated accordingly. However, this commit does not fix the underlying issue: llvm-dwarfdump does not correctly verify the debug abbreviation section to catch these kinds of mistakes. I have updated DWARFVerifier to not dereference a pointer without first checking it and left a FIXME for future contributors. Differential Revision: https://reviews.llvm.org/D151353 --- .../llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h | 2 +- llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp | 25 +- llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp | 33 ++- llvm/test/DebugInfo/ARM/dwarfdump-rela.yaml | 2 +- llvm/test/DebugInfo/X86/dwarfdump-header-64.s | 1 + llvm/test/DebugInfo/X86/dwarfdump-rela-dwo.s | 1 + llvm/test/tools/dsymutil/Inputs/empty-CU.o | Bin 388 -> 0 bytes llvm/test/tools/dsymutil/Inputs/empty-CU.s | 9 +- llvm/test/tools/dsymutil/Inputs/swift-interface.s | 329 ++++++++++++--------- llvm/test/tools/dsymutil/X86/empty-CU.test | 3 +- llvm/test/tools/llvm-dwarfdump/X86/debug-abbrev.s | 4 +- llvm/test/tools/llvm-dwarfdump/X86/no_debug_addr.s | 1 + .../test/tools/llvm-dwarfdump/X86/verify_strings.s | 1 + .../llvm-dwarfdump/X86/verify_unit_header_chain.s | 1 + .../DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp | 171 +++++++++-- 15 files changed, 392 insertions(+), 191 deletions(-) delete mode 100644 llvm/test/tools/dsymutil/Inputs/empty-CU.o diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h index aa3885d..76833cc 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h @@ -34,7 +34,7 @@ public: uint64_t getOffset() const { return Offset; } void dump(raw_ostream &OS) const; - bool extract(DataExtractor Data, uint64_t *OffsetPtr); + Error extract(DataExtractor Data, uint64_t *OffsetPtr); const DWARFAbbreviationDeclaration * getAbbreviationDeclaration(uint32_t AbbrCode) const; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp index a8df634..54093dd 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp @@ -25,21 +25,18 @@ void DWARFAbbreviationDeclarationSet::clear() { Decls.clear(); } -bool DWARFAbbreviationDeclarationSet::extract(DataExtractor Data, - uint64_t *OffsetPtr) { +Error DWARFAbbreviationDeclarationSet::extract(DataExtractor Data, + uint64_t *OffsetPtr) { clear(); const uint64_t BeginOffset = *OffsetPtr; Offset = BeginOffset; DWARFAbbreviationDeclaration AbbrDecl; uint32_t PrevAbbrCode = 0; while (true) { - llvm::Expected ES = + Expected ES = AbbrDecl.extract(Data, OffsetPtr); - if (!ES) { - // FIXME: We should propagate the error upwards. - llvm::consumeError(ES.takeError()); - break; - } + if (!ES) + return ES.takeError(); if (*ES == DWARFAbbreviationDeclaration::ExtractState::Complete) break; @@ -53,7 +50,7 @@ bool DWARFAbbreviationDeclarationSet::extract(DataExtractor Data, PrevAbbrCode = AbbrDecl.getCode(); Decls.push_back(std::move(AbbrDecl)); } - return BeginOffset != *OffsetPtr; + return Error::success(); } void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const { @@ -127,8 +124,11 @@ void DWARFDebugAbbrev::parse() const { ++I; uint64_t CUAbbrOffset = Offset; DWARFAbbreviationDeclarationSet AbbrDecls; - if (!AbbrDecls.extract(*Data, &Offset)) + if (Error Err = AbbrDecls.extract(*Data, &Offset)) { + // FIXME: We should propagate the error upwards. + consumeError(std::move(Err)); break; + } AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls))); } Data = std::nullopt; @@ -164,8 +164,11 @@ DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const { if (Data && CUAbbrOffset < Data->getData().size()) { uint64_t Offset = CUAbbrOffset; DWARFAbbreviationDeclarationSet AbbrDecls; - if (!AbbrDecls.extract(*Data, &Offset)) + if (Error Err = AbbrDecls.extract(*Data, &Offset)) { + // FIXME: We should propagate the error upwards. + consumeError(std::move(Err)); return nullptr; + } PrevAbbrOffsetPos = AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls))) .first; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index e0f2fdd..5459144 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -299,20 +299,27 @@ unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) { } unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) { + if (!Abbrev) + return 0; + + const DWARFAbbreviationDeclarationSet *AbbrDecls = + Abbrev->getAbbreviationDeclarationSet(0); + // FIXME: If we failed to get a DWARFAbbreviationDeclarationSet, it's possible + // that there are errors. We need to propagate the error from + // getAbbreviationDeclarationSet. + if (!AbbrDecls) + return 0; + unsigned NumErrors = 0; - 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) { - error() << "Abbreviation declaration contains multiple " - << AttributeString(Attribute.Attr) << " attributes.\n"; - AbbrDecl.dump(OS); - ++NumErrors; - } + for (auto AbbrDecl : *AbbrDecls) { + SmallDenseSet AttributeSet; + for (auto Attribute : AbbrDecl.attributes()) { + auto Result = AttributeSet.insert(Attribute.Attr); + if (!Result.second) { + error() << "Abbreviation declaration contains multiple " + << AttributeString(Attribute.Attr) << " attributes.\n"; + AbbrDecl.dump(OS); + ++NumErrors; } } } diff --git a/llvm/test/DebugInfo/ARM/dwarfdump-rela.yaml b/llvm/test/DebugInfo/ARM/dwarfdump-rela.yaml index 9e307f4..f65e56a 100644 --- a/llvm/test/DebugInfo/ARM/dwarfdump-rela.yaml +++ b/llvm/test/DebugInfo/ARM/dwarfdump-rela.yaml @@ -24,7 +24,7 @@ Sections: Content: 17000000050001040000000001A000000000000000020000000000 - Name: .debug_abbrev Type: SHT_PROGBITS - Content: 011101030E49130000022400030E0000 + Content: 011101030E49130000022400030E000000 - Name: .debug_str Type: SHT_PROGBITS - Name: .rela.debug_info diff --git a/llvm/test/DebugInfo/X86/dwarfdump-header-64.s b/llvm/test/DebugInfo/X86/dwarfdump-header-64.s index 6f3cf69..a8f250a 100644 --- a/llvm/test/DebugInfo/X86/dwarfdump-header-64.s +++ b/llvm/test/DebugInfo/X86/dwarfdump-header-64.s @@ -41,6 +41,7 @@ abbrev: .byte 0x17 # DW_FORM_sec_offset .byte 0x00 # EOM(1) .byte 0x00 # EOM(2) + .byte 0x00 # EOM(3) .ifdef ELF .section .debug_info,"",@progbits diff --git a/llvm/test/DebugInfo/X86/dwarfdump-rela-dwo.s b/llvm/test/DebugInfo/X86/dwarfdump-rela-dwo.s index cff1331..d55f70f 100644 --- a/llvm/test/DebugInfo/X86/dwarfdump-rela-dwo.s +++ b/llvm/test/DebugInfo/X86/dwarfdump-rela-dwo.s @@ -31,6 +31,7 @@ .byte 0x25 # DW_FORM_strx1 .byte 0x00 # EOM(1) .byte 0x00 # EOM(2) + .byte 0x00 # EOM(3) .section .debug_info.dwo,"e",@progbits # CHECK-LABEL: .debug_info.dwo diff --git a/llvm/test/tools/dsymutil/Inputs/empty-CU.o b/llvm/test/tools/dsymutil/Inputs/empty-CU.o deleted file mode 100644 index 11c5905bc12ae4ea9984582b9bc900a2f32b5cb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 388 zcmX^A>+L^w1_nlE1|R{%OhD`bVnBf;khVbL!^B~<43v=pRRiM#&13*!khvfbA77GM zQ37E@_#v(lAqYM?3uYdYcmom}XkJQcQfYd8W?ou8NIX8?CEPK{4Ot18Ee;jIVjjq= zZ~!weF)67iwG7idm^rLa9rc)Df?}QuP@MosEe{u12M3UZgar#DB3xJ)1%cuKUuYWR diff --git a/llvm/test/tools/dsymutil/Inputs/empty-CU.s b/llvm/test/tools/dsymutil/Inputs/empty-CU.s index c539588..d5ba26c 100644 --- a/llvm/test/tools/dsymutil/Inputs/empty-CU.s +++ b/llvm/test/tools/dsymutil/Inputs/empty-CU.s @@ -10,7 +10,8 @@ .byte 4 .section __DWARF,__debug_abbrev,regular,debug .byte 1 # Abbrev code -.byte 0x11 # TAG_compile_unit -.byte 0 # no children -.byte 0 # no attributes -.byte 0 +.byte 0x11 # DW_TAG_compile_unit +.byte 0 # DW_CHILDREN_no +.byte 0 # Terminating attribute +.byte 0 # Terminating form +.byte 0 # Terminating abbrev code diff --git a/llvm/test/tools/dsymutil/Inputs/swift-interface.s b/llvm/test/tools/dsymutil/Inputs/swift-interface.s index f08ab9a..a69f008 100644 --- a/llvm/test/tools/dsymutil/Inputs/swift-interface.s +++ b/llvm/test/tools/dsymutil/Inputs/swift-interface.s @@ -2,16 +2,16 @@ ##; ##; target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" ##; target triple = "x86_64-apple-macosx10.9.0" -##; +##; ##; @__swift_reflection_version = linkonce_odr hidden constant i16 3 ##; @llvm.used = appending global [1 x i8*] [i8* bitcast (i16* @__swift_reflection_version to i8*)], section "llvm.metadata", align 8 -##; +##; ##; define i32 @main(i32, i8**) !dbg !29 { ##; entry: ##; %2 = bitcast i8** %1 to i8* ##; ret i32 0, !dbg !35 ##; } -##; +##; ##; !llvm.dbg.cu = !{!0} ##; !swift.module.flags = !{!14} ##; !llvm.module.flags = !{!20, !21, !24} @@ -23,9 +23,9 @@ ##; !4 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !1, entity: !5, file: !1) ##; !5 = !DIModule(scope: null, name: "Foo", includePath: "/Foo/x86_64.swiftinterface") ##; !6 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !1, entity: !7, file: !1) -##; !7 = !DIModule(scope: null, name: "Swift", includePath: "/SDK/Swift.swiftmodule/x86_64.swiftinterface", sysroot: "/SDK") +##; !7 = !DIModule(scope: null, name: "Swift", includePath: "/SDK/Swift.swiftmodule/x86_64.swiftinterface") ##; !8 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !1, entity: !7, file: !1) -##; !9 = !DIModule(scope: null, name: "Foundation", includePath: "/SDK/Foundation.swiftmodu +##; !9 = !DIModule(scope: null, name: "Foundation", includePath: "/SDK/Foundation.swiftmodule") ##; !14 = !{!"standard-library", i1 false} ##; !20 = !{i32 2, !"Dwarf Version", i32 4} ##; !21 = !{i32 2, !"Debug Info Version", i32 3} @@ -36,14 +36,14 @@ ##; !35 = !DILocation(line: 0, scope: !36) ##; !36 = !DILexicalBlockFile(scope: !29, file: !37, discriminator: 0) ##; !37 = !DIFile(filename: "", directory: "") - .section __TEXT,__text,regular,pure_instructions + .section __TEXT,__text,regular,pure_instructions .macosx_version_min 10, 9 - .globl _main ## -- Begin function main + .globl _main ## -- Begin function main .p2align 4, 0x90 _main: ## @main Lfunc_begin0: - .file 1 "/ParseableInterfaceImports.swift" - .loc 1 0 0 ## ParseableInterfaceImports.swift:0:0 + .file 1 "/" "ParseableInterfaceImports.swift" + .loc 1 0 0 ## ParseableInterfaceImports.swift:0:0 .cfi_startproc ## %bb.0: ## %entry xorl %eax, %eax @@ -56,160 +56,209 @@ Lfunc_end0: .section __TEXT,__const .globl ___swift_reflection_version .weak_definition ___swift_reflection_version - .p2align 1 + .p2align 1, 0x0 ___swift_reflection_version: - .short 3 ## 0x3 + .short 3 ## 0x3 .no_dead_strip ___swift_reflection_version - .section __DWARF,__debug_str,regular,debug -Linfo_string: - .byte 0 ## string offset=0 - .asciz "ParseableInterfaceImports.swift" ## string offset=1 - .asciz "/" ## string offset=33 - .asciz "Foo" ## string offset=35 - .asciz "/Foo/x86_64.swiftinterface" ## string offset=39 - .asciz "Swift" ## string offset=66 - .asciz "/SDK/Swift.swiftmodule/x86_64.swiftinterface" ## string offset=72 - .asciz "/SDK" ## string offset=117 - .asciz "main" ## string offset=122 - .asciz "Foundation" ## string offset=127 - .asciz "/SDK/Foundation.swiftmodule/x86_64.swiftinterface" ## string offset=138 .section __DWARF,__debug_abbrev,regular,debug Lsection_abbrev: - .byte 1 ## Abbreviation Code - .byte 17 ## DW_TAG_compile_unit - .byte 1 ## DW_CHILDREN_yes - .byte 37 ## DW_AT_producer - .byte 14 ## DW_FORM_strp - .byte 19 ## DW_AT_language - .byte 5 ## DW_FORM_data2 - .byte 3 ## DW_AT_name - .byte 14 ## DW_FORM_strp - .ascii "\202|" ## DW_AT_LLVM_sysroot - .byte 14 ## DW_FORM_strp - .byte 16 ## DW_AT_stmt_list - .byte 23 ## DW_FORM_sec_offset - .byte 27 ## DW_AT_comp_dir - .byte 14 ## DW_FORM_strp - .ascii "\345\177" ## DW_AT_APPLE_major_runtime_vers - .byte 11 ## DW_FORM_data1 - .byte 17 ## DW_AT_low_pc - .byte 1 ## DW_FORM_addr - .byte 18 ## DW_AT_high_pc - .byte 6 ## DW_FORM_data4 - .byte 0 ## EOM(1) - .byte 0 ## EOM(2) - .byte 2 ## Abbreviation Code - .byte 30 ## DW_TAG_module - .byte 1 ## DW_CHILDREN_yes - .byte 3 ## DW_AT_name - .byte 14 ## DW_FORM_strp - .ascii "\200|" ## DW_AT_LLVM_include_path - .byte 14 ## DW_FORM_strp - .byte 0 ## EOM(1) - .byte 0 ## EOM(2) - .byte 3 ## Abbreviation Code - .byte 46 ## DW_TAG_subprogram - .byte 0 ## DW_CHILDREN_no - .byte 17 ## DW_AT_low_pc - .byte 1 ## DW_FORM_addr - .byte 18 ## DW_AT_high_pc - .byte 6 ## DW_FORM_data4 - .ascii "\347\177" ## DW_AT_APPLE_omit_frame_ptr - .byte 25 ## DW_FORM_flag_present - .byte 64 ## DW_AT_frame_base - .byte 24 ## DW_FORM_exprloc - .byte 110 ## DW_AT_linkage_name - .byte 14 ## DW_FORM_strp - .byte 3 ## DW_AT_name - .byte 14 ## DW_FORM_strp - .byte 58 ## DW_AT_decl_file - .byte 11 ## DW_FORM_data1 - .byte 59 ## DW_AT_decl_line - .byte 11 ## DW_FORM_data1 - .byte 63 ## DW_AT_external - .byte 25 ## DW_FORM_flag_present - .byte 0 ## EOM(1) - .byte 0 ## EOM(2) - .byte 4 ## Abbreviation Code - .byte 58 ## DW_TAG_imported_module - .byte 0 ## DW_CHILDREN_no - .byte 24 ## DW_AT_import - .byte 19 ## DW_FORM_ref4 - .byte 0 ## EOM(1) - .byte 0 ## EOM(2) - .byte 5 ## Abbreviation Code - .byte 30 ## DW_TAG_module - .byte 0 ## DW_CHILDREN_no - .byte 3 ## DW_AT_name - .byte 14 ## DW_FORM_strp - .ascii "\200|" ## DW_AT_LLVM_include_path - .byte 14 ## DW_FORM_strp - .ascii "\202|" ## DW_AT_LLVM_sysroot - .byte 14 ## DW_FORM_strp - .byte 0 ## EOM(1) - .byte 0 ## EOM(2) - .byte 30 ## DW_TAG_module - .byte 1 ## DW_CHILDREN_no - .byte 3 ## DW_AT_name - .byte 14 ## DW_FORM_strp - .ascii "\200|" ## DW_AT_LLVM_include_path - .byte 14 ## DW_FORM_strp - .byte 0 ## EOM(1) - .byte 0 ## EOM(2) - .byte 0 ## EOM(3) + .byte 1 ## Abbreviation Code + .byte 17 ## DW_TAG_compile_unit + .byte 1 ## DW_CHILDREN_yes + .byte 37 ## DW_AT_producer + .byte 14 ## DW_FORM_strp + .byte 19 ## DW_AT_language + .byte 5 ## DW_FORM_data2 + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .ascii "\202|" ## DW_AT_LLVM_sysroot + .byte 14 ## DW_FORM_strp + .byte 16 ## DW_AT_stmt_list + .byte 23 ## DW_FORM_sec_offset + .byte 27 ## DW_AT_comp_dir + .byte 14 ## DW_FORM_strp + .ascii "\345\177" ## DW_AT_APPLE_major_runtime_vers + .byte 11 ## DW_FORM_data1 + .byte 17 ## DW_AT_low_pc + .byte 1 ## DW_FORM_addr + .byte 18 ## DW_AT_high_pc + .byte 6 ## DW_FORM_data4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 2 ## Abbreviation Code + .byte 30 ## DW_TAG_module + .byte 1 ## DW_CHILDREN_yes + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .ascii "\200|" ## DW_AT_LLVM_include_path + .byte 14 ## DW_FORM_strp + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 3 ## Abbreviation Code + .byte 46 ## DW_TAG_subprogram + .byte 0 ## DW_CHILDREN_no + .byte 17 ## DW_AT_low_pc + .byte 1 ## DW_FORM_addr + .byte 18 ## DW_AT_high_pc + .byte 6 ## DW_FORM_data4 + .ascii "\347\177" ## DW_AT_APPLE_omit_frame_ptr + .byte 25 ## DW_FORM_flag_present + .byte 64 ## DW_AT_frame_base + .byte 24 ## DW_FORM_exprloc + .byte 110 ## DW_AT_linkage_name + .byte 14 ## DW_FORM_strp + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 63 ## DW_AT_external + .byte 25 ## DW_FORM_flag_present + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 4 ## Abbreviation Code + .byte 58 ## DW_TAG_imported_module + .byte 0 ## DW_CHILDREN_no + .byte 24 ## DW_AT_import + .byte 19 ## DW_FORM_ref4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 5 ## Abbreviation Code + .byte 30 ## DW_TAG_module + .byte 0 ## DW_CHILDREN_no + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .ascii "\200|" ## DW_AT_LLVM_include_path + .byte 14 ## DW_FORM_strp + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 0 ## EOM(3) .section __DWARF,__debug_info,regular,debug Lsection_info: Lcu_begin0: .set Lset0, Ldebug_info_end0-Ldebug_info_start0 ## Length of Unit .long Lset0 Ldebug_info_start0: - .short 4 ## DWARF version number + .short 4 ## DWARF version number .set Lset1, Lsection_abbrev-Lsection_abbrev ## Offset Into Abbrev. Section .long Lset1 - .byte 8 ## Address Size (in bytes) - .byte 1 ## Abbrev [1] 0xb:0x5b DW_TAG_compile_unit - .long 0 ## DW_AT_producer - .short 30 ## DW_AT_language - .long 1 ## DW_AT_name - .long 117 ## DW_AT_name + .byte 8 ## Address Size (in bytes) + .byte 1 ## Abbrev [1] 0xb:0x60 DW_TAG_compile_unit + .long 0 ## DW_AT_producer + .short 30 ## DW_AT_language + .long 1 ## DW_AT_name + .long 33 ## DW_AT_LLVM_sysroot .set Lset2, Lline_table_start0-Lsection_line ## DW_AT_stmt_list .long Lset2 - .long 33 ## DW_AT_comp_dir - .byte 5 ## DW_AT_APPLE_major_runtime_vers - .quad Lfunc_begin0 ## DW_AT_low_pc + .long 38 ## DW_AT_comp_dir + .byte 5 ## DW_AT_APPLE_major_runtime_vers + .quad Lfunc_begin0 ## DW_AT_low_pc .set Lset3, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc .long Lset3 - .byte 2 ## Abbrev [2] 0x2b:0x23 DW_TAG_module - .long 35 ## DW_AT_name - .long 39 ## DW_AT_LLVM_include_path - .byte 3 ## Abbrev [3] 0x34:0x19 DW_TAG_subprogram - .quad Lfunc_begin0 ## DW_AT_low_pc + .byte 2 ## Abbrev [2] 0x2f:0x23 DW_TAG_module + .long 40 ## DW_AT_name + .long 44 ## DW_AT_LLVM_include_path + .byte 3 ## Abbrev [3] 0x38:0x19 DW_TAG_subprogram + .quad Lfunc_begin0 ## DW_AT_low_pc .set Lset4, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc .long Lset4 ## DW_AT_APPLE_omit_frame_ptr - .byte 1 ## DW_AT_frame_base + .byte 1 ## DW_AT_frame_base .byte 87 - .long 122 ## DW_AT_linkage_name - .long 122 ## DW_AT_name - .byte 1 ## DW_AT_decl_file - .byte 1 ## DW_AT_decl_line + .long 122 ## DW_AT_linkage_name + .long 122 ## DW_AT_name + .byte 1 ## DW_AT_decl_file + .byte 1 ## DW_AT_decl_line ## DW_AT_external - .byte 0 ## End Of Children Mark - .byte 4 ## Abbrev [4] 0x4e:0x5 DW_TAG_imported_module - .long 47 ## DW_AT_import - .byte 5 ## Abbrev [5] 0x53:0xd DW_TAG_module - .long 66 ## DW_AT_name - .long 72 ## DW_AT_LLVM_include_path - .long 117 ## DW_AT_LLVM_sysroot - .byte 4 ## Abbrev [4] 0x60:0x5 DW_TAG_imported_module - .long 105 ## DW_AT_import - .byte 2 ## Abbrev [2] 0x2b:0x23 DW_TAG_module - .long 127 ## DW_AT_name - .long 138 ## DW_AT_LLVM_include_path - .byte 0 ## End Of Children Mark - .byte 0 ## End Of Children Mark + .byte 0 ## End Of Children Mark + .byte 4 ## Abbrev [4] 0x52:0x5 DW_TAG_imported_module + .long 47 ## DW_AT_import + .byte 5 ## Abbrev [5] 0x57:0x9 DW_TAG_module + .long 71 ## DW_AT_name + .long 77 ## DW_AT_LLVM_include_path + .byte 4 ## Abbrev [4] 0x60:0x5 DW_TAG_imported_module + .long 87 ## DW_AT_import + .byte 4 ## Abbrev [4] 0x65:0x5 DW_TAG_imported_module + .long 87 ## DW_AT_import + .byte 0 ## End Of Children Mark Ldebug_info_end0: + .section __DWARF,__debug_str,regular,debug +Linfo_string: + .byte 0 ## string offset=0 + .asciz "ParseableInterfaceImports.swift" ## string offset=1 + .asciz "/SDK" ## string offset=33 + .asciz "/" ## string offset=38 + .asciz "Foo" ## string offset=40 + .asciz "/Foo/x86_64.swiftinterface" ## string offset=44 + .asciz "Swift" ## string offset=71 + .asciz "/SDK/Swift.swiftmodule/x86_64.swiftinterface" ## string offset=77 + .asciz "main" ## string offset=122 + .section __DWARF,__apple_names,regular,debug +Lnames_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 1 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long 0 ## Bucket 0 + .long 2090499946 ## Hash in Bucket 0 +.set Lset5, LNames0-Lnames_begin ## Offset in Bucket 0 + .long Lset5 +LNames0: + .long 122 ## main + .long 1 ## Num DIEs + .long 56 + .long 0 + .section __DWARF,__apple_objc,regular,debug +Lobjc_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 0 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long -1 ## Bucket 0 + .section __DWARF,__apple_namespac,regular,debug +Lnamespac_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 0 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long -1 ## Bucket 0 + .section __DWARF,__apple_types,regular,debug +Ltypes_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 0 ## Header Hash Count + .long 20 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 3 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .short 3 ## DW_ATOM_die_tag + .short 5 ## DW_FORM_data2 + .short 4 ## DW_ATOM_type_flags + .short 11 ## DW_FORM_data1 + .long -1 ## Bucket 0 .subsections_via_symbols .section __DWARF,__debug_line,regular,debug Lsection_line: diff --git a/llvm/test/tools/dsymutil/X86/empty-CU.test b/llvm/test/tools/dsymutil/X86/empty-CU.test index bd3a544..7b06607 100644 --- a/llvm/test/tools/dsymutil/X86/empty-CU.test +++ b/llvm/test/tools/dsymutil/X86/empty-CU.test @@ -1,4 +1,5 @@ -RUN: dsymutil --update -f %p/../Inputs/empty-CU.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s +RUN: llvm-mc %p/../Inputs/empty-CU.s -filetype obj -triple x86_64-apple-darwin -o %t.o +RUN: dsymutil --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s CHECK: .debug_info contents: CHECK: 0x00000000: Compile Unit: length = 0x00000008, format = DWARF32, version = 0x0003, abbr_offset = 0x0000, addr_size = 0x04 (next unit at 0x0000000c) diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug-abbrev.s b/llvm/test/tools/llvm-dwarfdump/X86/debug-abbrev.s index 04e0845..f9fccc9 100644 --- a/llvm/test/tools/llvm-dwarfdump/X86/debug-abbrev.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug-abbrev.s @@ -79,7 +79,7 @@ .byte 0x02 ## Invalid children encoding (interpreted as DW_CHILDREN_no). .byte 0, 0 ## End of attributes. - .byte 0 ## End of abbrevs. + .byte 0 ## End of first abbreviation set. ## Second .debug_abbrev set. .byte 0x42 ## Abbreviation Code (duplicate in different unit) @@ -88,3 +88,5 @@ .byte 0x66 ## DW_AT_elemental .byte 0x19 ## DW_FORM_flag_present .byte 0, 0 ## End of attributes. + + .byte 0 # End of second abbreviation set. diff --git a/llvm/test/tools/llvm-dwarfdump/X86/no_debug_addr.s b/llvm/test/tools/llvm-dwarfdump/X86/no_debug_addr.s index bf66067..2885891 100644 --- a/llvm/test/tools/llvm-dwarfdump/X86/no_debug_addr.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/no_debug_addr.s @@ -28,6 +28,7 @@ .byte 35 # DW_FORM_rnglistx .byte 0 # EOM(1) .byte 0 # EOM(2) + .byte 0 # EOM(3) .section .debug_rnglists.dwo,"e",@progbits .long .Ldebug_rnglist_table_end1-.Ldebug_rnglist_table_start1 # Length diff --git a/llvm/test/tools/llvm-dwarfdump/X86/verify_strings.s b/llvm/test/tools/llvm-dwarfdump/X86/verify_strings.s index 9beb7a1..b8666f9 100644 --- a/llvm/test/tools/llvm-dwarfdump/X86/verify_strings.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/verify_strings.s @@ -35,6 +35,7 @@ str_producer: .byte 0x17 # DW_FORM_sec_offset .byte 0x00 # EOM(1) .byte 0x00 # EOM(2) + .byte 0x00 # EOM(3) .section .debug_info,"",@progbits diff --git a/llvm/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s b/llvm/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s index baee5d8..5921f75 100644 --- a/llvm/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/verify_unit_header_chain.s @@ -28,6 +28,7 @@ Linfo_string: Lsection_abbrev: .byte 1 ## Abbreviation Code .byte 17 ## DW_TAG_compile_unit + .byte 0 ## DW_CHILDREN_no .byte 0 ## EOM(1) .byte 0 ## EOM(2) .byte 0 ## EOM(3) diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp index 62627ae..7ba22d2 100644 --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugAbbrevTest.cpp @@ -20,8 +20,8 @@ using namespace dwarf; enum OrderKind : bool { InOrder, OutOfOrder }; -void writeAbbreviationDeclarations(raw_ostream &OS, uint32_t FirstCode, - OrderKind Order) { +void writeValidAbbreviationDeclarations(raw_ostream &OS, uint32_t FirstCode, + OrderKind Order) { encodeULEB128(FirstCode, OS); encodeULEB128(DW_TAG_compile_unit, OS); OS << static_cast(DW_CHILDREN_yes); @@ -57,14 +57,13 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetExtractSuccess) { raw_svector_ostream OS(RawData); uint32_t FirstCode = 5; - writeAbbreviationDeclarations(OS, FirstCode, InOrder); + writeValidAbbreviationDeclarations(OS, FirstCode, InOrder); encodeULEB128(0, OS); uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - const bool DataWasExtracted = AbbrevSet.extract(Data, &Offset); - EXPECT_TRUE(DataWasExtracted); + ASSERT_THAT_ERROR(AbbrevSet.extract(Data, &Offset), Succeeded()); // The Abbreviation Declarations are in order and contiguous, so we want to // make sure that FirstAbbrCode was correctly set. EXPECT_EQ(AbbrevSet.getFirstAbbrCode(), FirstCode); @@ -89,14 +88,13 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetExtractSuccessOutOfOrder) { raw_svector_ostream OS(RawData); uint32_t FirstCode = 2; - writeAbbreviationDeclarations(OS, FirstCode, OutOfOrder); + writeValidAbbreviationDeclarations(OS, FirstCode, OutOfOrder); encodeULEB128(0, OS); uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - const bool DataWasExtracted = AbbrevSet.extract(Data, &Offset); - EXPECT_TRUE(DataWasExtracted); + ASSERT_THAT_ERROR(AbbrevSet.extract(Data, &Offset), Succeeded()); // The declarations are out of order, ensure that FirstAbbrCode is UINT32_MAX. EXPECT_EQ(AbbrevSet.getFirstAbbrCode(), UINT32_MAX); @@ -126,7 +124,10 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetCodeExtractionError) { uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - EXPECT_FALSE(AbbrevSet.extract(Data, &Offset)); + ASSERT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage("unable to decode LEB128 at offset 0x00000000: " + "malformed uleb128, extends past end")); EXPECT_EQ(Offset, 0u); } @@ -139,7 +140,10 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetCodeExtractionError) { uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - EXPECT_FALSE(AbbrevSet.extract(Data, &Offset)); + ASSERT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage("unable to decode LEB128 at offset 0x00000000: " + "uleb128 too big for uint64")); EXPECT_EQ(Offset, 0u); } } @@ -157,7 +161,10 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetTagExtractionError) { uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + ASSERT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage("unable to decode LEB128 at offset 0x00000001: " + "malformed uleb128, extends past end")); // Only the code was extracted correctly. EXPECT_EQ(Offset, 1u); } @@ -172,13 +179,16 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetTagExtractionError) { uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + ASSERT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage("unable to decode LEB128 at offset 0x00000001: " + "uleb128 too big for uint64")); // Only the code was extracted correctly. EXPECT_EQ(Offset, 1u); } } -TEST(DWARFDebugAbbrevTest, DWARFAbbreviatioDeclSetChildExtractionError) { +TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetChildExtractionError) { SmallString<64> RawData; const uint32_t Code = 1; const dwarf::Tag Tag = DW_TAG_compile_unit; @@ -188,11 +198,13 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbreviatioDeclSetChildExtractionError) { raw_svector_ostream OS(RawData); encodeULEB128(Code, OS); encodeULEB128(Tag, OS); - uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + ASSERT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage( + "unexpected end of data at offset 0x2 while reading [0x2, 0x3)")); // The code and the tag were extracted correctly. EXPECT_EQ(Offset, 2u); } @@ -214,7 +226,10 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetAttributeExtractionError) { uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + ASSERT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage("unable to decode LEB128 at offset 0x00000003: " + "malformed uleb128, extends past end")); // The code, tag, and child byte were extracted correctly. EXPECT_EQ(Offset, 3u); } @@ -231,7 +246,10 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetAttributeExtractionError) { uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + ASSERT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage("unable to decode LEB128 at offset 0x00000003: " + "uleb128 too big for uint64")); // The code, tag, and child byte were extracted correctly. EXPECT_EQ(Offset, 3u); } @@ -256,7 +274,10 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetFormExtractionError) { uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + ASSERT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage("unable to decode LEB128 at offset 0x00000004: " + "malformed uleb128, extends past end")); // The code, tag, child byte, and first attribute were extracted correctly. EXPECT_EQ(Offset, 4u); } @@ -274,8 +295,120 @@ TEST(DWARFDebugAbbrevTest, DWARFAbbreviationDeclSetFormExtractionError) { uint64_t Offset = 0; DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); DWARFAbbreviationDeclarationSet AbbrevSet; - EXPECT_TRUE(AbbrevSet.extract(Data, &Offset)); + ASSERT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage("unable to decode LEB128 at offset 0x00000004: " + "uleb128 too big for uint64")); // The code, tag, child byte, and first attribute were extracted correctly. EXPECT_EQ(Offset, 4u); } } + +TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetInvalidTag) { + SmallString<64> RawData; + raw_svector_ostream OS(RawData); + uint32_t FirstCode = 1; + // First, we're going to manually add good data. + writeValidAbbreviationDeclarations(OS, FirstCode, InOrder); + + // Afterwards, we're going to write an Abbreviation Decl manually with an + // invalid tag. + encodeULEB128(FirstCode + 2, OS); + encodeULEB128(0, OS); // Invalid Tag + OS << static_cast(DW_CHILDREN_no); + encodeULEB128(DW_AT_name, OS); + encodeULEB128(DW_FORM_strp, OS); + encodeULEB128(0, OS); + encodeULEB128(0, OS); + + encodeULEB128(0, OS); + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage("abbreviation declaration requires a non-null tag")); +} + +TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetInvalidAttrValidForm) { + SmallString<64> RawData; + raw_svector_ostream OS(RawData); + uint32_t FirstCode = 120; + // First, we're going to manually add good data. + writeValidAbbreviationDeclarations(OS, FirstCode, InOrder); + + // Afterwards, we're going to write an Abbreviation Decl manually with an + // invalid attribute but valid form. + encodeULEB128(FirstCode - 5, OS); + encodeULEB128(DW_TAG_compile_unit, OS); + OS << static_cast(DW_CHILDREN_no); + encodeULEB128(0, OS); // Invalid attribute followed by an invalid form. + encodeULEB128(DW_FORM_strp, OS); + encodeULEB128(0, OS); + encodeULEB128(0, OS); + + encodeULEB128(0, OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage( + "malformed abbreviation declaration attribute. Either the " + "attribute or the form is zero while the other is not")); +} + +TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetValidAttrInvalidForm) { + SmallString<64> RawData; + raw_svector_ostream OS(RawData); + uint32_t FirstCode = 120; + // First, we're going to manually add good data. + writeValidAbbreviationDeclarations(OS, FirstCode, InOrder); + + // Afterwards, we're going to write an Abbreviation Decl manually with a + // valid attribute but invalid form. + encodeULEB128(FirstCode - 5, OS); + encodeULEB128(DW_TAG_compile_unit, OS); + OS << static_cast(DW_CHILDREN_no); + encodeULEB128(DW_AT_name, OS); + encodeULEB128(0, OS); // Invalid form after a valid attribute. + encodeULEB128(0, OS); + encodeULEB128(0, OS); + + encodeULEB128(0, OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage( + "malformed abbreviation declaration attribute. Either the " + "attribute or the form is zero while the other is not")); +} + +TEST(DWARFDebugAbbrevTest, DWARFAbbrevDeclSetMissingTerminator) { + SmallString<64> RawData; + raw_svector_ostream OS(RawData); + uint32_t FirstCode = 120; + // First, we're going to manually add good data. + writeValidAbbreviationDeclarations(OS, FirstCode, InOrder); + + // Afterwards, we're going to write an Abbreviation Decl manually without a + // termintating sequence. + encodeULEB128(FirstCode + 7, OS); + encodeULEB128(DW_TAG_compile_unit, OS); + OS << static_cast(DW_CHILDREN_no); + encodeULEB128(DW_AT_name, OS); + encodeULEB128(DW_FORM_strp, OS); + + uint64_t Offset = 0; + DataExtractor Data(RawData, sys::IsLittleEndianHost, sizeof(uint64_t)); + DWARFAbbreviationDeclarationSet AbbrevSet; + EXPECT_THAT_ERROR( + AbbrevSet.extract(Data, &Offset), + FailedWithMessage( + "abbreviation declaration attribute list was not terminated with a " + "null entry")); +} -- 2.7.4