diff --git a/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/lib/DebugInfo/DWARF/DWARFVerifier.cpp index f3b242c47d7..128bd0651ba 100644 --- a/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -611,6 +611,45 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, } break; } + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: { + auto Index = AttrValue.Value.getRawUValue(); + auto DieCU = Die.getDwarfUnit(); + // Check that we have a valid DWARF v5 string offsets table. + if (!DieCU->getStringOffsetsTableContribution()) { + ++NumErrors; + error() << FormEncodingString(Form) + << " used without a valid string offsets table:\n"; + dump(Die) << '\n'; + break; + } + // Check that the index is within the bounds of the section. + unsigned ItemSize = DieCU->getDwarfStringOffsetsByteSize(); + // Use a 64-bit type to calculate the offset to guard against overflow. + uint64_t Offset = + (uint64_t)DieCU->getStringOffsetsBase() + Index * ItemSize; + if (DObj.getStringOffsetSection().Data.size() < Offset + ItemSize) { + ++NumErrors; + error() << FormEncodingString(Form) << " uses index " + << format("%" PRIu64, Index) << ", which is too large:\n"; + dump(Die) << '\n'; + break; + } + // Check that the string offset is valid. + uint64_t StringOffset = *DieCU->getStringOffsetSectionItem(Index); + if (StringOffset >= DObj.getStringSection().size()) { + ++NumErrors; + error() << FormEncodingString(Form) << " uses index " + << format("%" PRIu64, Index) + << ", but the referenced string" + " offset is beyond .debug_str bounds:\n"; + dump(Die) << '\n'; + } + break; + } default: break; } diff --git a/test/DebugInfo/X86/dwarfdump-str-offsets.s b/test/DebugInfo/X86/dwarfdump-str-offsets.s index e68f08b9c7a..2f4215a04ba 100644 --- a/test/DebugInfo/X86/dwarfdump-str-offsets.s +++ b/test/DebugInfo/X86/dwarfdump-str-offsets.s @@ -1,5 +1,6 @@ # RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o # RUN: llvm-dwarfdump -v %t.o 2> %t.err | FileCheck --check-prefix=COMMON --check-prefix=SPLIT %s +# RUN: llvm-dwarfdump -verify %t.o | FileCheck --check-prefix=VERIFY %s # # Check that we don't report an error on a non-existent range list table. # RUN: FileCheck -allow-empty --check-prefix ERR %s < %t.err @@ -136,6 +137,8 @@ dwo_str_TU_5_type: .byte 0x00 # DW_CHILDREN_no .byte 0x03 # DW_AT_name .byte 0x26 # DW_FORM_strx2 + .byte 0x49 # DW_AT_type + .byte 0x13 # DW_FORM_ref4 .byte 0x00 # EOM(1) .byte 0x00 # EOM(2) .byte 0x06 # Abbrev code @@ -143,6 +146,8 @@ dwo_str_TU_5_type: .byte 0x00 # DW_CHILDREN_no .byte 0x03 # DW_AT_name .byte 0x27 # DW_FORM_strx3 + .byte 0x49 # DW_AT_type + .byte 0x13 # DW_FORM_ref4 .byte 0x00 # EOM(1) .byte 0x00 # EOM(2) .byte 0x07 # Abbrev code @@ -150,6 +155,15 @@ dwo_str_TU_5_type: .byte 0x00 # DW_CHILDREN_no .byte 0x03 # DW_AT_name .byte 0x28 # DW_FORM_strx4 + .byte 0x49 # DW_AT_type + .byte 0x13 # DW_FORM_ref4 + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + .byte 0x08 # Abbrev code + .byte 0x24 # DW_TAG_base_type + .byte 0x00 # DW_CHILDREN_no + .byte 0x3e # DW_AT_encoding + .byte 0x0b # DW_FORM_data1 .byte 0x00 # EOM(1) .byte 0x00 # EOM(2) .byte 0x00 # EOM(3) @@ -202,17 +216,24 @@ CU1_5_version: # A subprogram DIE with DW_AT_name, using DW_FORM_strx1. .byte 4 # Abbreviation code .byte 3 # Subprogram name string (DW_FORM_strx1) -# A variable DIE with DW_AT_name, using DW_FORM_strx2. +# A variable DIE with DW_AT_name, using DW_FORM_strx2, and DW_AT_type. .byte 5 # Abbreviation code .short 0x0004 # Subprogram name string (DW_FORM_strx2) -# A variable DIE with DW_AT_name, using DW_FORM_strx3. + .long TypeDie-.debug_info +# A variable DIE with DW_AT_name, using DW_FORM_strx3, and DW_AT_type. .byte 6 # Abbreviation code .byte 5 # Subprogram name string (DW_FORM_strx3) .short 0 # Subprogram name string (DW_FORM_strx3) -# A variable DIE with DW_AT_name, using DW_FORM_strx4. + .long TypeDie-.debug_info +# A variable DIE with DW_AT_name, using DW_FORM_strx4, and DW_AT_type. .byte 7 # Abbreviation code - .quad 0x00000006 # Subprogram name string (DW_FORM_strx4) + .long 6 # Subprogram name string (DW_FORM_strx4) + .long TypeDie-.debug_info .byte 0 # NULL +# A base type DIE with DW_AT_encoding. +TypeDie: + .byte 8 # Abbreviation code + .byte 5 # DW_ATE_signed .byte 0 # NULL .byte 0 # NULL CU1_5_end: @@ -386,4 +407,6 @@ TU_split_5_end: # SPLIT-NEXT: 0x00000014: 00000047 "V5_split_type_unit" # SPLIT-NEXT: 0x00000018: 0000005a "V5_split_Mystruct" +# VERIFY: No errors. + # ERR-NOT: parsing a range list table: diff --git a/test/tools/llvm-dwarfdump/X86/verify_debug_info.s b/test/tools/llvm-dwarfdump/X86/verify_debug_info.s index e5a748b89f9..e3eae9b986f 100644 --- a/test/tools/llvm-dwarfdump/X86/verify_debug_info.s +++ b/test/tools/llvm-dwarfdump/X86/verify_debug_info.s @@ -7,7 +7,7 @@ # CHECK-NEXT: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000000] = "clang version 5.0.0 (trunk 308185) (llvm/trunk 308186)") # CHECK-NEXT: DW_AT_language [DW_FORM_data2] (DW_LANG_C99) # CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000037] = "basic.c") -# CHECK-NEXT: DW_AT_stmt_list [DW_FORM_strx4] ( indexed (00000000) string = ) +# CHECK-NEXT: DW_AT_stmt_list [DW_FORM_block4] # 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:]]}} @@ -82,7 +82,7 @@ Lsection_abbrev: .byte 3 ## DW_AT_name .byte 14 ## DW_FORM_strp .byte 16 ## DW_AT_stmt_list - .byte 40 ## DW_FORM_sec_offset -- error: DIE has invalid DW_AT_stmt_list encoding: + .byte 4 ## DW_FORM_sec_offset -- error: DIE has invalid DW_AT_stmt_list encoding: .byte 27 ## DW_AT_comp_dir .byte 14 ## DW_FORM_strp .byte 17 ## DW_AT_low_pc diff --git a/test/tools/llvm-dwarfdump/X86/verify_strings.s b/test/tools/llvm-dwarfdump/X86/verify_strings.s new file mode 100644 index 00000000000..e09ffd502cb --- /dev/null +++ b/test/tools/llvm-dwarfdump/X86/verify_strings.s @@ -0,0 +1,88 @@ +# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o +# RUN: not llvm-dwarfdump -verify %t.o | FileCheck --check-prefix=VERIFY %s + +# Check that the verifier correctly diagnoses various error conditions with +# the usage of string indices and string offsets tables. + + .section .debug_str,"MS",@progbits,1 +str_producer: + .asciz "Handmade DWARF producer" + + .section .debug_str_offsets,"",@progbits +# The string offsets table + .long .debug_str_offsets_segment0_end-.debug_str_offsets_base0+4 + .short 5 # DWARF version + .short 0 # Padding +.debug_str_offsets_base0: + .long str_producer + .long 1000 # Invalid string address. +.debug_str_offsets_segment0_end: + +# A simple abbrev section with a basic compile unit DIE. + .section .debug_abbrev,"",@progbits + .byte 0x01 # Abbrev code + .byte 0x11 # DW_TAG_compile_unit + .byte 0x01 # DW_CHILDREN_no + .byte 0x25 # DW_AT_producer + .byte 0x1a # DW_FORM_strx + .byte 0x72 # DW_AT_str_offsets_base + .byte 0x17 # DW_FORM_sec_offset + .byte 0x00 # EOM(1) + .byte 0x00 # EOM(2) + + .section .debug_info,"",@progbits + +# The first unit's CU DIE has an invalid DW_AT_str_offsets_base which +# renders any string index unresolvable. + +# DWARF v5 CU header. + .long CU1_5_end-CU1_5_version # Length of Unit +CU1_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, which has DW_AT_producer and DW_AT_str_offsets. + .byte 1 # Abbreviation code + .byte 0 # Index of string for DW_AT_producer. + .long 1000 # Bad value for DW_AT_str_offsets_base + .byte 0 # NULL +CU1_5_end: + +# The second unit's CU DIE uses an invalid string index. + +# DWARF v5 CU header + .long CU2_5_end-CU2_5_version # Length of Unit +CU2_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, which has DW_AT_producer and DW_AT_str_offsets. + .byte 1 # Abbreviation code + .byte 100 # Invalid string index + .long .debug_str_offsets_base0 + .byte 0 # NULL +CU2_5_end: + +# The third unit's CU DIE uses a valid string index but the entry in the +# string offsets table is invalid. + +# DWARF v5 CU header + .long CU3_5_end-CU3_5_version # Length of Unit +CU3_5_version: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section +# The compile-unit DIE, which has DW_AT_producer and DW_AT_str_offsets. + .byte 1 # Abbreviation code + .byte 1 # Index of string for DW_AT_producer. + .long .debug_str_offsets_base0 + .byte 0 # NULL +CU3_5_end: + +# VERIFY-DAG: error: DW_FORM_strx used without a valid string offsets table: +# VERIFY-DAG: error: DW_FORM_strx uses index 100, which is too large: +# VERIFY-DAG: error: DW_FORM_strx uses index 1, but the referenced string offset +# VERIFY-DAG-SAME: is beyond .debug_str bounds: