[llvm] 1a78904 - [DebugInfo] Report errors for truncated debug line standard opcode

James Henderson via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 15 03:50:28 PDT 2020


Author: James Henderson
Date: 2020-06-15T11:50:12+01:00
New Revision: 1a7890475200f0fa6d048edee4ca17b069bc0777

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

LOG: [DebugInfo] Report errors for truncated debug line standard opcode

Standard opcodes usually have ULEB128 arguments, so it is generally not
possible to recover from such errors. This patch causes the parser to
stop parsing the table in such situations.

Also don't emit the operands or add data to the table if there is an
error reading these opcodes.

Reviewed by: JDevlieghere

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

Added: 
    

Modified: 
    llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
    llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index df9a496cf57f..398d38e545b3 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -690,6 +690,17 @@ DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode,
   return {AddrAdvanceResult.AddrDelta, LineOffset};
 }
 
+/// Parse a ULEB128 using the specified \p Cursor. \returns the parsed value on
+/// success, or None if \p Cursor is in a failing state.
+template <typename T>
+static Optional<T> parseULEB128(DWARFDataExtractor &Data,
+                                DataExtractor::Cursor &Cursor) {
+  T Value = Data.getULEB128(Cursor);
+  if (Cursor)
+    return Value;
+  return None;
+}
+
 Error DWARFDebugLine::LineTable::parse(
     DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
     const DWARFContext &Ctx, const DWARFUnit *U,
@@ -918,6 +929,7 @@ Error DWARFDebugLine::LineTable::parse(
             ExtOffset, Len, Cursor.tell() - ExtOffset));
       *OffsetPtr = End;
     } else if (Opcode < Prologue.OpcodeBase) {
+      DataExtractor::Cursor Cursor(*OffsetPtr);
       if (Verbose)
         *OS << LNStandardString(Opcode);
       switch (Opcode) {
@@ -938,9 +950,10 @@ Error DWARFDebugLine::LineTable::parse(
         // Takes a single unsigned LEB128 operand, multiplies it by the
         // min_inst_length field of the prologue, and adds the
         // result to the address register of the state machine.
-        {
-          uint64_t AddrOffset = State.advanceAddr(
-              TableData.getULEB128(OffsetPtr), Opcode, OpcodeOffset);
+        if (Optional<uint64_t> Operand =
+                parseULEB128<uint64_t>(TableData, Cursor)) {
+          uint64_t AddrOffset =
+              State.advanceAddr(*Operand, Opcode, OpcodeOffset);
           if (Verbose)
             *OS << " (" << AddrOffset << ")";
         }
@@ -949,25 +962,36 @@ Error DWARFDebugLine::LineTable::parse(
       case DW_LNS_advance_line:
         // Takes a single signed LEB128 operand and adds that value to
         // the line register of the state machine.
-        State.Row.Line += TableData.getSLEB128(OffsetPtr);
-        if (Verbose)
-          *OS << " (" << State.Row.Line << ")";
+        {
+          int64_t LineDelta = TableData.getSLEB128(Cursor);
+          if (Cursor) {
+            State.Row.Line += LineDelta;
+            if (Verbose)
+              *OS << " (" << State.Row.Line << ")";
+          }
+        }
         break;
 
       case DW_LNS_set_file:
         // Takes a single unsigned LEB128 operand and stores it in the file
         // register of the state machine.
-        State.Row.File = TableData.getULEB128(OffsetPtr);
-        if (Verbose)
-          *OS << " (" << State.Row.File << ")";
+        if (Optional<uint16_t> File =
+                parseULEB128<uint16_t>(TableData, Cursor)) {
+          State.Row.File = *File;
+          if (Verbose)
+            *OS << " (" << State.Row.File << ")";
+        }
         break;
 
       case DW_LNS_set_column:
         // Takes a single unsigned LEB128 operand and stores it in the
         // column register of the state machine.
-        State.Row.Column = TableData.getULEB128(OffsetPtr);
-        if (Verbose)
-          *OS << " (" << State.Row.Column << ")";
+        if (Optional<uint16_t> Column =
+                parseULEB128<uint16_t>(TableData, Cursor)) {
+          State.Row.Column = *Column;
+          if (Verbose)
+            *OS << " (" << State.Row.Column << ")";
+        }
         break;
 
       case DW_LNS_negate_stmt:
@@ -1013,10 +1037,13 @@ Error DWARFDebugLine::LineTable::parse(
         // requires the use of DW_LNS_advance_pc. Such assemblers, however,
         // can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
         {
-          uint16_t PCOffset = TableData.getRelocatedValue(2, OffsetPtr);
-          State.Row.Address.Address += PCOffset;
-          if (Verbose)
-            *OS << format(" (0x%4.4" PRIx16 ")", PCOffset);
+          uint16_t PCOffset =
+              TableData.getRelocatedValue(Cursor, 2);
+          if (Cursor) {
+            State.Row.Address.Address += PCOffset;
+            if (Verbose)
+              *OS << format(" (0x%4.4" PRIx16 ")", PCOffset);
+          }
         }
         break;
 
@@ -1034,10 +1061,12 @@ Error DWARFDebugLine::LineTable::parse(
 
       case DW_LNS_set_isa:
         // Takes a single unsigned LEB128 operand and stores it in the
-        // column register of the state machine.
-        State.Row.Isa = TableData.getULEB128(OffsetPtr);
-        if (Verbose)
-          *OS << " (" << (uint64_t)State.Row.Isa << ")";
+        // ISA register of the state machine.
+        if (Optional<uint8_t> Isa = parseULEB128<uint8_t>(TableData, Cursor)) {
+          State.Row.Isa = *Isa;
+          if (Verbose)
+            *OS << " (" << (uint64_t)State.Row.Isa << ")";
+        }
         break;
 
       default:
@@ -1049,16 +1078,22 @@ Error DWARFDebugLine::LineTable::parse(
           if (Verbose)
             *OS << "Unrecognized standard opcode";
           uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1];
-          if (OpcodeLength != 0) {
-            if (Verbose)
-              *OS << " (operands: ";
-            for (uint8_t I = 0; I < OpcodeLength; ++I) {
-              uint64_t Value = TableData.getULEB128(OffsetPtr);
-              if (Verbose) {
-                if (I > 0)
-                  *OS << ", ";
-                *OS << format("0x%16.16" PRIx64, Value);
-              }
+          std::vector<uint64_t> Operands;
+          for (uint8_t I = 0; I < OpcodeLength; ++I) {
+            if (Optional<uint64_t> Value =
+                    parseULEB128<uint64_t>(TableData, Cursor))
+              Operands.push_back(*Value);
+            else
+              break;
+          }
+          if (Verbose && !Operands.empty()) {
+            *OS << " (operands: ";
+            bool First = true;
+            for (uint64_t Value : Operands) {
+              if (!First)
+                *OS << ", ";
+              First = false;
+              *OS << format("0x%16.16" PRIx64, Value);
             }
             if (Verbose)
               *OS << ')';
@@ -1066,6 +1101,17 @@ Error DWARFDebugLine::LineTable::parse(
         }
         break;
       }
+
+      *OffsetPtr = Cursor.tell();
+
+      // Most standard opcode failures are due to failures to read ULEBs. Bail
+      // out of parsing, since we don't know where to continue reading from as
+      // there is no stated length for such byte sequences.
+      if (!Cursor) {
+        if (Verbose)
+          *OS << "\n\n";
+        return Cursor.takeError();
+      }
     } else {
       // Special Opcodes.
       ParsingState::AddrAndLineDelta Delta =

diff  --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
index 6a99bbf83ae1..11256610fadb 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugLineTest.cpp
@@ -1382,25 +1382,27 @@ TEST_F(DebugLineBasicFixture, VerboseOutput) {
 
 using ValueAndLengths = std::vector<LineTable::ValueAndLength>;
 
-struct TruncatedExtendedOpcodeFixture
-    : public TestWithParam<std::tuple<uint64_t, uint64_t, uint8_t,
-                                      ValueAndLengths, StringRef, StringRef>>,
-      public CommonFixture {
-  void SetUp() {
-    std::tie(BodyLength, OpcodeLength, Opcode, Operands, ExpectedOutput,
-             ExpectedErr) = GetParam();
-  }
-
-  void runTest() {
+struct TruncatedOpcodeFixtureBase : public CommonFixture {
+  LineTable &setupTable() {
     LineTable &LT = Gen->addLineTable();
-    // Creating the prologue before adding the opcode ensures that the unit
+
+    // Creating the prologue before adding any opcodes ensures that the unit
     // length does not include the table body.
     DWARFDebugLine::Prologue Prologue = LT.createBasicPrologue();
-    Prologue.TotalLength += BodyLength;
+
+    // Add an unrecognised standard opcode, and adjust prologue properties
+    // accordingly.
+    Prologue.TotalLength += BodyLength + 1;
+    ++Prologue.PrologueLength;
+    ++Prologue.OpcodeBase;
+    Prologue.StandardOpcodeLengths.push_back(2);
     LT.setPrologue(Prologue);
-    LT.addExtendedOpcode(OpcodeLength, Opcode, Operands);
-    generate();
 
+    return LT;
+  }
+
+  void runTest(uint8_t OpcodeValue) {
+    generate();
     DWARFDebugLine::SectionParser Parser(LineData, *Context, CUs, TUs);
     std::string Output;
     raw_string_ostream OS(Output);
@@ -1408,28 +1410,52 @@ struct TruncatedExtendedOpcodeFixture
                      /*Verbose=*/true);
     OS.flush();
 
-    StringRef LinePrefix = "0x0000002e: 00 ";
+    std::string LinePrefix =
+        ("0x0000002f: 0" + Twine::utohexstr(OpcodeValue) + " ").str();
     StringRef OutputRef(Output);
     StringRef OutputToCheck = OutputRef.split(LinePrefix).second;
     // Each extended opcode ends with a new line and then the table ends with an
     // additional blank line.
     EXPECT_EQ((ExpectedOutput + "\n\n").str(), OutputToCheck);
-    EXPECT_THAT_ERROR(std::move(Recoverable),
-                      FailedWithMessage(ExpectedErr.str()));
   }
 
   uint64_t BodyLength;
-  uint64_t OpcodeLength;
   uint8_t Opcode;
   ValueAndLengths Operands;
   StringRef ExpectedOutput;
   StringRef ExpectedErr;
 };
 
+struct TruncatedStandardOpcodeFixture
+    : public TestWithParam<
+          std::tuple<uint64_t, uint8_t, ValueAndLengths, StringRef, StringRef>>,
+      public TruncatedOpcodeFixtureBase {
+  void SetUp() {
+    std::tie(BodyLength, Opcode, Operands, ExpectedOutput, ExpectedErr) =
+        GetParam();
+  }
+};
+
+struct TruncatedExtendedOpcodeFixture
+    : public TestWithParam<std::tuple<uint64_t, uint64_t, uint8_t,
+                                      ValueAndLengths, StringRef, StringRef>>,
+      public TruncatedOpcodeFixtureBase {
+  void SetUp() {
+    std::tie(BodyLength, OpcodeLength, Opcode, Operands, ExpectedOutput,
+             ExpectedErr) = GetParam();
+  }
+
+  uint64_t OpcodeLength;
+};
+
 TEST_P(TruncatedExtendedOpcodeFixture, ErrorForTruncatedExtendedOpcode) {
   if (!setupGenerator())
     return;
-  runTest();
+  LineTable &LT = setupTable();
+  LT.addExtendedOpcode(OpcodeLength, Opcode, Operands);
+  runTest(0);
+  EXPECT_THAT_ERROR(std::move(Recoverable),
+                    FailedWithMessage(ExpectedErr.str()));
 }
 
 INSTANTIATE_TEST_CASE_P(
@@ -1437,18 +1463,18 @@ INSTANTIATE_TEST_CASE_P(
     Values(
         std::make_tuple(1, 1, DW_LNE_end_sequence, ValueAndLengths(),
                         "Badly formed extended line op (length 0)",
-                        "unable to decode LEB128 at offset 0x0000002f: "
+                        "unable to decode LEB128 at offset 0x00000030: "
                         "malformed uleb128, extends past end"),
         std::make_tuple(
             2, 9, DW_LNE_set_address,
             ValueAndLengths{{0x12345678, LineTable::Quad}},
             "Unrecognized extended op 0x00 length 9",
-            "unexpected end of data at offset 0x30 while reading [0x30, 0x31)"),
+            "unexpected end of data at offset 0x31 while reading [0x31, 0x32)"),
         std::make_tuple(
             3, 9, DW_LNE_set_address,
             ValueAndLengths{{0x12345678, LineTable::Quad}},
             "DW_LNE_set_address (0x0000000000000000)",
-            "unexpected end of data at offset 0x31 while reading [0x31, 0x39)"),
+            "unexpected end of data at offset 0x32 while reading [0x32, 0x3a)"),
         std::make_tuple(3, 5, DW_LNE_define_file,
                         ValueAndLengths{{'a', LineTable::Byte},
                                         {'\0', LineTable::Byte},
@@ -1457,7 +1483,7 @@ INSTANTIATE_TEST_CASE_P(
                                         {1, LineTable::ULEB}},
                         "DW_LNE_define_file (, dir=0, "
                         "mod_time=(0x0000000000000000), length=0)",
-                        "no null terminated string at offset 0x31"),
+                        "no null terminated string at offset 0x32"),
         std::make_tuple(5, 5, DW_LNE_define_file,
                         ValueAndLengths{{'a', LineTable::Byte},
                                         {'\0', LineTable::Byte},
@@ -1466,7 +1492,7 @@ INSTANTIATE_TEST_CASE_P(
                                         {1, LineTable::ULEB}},
                         "DW_LNE_define_file (a, dir=0, "
                         "mod_time=(0x0000000000000000), length=0)",
-                        "unable to decode LEB128 at offset 0x00000033: "
+                        "unable to decode LEB128 at offset 0x00000034: "
                         "malformed uleb128, extends past end"),
         std::make_tuple(6, 5, DW_LNE_define_file,
                         ValueAndLengths{{'a', LineTable::Byte},
@@ -1476,7 +1502,7 @@ INSTANTIATE_TEST_CASE_P(
                                         {1, LineTable::ULEB}},
                         "DW_LNE_define_file (a, dir=1, "
                         "mod_time=(0x0000000000000000), length=0)",
-                        "unable to decode LEB128 at offset 0x00000034: "
+                        "unable to decode LEB128 at offset 0x00000035: "
                         "malformed uleb128, extends past end"),
         std::make_tuple(7, 5, DW_LNE_define_file,
                         ValueAndLengths{{'a', LineTable::Byte},
@@ -1486,14 +1512,70 @@ INSTANTIATE_TEST_CASE_P(
                                         {1, LineTable::ULEB}},
                         "DW_LNE_define_file (a, dir=1, "
                         "mod_time=(0x0000000000000001), length=0)",
-                        "unable to decode LEB128 at offset 0x00000035: "
+                        "unable to decode LEB128 at offset 0x00000036: "
                         "malformed uleb128, extends past end"),
         std::make_tuple(3, 2, DW_LNE_set_discriminator,
                         ValueAndLengths{{1, LineTable::ULEB}},
                         "DW_LNE_set_discriminator (0)",
-                        "unable to decode LEB128 at offset 0x00000031: "
+                        "unable to decode LEB128 at offset 0x00000032: "
                         "malformed uleb128, extends past end")), );
 
+TEST_P(TruncatedStandardOpcodeFixture, ErrorForTruncatedStandardOpcode) {
+  if (!setupGenerator())
+    return;
+  LineTable &LT = setupTable();
+  LT.addStandardOpcode(Opcode, Operands);
+  runTest(Opcode);
+  EXPECT_THAT_ERROR(std::move(Unrecoverable),
+                    FailedWithMessage(ExpectedErr.str()));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    TruncatedStandardOpcodeParams, TruncatedStandardOpcodeFixture,
+    Values(
+        std::make_tuple(2, DW_LNS_advance_pc,
+                        ValueAndLengths{{0x100, LineTable::ULEB}},
+                        "DW_LNS_advance_pc",
+                        "unable to decode LEB128 at offset 0x00000030: "
+                        "malformed uleb128, extends past end"),
+        std::make_tuple(2, DW_LNS_advance_line,
+                        ValueAndLengths{{0x200, LineTable::SLEB}},
+                        "DW_LNS_advance_line",
+                        "unable to decode LEB128 at offset 0x00000030: "
+                        "malformed sleb128, extends past end"),
+        std::make_tuple(2, DW_LNS_set_file,
+                        ValueAndLengths{{0x300, LineTable::ULEB}},
+                        "DW_LNS_set_file",
+                        "unable to decode LEB128 at offset 0x00000030: "
+                        "malformed uleb128, extends past end"),
+        std::make_tuple(2, DW_LNS_set_column,
+                        ValueAndLengths{{0x400, LineTable::ULEB}},
+                        "DW_LNS_set_column",
+                        "unable to decode LEB128 at offset 0x00000030: "
+                        "malformed uleb128, extends past end"),
+        std::make_tuple(
+            2, DW_LNS_fixed_advance_pc,
+            ValueAndLengths{{0x500, LineTable::Half}},
+            "DW_LNS_fixed_advance_pc",
+            "unexpected end of data at offset 0x31 while reading [0x30, 0x32)"),
+        std::make_tuple(2, DW_LNS_set_isa,
+                        ValueAndLengths{{0x600, LineTable::ULEB}},
+                        "DW_LNS_set_isa",
+                        "unable to decode LEB128 at offset 0x00000030: "
+                        "malformed uleb128, extends past end"),
+        std::make_tuple(2, 0xd,
+                        ValueAndLengths{{0x700, LineTable::ULEB},
+                                        {0x800, LineTable::ULEB}},
+                        "Unrecognized standard opcode",
+                        "unable to decode LEB128 at offset 0x00000030: "
+                        "malformed uleb128, extends past end"),
+        std::make_tuple(
+            4, 0xd,
+            ValueAndLengths{{0x900, LineTable::ULEB}, {0xa00, LineTable::ULEB}},
+            "Unrecognized standard opcode (operands: 0x0000000000000900)",
+            "unable to decode LEB128 at offset 0x00000032: "
+            "malformed uleb128, extends past end")), );
+
 TEST_F(DebugLineBasicFixture, PrintPathsProperly) {
   if (!setupGenerator(5))
     return;


        


More information about the llvm-commits mailing list