diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 | 
| commit | 71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch) | |
| tree | 5343938942df402b49ec7300a1c25a2d4ccd5821 /lib/Object/MachOObjectFile.cpp | |
| parent | 31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff) | |
Notes
Diffstat (limited to 'lib/Object/MachOObjectFile.cpp')
| -rw-r--r-- | lib/Object/MachOObjectFile.cpp | 856 | 
1 files changed, 779 insertions, 77 deletions
diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 5b018676eba3..1753d2baaedd 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -106,13 +106,6 @@ static StringRef parseSegmentOrSectionName(const char *P) {    return StringRef(P, 16);  } -// Helper to advance a section or symbol iterator multiple increments at a time. -template<class T> -static void advance(T &it, size_t Val) { -  while (Val--) -    ++it; -} -  static unsigned getCPUType(const MachOObjectFile &O) {    return O.getHeader().cputype;  } @@ -368,7 +361,7 @@ static Error parseSegmentLoadCommand(                              CmdName + " extends past the end of the file");      if (S.vmsize != 0 && S.filesize > S.vmsize)        return malformedError("load command " + Twine(LoadCommandIndex) + -                            " fileoff field in " + CmdName + +                            " filesize field in " + CmdName +                              " greater than vmsize field");      IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname);    } else @@ -784,6 +777,52 @@ static Error checkVersCommand(const MachOObjectFile &Obj,    return Error::success();  } +static Error checkNoteCommand(const MachOObjectFile &Obj, +                              const MachOObjectFile::LoadCommandInfo &Load, +                              uint32_t LoadCommandIndex, +                              std::list<MachOElement> &Elements) { +  if (Load.C.cmdsize != sizeof(MachO::note_command)) +    return malformedError("load command " + Twine(LoadCommandIndex) +  +                          " LC_NOTE has incorrect cmdsize"); +  MachO::note_command Nt = getStruct<MachO::note_command>(Obj, Load.Ptr); +  uint64_t FileSize = Obj.getData().size(); +  if (Nt.offset > FileSize) +    return malformedError("offset field of LC_NOTE command " + +                          Twine(LoadCommandIndex) + " extends " +                          "past the end of the file"); +  uint64_t BigSize = Nt.offset; +  BigSize += Nt.size; +  if (BigSize > FileSize) +    return malformedError("size field plus offset field of LC_NOTE command " + +                          Twine(LoadCommandIndex) + " extends past the end of " +                          "the file"); +  if (Error Err = checkOverlappingElement(Elements, Nt.offset, Nt.size, +                                          "LC_NOTE data")) +    return Err; +  return Error::success(); +} + +static Error +parseBuildVersionCommand(const MachOObjectFile &Obj, +                         const MachOObjectFile::LoadCommandInfo &Load, +                         SmallVectorImpl<const char*> &BuildTools, +                         uint32_t LoadCommandIndex) { +  MachO::build_version_command BVC = +      getStruct<MachO::build_version_command>(Obj, Load.Ptr); +  if (Load.C.cmdsize != +      sizeof(MachO::build_version_command) + +          BVC.ntools * sizeof(MachO::build_tool_version)) +    return malformedError("load command " + Twine(LoadCommandIndex) + +                          " LC_BUILD_VERSION_COMMAND has incorrect cmdsize"); + +  auto Start = Load.Ptr + sizeof(MachO::build_version_command); +  BuildTools.resize(BVC.ntools); +  for (unsigned i = 0; i < BVC.ntools; ++i) +    BuildTools[i] = Start + i * sizeof(MachO::build_tool_version); + +  return Error::success(); +} +  static Error checkRpathCommand(const MachOObjectFile &Obj,                                 const MachOObjectFile::LoadCommandInfo &Load,                                 uint32_t LoadCommandIndex) { @@ -931,7 +970,26 @@ static Error checkThreadCommand(const MachOObjectFile &Obj,        sys::swapByteOrder(count);      state += sizeof(uint32_t); -    if (cputype == MachO::CPU_TYPE_X86_64) { +    if (cputype == MachO::CPU_TYPE_I386) { +      if (flavor == MachO::x86_THREAD_STATE32) { +        if (count != MachO::x86_THREAD_STATE32_COUNT) +          return malformedError("load command " + Twine(LoadCommandIndex) + +                                " count not x86_THREAD_STATE32_COUNT for " +                                "flavor number " + Twine(nflavor) + " which is " +                                "a x86_THREAD_STATE32 flavor in " + CmdName + +                                " command"); +        if (state + sizeof(MachO::x86_thread_state32_t) > end) +          return malformedError("load command " + Twine(LoadCommandIndex) + +                                " x86_THREAD_STATE32 extends past end of " +                                "command in " + CmdName + " command"); +        state += sizeof(MachO::x86_thread_state32_t); +      } else { +        return malformedError("load command " + Twine(LoadCommandIndex) + +                              " unknown flavor (" + Twine(flavor) + ") for " +                              "flavor number " + Twine(nflavor) + " in " + +                              CmdName + " command"); +      } +    } else if (cputype == MachO::CPU_TYPE_X86_64) {        if (flavor == MachO::x86_THREAD_STATE64) {          if (count != MachO::x86_THREAD_STATE64_COUNT)            return malformedError("load command " + Twine(LoadCommandIndex) + @@ -1280,6 +1338,12 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,        if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,                                    "LC_VERSION_MIN_WATCHOS")))          return; +    } else if (Load.C.cmd == MachO::LC_NOTE) { +      if ((Err = checkNoteCommand(*this, Load, I, Elements))) +        return; +    } else if (Load.C.cmd == MachO::LC_BUILD_VERSION) { +      if ((Err = parseBuildVersionCommand(*this, Load, BuildTools, I))) +        return;      } else if (Load.C.cmd == MachO::LC_RPATH) {        if ((Err = checkRpathCommand(*this, Load, I)))          return; @@ -2201,6 +2265,10 @@ std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index,    return std::error_code();  } +uint32_t MachOObjectFile::getLibraryCount() const { +  return Libraries.size(); +} +  section_iterator  MachOObjectFile::getRelocationRelocatedSection(relocation_iterator Rel) const {    DataRefImpl Sec; @@ -2383,6 +2451,8 @@ Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType,          *ArchFlag = "armv7em";        return Triple("thumbv7em-apple-darwin");      case MachO::CPU_SUBTYPE_ARM_V7K: +      if (McpuDefault) +        *McpuDefault = "cortex-a7";        if (ArchFlag)          *ArchFlag = "armv7k";        return Triple("armv7k-apple-darwin"); @@ -2393,6 +2463,8 @@ Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType,          *ArchFlag = "armv7m";        return Triple("thumbv7m-apple-darwin");      case MachO::CPU_SUBTYPE_ARM_V7S: +      if (McpuDefault) +        *McpuDefault = "cortex-a7";        if (ArchFlag)          *ArchFlag = "armv7s";        return Triple("armv7s-apple-darwin"); @@ -2402,6 +2474,8 @@ Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType,    case MachO::CPU_TYPE_ARM64:      switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {      case MachO::CPU_SUBTYPE_ARM64_ALL: +      if (McpuDefault) +        *McpuDefault = "cyclone";        if (ArchFlag)          *ArchFlag = "arm64";        return Triple("arm64-apple-darwin"); @@ -2674,10 +2748,11 @@ iterator_range<export_iterator> MachOObjectFile::exports() const {    return exports(getDyldInfoExportsTrie());  } -MachORebaseEntry::MachORebaseEntry(ArrayRef<uint8_t> Bytes, bool is64Bit) -    : Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(0), -      RemainingLoopCount(0), AdvanceAmount(0), RebaseType(0), -      PointerSize(is64Bit ? 8 : 4), Malformed(false), Done(false) {} +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(-1), RemainingLoopCount(0), AdvanceAmount(0), RebaseType(0), +      PointerSize(is64Bit ? 8 : 4), Done(false) {}  void MachORebaseEntry::moveToFirst() {    Ptr = Opcodes.begin(); @@ -2691,22 +2766,29 @@ 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;    } +  // REBASE_OPCODE_DONE is only used for padding if we are not aligned to +  // pointer size. Therefore it is possible to reach the end without ever having +  // seen REBASE_OPCODE_DONE.    if (Ptr == Opcodes.end()) {      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; @@ -2716,6 +2798,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: " @@ -2723,7 +2812,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: " @@ -2732,22 +2837,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: " @@ -2757,8 +2920,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: " @@ -2768,8 +2961,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: " @@ -2779,8 +2999,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: " @@ -2790,23 +3048,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; } @@ -2822,6 +3082,24 @@ StringRef MachORebaseEntry::typeName() const {    return "unknown";  } +// For use with the SegIndex of a checked Mach-O Rebase entry +// to get the segment name. +StringRef MachORebaseEntry::segmentName() const { +  return O->BindRebaseSegmentName(SegmentIndex); +} + +// For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry +// to get the section name. +StringRef MachORebaseEntry::sectionName() const { +  return O->BindRebaseSectionName(SegmentIndex, SegmentOffset); +} + +// For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry +// to get the address. +uint64_t MachORebaseEntry::address() const { +  return O->BindRebaseAddress(SegmentIndex, SegmentOffset); +} +  bool MachORebaseEntry::operator==(const MachORebaseEntry &Other) const {  #ifdef EXPENSIVE_CHECKS    assert(Opcodes == Other.Opcodes && "compare iterators of different files"); @@ -2834,25 +3112,29 @@ bool MachORebaseEntry::operator==(const MachORebaseEntry &Other) const {  }  iterator_range<rebase_iterator> -MachOObjectFile::rebaseTable(ArrayRef<uint8_t> Opcodes, bool is64) { -  MachORebaseEntry Start(Opcodes, is64); +MachOObjectFile::rebaseTable(Error &Err, MachOObjectFile *O, +                             ArrayRef<uint8_t> Opcodes, bool is64) { +  if (O->BindRebaseSectionTable == nullptr) +    O->BindRebaseSectionTable = llvm::make_unique<BindRebaseSegInfo>(O); +  MachORebaseEntry Start(&Err, O, Opcodes, is64);    Start.moveToFirst(); -  MachORebaseEntry Finish(Opcodes, is64); +  MachORebaseEntry Finish(&Err, O, Opcodes, is64);    Finish.moveToEnd();    return make_range(rebase_iterator(Start), rebase_iterator(Finish));  } -iterator_range<rebase_iterator> MachOObjectFile::rebaseTable() const { -  return rebaseTable(getDyldInfoRebaseOpcodes(), is64Bit()); +iterator_range<rebase_iterator> MachOObjectFile::rebaseTable(Error &Err) { +  return rebaseTable(Err, this, getDyldInfoRebaseOpcodes(), is64Bit());  } -MachOBindEntry::MachOBindEntry(ArrayRef<uint8_t> Bytes, bool is64Bit, Kind BK) -    : Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(0), -      Ordinal(0), Flags(0), Addend(0), RemainingLoopCount(0), AdvanceAmount(0), -      BindType(0), PointerSize(is64Bit ? 8 : 4), -      TableKind(BK), Malformed(false), Done(false) {} +MachOBindEntry::MachOBindEntry(Error *E, const MachOObjectFile *O, +                               ArrayRef<uint8_t> Bytes, bool is64Bit, Kind BK) +    : 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), Done(false) {}  void MachOBindEntry::moveToFirst() {    Ptr = Opcodes.begin(); @@ -2866,24 +3148,31 @@ void MachOBindEntry::moveToEnd() {  }  void MachOBindEntry::moveNext() { +  ErrorAsOutParameter ErrAsOutParam(E);    // If in the middle of some loop, move to next binding in loop.    SegmentOffset += AdvanceAmount;    if (RemainingLoopCount) {      --RemainingLoopCount;      return;    } +  // BIND_OPCODE_DONE is only used for padding if we are not aligned to +  // pointer size. Therefore it is possible to reach the end without ever having +  // seen BIND_OPCODE_DONE.    if (Ptr == Opcodes.end()) {      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::BIND_IMMEDIATE_MASK;      uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK;      int8_t SignExtended;      const uint8_t *SymStart; +    uint32_t Count, Skip; +    const char *error = nullptr;      switch (Opcode) {      case MachO::BIND_OPCODE_DONE:        if (TableKind == Kind::Lazy) { @@ -2899,28 +3188,81 @@ 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()) { +        *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad " +             "library ordinal: " + Twine((int)ImmValue) + " (max " + +             Twine((int)O->getLibraryCount()) + ") for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      }        DEBUG_WITH_TYPE(            "mach-o-bind",            llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: "                         << "Ordinal=" << Ordinal << "\n");        break;      case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: -      Ordinal = readULEB128(); +      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) { +        *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB " + +             Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      if (Ordinal > (int)O->getLibraryCount()) { +        *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad " +             "library ordinal: " + Twine((int)Ordinal) + " (max " + +             Twine((int)O->getLibraryCount()) + ") for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      }        DEBUG_WITH_TYPE(            "mach-o-bind",            llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: "                         << "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; +        LibraryOrdinalSet = true; +        if (Ordinal < MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) { +          *E = malformedError("for BIND_OPCODE_SET_DYLIB_SPECIAL_IMM unknown " +               "special ordinal: " + Twine((int)Ordinal) + " for opcode at: " +               "0x" + utohexstr(OpcodeStart - Opcodes.begin())); +          moveToEnd(); +          return; +        }        } else          Ordinal = 0;        DEBUG_WITH_TYPE( @@ -2931,9 +3273,16 @@ void MachOBindEntry::moveNext() {      case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:        Flags = ImmValue;        SymStart = Ptr; -      while (*Ptr) { +      while (*Ptr && (Ptr < Opcodes.end())) {          ++Ptr;        } +      if (Ptr == Opcodes.end()) { +          *E = malformedError("for BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM " +               "symbol name extends past opcodes for opcode at: 0x" + +               utohexstr(OpcodeStart - Opcodes.begin())); +          moveToEnd(); +          return; +      }        SymbolName = StringRef(reinterpret_cast<const char*>(SymStart),                               Ptr-SymStart);        ++Ptr; @@ -2948,15 +3297,27 @@ void MachOBindEntry::moveNext() {        break;      case MachO::BIND_OPCODE_SET_TYPE_IMM:        BindType = ImmValue; +      if (ImmValue > MachO::BIND_TYPE_TEXT_PCREL32) { +          *E = malformedError("for BIND_OPCODE_SET_TYPE_IMM bad bind type: " + +               Twine((int)ImmValue) + " for opcode at: 0x" + +               utohexstr(OpcodeStart - Opcodes.begin())); +          moveToEnd(); +          return; +      }        DEBUG_WITH_TYPE(            "mach-o-bind",            llvm::dbgs() << "BIND_OPCODE_SET_TYPE_IMM: "                         << "BindType=" << (int)BindType << "\n");        break;      case MachO::BIND_OPCODE_SET_ADDEND_SLEB: -      Addend = readSLEB128(); -      if (TableKind == Kind::Lazy) -        Malformed = true; +      Addend = readSLEB128(&error); +      if (error) { +        *E = malformedError("for BIND_OPCODE_SET_ADDEND_SLEB " + +             Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      }        DEBUG_WITH_TYPE(            "mach-o-bind",            llvm::dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: " @@ -2964,7 +3325,22 @@ void MachOBindEntry::moveNext() {        break;      case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:        SegmentIndex = ImmValue; -      SegmentOffset = readULEB128(); +      SegmentOffset = readULEB128(&error); +      if (error) { +        *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + +             Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); +      if (error) { +        *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + +             Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      }        DEBUG_WITH_TYPE(            "mach-o-bind",            llvm::dbgs() << "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: " @@ -2973,7 +3349,22 @@ void MachOBindEntry::moveNext() {                         << "\n");        break;      case MachO::BIND_OPCODE_ADD_ADDR_ULEB: -      SegmentOffset += readULEB128(); +      SegmentOffset += readULEB128(&error); +      if (error) { +        *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + +             Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); +      if (error) { +        *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + +             Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      }        DEBUG_WITH_TYPE("mach-o-bind",                        llvm::dbgs() << "BIND_OPCODE_ADD_ADDR_ULEB: "                                     << format("SegmentOffset=0x%06X", @@ -2982,16 +3373,83 @@ void MachOBindEntry::moveNext() {      case MachO::BIND_OPCODE_DO_BIND:        AdvanceAmount = PointerSize;        RemainingLoopCount = 0; +      error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); +      if (error) { +        *E = malformedError("for BIND_OPCODE_DO_BIND " + Twine(error) + +             " for opcode at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      if (SymbolName == StringRef()) { +        *E = malformedError("for BIND_OPCODE_DO_BIND missing preceding " +             "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      if (!LibraryOrdinalSet && TableKind != Kind::Weak) { +        *E = malformedError("for BIND_OPCODE_DO_BIND missing preceding " +             "BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      }        DEBUG_WITH_TYPE("mach-o-bind",                        llvm::dbgs() << "BIND_OPCODE_DO_BIND: "                                     << format("SegmentOffset=0x%06X",                                               SegmentOffset) << "\n");        return;       case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: -      AdvanceAmount = readULEB128() + PointerSize; +      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 " + +             Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      if (SymbolName == StringRef()) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing " +             "preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode " +             "at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      if (!LibraryOrdinalSet && TableKind != Kind::Weak) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing " +             "preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      AdvanceAmount = readULEB128(&error) + PointerSize; +      if (error) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " + +             Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      // Note, this is not really an error until the next bind but make no sense +      // for a BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB to not be followed by another +      // bind operation. +      error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset + +                                            AdvanceAmount, false); +      if (error) { +        *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB (after adding " +             "ULEB) " + Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      }        RemainingLoopCount = 0; -      if (TableKind == Kind::Lazy) -        Malformed = true;        DEBUG_WITH_TYPE(            "mach-o-bind",            llvm::dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: " @@ -3001,10 +3459,47 @@ 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 " + +             Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      if (SymbolName == StringRef()) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " +             "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for " +             "opcode at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      if (!LibraryOrdinalSet && TableKind != Kind::Weak) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " +             "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode " +             "at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      }        AdvanceAmount = ImmValue * PointerSize + PointerSize;        RemainingLoopCount = 0; -      if (TableKind == Kind::Lazy) -        Malformed = true; +      error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset + +                                            AdvanceAmount, false); +      if (error) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_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-bind",                        llvm::dbgs()                        << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: " @@ -3012,10 +3507,65 @@ void MachOBindEntry::moveNext() {                                               SegmentOffset) << "\n");        return;      case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: -      RemainingLoopCount = readULEB128() - 1; -      AdvanceAmount = readULEB128() + PointerSize; -      if (TableKind == Kind::Lazy) -        Malformed = true; +      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; +      else +        RemainingLoopCount = 0; +      if (error) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " +                            " (count value) " + Twine(error) + " for opcode at" +                            ": 0x" + utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      Skip = readULEB128(&error); +      AdvanceAmount = Skip + PointerSize; +      if (error) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " +                            " (skip value) " + Twine(error) + " 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_ULEB_TIMES_SKIPPING_ULEB " +             + Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      if (SymbolName == StringRef()) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " +             "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for " +             "opcode at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      if (!LibraryOrdinalSet && TableKind != Kind::Weak) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " +             "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode " +             "at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +        return; +      } +      error = O->BindEntryCheckCountAndSkip(Count, Skip, PointerSize, +                                            SegmentIndex, SegmentOffset); +      if (error) { +        *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " +             + Twine(error) + " for opcode at: 0x" + +             utohexstr(OpcodeStart - Opcodes.begin())); +        moveToEnd(); +	return; +      }        DEBUG_WITH_TYPE(            "mach-o-bind",            llvm::dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: " @@ -3025,34 +3575,34 @@ 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())); +      moveToEnd(); +      return;      }    }  } -uint64_t MachOBindEntry::readULEB128() { +uint64_t MachOBindEntry::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;  } -int64_t MachOBindEntry::readSLEB128() { +int64_t MachOBindEntry::readSLEB128(const char **error) {    unsigned Count; -  int64_t Result = decodeSLEB128(Ptr, &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;  } -uint32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; } +int32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; }  uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; } @@ -3076,6 +3626,24 @@ uint32_t MachOBindEntry::flags() const { return Flags; }  int MachOBindEntry::ordinal() const { return Ordinal; } +// For use with the SegIndex of a checked Mach-O Bind entry +// to get the segment name. +StringRef MachOBindEntry::segmentName() const { +  return O->BindRebaseSegmentName(SegmentIndex); +} + +// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry +// to get the section name. +StringRef MachOBindEntry::sectionName() const { +  return O->BindRebaseSectionName(SegmentIndex, SegmentOffset); +} + +// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry +// to get the address. +uint64_t MachOBindEntry::address() const { +  return O->BindRebaseAddress(SegmentIndex, SegmentOffset); +} +  bool MachOBindEntry::operator==(const MachOBindEntry &Other) const {  #ifdef EXPENSIVE_CHECKS    assert(Opcodes == Other.Opcodes && "compare iterators of different files"); @@ -3087,30 +3655,149 @@ bool MachOBindEntry::operator==(const MachOBindEntry &Other) const {           (Done == Other.Done);  } +// Build table of sections so SegIndex/SegOffset pairs can be translated. +BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) { +  uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0; +  StringRef CurSegName; +  uint64_t CurSegAddress; +  for (const SectionRef &Section : Obj->sections()) { +    SectionInfo Info; +    Section.getName(Info.SectionName); +    Info.Address = Section.getAddress(); +    Info.Size = Section.getSize(); +    Info.SegmentName = +        Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl()); +    if (!Info.SegmentName.equals(CurSegName)) { +      ++CurSegIndex; +      CurSegName = Info.SegmentName; +      CurSegAddress = Info.Address; +    } +    Info.SegmentIndex = CurSegIndex - 1; +    Info.OffsetInSegment = Info.Address - CurSegAddress; +    Info.SegmentStartAddress = CurSegAddress; +    Sections.push_back(Info); +  } +  MaxSegIndex = CurSegIndex; +} + +// For use with a SegIndex,SegOffset pair in MachOBindEntry::moveNext() to +// validate a MachOBindEntry or MachORebaseEntry. +const char * BindRebaseSegInfo::checkSegAndOffset(int32_t SegIndex, +                                                  uint64_t SegOffset, +                                                  bool endInvalid) { +  if (SegIndex == -1) +    return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"; +  if (SegIndex >= MaxSegIndex) +    return "bad segIndex (too large)"; +  for (const SectionInfo &SI : Sections) { +    if (SI.SegmentIndex != SegIndex) +      continue; +    if (SI.OffsetInSegment > SegOffset) +      continue; +    if (SegOffset > (SI.OffsetInSegment + SI.Size)) +      continue; +    if (endInvalid && SegOffset >= (SI.OffsetInSegment + SI.Size)) +      continue; +    return nullptr; +  } +  return "bad segOffset, too large"; +} + +// For use in MachOBindEntry::moveNext() to validate a MachOBindEntry for +// 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) { +  const SectionInfo &SI = findSection(SegIndex, SegOffset); +  uint64_t addr = SI.SegmentStartAddress + SegOffset; +  if (addr >= SI.Address + SI.Size) +    return "bad segOffset, too large"; +  uint64_t i = 0; +  if (Count > 1) +    i = (Skip + PointerSize) * (Count - 1); +  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; +} + +// For use with the SegIndex of a checked Mach-O Bind or Rebase entry +// to get the segment name. +StringRef BindRebaseSegInfo::segmentName(int32_t SegIndex) { +  for (const SectionInfo &SI : Sections) { +    if (SI.SegmentIndex == SegIndex) +      return SI.SegmentName; +  } +  llvm_unreachable("invalid SegIndex"); +} + +// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase +// to get the SectionInfo. +const BindRebaseSegInfo::SectionInfo &BindRebaseSegInfo::findSection( +                                     int32_t SegIndex, uint64_t SegOffset) { +  for (const SectionInfo &SI : Sections) { +    if (SI.SegmentIndex != SegIndex) +      continue; +    if (SI.OffsetInSegment > SegOffset) +      continue; +    if (SegOffset >= (SI.OffsetInSegment + SI.Size)) +      continue; +    return SI; +  } +  llvm_unreachable("SegIndex and SegOffset not in any section"); +} + +// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase +// entry to get the section name. +StringRef BindRebaseSegInfo::sectionName(int32_t SegIndex, +                                         uint64_t SegOffset) { +  return findSection(SegIndex, SegOffset).SectionName; +} + +// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase +// entry to get the address. +uint64_t BindRebaseSegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) { +  const SectionInfo &SI = findSection(SegIndex, OffsetInSeg); +  return SI.SegmentStartAddress + OffsetInSeg; +} +  iterator_range<bind_iterator> -MachOObjectFile::bindTable(ArrayRef<uint8_t> Opcodes, bool is64, +MachOObjectFile::bindTable(Error &Err, MachOObjectFile *O, +                           ArrayRef<uint8_t> Opcodes, bool is64,                             MachOBindEntry::Kind BKind) { -  MachOBindEntry Start(Opcodes, is64, BKind); +  if (O->BindRebaseSectionTable == nullptr) +    O->BindRebaseSectionTable = llvm::make_unique<BindRebaseSegInfo>(O); +  MachOBindEntry Start(&Err, O, Opcodes, is64, BKind);    Start.moveToFirst(); -  MachOBindEntry Finish(Opcodes, is64, BKind); +  MachOBindEntry Finish(&Err, O, Opcodes, is64, BKind);    Finish.moveToEnd();    return make_range(bind_iterator(Start), bind_iterator(Finish));  } -iterator_range<bind_iterator> MachOObjectFile::bindTable() const { -  return bindTable(getDyldInfoBindOpcodes(), is64Bit(), +iterator_range<bind_iterator> MachOObjectFile::bindTable(Error &Err) { +  return bindTable(Err, this, getDyldInfoBindOpcodes(), is64Bit(),                     MachOBindEntry::Kind::Regular);  } -iterator_range<bind_iterator> MachOObjectFile::lazyBindTable() const { -  return bindTable(getDyldInfoLazyBindOpcodes(), is64Bit(), +iterator_range<bind_iterator> MachOObjectFile::lazyBindTable(Error &Err) { +  return bindTable(Err, this, getDyldInfoLazyBindOpcodes(), is64Bit(),                     MachOBindEntry::Kind::Lazy);  } -iterator_range<bind_iterator> MachOObjectFile::weakBindTable() const { -  return bindTable(getDyldInfoWeakBindOpcodes(), is64Bit(), +iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) { +  return bindTable(Err, this, getDyldInfoWeakBindOpcodes(), is64Bit(),                     MachOBindEntry::Kind::Weak);  } @@ -3289,6 +3976,21 @@ MachOObjectFile::getVersionMinLoadCommand(const LoadCommandInfo &L) const {    return getStruct<MachO::version_min_command>(*this, L.Ptr);  } +MachO::note_command +MachOObjectFile::getNoteLoadCommand(const LoadCommandInfo &L) const { +  return getStruct<MachO::note_command>(*this, L.Ptr); +} + +MachO::build_version_command +MachOObjectFile::getBuildVersionLoadCommand(const LoadCommandInfo &L) const { +  return getStruct<MachO::build_version_command>(*this, L.Ptr); +} + +MachO::build_tool_version +MachOObjectFile::getBuildToolVersion(unsigned index) const { +  return getStruct<MachO::build_tool_version>(*this, BuildTools[index]); +} +  MachO::dylib_command  MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const {    return getStruct<MachO::dylib_command>(*this, L.Ptr);  | 
