summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Robinson <paul.robinson@sony.com>2017-11-22 15:14:49 +0000
committerPaul Robinson <paul.robinson@sony.com>2017-11-22 15:14:49 +0000
commita513cc4aa1fa4e0e6a0c3c427e408ad42e2947c7 (patch)
treefec23ed676af4b8476d0947fa7c2198b29f933d1
parent72bc6f1e396bd737764e7c35fbef7e4fbe70526d (diff)
[DWARF] Fix handling of extended line-number opcodes
Differential Revision: https://reviews.llvm.org/D40200 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@318838 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugLine.cpp29
-rw-r--r--test/DebugInfo/X86/dwarfdump-bogus-LNE.s152
-rw-r--r--test/MC/ELF/discriminator.s4
3 files changed, 178 insertions, 7 deletions
diff --git a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index c99c7a9277e..1753d57ada6 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -427,9 +427,15 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
if (Opcode == 0) {
// Extended Opcodes always start with a zero opcode followed by
// a uleb128 length so you can skip ones you don't know about
- uint32_t ExtOffset = *OffsetPtr;
uint64_t Len = DebugLineData.getULEB128(OffsetPtr);
- uint32_t ArgSize = Len - (*OffsetPtr - ExtOffset);
+ uint32_t ExtOffset = *OffsetPtr;
+
+ // Tolerate zero-length; assume length is correct and soldier on.
+ if (Len == 0) {
+ if (OS)
+ *OS << "Badly formed extended line op (length 0)\n";
+ continue;
+ }
uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr);
if (OS)
@@ -508,11 +514,24 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
break;
default:
- // Length doesn't include the zero opcode byte or the length itself, but
- // it does include the sub_opcode, so we have to adjust for that below
- (*OffsetPtr) += ArgSize;
+ if (OS)
+ *OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode)
+ << format(" length %" PRIx64, Len);
+ // Len doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that.
+ (*OffsetPtr) += Len - 1;
break;
}
+ // Make sure the stated and parsed lengths are the same.
+ // Otherwise we have an unparseable line-number program.
+ if (*OffsetPtr - ExtOffset != Len) {
+ fprintf(stderr, "Unexpected line op length at offset 0x%8.8" PRIx32
+ " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx32 "\n",
+ ExtOffset, Len, *OffsetPtr - ExtOffset);
+ // Skip the rest of the line-number program.
+ *OffsetPtr = EndOffset;
+ return false;
+ }
} else if (Opcode < Prologue.OpcodeBase) {
if (OS)
*OS << LNStandardString(Opcode);
diff --git a/test/DebugInfo/X86/dwarfdump-bogus-LNE.s b/test/DebugInfo/X86/dwarfdump-bogus-LNE.s
new file mode 100644
index 00000000000..f1dc256bdfb
--- /dev/null
+++ b/test/DebugInfo/X86/dwarfdump-bogus-LNE.s
@@ -0,0 +1,152 @@
+# Test object to verify dwarfdump handles a syntactically correct line-number
+# program containing unrecognized extended opcodes.
+# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o
+# RUN: llvm-dwarfdump -v %t.o | FileCheck %s
+# RUN: llvm-dwarfdump -v %t.o 2>&1 | FileCheck %s --check-prefix=ERR
+
+ .section .text
+ # Dummy function
+foo: ret
+
+# FIXME: When we can dump a line-table without a unit, we could remove
+# the .debug_abbrev and .debug_info sections from this test.
+ .section .debug_abbrev,"",@progbits
+ .byte 0x01 # Abbrev code
+ .byte 0x11 # DW_TAG_compile_unit
+ .byte 0x00 # DW_CHILDREN_no
+ .byte 0x10 # DW_AT_stmt_list
+ .byte 0x17 # DW_FORM_sec_offset
+ .byte 0x00 # EOM(1)
+ .byte 0x00 # EOM(2)
+
+ .section .debug_info,"",@progbits
+ .long CU_end-CU_version # Length of Unit
+CU_version:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+# The compile-unit DIE, with DW_AT_stmt_list.
+ .byte 1
+ .long LT_start
+ .byte 0 # NULL
+CU_end:
+
+ .long CU2_end-CU2_version # Length of Unit
+CU2_version:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+# The compile-unit DIE, with DW_AT_stmt_list.
+ .byte 1
+ .long LT2_start
+ .byte 0 # NULL
+CU2_end:
+
+ .section .debug_line,"",@progbits
+# CHECK-LABEL: .debug_line contents:
+
+# DWARF v4 line-table header.
+LT_start:
+ .long LT_end-LT_version # Length of Unit (DWARF-32 format)
+LT_version:
+ .short 4 # DWARF version number
+ .long LT_header_end-LT_params # Length of Prologue
+LT_params:
+ .byte 1 # Minimum Instruction Length
+ .byte 1 # Maximum Operations per Instruction
+ .byte 1 # Default is_stmt
+ .byte -5 # Line Base
+ .byte 14 # Line Range
+ .byte 13 # Opcode Base
+ .byte 0 # Standard Opcode Lengths
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 1
+ # No directories.
+ .byte 0
+ # No files.
+ .byte 0
+LT_header_end:
+ # Bogus extended opcode with zero length.
+ .byte 0 # Extended opcode indicator.
+ .byte 0 # LEB length of extended opcode + operands.
+ # Real opcode and operand.
+ .byte 0
+ .byte 9
+ .byte 2 # DW_LNE_set_address
+ .quad .text
+ # Bogus extended opcode with multibyte LEB length.
+ .byte 0
+ .byte 0x82 # Length of 2 but with additional length byte.
+ .byte 0 # Additional length byte.
+ .byte 0x47 # Unrecognized opcode...
+ .byte 0 # with its 1-byte operand.
+ # Proper end-sequence opcode.
+ .byte 0
+ .byte 1
+ .byte 1 # DW_LNE_end_sequence
+LT_end:
+
+# CHECK: Line table prologue:
+# CHECK: version: 4
+# Exact prologue length isn't important but it tells us where to expect the
+# line-number program to start, and we do want to verify those offsets.
+# CHECK-NEXT: prologue_length: 0x00000014
+# CHECK: 0x0000001e: 00 Badly formed extended line op
+# CHECK-NEXT: 0x00000020: 00 DW_LNE_set_address
+# CHECK-NEXT: 0x0000002b: 00 Unrecognized extended op 0x47 length 2
+# CHECK-NEXT: 0x00000030: 00 DW_LNE_end_sequence
+# CHECK-NEXT: 0x0000000000000000 {{.*}} is_stmt end_sequence
+
+
+# DWARF v4 line-table header #2.
+LT2_start:
+ .long LT2_end-LT2_version # Length of Unit (DWARF-32 format)
+LT2_version:
+ .short 4 # DWARF version number
+ .long LT2_header_end-LT2_params # Length of Prologue
+LT2_params:
+ .byte 1 # Minimum Instruction Length
+ .byte 1 # Maximum Operations per Instruction
+ .byte 1 # Default is_stmt
+ .byte -5 # Line Base
+ .byte 14 # Line Range
+ .byte 13 # Opcode Base
+ .byte 0 # Standard Opcode Lengths
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 0
+ .byte 1
+ .byte 0
+ .byte 0
+ .byte 1
+ # No directories.
+ .byte 0
+ # No files.
+ .byte 0
+LT2_header_end:
+ # Real opcode and operand.
+ .byte 0
+ .byte 9
+ .byte 2 # DW_LNE_set_address
+ .quad .text
+ # Real opcode with incorrect length.
+ .byte 0
+ .byte 2 # Wrong length, should be 1.
+ .byte 1 # DW_LNE_end_sequence
+LT2_end:
+
+# ERR: Unexpected line op length at offset 0x0000005e
+# ERR-SAME: expected 0x02 found 0x01
diff --git a/test/MC/ELF/discriminator.s b/test/MC/ELF/discriminator.s
index 8edb4c006a1..17b8ee41f29 100644
--- a/test/MC/ELF/discriminator.s
+++ b/test/MC/ELF/discriminator.s
@@ -17,7 +17,7 @@ foo:
.long 34 # Length of Unit
.short 4 # DWARF version number
.long .L.debug_abbrev_begin # Offset Into Abbrev. Section
- .byte 8 # Address Size (in bytes)
+ .byte 4 # Address Size (in bytes)
.byte 1 # Abbrev [1] 0xb:0x1b DW_TAG_compile_unit
.long info_string0 # DW_AT_producer
.short 12 # DW_AT_language
@@ -58,4 +58,4 @@ foo:
# DWARF-DUMP: Address Line Column File ISA Discriminator Flags
# DWARF-DUMP: ------------------ ------ ------ ------ --- ------------- -------------
-# DWARF-DUMP: 0x0001021300000000 1 0 1 0 1 is_stmt
+# DWARF-DUMP: 0x0000000000000000 2 0 1 0 1 is_stmt