[DWARF] Fix handling of extended line-number opcodes

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

llvm-svn: 318838
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index c99c7a9..1753d57 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -427,9 +427,15 @@
     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 @@
         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);