[llvm] f1be770 - [DebugInfo] Make incorrect debug line extended opcode length non-fatal

James Henderson via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 27 07:33:02 PST 2020


Author: James Henderson
Date: 2020-01-27T15:32:41Z
New Revision: f1be770ff6886a145db08b63397e8ddb6ac59bd0

URL: https://github.com/llvm/llvm-project/commit/f1be770ff6886a145db08b63397e8ddb6ac59bd0
DIFF: https://github.com/llvm/llvm-project/commit/f1be770ff6886a145db08b63397e8ddb6ac59bd0.diff

LOG: [DebugInfo] Make incorrect debug line extended opcode length non-fatal

It is possible to try to keep parsing a debug line program even when the
length of an extended opcode does not match what is expected for that
opcode. This patch changes what was previously a fatal error to be
non-fatal. The parser now continues by assuming the the claimed length
is correct, even if it means moving the offset backwards.

Reviewed by: dblaikie

Differential Revision: https://reviews.llvm.org/D72155

Added: 
    

Modified: 
    llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
    llvm/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s
    llvm/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test
    llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 2eceadb65520..b97753eb9ddb 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -685,13 +685,18 @@ Error DWARFDebugLine::LineTable::parse(
         (*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)
-        return createStringError(errc::illegal_byte_sequence,
-                           "unexpected line op length at offset 0x%8.8" PRIx64
-                           " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx64,
-                           ExtOffset, Len, *OffsetPtr - ExtOffset);
+      // Make sure the length as recorded in the table and the standard length
+      // for the opcode match. If they don't, continue from the end as claimed
+      // by the table.
+      uint64_t End = ExtOffset + Len;
+      if (*OffsetPtr != End) {
+        RecoverableErrorCallback(createStringError(
+            errc::illegal_byte_sequence,
+            "unexpected line op length at offset 0x%8.8" PRIx64
+            " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx64,
+            ExtOffset, Len, *OffsetPtr - ExtOffset));
+        *OffsetPtr = End;
+      }
     } else if (Opcode < Prologue.OpcodeBase) {
       if (OS)
         *OS << LNStandardString(Opcode);

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s b/llvm/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s
index 66c71f980e97..8c7614afd359 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s
+++ b/llvm/test/tools/llvm-dwarfdump/X86/Inputs/debug_line_malformed.s
@@ -114,7 +114,7 @@
 .byte   0, 1, 1        # DW_LNE_end_sequence
 .Lunit_long_prologue_end:
 
-# Over-long extended opcode.
+# Incorrect length extended opcodes.
 .long   .Lunit_long_opcode_end - .Lunit_long_opcode_start # unit length
 .Lunit_long_opcode_start:
 .short  4               # version
@@ -139,6 +139,9 @@
 .byte   0, 9, 2         # DW_LNE_set_address
 .quad   0xabbadaba
 .byte   0, 2, 1         # DW_LNE_end_sequence (too long)
+.byte   6               # DW_LNS_negate_stmt (but will be consumed with the end sequence above).
+.byte   0, 1, 4         # DW_LNE_set_discriminator (too short)
+.byte   0xa             # Parsed as argument for set_discriminator and also DW_LNS_set_prologue_end.
 .byte   0, 9, 2         # DW_LNE_set_address
 .quad   0xbabb1e45
 .byte   0, 1, 1         # DW_LNE_end_sequence

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test b/llvm/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test
index 6bdc526570fa..52732c02f3e3 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test
+++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_line_invalid.test
@@ -36,7 +36,7 @@
 # RUN: FileCheck %s --input-file=%t-malformed-off-first.err --check-prefix=ALL
 
 ## Don't stop looking for the later unit if non-fatal issues are found.
-# RUN: llvm-dwarfdump -debug-line=0x2af %t-malformed.o 2> %t-malformed-off-last.err \
+# RUN: llvm-dwarfdump -debug-line=0x2b4 %t-malformed.o 2> %t-malformed-off-last.err \
 # RUN:   | FileCheck %s --check-prefix=LAST --implicit-check-not='debug_line[{{.*}}]'
 # RUN: FileCheck %s --input-file=%t-malformed-off-last.err --check-prefix=ALL
 
@@ -96,21 +96,18 @@
 
 ## Case 6: Extended opcode with incorrect length versus expected.
 # NONFATAL:      debug_line[0x00000111]
-## Dumping prints the line table prologue and any valid operations up to the
-## point causing the problem.
 # NONFATAL-NEXT: Line table prologue
-# NONFATAL:      0x00000000abbadaba {{.*}} end_sequence
-# NONFATAL-NOT:  is_stmt
+# NONFATAL: 0x00000000abbadaba {{.*}} end_sequence
+# NONFATAL: 0x00000000babb1e45 {{.*}} 10 is_stmt prologue_end end_sequence{{$}}
 
-## For minor issues, we can dump the whole table.
 ## Case 7: No end of sequence.
-# NONFATAL:      debug_line[0x00000167]
+# NONFATAL:      debug_line[0x0000016c]
 # NONFATAL-NEXT: Line table prologue
 # NONFATAL:      0x00000000deadfade {{.*}} is_stmt
 # NONFATAL-NOT:  end_sequence
 
 ## Case 8: Very short prologue length for V5 (ends during parameters).
-# NONFATAL:      debug_line[0x000001ad]
+# NONFATAL:      debug_line[0x000001b2]
 # NONFATAL-NEXT: Line table prologue
 # NONFATAL:      standard_opcode_lengths[DW_LNS_set_isa] = 1
 # NONFATAL-NEXT: include_directories[  0] = "/tmp"
@@ -120,7 +117,7 @@
 # NONFATAL-NOT:  Address
 
 ## Case 9: V5 prologue ends during file table.
-# NONFATAL:      debug_line[0x000001ed]
+# NONFATAL:      debug_line[0x000001f2]
 # NONFATAL-NEXT: Line table prologue
 # NONFATAL:      include_directories[  0] = "/tmp"
 # NONFATAL-NEXT: file_names[  0]:
@@ -129,7 +126,7 @@
 # NONFATAL-NOT:  Address
 
 ## Case 10: V5 prologue ends during directory table.
-# NONFATAL:      debug_line[0x0000022d]
+# NONFATAL:      debug_line[0x00000232]
 # NONFATAL-NEXT: Line table prologue
 # NONFATAL:      include_directories[  0] = "/tmp"
 # NONFATAL-NEXT: file_names[  0]:
@@ -138,13 +135,13 @@
 # NONFATAL-NOT:  Address
 
 ## Case 11: V5 invalid MD5 hash form.
-# NONFATAL:      debug_line[0x0000026d]
+# NONFATAL:      debug_line[0x00000272]
 # NONFATAL-NEXT: Line table prologue
 # NONFATAL:      include_directories[  0] = "/tmp"
 # NONFATAL-NOT:  file_names
 # NONFATAL-NOT:  Address
 
-# LAST:          debug_line[0x000002af]
+# LAST:          debug_line[0x000002b4]
 # LAST:          0x00000000cafebabe {{.*}} end_sequence
 
 # RESERVED: warning: parsing line table prologue at offset 0x00000048 unsupported reserved unit length found of value 0xfffffffe
@@ -158,10 +155,11 @@
 # ALL-NEXT: warning: parsing line table prologue at 0x00000081 should have ended at 0x000000b9 but it ended at 0x000000ba
 # ALL-NEXT: warning: parsing line table prologue at 0x000000c9 should have ended at 0x00000104 but it ended at 0x00000103
 # OTHER-NEXT: warning: unexpected line op length at offset 0x00000158 expected 0x02 found 0x01
-# OTHER-NEXT: warning: last sequence in debug line table at offset 0x00000167 is not terminated
-# ALL-NEXT: warning: parsing line table prologue at 0x000001ad should have ended at 0x000001c8 but it ended at 0x000001df
-# ALL-NEXT: warning: parsing line table prologue at 0x000001ed should have ended at 0x00000218 but it ended at 0x0000021f
-# ALL-NEXT: warning: parsing line table prologue at 0x0000022d should have ended at 0x0000024f but it ended at 0x0000025f
-# ALL-NEXT: warning: parsing line table prologue at 0x0000026d found an invalid directory or file table description at 0x000002a2
+# OTHER-NEXT: warning: unexpected line op length at offset 0x0000015c expected 0x01 found 0x02
+# OTHER-NEXT: warning: last sequence in debug line table at offset 0x0000016c is not terminated
+# ALL-NEXT: warning: parsing line table prologue at 0x000001b2 should have ended at 0x000001cd but it ended at 0x000001e4
+# ALL-NEXT: warning: parsing line table prologue at 0x000001f2 should have ended at 0x0000021d but it ended at 0x00000224
+# ALL-NEXT: warning: parsing line table prologue at 0x00000232 should have ended at 0x00000254 but it ended at 0x00000264
+# ALL-NEXT: warning: parsing line table prologue at 0x00000272 found an invalid directory or file table description at 0x000002a7
 # ALL-NEXT: warning: failed to parse file entry because the MD5 hash is invalid
 # ALL-NOT:  warning:

diff  --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
index 63ba0d26857a..731afafc1aa1 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
@@ -428,19 +428,62 @@ INSTANTIATE_TEST_CASE_P(
            std::make_pair(4, DWARF64), // Test v4 fields and DWARF64.
            std::make_pair(5, DWARF32), std::make_pair(5, DWARF64)), );
 
-TEST_F(DebugLineBasicFixture, ErrorForInvalidExtendedOpcodeLength) {
+TEST_F(DebugLineBasicFixture, ErrorForExtendedOpcodeLengthSmallerThanExpected) {
   if (!setupGenerator())
     return;
 
   LineTable &LT = Gen->addLineTable();
+  LT.addByte(0xaa);
+  // The Length should be 1 + sizeof(ULEB) for a set discriminator opcode.
+  // The operand will be read for both the discriminator opcode and then parsed
+  // again as DW_LNS_negate_stmt, to respect the claimed length.
+  LT.addExtendedOpcode(1, DW_LNE_set_discriminator,
+                       {{DW_LNS_negate_stmt, LineTable::ULEB}});
+  LT.addByte(0xbb);
+  LT.addStandardOpcode(DW_LNS_const_add_pc, {});
+  LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
+
+  generate();
+
+  auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
+                                                    nullptr, RecordRecoverable);
+  checkError(
+      "unexpected line op length at offset 0x00000031 expected 0x01 found 0x02",
+      std::move(Recoverable));
+  ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
+  ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 3u);
+  EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 1u);
+  EXPECT_EQ((*ExpectedLineTable)->Rows[1].IsStmt, 0u);
+  EXPECT_EQ((*ExpectedLineTable)->Rows[1].Discriminator, DW_LNS_negate_stmt);
+}
+
+TEST_F(DebugLineBasicFixture, ErrorForExtendedOpcodeLengthLargerThanExpected) {
+  if (!setupGenerator())
+    return;
+
+  LineTable &LT = Gen->addLineTable();
+  LT.addByte(0xaa);
+  LT.addStandardOpcode(DW_LNS_const_add_pc, {});
   // The Length should be 1 for an end sequence opcode.
   LT.addExtendedOpcode(2, DW_LNE_end_sequence, {});
+  // The negate statement opcode will be skipped.
+  LT.addStandardOpcode(DW_LNS_negate_stmt, {});
+  LT.addByte(0xbb);
+  LT.addStandardOpcode(DW_LNS_const_add_pc, {});
+  LT.addExtendedOpcode(1, DW_LNE_end_sequence, {});
 
   generate();
 
-  checkGetOrParseLineTableEmitsFatalError(
-      "unexpected line op length at offset "
-      "0x00000030 expected 0x02 found 0x01");
+  auto ExpectedLineTable = Line.getOrParseLineTable(LineData, 0, *Context,
+                                                    nullptr, RecordRecoverable);
+  checkError(
+      "unexpected line op length at offset 0x00000032 expected 0x02 found 0x01",
+      std::move(Recoverable));
+  ASSERT_THAT_EXPECTED(ExpectedLineTable, Succeeded());
+  ASSERT_EQ((*ExpectedLineTable)->Rows.size(), 4u);
+  EXPECT_EQ((*ExpectedLineTable)->Sequences.size(), 2u);
+  ASSERT_EQ((*ExpectedLineTable)->Sequences[1].FirstRowIndex, 2u);
+  EXPECT_EQ((*ExpectedLineTable)->Rows[2].IsStmt, 1u);
 }
 
 TEST_F(DebugLineBasicFixture, ErrorForUnitLengthTooLarge) {
@@ -695,11 +738,11 @@ TEST_F(DebugLineBasicFixture, ParserReportsNonPrologueProblemsWhenParsing) {
 
   DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
   Parser.parseNext(RecordRecoverable, RecordUnrecoverable);
-  EXPECT_FALSE(Recoverable);
+  EXPECT_FALSE(Unrecoverable);
   ASSERT_FALSE(Parser.done());
   checkError(
       "unexpected line op length at offset 0x00000030 expected 0x42 found 0x01",
-      std::move(Unrecoverable));
+      std::move(Recoverable));
 
   // Reset the error state so that it does not confuse the next set of checks.
   Unrecoverable = Error::success();


        


More information about the llvm-commits mailing list