]> granicus.if.org Git - llvm/commitdiff
Add the error handling for Mach-O dyld compact lazy bind, weak bind and
authorKevin Enderby <enderby@apple.com>
Mon, 27 Mar 2017 20:09:23 +0000 (20:09 +0000)
committerKevin Enderby <enderby@apple.com>
Mon, 27 Mar 2017 20:09:23 +0000 (20:09 +0000)
rebase entry errors and test cases for each of the error checks.

Also verified with Nick Kledzik that a BIND_OPCODE_SET_ADDEND_SLEB
opcode is legal in a lazy bind table, so code that had that as an error
check was removed.

With MachORebaseEntry and MachOBindEntry classes now returning
an llvm::Error in all cases for malformed input the variables Malformed
and logic to set use them is no longer needed and has been removed
from those classes.

Also in a few places, removed the redundant Done assignment to true
when also calling moveToEnd() as it does that assignment.

This only leaves the dyld compact export entries left to have
error handling yet to be added for the dyld compact info.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@298883 91177308-0d34-0410-b5e6-96231b3b80d8

22 files changed:
include/llvm/Object/MachO.h
lib/Object/MachOObjectFile.cpp
test/tools/llvm-objdump/Inputs/macho-bind-missing-done [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-add-addr-imm-scaled [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-uleb-times-skipping-uleb [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-lazy-do_bind_add_addr_uleb [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-imm-scaled [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb-too-big [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-bad-opcode-value [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-imm-times [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-missing-done [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-seg-too-big [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-segoff-too-big [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-set-type-imm [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-uleb-malformed-uleb128 [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times-skipping-uleb [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-imm [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-uleb [new file with mode: 0755]
test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-special-imm [new file with mode: 0755]
test/tools/llvm-objdump/macho-bad-bind.test

index 019f777ed65e250b1e3b0d27ec0e1a80490e84b5..1ee571cce738eca551c6fa511e8b806a4b3c6bde 100644 (file)
@@ -146,7 +146,7 @@ public:
   MachORebaseEntry(Error *Err, const MachOObjectFile *O,
                    ArrayRef<uint8_t> opcodes, bool is64Bit);
 
-  uint32_t segmentIndex() const;
+  int32_t segmentIndex() const;
   uint64_t segmentOffset() const;
   StringRef typeName() const;
   StringRef segmentName() const;
@@ -161,19 +161,18 @@ private:
   friend class MachOObjectFile;
   void moveToFirst();
   void moveToEnd();
-  uint64_t readULEB128();
+  uint64_t readULEB128(const char **error);
 
   Error *E;
   const MachOObjectFile *O;
   ArrayRef<uint8_t> Opcodes;
   const uint8_t *Ptr;
   uint64_t SegmentOffset;
-  uint32_t SegmentIndex;
+  int32_t SegmentIndex;
   uint64_t RemainingLoopCount;
   uint64_t AdvanceAmount;
   uint8_t  RebaseType;
   uint8_t  PointerSize;
-  bool     Malformed;
   bool     Done;
 };
 typedef content_iterator<MachORebaseEntry> rebase_iterator;
@@ -231,7 +230,6 @@ private:
   uint8_t  BindType;
   uint8_t  PointerSize;
   Kind     TableKind;
-  bool     Malformed;
   bool     Done;
 };
 typedef content_iterator<MachOBindEntry> bind_iterator;
@@ -378,6 +376,22 @@ public:
                                                      SegIndex, SegOffset);
   }
 
+  /// For use with a SegIndex,SegOffset pair in MachORebaseEntry::moveNext() to
+  /// validate a MachORebaseEntry.
+  const char *RebaseEntryCheckSegAndOffset(int32_t SegIndex, uint64_t SegOffset,
+                                           bool endInvalid) const {
+    return BindRebaseSectionTable->checkSegAndOffset(SegIndex, SegOffset,
+                                                     endInvalid);
+  }
+  /// For use in MachORebaseEntry::moveNext() to validate a MachORebaseEntry for
+  /// the REBASE_OPCODE_DO_*_TIMES* opcodes.
+  const char *RebaseEntryCheckCountAndSkip(uint32_t Count, uint32_t Skip,
+                                         uint8_t PointerSize, int32_t SegIndex,
+                                         uint64_t SegOffset) const {
+    return BindRebaseSectionTable->checkCountAndSkip(Count, Skip, PointerSize,
+                                                     SegIndex, SegOffset);
+  }
+
   /// For use with the SegIndex of a checked Mach-O Bind or Rebase entry to
   /// get the segment name.
   StringRef BindRebaseSegmentName(int32_t SegIndex) const {
index 0ca1fea6179a75be0343d28f440eb05db547e844..8124c18f30e97467dd252076819c5a53b4336c6b 100644 (file)
@@ -2758,8 +2758,8 @@ iterator_range<export_iterator> MachOObjectFile::exports() const {
 MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O,
                                    ArrayRef<uint8_t> Bytes, bool is64Bit)
     : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0),
-      SegmentIndex(0), RemainingLoopCount(0), AdvanceAmount(0), RebaseType(0),
-      PointerSize(is64Bit ? 8 : 4), Malformed(false), Done(false) {}
+      SegmentIndex(-1), RemainingLoopCount(0), AdvanceAmount(0), RebaseType(0),
+      PointerSize(is64Bit ? 8 : 4), Done(false) {}
 
 void MachORebaseEntry::moveToFirst() {
   Ptr = Opcodes.begin();
@@ -2773,22 +2773,31 @@ void MachORebaseEntry::moveToEnd() {
 }
 
 void MachORebaseEntry::moveNext() {
+  ErrorAsOutParameter ErrAsOutParam(E);
   // If in the middle of some loop, move to next rebasing in loop.
   SegmentOffset += AdvanceAmount;
   if (RemainingLoopCount) {
     --RemainingLoopCount;
     return;
   }
-  if (Ptr == Opcodes.end()) {
+  if (Ptr >= Opcodes.end()) {
+    if (Opcodes.begin() != Opcodes.end() && Done != true) {
+      *E = malformedError("missing REBASE_OPCODE_DONE at end of opcodes");
+      moveToEnd();
+      return;
+    }
     Done = true;
     return;
   }
   bool More = true;
-  while (More && !Malformed) {
+  while (More) {
     // Parse next opcode and set up next loop.
+    const uint8_t *OpcodeStart = Ptr;
     uint8_t Byte = *Ptr++;
     uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK;
     uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK;
+    uint32_t Count, Skip;
+    const char *error = nullptr;
     switch (Opcode) {
     case MachO::REBASE_OPCODE_DONE:
       More = false;
@@ -2798,6 +2807,13 @@ void MachORebaseEntry::moveNext() {
       break;
     case MachO::REBASE_OPCODE_SET_TYPE_IMM:
       RebaseType = ImmValue;
+      if (RebaseType > MachO::REBASE_TYPE_TEXT_PCREL32) {
+          *E = malformedError("for REBASE_OPCODE_SET_TYPE_IMM bad bind type: " +
+               Twine((int)RebaseType) + " for opcode at: 0x" +
+               utohexstr(OpcodeStart - Opcodes.begin()));
+          moveToEnd();
+          return;
+      }
       DEBUG_WITH_TYPE(
           "mach-o-rebase",
           llvm::dbgs() << "REBASE_OPCODE_SET_TYPE_IMM: "
@@ -2805,7 +2821,23 @@ void MachORebaseEntry::moveNext() {
       break;
     case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
       SegmentIndex = ImmValue;
-      SegmentOffset = readULEB128();
+      SegmentOffset = readULEB128(&error);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
+      error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset,
+                                              true);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       DEBUG_WITH_TYPE(
           "mach-o-rebase",
           llvm::dbgs() << "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "
@@ -2814,22 +2846,80 @@ void MachORebaseEntry::moveNext() {
                        << "\n");
       break;
     case MachO::REBASE_OPCODE_ADD_ADDR_ULEB:
-      SegmentOffset += readULEB128();
+      SegmentOffset += readULEB128(&error);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
+      error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset,
+                                              true);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       DEBUG_WITH_TYPE("mach-o-rebase",
                       llvm::dbgs() << "REBASE_OPCODE_ADD_ADDR_ULEB: "
                                    << format("SegmentOffset=0x%06X",
                                              SegmentOffset) << "\n");
       break;
     case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+      error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset,
+                                              true);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       SegmentOffset += ImmValue * PointerSize;
+      error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset,
+                                              false);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED "
+             " (after adding immediate times the pointer size) " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       DEBUG_WITH_TYPE("mach-o-rebase",
                       llvm::dbgs() << "REBASE_OPCODE_ADD_ADDR_IMM_SCALED: "
                                    << format("SegmentOffset=0x%06X",
                                              SegmentOffset) << "\n");
       break;
     case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+      error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset,
+                                              true);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       AdvanceAmount = PointerSize;
-      RemainingLoopCount = ImmValue - 1;
+      Skip = 0;
+      Count = ImmValue;
+      if (ImmValue != 0)
+        RemainingLoopCount = ImmValue - 1;
+      else
+        RemainingLoopCount = 0;
+      error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize,
+                                              SegmentIndex, SegmentOffset);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES "
+             + Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+       return;
+      }
       DEBUG_WITH_TYPE(
           "mach-o-rebase",
           llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_IMM_TIMES: "
@@ -2839,8 +2929,38 @@ void MachORebaseEntry::moveNext() {
                        << "\n");
       return;
     case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+      error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset,
+                                              true);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       AdvanceAmount = PointerSize;
-      RemainingLoopCount = readULEB128() - 1;
+      Skip = 0;
+      Count = readULEB128(&error);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
+      if (Count != 0)
+        RemainingLoopCount = Count - 1;
+      else
+        RemainingLoopCount = 0;
+      error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize,
+                                              SegmentIndex, SegmentOffset);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES "
+             + Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+       return;
+      }
       DEBUG_WITH_TYPE(
           "mach-o-rebase",
           llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES: "
@@ -2850,8 +2970,35 @@ void MachORebaseEntry::moveNext() {
                        << "\n");
       return;
     case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
-      AdvanceAmount = readULEB128() + PointerSize;
+      error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset,
+                                              true);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
+      Skip = readULEB128(&error);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +
+             Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
+      AdvanceAmount = Skip + PointerSize;
+      Count = 1;
       RemainingLoopCount = 0;
+      error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize,
+                                              SegmentIndex, SegmentOffset);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB "
+             + Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+       return;
+      }
       DEBUG_WITH_TYPE(
           "mach-o-rebase",
           llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: "
@@ -2861,8 +3008,46 @@ void MachORebaseEntry::moveNext() {
                        << "\n");
       return;
     case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
-      RemainingLoopCount = readULEB128() - 1;
-      AdvanceAmount = readULEB128() + PointerSize;
+      error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset,
+                                              true);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
+             "ULEB " + Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
+      Count = readULEB128(&error);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
+             "ULEB " + Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
+      if (Count != 0)
+        RemainingLoopCount = Count - 1;
+      else
+        RemainingLoopCount = 0;
+      Skip = readULEB128(&error);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
+             "ULEB " + Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
+      AdvanceAmount = Skip + PointerSize;
+
+      error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize,
+                                              SegmentIndex, SegmentOffset);
+      if (error) {
+        *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
+             "ULEB " + Twine(error) + " for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+       return;
+      }
       DEBUG_WITH_TYPE(
           "mach-o-rebase",
           llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: "
@@ -2872,23 +3057,25 @@ void MachORebaseEntry::moveNext() {
                        << "\n");
       return;
     default:
-      Malformed = true;
+      *E = malformedError("bad rebase info (bad opcode value 0x" +
+           utohexstr(Opcode) + " for opcode at: 0x" +
+           utohexstr(OpcodeStart - Opcodes.begin()));
+      moveToEnd();
+      return;
     }
   }
 }
 
-uint64_t MachORebaseEntry::readULEB128() {
+uint64_t MachORebaseEntry::readULEB128(const char **error) {
   unsigned Count;
-  uint64_t Result = decodeULEB128(Ptr, &Count);
+  uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);
   Ptr += Count;
-  if (Ptr > Opcodes.end()) {
+  if (Ptr > Opcodes.end())
     Ptr = Opcodes.end();
-    Malformed = true;
-  }
   return Result;
 }
 
-uint32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; }
+int32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; }
 
 uint64_t MachORebaseEntry::segmentOffset() const { return SegmentOffset; }
 
@@ -2956,8 +3143,7 @@ MachOBindEntry::MachOBindEntry(Error *E, const MachOObjectFile *O,
     : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0),
       SegmentIndex(-1), LibraryOrdinalSet(false), Ordinal(0), Flags(0),
       Addend(0), RemainingLoopCount(0), AdvanceAmount(0), BindType(0),
-      PointerSize(is64Bit ? 8 : 4), TableKind(BK), Malformed(false),
-      Done(false) {}
+      PointerSize(is64Bit ? 8 : 4), TableKind(BK), Done(false) {}
 
 void MachOBindEntry::moveToFirst() {
   Ptr = Opcodes.begin();
@@ -2978,12 +3164,17 @@ void MachOBindEntry::moveNext() {
     --RemainingLoopCount;
     return;
   }
-  if (Ptr == Opcodes.end()) {
+  if (Ptr >= Opcodes.end()) {
+    if (Opcodes.begin() != Opcodes.end() && Done != true) {
+      *E = malformedError("missing BIND_OPCODE_DONE at end of opcodes");
+      moveToEnd();
+      return;
+    }
     Done = true;
     return;
   }
   bool More = true;
-  while (More && !Malformed) {
+  while (More) {
     // Parse next opcode and set up next loop.
     const uint8_t *OpcodeStart = Ptr;
     uint8_t Byte = *Ptr++;
@@ -3008,11 +3199,17 @@ void MachOBindEntry::moveNext() {
           break;
       }
       More = false;
-      Done = true;
       moveToEnd();
       DEBUG_WITH_TYPE("mach-o-bind", llvm::dbgs() << "BIND_OPCODE_DONE\n");
       break;
     case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+      if (TableKind == Kind::Weak) {
+        *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM not allowed in "
+             "weak bind table for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       Ordinal = ImmValue;
       LibraryOrdinalSet = true;
       if (ImmValue > O->getLibraryCount()) {
@@ -3029,6 +3226,13 @@ void MachOBindEntry::moveNext() {
                        << "Ordinal=" << Ordinal << "\n");
       break;
     case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+      if (TableKind == Kind::Weak) {
+        *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB not allowed in "
+             "weak bind table for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       Ordinal = readULEB128(&error);
       LibraryOrdinalSet = true;
       if (error) {
@@ -3052,6 +3256,13 @@ void MachOBindEntry::moveNext() {
                        << "Ordinal=" << Ordinal << "\n");
       break;
     case MachO::BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+      if (TableKind == Kind::Weak) {
+        *E = malformedError("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM not allowed in "
+             "weak bind table for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       if (ImmValue) {
         SignExtended = MachO::BIND_OPCODE_MASK | ImmValue;
         Ordinal = SignExtended;
@@ -3118,8 +3329,6 @@ void MachOBindEntry::moveNext() {
         moveToEnd();
         return;
       }
-      if (TableKind == Kind::Lazy)
-        Malformed = true;
       DEBUG_WITH_TYPE(
           "mach-o-bind",
           llvm::dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: "
@@ -3202,6 +3411,13 @@ void MachOBindEntry::moveNext() {
                                              SegmentOffset) << "\n");
       return;
      case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+      if (TableKind == Kind::Lazy) {
+        *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB not allowed in "
+             "lazy bind table for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true);
       if (error) {
         *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " +
@@ -3245,8 +3461,6 @@ void MachOBindEntry::moveNext() {
         return;
       }
       RemainingLoopCount = 0;
-      if (TableKind == Kind::Lazy)
-        Malformed = true;
       DEBUG_WITH_TYPE(
           "mach-o-bind",
           llvm::dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: "
@@ -3256,6 +3470,13 @@ void MachOBindEntry::moveNext() {
                        << "\n");
       return;
     case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+      if (TableKind == Kind::Lazy) {
+        *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED not "
+             "allowed in lazy bind table for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true);
       if (error) {
         *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " +
@@ -3290,8 +3511,6 @@ void MachOBindEntry::moveNext() {
         moveToEnd();
         return;
       }
-      if (TableKind == Kind::Lazy)
-        Malformed = true;
       DEBUG_WITH_TYPE("mach-o-bind",
                       llvm::dbgs()
                       << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: "
@@ -3299,6 +3518,13 @@ void MachOBindEntry::moveNext() {
                                              SegmentOffset) << "\n");
       return;
     case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+      if (TableKind == Kind::Lazy) {
+        *E = malformedError("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB not "
+             "allowed in lazy bind table for opcode at: 0x" +
+             utohexstr(OpcodeStart - Opcodes.begin()));
+        moveToEnd();
+        return;
+      }
       Count = readULEB128(&error);
       if (Count != 0)
         RemainingLoopCount = Count - 1;
@@ -3351,8 +3577,6 @@ void MachOBindEntry::moveNext() {
         moveToEnd();
        return;
       }
-      if (TableKind == Kind::Lazy)
-        Malformed = true;
       DEBUG_WITH_TYPE(
           "mach-o-bind",
           llvm::dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: "
@@ -3362,7 +3586,6 @@ void MachOBindEntry::moveNext() {
                        << "\n");
       return;
     default:
-      Malformed = true;
       *E = malformedError("bad bind info (bad opcode value 0x" +
            utohexstr(Opcode) + " for opcode at: 0x" +
            utohexstr(OpcodeStart - Opcodes.begin()));
@@ -3376,10 +3599,8 @@ uint64_t MachOBindEntry::readULEB128(const char **error) {
   unsigned Count;
   uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);
   Ptr += Count;
-  if (Ptr > Opcodes.end()) {
+  if (Ptr > Opcodes.end())
     Ptr = Opcodes.end();
-    Malformed = true;
-  }
   return Result;
 }
 
@@ -3387,10 +3608,8 @@ int64_t MachOBindEntry::readSLEB128(const char **error) {
   unsigned Count;
   int64_t Result = decodeSLEB128(Ptr, &Count, Opcodes.end(), error);
   Ptr += Count;
-  if (Ptr > Opcodes.end()) {
+  if (Ptr > Opcodes.end())
     Ptr = Opcodes.end();
-    Malformed = true;
-  }
   return Result;
 }
 
@@ -3473,12 +3692,12 @@ BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) {
 }
 
 // For use with a SegIndex,SegOffset pair in MachOBindEntry::moveNext() to
-// validate a MachOBindEntry.
+// validate a MachOBindEntry or MachORebaseEntry.
 const char * BindRebaseSegInfo::checkSegAndOffset(int32_t SegIndex,
                                                   uint64_t SegOffset,
                                                   bool endInvalid) {
   if (SegIndex == -1)
-    return "missing preceding BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB";
+    return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB";
   if (SegIndex >= MaxSegIndex)
     return "bad segIndex (too large)";
   for (const SectionInfo &SI : Sections) {
@@ -3496,12 +3715,14 @@ const char * BindRebaseSegInfo::checkSegAndOffset(int32_t SegIndex,
 }
 
 // For use in MachOBindEntry::moveNext() to validate a MachOBindEntry for
-// the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode.  The SegIndex
-// and SegOffset must have been already checked.
+// the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode and for use in
+// MachORebaseEntry::moveNext() to validate a MachORebaseEntry for
+// REBASE_OPCODE_DO_*_TIMES* opcodes.  The SegIndex and SegOffset must have
+// been already checked.
 const char * BindRebaseSegInfo::checkCountAndSkip(uint32_t Count, uint32_t Skip,
                                                   uint8_t PointerSize,
-                                                 int32_t SegIndex,
-                                                 uint64_t SegOffset) {
+                                                  int32_t SegIndex,
+                                                  uint64_t SegOffset) {
   const SectionInfo &SI = findSection(SegIndex, SegOffset);
   uint64_t addr = SI.SegmentStartAddress + SegOffset;
   if (addr >= SI.Address + SI.Size)
@@ -3509,8 +3730,15 @@ const char * BindRebaseSegInfo::checkCountAndSkip(uint32_t Count, uint32_t Skip,
   uint64_t i = 0;
   if (Count > 1)
     i = (Skip + PointerSize) * (Count - 1);
-  if (addr + i >= SI.Address + SI.Size)
-    return "bad count and skip, too large";
+  else if (Count == 1)
+    i = Skip + PointerSize;
+  if (addr + i >= SI.Address + SI.Size) {
+    // For rebase opcodes they can step from one section to another.
+    uint64_t TrailingSegOffset = (addr + i) - SI.SegmentStartAddress;
+    const char *error = checkSegAndOffset(SegIndex, TrailingSegOffset, false);
+    if (error)
+      return "bad count and skip, too large";
+  }
   return nullptr;
 }
 
diff --git a/test/tools/llvm-objdump/Inputs/macho-bind-missing-done b/test/tools/llvm-objdump/Inputs/macho-bind-missing-done
new file mode 100755 (executable)
index 0000000..ced8840
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-bind-missing-done differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-add-addr-imm-scaled b/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-add-addr-imm-scaled
new file mode 100755 (executable)
index 0000000..a7d5abe
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-add-addr-imm-scaled differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-uleb-times-skipping-uleb b/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-uleb-times-skipping-uleb
new file mode 100755 (executable)
index 0000000..1f02883
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-uleb-times-skipping-uleb differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-lazy-do_bind_add_addr_uleb b/test/tools/llvm-objdump/Inputs/macho-lazy-do_bind_add_addr_uleb
new file mode 100755 (executable)
index 0000000..63f0346
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-lazy-do_bind_add_addr_uleb differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-imm-scaled b/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-imm-scaled
new file mode 100755 (executable)
index 0000000..6b0c1bd
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-imm-scaled differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb b/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb
new file mode 100755 (executable)
index 0000000..e409590
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb-too-big b/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb-too-big
new file mode 100755 (executable)
index 0000000..68b72ec
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb-too-big differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-bad-opcode-value b/test/tools/llvm-objdump/Inputs/macho-rebase-bad-opcode-value
new file mode 100755 (executable)
index 0000000..59e0d4f
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-bad-opcode-value differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-imm-times b/test/tools/llvm-objdump/Inputs/macho-rebase-imm-times
new file mode 100755 (executable)
index 0000000..be2286b
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-imm-times differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-missing-done b/test/tools/llvm-objdump/Inputs/macho-rebase-missing-done
new file mode 100755 (executable)
index 0000000..633a117
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-missing-done differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-seg-too-big b/test/tools/llvm-objdump/Inputs/macho-rebase-seg-too-big
new file mode 100755 (executable)
index 0000000..12b5232
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-seg-too-big differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-segoff-too-big b/test/tools/llvm-objdump/Inputs/macho-rebase-segoff-too-big
new file mode 100755 (executable)
index 0000000..4dfb19d
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-segoff-too-big differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-set-type-imm b/test/tools/llvm-objdump/Inputs/macho-rebase-set-type-imm
new file mode 100755 (executable)
index 0000000..947db0e
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-set-type-imm differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-malformed-uleb128 b/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-malformed-uleb128
new file mode 100755 (executable)
index 0000000..045f425
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-malformed-uleb128 differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times b/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times
new file mode 100755 (executable)
index 0000000..c12f256
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times-skipping-uleb b/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times-skipping-uleb
new file mode 100755 (executable)
index 0000000..5bec8ca
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times-skipping-uleb differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-imm b/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-imm
new file mode 100755 (executable)
index 0000000..1d8785c
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-imm differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-uleb b/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-uleb
new file mode 100755 (executable)
index 0000000..bf7babc
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-uleb differ
diff --git a/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-special-imm b/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-special-imm
new file mode 100755 (executable)
index 0000000..d13f6ec
Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-special-imm differ
index dea86bb6514a005a58d7deb87a390f558b183039..baf8dee3234746e06c68a3bd697328b50da7bc0e 100644 (file)
@@ -29,7 +29,7 @@ RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-add_addr_uleb 2>&1 | Fil
 ADD_ADDR_ULEB: macho-bind-add_addr_uleb': truncated or malformed object (for BIND_OPCODE_ADD_ADDR_ULEB bad segOffset, too large for opcode at: 0x17)
 
 RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-do-bind-no-segIndex 2>&1 | FileCheck -check-prefix BIND-NO-SEGINDEX %s 
-BIND-NO-SEGINDEX: macho-bind-do-bind-no-segIndex': truncated or malformed object (for BIND_OPCODE_DO_BIND missing preceding BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB for opcode at: 0x15)
+BIND-NO-SEGINDEX: macho-bind-do-bind-no-segIndex': truncated or malformed object (for BIND_OPCODE_DO_BIND missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB for opcode at: 0x15)
 
 RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-bind-add-addr-uleb 2>&1 | FileCheck -check-prefix ADD-ADDR-ULEB %s 
 ADD-ADDR-ULEB: macho-bind-bind-add-addr-uleb': truncated or malformed object (for BIND_OPCODE_ADD_ADDR_ULEB (after adding ULEB) bad segOffset, too large for opcode at: 0x18)
@@ -48,3 +48,60 @@ DO-BIND-NO-DYLIB-ORDINAL: macho-do-bind-no-dylib-ordinal': truncated or malforme
 
 RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-bad-opcode-value 2>&1 | FileCheck -check-prefix BAD-OPCODE-VALUE %s 
 BAD-OPCODE-VALUE: macho-bind-bad-opcode-value': truncated or malformed object (bad bind info (bad opcode value 0xD0 for opcode at: 0x18)
+
+RUN: not llvm-objdump -macho -lazy-bind %p/Inputs/macho-lazy-do_bind_add_addr_uleb 2>&1 | FileCheck -check-prefix LAZY_DO_BIND_ADD_ADDR_ULEB %s 
+LAZY_DO_BIND_ADD_ADDR_ULEB: macho-lazy-do_bind_add_addr_uleb': truncated or malformed object (BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB not allowed in lazy bind table for opcode at: 0xC)
+
+RUN: not llvm-objdump -macho -lazy-bind %p/Inputs/macho-lazy-do-bind-add-addr-imm-scaled 2>&1 | FileCheck -check-prefix LAZY-DO-BIND-ADD-ADDR-IMM-SCALED %s 
+LAZY-DO-BIND-ADD-ADDR-IMM-SCALED: macho-lazy-do-bind-add-addr-imm-scaled': truncated or malformed object (BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED not allowed in lazy bind table for opcode at: 0xC)
+
+RUN: not llvm-objdump -macho -lazy-bind %p/Inputs/macho-lazy-do-bind-uleb-times-skipping-uleb 2>&1 | FileCheck -check-prefix LAZY-DO-BIND-ULEB-TIMES-SKIPPING-ULEB %s 
+LAZY-DO-BIND-ULEB-TIMES-SKIPPING-ULEB: macho-lazy-do-bind-uleb-times-skipping-uleb': truncated or malformed object (BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB not allowed in lazy bind table for opcode at: 0xC)
+
+RUN: not llvm-objdump -macho -weak-bind %p/Inputs/macho-weak-bind-set-dylib-ordinal-imm 2>&1 | FileCheck -check-prefix WEAK-BIND-SET-DYLIB-ORDINAL-IMM %s 
+WEAK-BIND-SET-DYLIB-ORDINAL-IMM: macho-weak-bind-set-dylib-ordinal-imm': truncated or malformed object (BIND_OPCODE_SET_DYLIB_ORDINAL_IMM not allowed in weak bind table for opcode at: 0x2)
+
+RUN: not llvm-objdump -macho -weak-bind %p/Inputs/macho-weak-bind-set-dylib-ordinal-uleb 2>&1 | FileCheck -check-prefix WEAK-BIND-SET-DYLIB-ORDINAL-ULEB %s 
+WEAK-BIND-SET-DYLIB-ORDINAL-ULEB: macho-weak-bind-set-dylib-ordinal-uleb': truncated or malformed object (BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB not allowed in weak bind table for opcode at: 0x2)
+
+RUN: not llvm-objdump -macho -weak-bind %p/Inputs/macho-weak-bind-set-dylib-special-imm 2>&1 | FileCheck -check-prefix WEAK-BIND-SET-DYLIB-SPECIAL-IMM %s 
+WEAK-BIND-SET-DYLIB-SPECIAL-IMM: macho-weak-bind-set-dylib-special-imm': truncated or malformed object (BIND_OPCODE_SET_DYLIB_SPECIAL_IMM not allowed in weak bind table for opcode at: 0x2)
+
+RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-missing-done 2>&1 | FileCheck -check-prefix BIND-MISSING-DONE %s 
+BIND-MISSING-DONE: macho-bind-missing-done': truncated or malformed object (missing BIND_OPCODE_DONE at end of opcodes)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-set-type-imm 2>&1 | FileCheck -check-prefix REBASE-SET-TYPE-IMM %s 
+REBASE-SET-TYPE-IMM: macho-rebase-set-type-imm': truncated or malformed object (for REBASE_OPCODE_SET_TYPE_IMM bad bind type: 5 for opcode at: 0x0)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-uleb-malformed-uleb128 2>&1 | FileCheck -check-prefix REBASE-ULEB-MALFORMED-ULEB128 %s 
+REBASE-ULEB-MALFORMED-ULEB128: macho-rebase-uleb-malformed-uleb128': truncated or malformed object (for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB malformed uleb128, extends past end for opcode at: 0x1)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-seg-too-big 2>&1 | FileCheck -check-prefix REBASE-SEG-TOO-BIG %s 
+REBASE-SEG-TOO-BIG: macho-rebase-seg-too-big': truncated or malformed object (for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB bad segIndex (too large) for opcode at: 0x1)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-segoff-too-big 2>&1 | FileCheck -check-prefix REBASE-SEGOFF-TOO-BIG %s 
+REBASE-SEGOFF-TOO-BIG: macho-rebase-segoff-too-big': truncated or malformed object (for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB bad segOffset, too large for opcode at: 0x1)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-add-addr-uleb 2>&1 | FileCheck -check-prefix REBASE-ADD-ADDR-ULEB %s 
+REBASE-ADD-ADDR-ULEB: macho-rebase-add-addr-uleb': truncated or malformed object (for REBASE_OPCODE_ADD_ADDR_ULEB bad segOffset, too large for opcode at: 0x3)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-add-addr-imm-scaled 2>&1 | FileCheck -check-prefix REBASE-ADD-ADDR-IMM-SCALED %s 
+REBASE-ADD-ADDR-IMM-SCALED: macho-rebase-add-addr-imm-scaled': truncated or malformed object (for REBASE_OPCODE_ADD_ADDR_IMM_SCALED  (after adding immediate times the pointer size) bad segOffset, too large for opcode at: 0x3)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-imm-times 2>&1 | FileCheck -check-prefix REBASE-IMM-TIMES %s 
+REBASE-IMM-TIMES: macho-rebase-imm-times': truncated or malformed object (for REBASE_OPCODE_DO_REBASE_IMM_TIMES bad count and skip, too large for opcode at: 0x3)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-uleb-times 2>&1 | FileCheck -check-prefix REBASE-ULEB-TIMES %s 
+REBASE-ULEB-TIMES: macho-rebase-uleb-times': truncated or malformed object (for REBASE_OPCODE_DO_REBASE_ULEB_TIMES bad count and skip, too large for opcode at: 0x3)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-add-addr-uleb-too-big 2>&1 | FileCheck -check-prefix REBASE-ADD-ADDR-ULEB-TOO-BIG %s 
+REBASE-ADD-ADDR-ULEB-TOO-BIG: macho-rebase-add-addr-uleb-too-big': truncated or malformed object (for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB bad count and skip, too large for opcode at: 0x3)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-uleb-times-skipping-uleb 2>&1 | FileCheck -check-prefix REBASE-ULEB-TIMES-SKIPPING-ULEB %s 
+REBASE-ULEB-TIMES-SKIPPING-ULEB: macho-rebase-uleb-times-skipping-uleb': truncated or malformed object (for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB bad count and skip, too large for opcode at: 0x3)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-bad-opcode-value 2>&1 | FileCheck -check-prefix REBASE-BAD-OPCODE-VALUE %s 
+REBASE-BAD-OPCODE-VALUE: macho-rebase-bad-opcode-value': truncated or malformed object (bad rebase info (bad opcode value 0xD0 for opcode at: 0x4)
+
+RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-missing-done 2>&1 | FileCheck -check-prefix REBASE-MISSING-DONE %s 
+REBASE-MISSING-DONE: macho-rebase-missing-done': truncated or malformed object (missing REBASE_OPCODE_DONE at end of opcodes)