10b57cec5SDimitry Andric //===- MachOObjectFile.cpp - Mach-O object file binding -------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the MachOObjectFile class, which binds the MachOObject
100b57cec5SDimitry Andric // class to the generic ObjectFile wrapper.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
150b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
160b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
170b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
180b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
190b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
20bdd1243dSDimitry Andric #include "llvm/ADT/bit.h"
210b57cec5SDimitry Andric #include "llvm/BinaryFormat/MachO.h"
221fd87a68SDimitry Andric #include "llvm/BinaryFormat/Swift.h"
230b57cec5SDimitry Andric #include "llvm/Object/Error.h"
240b57cec5SDimitry Andric #include "llvm/Object/MachO.h"
250b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
260b57cec5SDimitry Andric #include "llvm/Object/SymbolicFile.h"
270b57cec5SDimitry Andric #include "llvm/Support/DataExtractor.h"
280b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
290eae32dcSDimitry Andric #include "llvm/Support/Errc.h"
300b57cec5SDimitry Andric #include "llvm/Support/Error.h"
310b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
320eae32dcSDimitry Andric #include "llvm/Support/FileSystem.h"
330b57cec5SDimitry Andric #include "llvm/Support/Format.h"
340b57cec5SDimitry Andric #include "llvm/Support/LEB128.h"
3581ad6265SDimitry Andric #include "llvm/Support/MemoryBufferRef.h"
360eae32dcSDimitry Andric #include "llvm/Support/Path.h"
370b57cec5SDimitry Andric #include "llvm/Support/SwapByteOrder.h"
380b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
39fe013be4SDimitry Andric #include "llvm/TargetParser/Host.h"
40fe013be4SDimitry Andric #include "llvm/TargetParser/Triple.h"
410b57cec5SDimitry Andric #include <algorithm>
420b57cec5SDimitry Andric #include <cassert>
430b57cec5SDimitry Andric #include <cstddef>
440b57cec5SDimitry Andric #include <cstdint>
450b57cec5SDimitry Andric #include <cstring>
460b57cec5SDimitry Andric #include <limits>
470b57cec5SDimitry Andric #include <list>
480b57cec5SDimitry Andric #include <memory>
490b57cec5SDimitry Andric #include <system_error>
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric using namespace llvm;
520b57cec5SDimitry Andric using namespace object;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric namespace {
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   struct section_base {
570b57cec5SDimitry Andric     char sectname[16];
580b57cec5SDimitry Andric     char segname[16];
590b57cec5SDimitry Andric   };
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric } // end anonymous namespace
620b57cec5SDimitry Andric 
malformedError(const Twine & Msg)630b57cec5SDimitry Andric static Error malformedError(const Twine &Msg) {
640b57cec5SDimitry Andric   return make_error<GenericBinaryError>("truncated or malformed object (" +
650b57cec5SDimitry Andric                                             Msg + ")",
660b57cec5SDimitry Andric                                         object_error::parse_failed);
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric // FIXME: Replace all uses of this function with getStructOrErr.
700b57cec5SDimitry Andric template <typename T>
getStruct(const MachOObjectFile & O,const char * P)710b57cec5SDimitry Andric static T getStruct(const MachOObjectFile &O, const char *P) {
720b57cec5SDimitry Andric   // Don't read before the beginning or past the end of the file
730b57cec5SDimitry Andric   if (P < O.getData().begin() || P + sizeof(T) > O.getData().end())
740b57cec5SDimitry Andric     report_fatal_error("Malformed MachO file.");
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   T Cmd;
770b57cec5SDimitry Andric   memcpy(&Cmd, P, sizeof(T));
780b57cec5SDimitry Andric   if (O.isLittleEndian() != sys::IsLittleEndianHost)
790b57cec5SDimitry Andric     MachO::swapStruct(Cmd);
800b57cec5SDimitry Andric   return Cmd;
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric template <typename T>
getStructOrErr(const MachOObjectFile & O,const char * P)840b57cec5SDimitry Andric static Expected<T> getStructOrErr(const MachOObjectFile &O, const char *P) {
850b57cec5SDimitry Andric   // Don't read before the beginning or past the end of the file
860b57cec5SDimitry Andric   if (P < O.getData().begin() || P + sizeof(T) > O.getData().end())
870b57cec5SDimitry Andric     return malformedError("Structure read out-of-range");
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   T Cmd;
900b57cec5SDimitry Andric   memcpy(&Cmd, P, sizeof(T));
910b57cec5SDimitry Andric   if (O.isLittleEndian() != sys::IsLittleEndianHost)
920b57cec5SDimitry Andric     MachO::swapStruct(Cmd);
930b57cec5SDimitry Andric   return Cmd;
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric static const char *
getSectionPtr(const MachOObjectFile & O,MachOObjectFile::LoadCommandInfo L,unsigned Sec)970b57cec5SDimitry Andric getSectionPtr(const MachOObjectFile &O, MachOObjectFile::LoadCommandInfo L,
980b57cec5SDimitry Andric               unsigned Sec) {
990b57cec5SDimitry Andric   uintptr_t CommandAddr = reinterpret_cast<uintptr_t>(L.Ptr);
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   bool Is64 = O.is64Bit();
1020b57cec5SDimitry Andric   unsigned SegmentLoadSize = Is64 ? sizeof(MachO::segment_command_64) :
1030b57cec5SDimitry Andric                                     sizeof(MachO::segment_command);
1040b57cec5SDimitry Andric   unsigned SectionSize = Is64 ? sizeof(MachO::section_64) :
1050b57cec5SDimitry Andric                                 sizeof(MachO::section);
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + Sec * SectionSize;
1080b57cec5SDimitry Andric   return reinterpret_cast<const char*>(SectionAddr);
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
getPtr(const MachOObjectFile & O,size_t Offset,size_t MachOFilesetEntryOffset=0)111*c9157d92SDimitry Andric static const char *getPtr(const MachOObjectFile &O, size_t Offset,
112*c9157d92SDimitry Andric                           size_t MachOFilesetEntryOffset = 0) {
113*c9157d92SDimitry Andric   assert(Offset <= O.getData().size() &&
114*c9157d92SDimitry Andric          MachOFilesetEntryOffset <= O.getData().size());
115*c9157d92SDimitry Andric   return O.getData().data() + Offset + MachOFilesetEntryOffset;
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric static MachO::nlist_base
getSymbolTableEntryBase(const MachOObjectFile & O,DataRefImpl DRI)1190b57cec5SDimitry Andric getSymbolTableEntryBase(const MachOObjectFile &O, DataRefImpl DRI) {
1200b57cec5SDimitry Andric   const char *P = reinterpret_cast<const char *>(DRI.p);
1210b57cec5SDimitry Andric   return getStruct<MachO::nlist_base>(O, P);
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric 
parseSegmentOrSectionName(const char * P)1240b57cec5SDimitry Andric static StringRef parseSegmentOrSectionName(const char *P) {
1250b57cec5SDimitry Andric   if (P[15] == 0)
1260b57cec5SDimitry Andric     // Null terminated.
1270b57cec5SDimitry Andric     return P;
1280b57cec5SDimitry Andric   // Not null terminated, so this is a 16 char string.
1290b57cec5SDimitry Andric   return StringRef(P, 16);
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric 
getCPUType(const MachOObjectFile & O)1320b57cec5SDimitry Andric static unsigned getCPUType(const MachOObjectFile &O) {
1330b57cec5SDimitry Andric   return O.getHeader().cputype;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
getCPUSubType(const MachOObjectFile & O)136480093f4SDimitry Andric static unsigned getCPUSubType(const MachOObjectFile &O) {
137480093f4SDimitry Andric   return O.getHeader().cpusubtype;
138480093f4SDimitry Andric }
139480093f4SDimitry Andric 
1400b57cec5SDimitry Andric static uint32_t
getPlainRelocationAddress(const MachO::any_relocation_info & RE)1410b57cec5SDimitry Andric getPlainRelocationAddress(const MachO::any_relocation_info &RE) {
1420b57cec5SDimitry Andric   return RE.r_word0;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric static unsigned
getScatteredRelocationAddress(const MachO::any_relocation_info & RE)1460b57cec5SDimitry Andric getScatteredRelocationAddress(const MachO::any_relocation_info &RE) {
1470b57cec5SDimitry Andric   return RE.r_word0 & 0xffffff;
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
getPlainRelocationPCRel(const MachOObjectFile & O,const MachO::any_relocation_info & RE)1500b57cec5SDimitry Andric static bool getPlainRelocationPCRel(const MachOObjectFile &O,
1510b57cec5SDimitry Andric                                     const MachO::any_relocation_info &RE) {
1520b57cec5SDimitry Andric   if (O.isLittleEndian())
1530b57cec5SDimitry Andric     return (RE.r_word1 >> 24) & 1;
1540b57cec5SDimitry Andric   return (RE.r_word1 >> 7) & 1;
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric static bool
getScatteredRelocationPCRel(const MachO::any_relocation_info & RE)1580b57cec5SDimitry Andric getScatteredRelocationPCRel(const MachO::any_relocation_info &RE) {
1590b57cec5SDimitry Andric   return (RE.r_word0 >> 30) & 1;
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
getPlainRelocationLength(const MachOObjectFile & O,const MachO::any_relocation_info & RE)1620b57cec5SDimitry Andric static unsigned getPlainRelocationLength(const MachOObjectFile &O,
1630b57cec5SDimitry Andric                                          const MachO::any_relocation_info &RE) {
1640b57cec5SDimitry Andric   if (O.isLittleEndian())
1650b57cec5SDimitry Andric     return (RE.r_word1 >> 25) & 3;
1660b57cec5SDimitry Andric   return (RE.r_word1 >> 5) & 3;
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric static unsigned
getScatteredRelocationLength(const MachO::any_relocation_info & RE)1700b57cec5SDimitry Andric getScatteredRelocationLength(const MachO::any_relocation_info &RE) {
1710b57cec5SDimitry Andric   return (RE.r_word0 >> 28) & 3;
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric 
getPlainRelocationType(const MachOObjectFile & O,const MachO::any_relocation_info & RE)1740b57cec5SDimitry Andric static unsigned getPlainRelocationType(const MachOObjectFile &O,
1750b57cec5SDimitry Andric                                        const MachO::any_relocation_info &RE) {
1760b57cec5SDimitry Andric   if (O.isLittleEndian())
1770b57cec5SDimitry Andric     return RE.r_word1 >> 28;
1780b57cec5SDimitry Andric   return RE.r_word1 & 0xf;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
getSectionFlags(const MachOObjectFile & O,DataRefImpl Sec)1810b57cec5SDimitry Andric static uint32_t getSectionFlags(const MachOObjectFile &O,
1820b57cec5SDimitry Andric                                 DataRefImpl Sec) {
1830b57cec5SDimitry Andric   if (O.is64Bit()) {
1840b57cec5SDimitry Andric     MachO::section_64 Sect = O.getSection64(Sec);
1850b57cec5SDimitry Andric     return Sect.flags;
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric   MachO::section Sect = O.getSection(Sec);
1880b57cec5SDimitry Andric   return Sect.flags;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric static Expected<MachOObjectFile::LoadCommandInfo>
getLoadCommandInfo(const MachOObjectFile & Obj,const char * Ptr,uint32_t LoadCommandIndex)1920b57cec5SDimitry Andric getLoadCommandInfo(const MachOObjectFile &Obj, const char *Ptr,
1930b57cec5SDimitry Andric                    uint32_t LoadCommandIndex) {
1940b57cec5SDimitry Andric   if (auto CmdOrErr = getStructOrErr<MachO::load_command>(Obj, Ptr)) {
1950b57cec5SDimitry Andric     if (CmdOrErr->cmdsize + Ptr > Obj.getData().end())
1960b57cec5SDimitry Andric       return malformedError("load command " + Twine(LoadCommandIndex) +
1970b57cec5SDimitry Andric                             " extends past end of file");
1980b57cec5SDimitry Andric     if (CmdOrErr->cmdsize < 8)
1990b57cec5SDimitry Andric       return malformedError("load command " + Twine(LoadCommandIndex) +
2000b57cec5SDimitry Andric                             " with size less than 8 bytes");
2010b57cec5SDimitry Andric     return MachOObjectFile::LoadCommandInfo({Ptr, *CmdOrErr});
2020b57cec5SDimitry Andric   } else
2030b57cec5SDimitry Andric     return CmdOrErr.takeError();
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric static Expected<MachOObjectFile::LoadCommandInfo>
getFirstLoadCommandInfo(const MachOObjectFile & Obj)2070b57cec5SDimitry Andric getFirstLoadCommandInfo(const MachOObjectFile &Obj) {
2080b57cec5SDimitry Andric   unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64)
2090b57cec5SDimitry Andric                                       : sizeof(MachO::mach_header);
2100b57cec5SDimitry Andric   if (sizeof(MachO::load_command) > Obj.getHeader().sizeofcmds)
2110b57cec5SDimitry Andric     return malformedError("load command 0 extends past the end all load "
2120b57cec5SDimitry Andric                           "commands in the file");
213*c9157d92SDimitry Andric   return getLoadCommandInfo(
214*c9157d92SDimitry Andric       Obj, getPtr(Obj, HeaderSize, Obj.getMachOFilesetEntryOffset()), 0);
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric static Expected<MachOObjectFile::LoadCommandInfo>
getNextLoadCommandInfo(const MachOObjectFile & Obj,uint32_t LoadCommandIndex,const MachOObjectFile::LoadCommandInfo & L)2180b57cec5SDimitry Andric getNextLoadCommandInfo(const MachOObjectFile &Obj, uint32_t LoadCommandIndex,
2190b57cec5SDimitry Andric                        const MachOObjectFile::LoadCommandInfo &L) {
2200b57cec5SDimitry Andric   unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64)
2210b57cec5SDimitry Andric                                       : sizeof(MachO::mach_header);
2220b57cec5SDimitry Andric   if (L.Ptr + L.C.cmdsize + sizeof(MachO::load_command) >
223*c9157d92SDimitry Andric       Obj.getData().data() + Obj.getMachOFilesetEntryOffset() + HeaderSize +
224*c9157d92SDimitry Andric           Obj.getHeader().sizeofcmds)
2250b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex + 1) +
2260b57cec5SDimitry Andric                           " extends past the end all load commands in the file");
2270b57cec5SDimitry Andric   return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize, LoadCommandIndex + 1);
2280b57cec5SDimitry Andric }
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric template <typename T>
parseHeader(const MachOObjectFile & Obj,T & Header,Error & Err)2310b57cec5SDimitry Andric static void parseHeader(const MachOObjectFile &Obj, T &Header,
2320b57cec5SDimitry Andric                         Error &Err) {
2330b57cec5SDimitry Andric   if (sizeof(T) > Obj.getData().size()) {
2340b57cec5SDimitry Andric     Err = malformedError("the mach header extends past the end of the "
2350b57cec5SDimitry Andric                          "file");
2360b57cec5SDimitry Andric     return;
2370b57cec5SDimitry Andric   }
238*c9157d92SDimitry Andric   if (auto HeaderOrErr = getStructOrErr<T>(
239*c9157d92SDimitry Andric           Obj, getPtr(Obj, 0, Obj.getMachOFilesetEntryOffset())))
2400b57cec5SDimitry Andric     Header = *HeaderOrErr;
2410b57cec5SDimitry Andric   else
2420b57cec5SDimitry Andric     Err = HeaderOrErr.takeError();
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric // This is used to check for overlapping of Mach-O elements.
2460b57cec5SDimitry Andric struct MachOElement {
2470b57cec5SDimitry Andric   uint64_t Offset;
2480b57cec5SDimitry Andric   uint64_t Size;
2490b57cec5SDimitry Andric   const char *Name;
2500b57cec5SDimitry Andric };
2510b57cec5SDimitry Andric 
checkOverlappingElement(std::list<MachOElement> & Elements,uint64_t Offset,uint64_t Size,const char * Name)2520b57cec5SDimitry Andric static Error checkOverlappingElement(std::list<MachOElement> &Elements,
2530b57cec5SDimitry Andric                                      uint64_t Offset, uint64_t Size,
2540b57cec5SDimitry Andric                                      const char *Name) {
2550b57cec5SDimitry Andric   if (Size == 0)
2560b57cec5SDimitry Andric     return Error::success();
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   for (auto it = Elements.begin(); it != Elements.end(); ++it) {
259349cc55cSDimitry Andric     const auto &E = *it;
2600b57cec5SDimitry Andric     if ((Offset >= E.Offset && Offset < E.Offset + E.Size) ||
2610b57cec5SDimitry Andric         (Offset + Size > E.Offset && Offset + Size < E.Offset + E.Size) ||
2620b57cec5SDimitry Andric         (Offset <= E.Offset && Offset + Size >= E.Offset + E.Size))
2630b57cec5SDimitry Andric       return malformedError(Twine(Name) + " at offset " + Twine(Offset) +
2640b57cec5SDimitry Andric                             " with a size of " + Twine(Size) + ", overlaps " +
2650b57cec5SDimitry Andric                             E.Name + " at offset " + Twine(E.Offset) + " with "
2660b57cec5SDimitry Andric                             "a size of " + Twine(E.Size));
2670b57cec5SDimitry Andric     auto nt = it;
2680b57cec5SDimitry Andric     nt++;
2690b57cec5SDimitry Andric     if (nt != Elements.end()) {
270349cc55cSDimitry Andric       const auto &N = *nt;
2710b57cec5SDimitry Andric       if (Offset + Size <= N.Offset) {
2720b57cec5SDimitry Andric         Elements.insert(nt, {Offset, Size, Name});
2730b57cec5SDimitry Andric         return Error::success();
2740b57cec5SDimitry Andric       }
2750b57cec5SDimitry Andric     }
2760b57cec5SDimitry Andric   }
2770b57cec5SDimitry Andric   Elements.push_back({Offset, Size, Name});
2780b57cec5SDimitry Andric   return Error::success();
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric // Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all
2820b57cec5SDimitry Andric // sections to \param Sections, and optionally sets
2830b57cec5SDimitry Andric // \param IsPageZeroSegment to true.
2840b57cec5SDimitry Andric template <typename Segment, typename Section>
parseSegmentLoadCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,SmallVectorImpl<const char * > & Sections,bool & IsPageZeroSegment,uint32_t LoadCommandIndex,const char * CmdName,uint64_t SizeOfHeaders,std::list<MachOElement> & Elements)2850b57cec5SDimitry Andric static Error parseSegmentLoadCommand(
2860b57cec5SDimitry Andric     const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &Load,
2870b57cec5SDimitry Andric     SmallVectorImpl<const char *> &Sections, bool &IsPageZeroSegment,
2880b57cec5SDimitry Andric     uint32_t LoadCommandIndex, const char *CmdName, uint64_t SizeOfHeaders,
2890b57cec5SDimitry Andric     std::list<MachOElement> &Elements) {
2900b57cec5SDimitry Andric   const unsigned SegmentLoadSize = sizeof(Segment);
2910b57cec5SDimitry Andric   if (Load.C.cmdsize < SegmentLoadSize)
2920b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
2930b57cec5SDimitry Andric                           " " + CmdName + " cmdsize too small");
2940b57cec5SDimitry Andric   if (auto SegOrErr = getStructOrErr<Segment>(Obj, Load.Ptr)) {
2950b57cec5SDimitry Andric     Segment S = SegOrErr.get();
2960b57cec5SDimitry Andric     const unsigned SectionSize = sizeof(Section);
2970b57cec5SDimitry Andric     uint64_t FileSize = Obj.getData().size();
2980b57cec5SDimitry Andric     if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||
2990b57cec5SDimitry Andric         S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize)
3000b57cec5SDimitry Andric       return malformedError("load command " + Twine(LoadCommandIndex) +
3010b57cec5SDimitry Andric                             " inconsistent cmdsize in " + CmdName +
3020b57cec5SDimitry Andric                             " for the number of sections");
3030b57cec5SDimitry Andric     for (unsigned J = 0; J < S.nsects; ++J) {
3040b57cec5SDimitry Andric       const char *Sec = getSectionPtr(Obj, Load, J);
3050b57cec5SDimitry Andric       Sections.push_back(Sec);
3060b57cec5SDimitry Andric       auto SectionOrErr = getStructOrErr<Section>(Obj, Sec);
3070b57cec5SDimitry Andric       if (!SectionOrErr)
3080b57cec5SDimitry Andric         return SectionOrErr.takeError();
3090b57cec5SDimitry Andric       Section s = SectionOrErr.get();
3100b57cec5SDimitry Andric       if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
3110b57cec5SDimitry Andric           Obj.getHeader().filetype != MachO::MH_DSYM &&
3120b57cec5SDimitry Andric           s.flags != MachO::S_ZEROFILL &&
3130b57cec5SDimitry Andric           s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
3140b57cec5SDimitry Andric           s.offset > FileSize)
3150b57cec5SDimitry Andric         return malformedError("offset field of section " + Twine(J) + " in " +
3160b57cec5SDimitry Andric                               CmdName + " command " + Twine(LoadCommandIndex) +
3170b57cec5SDimitry Andric                               " extends past the end of the file");
3180b57cec5SDimitry Andric       if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
3190b57cec5SDimitry Andric           Obj.getHeader().filetype != MachO::MH_DSYM &&
3200b57cec5SDimitry Andric           s.flags != MachO::S_ZEROFILL &&
3210b57cec5SDimitry Andric           s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && S.fileoff == 0 &&
3220b57cec5SDimitry Andric           s.offset < SizeOfHeaders && s.size != 0)
3230b57cec5SDimitry Andric         return malformedError("offset field of section " + Twine(J) + " in " +
3240b57cec5SDimitry Andric                               CmdName + " command " + Twine(LoadCommandIndex) +
3250b57cec5SDimitry Andric                               " not past the headers of the file");
3260b57cec5SDimitry Andric       uint64_t BigSize = s.offset;
3270b57cec5SDimitry Andric       BigSize += s.size;
3280b57cec5SDimitry Andric       if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
3290b57cec5SDimitry Andric           Obj.getHeader().filetype != MachO::MH_DSYM &&
3300b57cec5SDimitry Andric           s.flags != MachO::S_ZEROFILL &&
3310b57cec5SDimitry Andric           s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
3320b57cec5SDimitry Andric           BigSize > FileSize)
3330b57cec5SDimitry Andric         return malformedError("offset field plus size field of section " +
3340b57cec5SDimitry Andric                               Twine(J) + " in " + CmdName + " command " +
3350b57cec5SDimitry Andric                               Twine(LoadCommandIndex) +
3360b57cec5SDimitry Andric                               " extends past the end of the file");
3370b57cec5SDimitry Andric       if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
3380b57cec5SDimitry Andric           Obj.getHeader().filetype != MachO::MH_DSYM &&
3390b57cec5SDimitry Andric           s.flags != MachO::S_ZEROFILL &&
3400b57cec5SDimitry Andric           s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
3410b57cec5SDimitry Andric           s.size > S.filesize)
3420b57cec5SDimitry Andric         return malformedError("size field of section " +
3430b57cec5SDimitry Andric                               Twine(J) + " in " + CmdName + " command " +
3440b57cec5SDimitry Andric                               Twine(LoadCommandIndex) +
3450b57cec5SDimitry Andric                               " greater than the segment");
3460b57cec5SDimitry Andric       if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
3470b57cec5SDimitry Andric           Obj.getHeader().filetype != MachO::MH_DSYM && s.size != 0 &&
3480b57cec5SDimitry Andric           s.addr < S.vmaddr)
3490b57cec5SDimitry Andric         return malformedError("addr field of section " + Twine(J) + " in " +
3500b57cec5SDimitry Andric                               CmdName + " command " + Twine(LoadCommandIndex) +
3510b57cec5SDimitry Andric                               " less than the segment's vmaddr");
3520b57cec5SDimitry Andric       BigSize = s.addr;
3530b57cec5SDimitry Andric       BigSize += s.size;
3540b57cec5SDimitry Andric       uint64_t BigEnd = S.vmaddr;
3550b57cec5SDimitry Andric       BigEnd += S.vmsize;
3560b57cec5SDimitry Andric       if (S.vmsize != 0 && s.size != 0 && BigSize > BigEnd)
3570b57cec5SDimitry Andric         return malformedError("addr field plus size of section " + Twine(J) +
3580b57cec5SDimitry Andric                               " in " + CmdName + " command " +
3590b57cec5SDimitry Andric                               Twine(LoadCommandIndex) +
3600b57cec5SDimitry Andric                               " greater than than "
3610b57cec5SDimitry Andric                               "the segment's vmaddr plus vmsize");
3620b57cec5SDimitry Andric       if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
3630b57cec5SDimitry Andric           Obj.getHeader().filetype != MachO::MH_DSYM &&
3640b57cec5SDimitry Andric           s.flags != MachO::S_ZEROFILL &&
3650b57cec5SDimitry Andric           s.flags != MachO::S_THREAD_LOCAL_ZEROFILL)
3660b57cec5SDimitry Andric         if (Error Err = checkOverlappingElement(Elements, s.offset, s.size,
3670b57cec5SDimitry Andric                                                 "section contents"))
3680b57cec5SDimitry Andric           return Err;
3690b57cec5SDimitry Andric       if (s.reloff > FileSize)
3700b57cec5SDimitry Andric         return malformedError("reloff field of section " + Twine(J) + " in " +
3710b57cec5SDimitry Andric                               CmdName + " command " + Twine(LoadCommandIndex) +
3720b57cec5SDimitry Andric                               " extends past the end of the file");
3730b57cec5SDimitry Andric       BigSize = s.nreloc;
3740b57cec5SDimitry Andric       BigSize *= sizeof(struct MachO::relocation_info);
3750b57cec5SDimitry Andric       BigSize += s.reloff;
3760b57cec5SDimitry Andric       if (BigSize > FileSize)
3770b57cec5SDimitry Andric         return malformedError("reloff field plus nreloc field times sizeof("
3780b57cec5SDimitry Andric                               "struct relocation_info) of section " +
3790b57cec5SDimitry Andric                               Twine(J) + " in " + CmdName + " command " +
3800b57cec5SDimitry Andric                               Twine(LoadCommandIndex) +
3810b57cec5SDimitry Andric                               " extends past the end of the file");
3820b57cec5SDimitry Andric       if (Error Err = checkOverlappingElement(Elements, s.reloff, s.nreloc *
3830b57cec5SDimitry Andric                                               sizeof(struct
3840b57cec5SDimitry Andric                                               MachO::relocation_info),
3850b57cec5SDimitry Andric                                               "section relocation entries"))
3860b57cec5SDimitry Andric         return Err;
3870b57cec5SDimitry Andric     }
3880b57cec5SDimitry Andric     if (S.fileoff > FileSize)
3890b57cec5SDimitry Andric       return malformedError("load command " + Twine(LoadCommandIndex) +
3900b57cec5SDimitry Andric                             " fileoff field in " + CmdName +
3910b57cec5SDimitry Andric                             " extends past the end of the file");
3920b57cec5SDimitry Andric     uint64_t BigSize = S.fileoff;
3930b57cec5SDimitry Andric     BigSize += S.filesize;
3940b57cec5SDimitry Andric     if (BigSize > FileSize)
3950b57cec5SDimitry Andric       return malformedError("load command " + Twine(LoadCommandIndex) +
3960b57cec5SDimitry Andric                             " fileoff field plus filesize field in " +
3970b57cec5SDimitry Andric                             CmdName + " extends past the end of the file");
3980b57cec5SDimitry Andric     if (S.vmsize != 0 && S.filesize > S.vmsize)
3990b57cec5SDimitry Andric       return malformedError("load command " + Twine(LoadCommandIndex) +
4000b57cec5SDimitry Andric                             " filesize field in " + CmdName +
4010b57cec5SDimitry Andric                             " greater than vmsize field");
4020b57cec5SDimitry Andric     IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname);
4030b57cec5SDimitry Andric   } else
4040b57cec5SDimitry Andric     return SegOrErr.takeError();
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   return Error::success();
4070b57cec5SDimitry Andric }
4080b57cec5SDimitry Andric 
checkSymtabCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char ** SymtabLoadCmd,std::list<MachOElement> & Elements)4090b57cec5SDimitry Andric static Error checkSymtabCommand(const MachOObjectFile &Obj,
4100b57cec5SDimitry Andric                                 const MachOObjectFile::LoadCommandInfo &Load,
4110b57cec5SDimitry Andric                                 uint32_t LoadCommandIndex,
4120b57cec5SDimitry Andric                                 const char **SymtabLoadCmd,
4130b57cec5SDimitry Andric                                 std::list<MachOElement> &Elements) {
4140b57cec5SDimitry Andric   if (Load.C.cmdsize < sizeof(MachO::symtab_command))
4150b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
4160b57cec5SDimitry Andric                           " LC_SYMTAB cmdsize too small");
4170b57cec5SDimitry Andric   if (*SymtabLoadCmd != nullptr)
4180b57cec5SDimitry Andric     return malformedError("more than one LC_SYMTAB command");
4190b57cec5SDimitry Andric   auto SymtabOrErr = getStructOrErr<MachO::symtab_command>(Obj, Load.Ptr);
4200b57cec5SDimitry Andric   if (!SymtabOrErr)
4210b57cec5SDimitry Andric     return SymtabOrErr.takeError();
4220b57cec5SDimitry Andric   MachO::symtab_command Symtab = SymtabOrErr.get();
4230b57cec5SDimitry Andric   if (Symtab.cmdsize != sizeof(MachO::symtab_command))
4240b57cec5SDimitry Andric     return malformedError("LC_SYMTAB command " + Twine(LoadCommandIndex) +
4250b57cec5SDimitry Andric                           " has incorrect cmdsize");
4260b57cec5SDimitry Andric   uint64_t FileSize = Obj.getData().size();
4270b57cec5SDimitry Andric   if (Symtab.symoff > FileSize)
4280b57cec5SDimitry Andric     return malformedError("symoff field of LC_SYMTAB command " +
4290b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end "
4300b57cec5SDimitry Andric                           "of the file");
4310b57cec5SDimitry Andric   uint64_t SymtabSize = Symtab.nsyms;
4320b57cec5SDimitry Andric   const char *struct_nlist_name;
4330b57cec5SDimitry Andric   if (Obj.is64Bit()) {
4340b57cec5SDimitry Andric     SymtabSize *= sizeof(MachO::nlist_64);
4350b57cec5SDimitry Andric     struct_nlist_name = "struct nlist_64";
4360b57cec5SDimitry Andric   } else {
4370b57cec5SDimitry Andric     SymtabSize *= sizeof(MachO::nlist);
4380b57cec5SDimitry Andric     struct_nlist_name = "struct nlist";
4390b57cec5SDimitry Andric   }
4400b57cec5SDimitry Andric   uint64_t BigSize = SymtabSize;
4410b57cec5SDimitry Andric   BigSize += Symtab.symoff;
4420b57cec5SDimitry Andric   if (BigSize > FileSize)
4430b57cec5SDimitry Andric     return malformedError("symoff field plus nsyms field times sizeof(" +
4440b57cec5SDimitry Andric                           Twine(struct_nlist_name) + ") of LC_SYMTAB command " +
4450b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end "
4460b57cec5SDimitry Andric                           "of the file");
4470b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Symtab.symoff, SymtabSize,
4480b57cec5SDimitry Andric                                           "symbol table"))
4490b57cec5SDimitry Andric     return Err;
4500b57cec5SDimitry Andric   if (Symtab.stroff > FileSize)
4510b57cec5SDimitry Andric     return malformedError("stroff field of LC_SYMTAB command " +
4520b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end "
4530b57cec5SDimitry Andric                           "of the file");
4540b57cec5SDimitry Andric   BigSize = Symtab.stroff;
4550b57cec5SDimitry Andric   BigSize += Symtab.strsize;
4560b57cec5SDimitry Andric   if (BigSize > FileSize)
4570b57cec5SDimitry Andric     return malformedError("stroff field plus strsize field of LC_SYMTAB "
4580b57cec5SDimitry Andric                           "command " + Twine(LoadCommandIndex) + " extends "
4590b57cec5SDimitry Andric                           "past the end of the file");
4600b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Symtab.stroff,
4610b57cec5SDimitry Andric                                           Symtab.strsize, "string table"))
4620b57cec5SDimitry Andric     return Err;
4630b57cec5SDimitry Andric   *SymtabLoadCmd = Load.Ptr;
4640b57cec5SDimitry Andric   return Error::success();
4650b57cec5SDimitry Andric }
4660b57cec5SDimitry Andric 
checkDysymtabCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char ** DysymtabLoadCmd,std::list<MachOElement> & Elements)4670b57cec5SDimitry Andric static Error checkDysymtabCommand(const MachOObjectFile &Obj,
4680b57cec5SDimitry Andric                                   const MachOObjectFile::LoadCommandInfo &Load,
4690b57cec5SDimitry Andric                                   uint32_t LoadCommandIndex,
4700b57cec5SDimitry Andric                                   const char **DysymtabLoadCmd,
4710b57cec5SDimitry Andric                                   std::list<MachOElement> &Elements) {
4720b57cec5SDimitry Andric   if (Load.C.cmdsize < sizeof(MachO::dysymtab_command))
4730b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
4740b57cec5SDimitry Andric                           " LC_DYSYMTAB cmdsize too small");
4750b57cec5SDimitry Andric   if (*DysymtabLoadCmd != nullptr)
4760b57cec5SDimitry Andric     return malformedError("more than one LC_DYSYMTAB command");
4770b57cec5SDimitry Andric   auto DysymtabOrErr =
4780b57cec5SDimitry Andric     getStructOrErr<MachO::dysymtab_command>(Obj, Load.Ptr);
4790b57cec5SDimitry Andric   if (!DysymtabOrErr)
4800b57cec5SDimitry Andric     return DysymtabOrErr.takeError();
4810b57cec5SDimitry Andric   MachO::dysymtab_command Dysymtab = DysymtabOrErr.get();
4820b57cec5SDimitry Andric   if (Dysymtab.cmdsize != sizeof(MachO::dysymtab_command))
4830b57cec5SDimitry Andric     return malformedError("LC_DYSYMTAB command " + Twine(LoadCommandIndex) +
4840b57cec5SDimitry Andric                           " has incorrect cmdsize");
4850b57cec5SDimitry Andric   uint64_t FileSize = Obj.getData().size();
4860b57cec5SDimitry Andric   if (Dysymtab.tocoff > FileSize)
4870b57cec5SDimitry Andric     return malformedError("tocoff field of LC_DYSYMTAB command " +
4880b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
4890b57cec5SDimitry Andric                           "the file");
4900b57cec5SDimitry Andric   uint64_t BigSize = Dysymtab.ntoc;
4910b57cec5SDimitry Andric   BigSize *= sizeof(MachO::dylib_table_of_contents);
4920b57cec5SDimitry Andric   BigSize += Dysymtab.tocoff;
4930b57cec5SDimitry Andric   if (BigSize > FileSize)
4940b57cec5SDimitry Andric     return malformedError("tocoff field plus ntoc field times sizeof(struct "
4950b57cec5SDimitry Andric                           "dylib_table_of_contents) of LC_DYSYMTAB command " +
4960b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
4970b57cec5SDimitry Andric                           "the file");
4980b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Dysymtab.tocoff,
4990b57cec5SDimitry Andric                                           Dysymtab.ntoc * sizeof(struct
5000b57cec5SDimitry Andric                                           MachO::dylib_table_of_contents),
5010b57cec5SDimitry Andric                                           "table of contents"))
5020b57cec5SDimitry Andric     return Err;
5030b57cec5SDimitry Andric   if (Dysymtab.modtaboff > FileSize)
5040b57cec5SDimitry Andric     return malformedError("modtaboff field of LC_DYSYMTAB command " +
5050b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
5060b57cec5SDimitry Andric                           "the file");
5070b57cec5SDimitry Andric   BigSize = Dysymtab.nmodtab;
5080b57cec5SDimitry Andric   const char *struct_dylib_module_name;
5090b57cec5SDimitry Andric   uint64_t sizeof_modtab;
5100b57cec5SDimitry Andric   if (Obj.is64Bit()) {
5110b57cec5SDimitry Andric     sizeof_modtab = sizeof(MachO::dylib_module_64);
5120b57cec5SDimitry Andric     struct_dylib_module_name = "struct dylib_module_64";
5130b57cec5SDimitry Andric   } else {
5140b57cec5SDimitry Andric     sizeof_modtab = sizeof(MachO::dylib_module);
5150b57cec5SDimitry Andric     struct_dylib_module_name = "struct dylib_module";
5160b57cec5SDimitry Andric   }
5170b57cec5SDimitry Andric   BigSize *= sizeof_modtab;
5180b57cec5SDimitry Andric   BigSize += Dysymtab.modtaboff;
5190b57cec5SDimitry Andric   if (BigSize > FileSize)
5200b57cec5SDimitry Andric     return malformedError("modtaboff field plus nmodtab field times sizeof(" +
5210b57cec5SDimitry Andric                           Twine(struct_dylib_module_name) + ") of LC_DYSYMTAB "
5220b57cec5SDimitry Andric                           "command " + Twine(LoadCommandIndex) + " extends "
5230b57cec5SDimitry Andric                           "past the end of the file");
5240b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Dysymtab.modtaboff,
5250b57cec5SDimitry Andric                                           Dysymtab.nmodtab * sizeof_modtab,
5260b57cec5SDimitry Andric                                           "module table"))
5270b57cec5SDimitry Andric     return Err;
5280b57cec5SDimitry Andric   if (Dysymtab.extrefsymoff > FileSize)
5290b57cec5SDimitry Andric     return malformedError("extrefsymoff field of LC_DYSYMTAB command " +
5300b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
5310b57cec5SDimitry Andric                           "the file");
5320b57cec5SDimitry Andric   BigSize = Dysymtab.nextrefsyms;
5330b57cec5SDimitry Andric   BigSize *= sizeof(MachO::dylib_reference);
5340b57cec5SDimitry Andric   BigSize += Dysymtab.extrefsymoff;
5350b57cec5SDimitry Andric   if (BigSize > FileSize)
5360b57cec5SDimitry Andric     return malformedError("extrefsymoff field plus nextrefsyms field times "
5370b57cec5SDimitry Andric                           "sizeof(struct dylib_reference) of LC_DYSYMTAB "
5380b57cec5SDimitry Andric                           "command " + Twine(LoadCommandIndex) + " extends "
5390b57cec5SDimitry Andric                           "past the end of the file");
5400b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Dysymtab.extrefsymoff,
5410b57cec5SDimitry Andric                                           Dysymtab.nextrefsyms *
5420b57cec5SDimitry Andric                                               sizeof(MachO::dylib_reference),
5430b57cec5SDimitry Andric                                           "reference table"))
5440b57cec5SDimitry Andric     return Err;
5450b57cec5SDimitry Andric   if (Dysymtab.indirectsymoff > FileSize)
5460b57cec5SDimitry Andric     return malformedError("indirectsymoff field of LC_DYSYMTAB command " +
5470b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
5480b57cec5SDimitry Andric                           "the file");
5490b57cec5SDimitry Andric   BigSize = Dysymtab.nindirectsyms;
5500b57cec5SDimitry Andric   BigSize *= sizeof(uint32_t);
5510b57cec5SDimitry Andric   BigSize += Dysymtab.indirectsymoff;
5520b57cec5SDimitry Andric   if (BigSize > FileSize)
5530b57cec5SDimitry Andric     return malformedError("indirectsymoff field plus nindirectsyms field times "
5540b57cec5SDimitry Andric                           "sizeof(uint32_t) of LC_DYSYMTAB command " +
5550b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
5560b57cec5SDimitry Andric                           "the file");
5570b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Dysymtab.indirectsymoff,
5580b57cec5SDimitry Andric                                           Dysymtab.nindirectsyms *
5590b57cec5SDimitry Andric                                           sizeof(uint32_t),
5600b57cec5SDimitry Andric                                           "indirect table"))
5610b57cec5SDimitry Andric     return Err;
5620b57cec5SDimitry Andric   if (Dysymtab.extreloff > FileSize)
5630b57cec5SDimitry Andric     return malformedError("extreloff field of LC_DYSYMTAB command " +
5640b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
5650b57cec5SDimitry Andric                           "the file");
5660b57cec5SDimitry Andric   BigSize = Dysymtab.nextrel;
5670b57cec5SDimitry Andric   BigSize *= sizeof(MachO::relocation_info);
5680b57cec5SDimitry Andric   BigSize += Dysymtab.extreloff;
5690b57cec5SDimitry Andric   if (BigSize > FileSize)
5700b57cec5SDimitry Andric     return malformedError("extreloff field plus nextrel field times sizeof"
5710b57cec5SDimitry Andric                           "(struct relocation_info) of LC_DYSYMTAB command " +
5720b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
5730b57cec5SDimitry Andric                           "the file");
5740b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Dysymtab.extreloff,
5750b57cec5SDimitry Andric                                           Dysymtab.nextrel *
5760b57cec5SDimitry Andric                                               sizeof(MachO::relocation_info),
5770b57cec5SDimitry Andric                                           "external relocation table"))
5780b57cec5SDimitry Andric     return Err;
5790b57cec5SDimitry Andric   if (Dysymtab.locreloff > FileSize)
5800b57cec5SDimitry Andric     return malformedError("locreloff field of LC_DYSYMTAB command " +
5810b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
5820b57cec5SDimitry Andric                           "the file");
5830b57cec5SDimitry Andric   BigSize = Dysymtab.nlocrel;
5840b57cec5SDimitry Andric   BigSize *= sizeof(MachO::relocation_info);
5850b57cec5SDimitry Andric   BigSize += Dysymtab.locreloff;
5860b57cec5SDimitry Andric   if (BigSize > FileSize)
5870b57cec5SDimitry Andric     return malformedError("locreloff field plus nlocrel field times sizeof"
5880b57cec5SDimitry Andric                           "(struct relocation_info) of LC_DYSYMTAB command " +
5890b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
5900b57cec5SDimitry Andric                           "the file");
5910b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Dysymtab.locreloff,
5920b57cec5SDimitry Andric                                           Dysymtab.nlocrel *
5930b57cec5SDimitry Andric                                               sizeof(MachO::relocation_info),
5940b57cec5SDimitry Andric                                           "local relocation table"))
5950b57cec5SDimitry Andric     return Err;
5960b57cec5SDimitry Andric   *DysymtabLoadCmd = Load.Ptr;
5970b57cec5SDimitry Andric   return Error::success();
5980b57cec5SDimitry Andric }
5990b57cec5SDimitry Andric 
checkLinkeditDataCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char ** LoadCmd,const char * CmdName,std::list<MachOElement> & Elements,const char * ElementName)6000b57cec5SDimitry Andric static Error checkLinkeditDataCommand(const MachOObjectFile &Obj,
6010b57cec5SDimitry Andric                                  const MachOObjectFile::LoadCommandInfo &Load,
6020b57cec5SDimitry Andric                                  uint32_t LoadCommandIndex,
6030b57cec5SDimitry Andric                                  const char **LoadCmd, const char *CmdName,
6040b57cec5SDimitry Andric                                  std::list<MachOElement> &Elements,
6050b57cec5SDimitry Andric                                  const char *ElementName) {
6060b57cec5SDimitry Andric   if (Load.C.cmdsize < sizeof(MachO::linkedit_data_command))
6070b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
6080b57cec5SDimitry Andric                           CmdName + " cmdsize too small");
6090b57cec5SDimitry Andric   if (*LoadCmd != nullptr)
6100b57cec5SDimitry Andric     return malformedError("more than one " + Twine(CmdName) + " command");
6110b57cec5SDimitry Andric   auto LinkDataOrError =
6120b57cec5SDimitry Andric     getStructOrErr<MachO::linkedit_data_command>(Obj, Load.Ptr);
6130b57cec5SDimitry Andric   if (!LinkDataOrError)
6140b57cec5SDimitry Andric     return LinkDataOrError.takeError();
6150b57cec5SDimitry Andric   MachO::linkedit_data_command LinkData = LinkDataOrError.get();
6160b57cec5SDimitry Andric   if (LinkData.cmdsize != sizeof(MachO::linkedit_data_command))
6170b57cec5SDimitry Andric     return malformedError(Twine(CmdName) + " command " +
6180b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " has incorrect cmdsize");
6190b57cec5SDimitry Andric   uint64_t FileSize = Obj.getData().size();
6200b57cec5SDimitry Andric   if (LinkData.dataoff > FileSize)
6210b57cec5SDimitry Andric     return malformedError("dataoff field of " + Twine(CmdName) + " command " +
6220b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
6230b57cec5SDimitry Andric                           "the file");
6240b57cec5SDimitry Andric   uint64_t BigSize = LinkData.dataoff;
6250b57cec5SDimitry Andric   BigSize += LinkData.datasize;
6260b57cec5SDimitry Andric   if (BigSize > FileSize)
6270b57cec5SDimitry Andric     return malformedError("dataoff field plus datasize field of " +
6280b57cec5SDimitry Andric                           Twine(CmdName) + " command " +
6290b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
6300b57cec5SDimitry Andric                           "the file");
6310b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, LinkData.dataoff,
6320b57cec5SDimitry Andric                                           LinkData.datasize, ElementName))
6330b57cec5SDimitry Andric     return Err;
6340b57cec5SDimitry Andric   *LoadCmd = Load.Ptr;
6350b57cec5SDimitry Andric   return Error::success();
6360b57cec5SDimitry Andric }
6370b57cec5SDimitry Andric 
checkDyldInfoCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char ** LoadCmd,const char * CmdName,std::list<MachOElement> & Elements)6380b57cec5SDimitry Andric static Error checkDyldInfoCommand(const MachOObjectFile &Obj,
6390b57cec5SDimitry Andric                                   const MachOObjectFile::LoadCommandInfo &Load,
6400b57cec5SDimitry Andric                                   uint32_t LoadCommandIndex,
6410b57cec5SDimitry Andric                                   const char **LoadCmd, const char *CmdName,
6420b57cec5SDimitry Andric                                   std::list<MachOElement> &Elements) {
6430b57cec5SDimitry Andric   if (Load.C.cmdsize < sizeof(MachO::dyld_info_command))
6440b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
6450b57cec5SDimitry Andric                           CmdName + " cmdsize too small");
6460b57cec5SDimitry Andric   if (*LoadCmd != nullptr)
6470b57cec5SDimitry Andric     return malformedError("more than one LC_DYLD_INFO and or LC_DYLD_INFO_ONLY "
6480b57cec5SDimitry Andric                           "command");
6490b57cec5SDimitry Andric   auto DyldInfoOrErr =
6500b57cec5SDimitry Andric     getStructOrErr<MachO::dyld_info_command>(Obj, Load.Ptr);
6510b57cec5SDimitry Andric   if (!DyldInfoOrErr)
6520b57cec5SDimitry Andric     return DyldInfoOrErr.takeError();
6530b57cec5SDimitry Andric   MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
6540b57cec5SDimitry Andric   if (DyldInfo.cmdsize != sizeof(MachO::dyld_info_command))
6550b57cec5SDimitry Andric     return malformedError(Twine(CmdName) + " command " +
6560b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " has incorrect cmdsize");
6570b57cec5SDimitry Andric   uint64_t FileSize = Obj.getData().size();
6580b57cec5SDimitry Andric   if (DyldInfo.rebase_off > FileSize)
6590b57cec5SDimitry Andric     return malformedError("rebase_off field of " + Twine(CmdName) +
6600b57cec5SDimitry Andric                           " command " + Twine(LoadCommandIndex) + " extends "
6610b57cec5SDimitry Andric                           "past the end of the file");
6620b57cec5SDimitry Andric   uint64_t BigSize = DyldInfo.rebase_off;
6630b57cec5SDimitry Andric   BigSize += DyldInfo.rebase_size;
6640b57cec5SDimitry Andric   if (BigSize > FileSize)
6650b57cec5SDimitry Andric     return malformedError("rebase_off field plus rebase_size field of " +
6660b57cec5SDimitry Andric                           Twine(CmdName) + " command " +
6670b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
6680b57cec5SDimitry Andric                           "the file");
6690b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, DyldInfo.rebase_off,
6700b57cec5SDimitry Andric                                           DyldInfo.rebase_size,
6710b57cec5SDimitry Andric                                           "dyld rebase info"))
6720b57cec5SDimitry Andric     return Err;
6730b57cec5SDimitry Andric   if (DyldInfo.bind_off > FileSize)
6740b57cec5SDimitry Andric     return malformedError("bind_off field of " + Twine(CmdName) +
6750b57cec5SDimitry Andric                           " command " + Twine(LoadCommandIndex) + " extends "
6760b57cec5SDimitry Andric                           "past the end of the file");
6770b57cec5SDimitry Andric   BigSize = DyldInfo.bind_off;
6780b57cec5SDimitry Andric   BigSize += DyldInfo.bind_size;
6790b57cec5SDimitry Andric   if (BigSize > FileSize)
6800b57cec5SDimitry Andric     return malformedError("bind_off field plus bind_size field of " +
6810b57cec5SDimitry Andric                           Twine(CmdName) + " command " +
6820b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
6830b57cec5SDimitry Andric                           "the file");
6840b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, DyldInfo.bind_off,
6850b57cec5SDimitry Andric                                           DyldInfo.bind_size,
6860b57cec5SDimitry Andric                                           "dyld bind info"))
6870b57cec5SDimitry Andric     return Err;
6880b57cec5SDimitry Andric   if (DyldInfo.weak_bind_off > FileSize)
6890b57cec5SDimitry Andric     return malformedError("weak_bind_off field of " + Twine(CmdName) +
6900b57cec5SDimitry Andric                           " command " + Twine(LoadCommandIndex) + " extends "
6910b57cec5SDimitry Andric                           "past the end of the file");
6920b57cec5SDimitry Andric   BigSize = DyldInfo.weak_bind_off;
6930b57cec5SDimitry Andric   BigSize += DyldInfo.weak_bind_size;
6940b57cec5SDimitry Andric   if (BigSize > FileSize)
6950b57cec5SDimitry Andric     return malformedError("weak_bind_off field plus weak_bind_size field of " +
6960b57cec5SDimitry Andric                           Twine(CmdName) + " command " +
6970b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
6980b57cec5SDimitry Andric                           "the file");
6990b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, DyldInfo.weak_bind_off,
7000b57cec5SDimitry Andric                                           DyldInfo.weak_bind_size,
7010b57cec5SDimitry Andric                                           "dyld weak bind info"))
7020b57cec5SDimitry Andric     return Err;
7030b57cec5SDimitry Andric   if (DyldInfo.lazy_bind_off > FileSize)
7040b57cec5SDimitry Andric     return malformedError("lazy_bind_off field of " + Twine(CmdName) +
7050b57cec5SDimitry Andric                           " command " + Twine(LoadCommandIndex) + " extends "
7060b57cec5SDimitry Andric                           "past the end of the file");
7070b57cec5SDimitry Andric   BigSize = DyldInfo.lazy_bind_off;
7080b57cec5SDimitry Andric   BigSize += DyldInfo.lazy_bind_size;
7090b57cec5SDimitry Andric   if (BigSize > FileSize)
7100b57cec5SDimitry Andric     return malformedError("lazy_bind_off field plus lazy_bind_size field of " +
7110b57cec5SDimitry Andric                           Twine(CmdName) + " command " +
7120b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
7130b57cec5SDimitry Andric                           "the file");
7140b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, DyldInfo.lazy_bind_off,
7150b57cec5SDimitry Andric                                           DyldInfo.lazy_bind_size,
7160b57cec5SDimitry Andric                                           "dyld lazy bind info"))
7170b57cec5SDimitry Andric     return Err;
7180b57cec5SDimitry Andric   if (DyldInfo.export_off > FileSize)
7190b57cec5SDimitry Andric     return malformedError("export_off field of " + Twine(CmdName) +
7200b57cec5SDimitry Andric                           " command " + Twine(LoadCommandIndex) + " extends "
7210b57cec5SDimitry Andric                           "past the end of the file");
7220b57cec5SDimitry Andric   BigSize = DyldInfo.export_off;
7230b57cec5SDimitry Andric   BigSize += DyldInfo.export_size;
7240b57cec5SDimitry Andric   if (BigSize > FileSize)
7250b57cec5SDimitry Andric     return malformedError("export_off field plus export_size field of " +
7260b57cec5SDimitry Andric                           Twine(CmdName) + " command " +
7270b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
7280b57cec5SDimitry Andric                           "the file");
7290b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, DyldInfo.export_off,
7300b57cec5SDimitry Andric                                           DyldInfo.export_size,
7310b57cec5SDimitry Andric                                           "dyld export info"))
7320b57cec5SDimitry Andric     return Err;
7330b57cec5SDimitry Andric   *LoadCmd = Load.Ptr;
7340b57cec5SDimitry Andric   return Error::success();
7350b57cec5SDimitry Andric }
7360b57cec5SDimitry Andric 
checkDylibCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char * CmdName)7370b57cec5SDimitry Andric static Error checkDylibCommand(const MachOObjectFile &Obj,
7380b57cec5SDimitry Andric                                const MachOObjectFile::LoadCommandInfo &Load,
7390b57cec5SDimitry Andric                                uint32_t LoadCommandIndex, const char *CmdName) {
7400b57cec5SDimitry Andric   if (Load.C.cmdsize < sizeof(MachO::dylib_command))
7410b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
7420b57cec5SDimitry Andric                           CmdName + " cmdsize too small");
7430b57cec5SDimitry Andric   auto CommandOrErr = getStructOrErr<MachO::dylib_command>(Obj, Load.Ptr);
7440b57cec5SDimitry Andric   if (!CommandOrErr)
7450b57cec5SDimitry Andric     return CommandOrErr.takeError();
7460b57cec5SDimitry Andric   MachO::dylib_command D = CommandOrErr.get();
7470b57cec5SDimitry Andric   if (D.dylib.name < sizeof(MachO::dylib_command))
7480b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
7490b57cec5SDimitry Andric                           CmdName + " name.offset field too small, not past "
7500b57cec5SDimitry Andric                           "the end of the dylib_command struct");
7510b57cec5SDimitry Andric   if (D.dylib.name >= D.cmdsize)
7520b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
7530b57cec5SDimitry Andric                           CmdName + " name.offset field extends past the end "
7540b57cec5SDimitry Andric                           "of the load command");
7550b57cec5SDimitry Andric   // Make sure there is a null between the starting offset of the name and
7560b57cec5SDimitry Andric   // the end of the load command.
7570b57cec5SDimitry Andric   uint32_t i;
7580b57cec5SDimitry Andric   const char *P = (const char *)Load.Ptr;
7590b57cec5SDimitry Andric   for (i = D.dylib.name; i < D.cmdsize; i++)
7600b57cec5SDimitry Andric     if (P[i] == '\0')
7610b57cec5SDimitry Andric       break;
7620b57cec5SDimitry Andric   if (i >= D.cmdsize)
7630b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
7640b57cec5SDimitry Andric                           CmdName + " library name extends past the end of the "
7650b57cec5SDimitry Andric                           "load command");
7660b57cec5SDimitry Andric   return Error::success();
7670b57cec5SDimitry Andric }
7680b57cec5SDimitry Andric 
checkDylibIdCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char ** LoadCmd)7690b57cec5SDimitry Andric static Error checkDylibIdCommand(const MachOObjectFile &Obj,
7700b57cec5SDimitry Andric                                  const MachOObjectFile::LoadCommandInfo &Load,
7710b57cec5SDimitry Andric                                  uint32_t LoadCommandIndex,
7720b57cec5SDimitry Andric                                  const char **LoadCmd) {
7730b57cec5SDimitry Andric   if (Error Err = checkDylibCommand(Obj, Load, LoadCommandIndex,
7740b57cec5SDimitry Andric                                      "LC_ID_DYLIB"))
7750b57cec5SDimitry Andric     return Err;
7760b57cec5SDimitry Andric   if (*LoadCmd != nullptr)
7770b57cec5SDimitry Andric     return malformedError("more than one LC_ID_DYLIB command");
7780b57cec5SDimitry Andric   if (Obj.getHeader().filetype != MachO::MH_DYLIB &&
7790b57cec5SDimitry Andric       Obj.getHeader().filetype != MachO::MH_DYLIB_STUB)
7800b57cec5SDimitry Andric     return malformedError("LC_ID_DYLIB load command in non-dynamic library "
7810b57cec5SDimitry Andric                           "file type");
7820b57cec5SDimitry Andric   *LoadCmd = Load.Ptr;
7830b57cec5SDimitry Andric   return Error::success();
7840b57cec5SDimitry Andric }
7850b57cec5SDimitry Andric 
checkDyldCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char * CmdName)7860b57cec5SDimitry Andric static Error checkDyldCommand(const MachOObjectFile &Obj,
7870b57cec5SDimitry Andric                               const MachOObjectFile::LoadCommandInfo &Load,
7880b57cec5SDimitry Andric                               uint32_t LoadCommandIndex, const char *CmdName) {
7890b57cec5SDimitry Andric   if (Load.C.cmdsize < sizeof(MachO::dylinker_command))
7900b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
7910b57cec5SDimitry Andric                           CmdName + " cmdsize too small");
7920b57cec5SDimitry Andric   auto CommandOrErr = getStructOrErr<MachO::dylinker_command>(Obj, Load.Ptr);
7930b57cec5SDimitry Andric   if (!CommandOrErr)
7940b57cec5SDimitry Andric     return CommandOrErr.takeError();
7950b57cec5SDimitry Andric   MachO::dylinker_command D = CommandOrErr.get();
7960b57cec5SDimitry Andric   if (D.name < sizeof(MachO::dylinker_command))
7970b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
7980b57cec5SDimitry Andric                           CmdName + " name.offset field too small, not past "
7990b57cec5SDimitry Andric                           "the end of the dylinker_command struct");
8000b57cec5SDimitry Andric   if (D.name >= D.cmdsize)
8010b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
8020b57cec5SDimitry Andric                           CmdName + " name.offset field extends past the end "
8030b57cec5SDimitry Andric                           "of the load command");
8040b57cec5SDimitry Andric   // Make sure there is a null between the starting offset of the name and
8050b57cec5SDimitry Andric   // the end of the load command.
8060b57cec5SDimitry Andric   uint32_t i;
8070b57cec5SDimitry Andric   const char *P = (const char *)Load.Ptr;
8080b57cec5SDimitry Andric   for (i = D.name; i < D.cmdsize; i++)
8090b57cec5SDimitry Andric     if (P[i] == '\0')
8100b57cec5SDimitry Andric       break;
8110b57cec5SDimitry Andric   if (i >= D.cmdsize)
8120b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
8130b57cec5SDimitry Andric                           CmdName + " dyld name extends past the end of the "
8140b57cec5SDimitry Andric                           "load command");
8150b57cec5SDimitry Andric   return Error::success();
8160b57cec5SDimitry Andric }
8170b57cec5SDimitry Andric 
checkVersCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char ** LoadCmd,const char * CmdName)8180b57cec5SDimitry Andric static Error checkVersCommand(const MachOObjectFile &Obj,
8190b57cec5SDimitry Andric                               const MachOObjectFile::LoadCommandInfo &Load,
8200b57cec5SDimitry Andric                               uint32_t LoadCommandIndex,
8210b57cec5SDimitry Andric                               const char **LoadCmd, const char *CmdName) {
8220b57cec5SDimitry Andric   if (Load.C.cmdsize != sizeof(MachO::version_min_command))
8230b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
8240b57cec5SDimitry Andric                           CmdName + " has incorrect cmdsize");
8250b57cec5SDimitry Andric   if (*LoadCmd != nullptr)
8260b57cec5SDimitry Andric     return malformedError("more than one LC_VERSION_MIN_MACOSX, "
8270b57cec5SDimitry Andric                           "LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_TVOS or "
8280b57cec5SDimitry Andric                           "LC_VERSION_MIN_WATCHOS command");
8290b57cec5SDimitry Andric   *LoadCmd = Load.Ptr;
8300b57cec5SDimitry Andric   return Error::success();
8310b57cec5SDimitry Andric }
8320b57cec5SDimitry Andric 
checkNoteCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,std::list<MachOElement> & Elements)8330b57cec5SDimitry Andric static Error checkNoteCommand(const MachOObjectFile &Obj,
8340b57cec5SDimitry Andric                               const MachOObjectFile::LoadCommandInfo &Load,
8350b57cec5SDimitry Andric                               uint32_t LoadCommandIndex,
8360b57cec5SDimitry Andric                               std::list<MachOElement> &Elements) {
8370b57cec5SDimitry Andric   if (Load.C.cmdsize != sizeof(MachO::note_command))
8380b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
8390b57cec5SDimitry Andric                           " LC_NOTE has incorrect cmdsize");
8400b57cec5SDimitry Andric   auto NoteCmdOrErr = getStructOrErr<MachO::note_command>(Obj, Load.Ptr);
8410b57cec5SDimitry Andric   if (!NoteCmdOrErr)
8420b57cec5SDimitry Andric     return NoteCmdOrErr.takeError();
8430b57cec5SDimitry Andric   MachO::note_command Nt = NoteCmdOrErr.get();
8440b57cec5SDimitry Andric   uint64_t FileSize = Obj.getData().size();
8450b57cec5SDimitry Andric   if (Nt.offset > FileSize)
8460b57cec5SDimitry Andric     return malformedError("offset field of LC_NOTE command " +
8470b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends "
8480b57cec5SDimitry Andric                           "past the end of the file");
8490b57cec5SDimitry Andric   uint64_t BigSize = Nt.offset;
8500b57cec5SDimitry Andric   BigSize += Nt.size;
8510b57cec5SDimitry Andric   if (BigSize > FileSize)
8520b57cec5SDimitry Andric     return malformedError("size field plus offset field of LC_NOTE command " +
8530b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
8540b57cec5SDimitry Andric                           "the file");
8550b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Nt.offset, Nt.size,
8560b57cec5SDimitry Andric                                           "LC_NOTE data"))
8570b57cec5SDimitry Andric     return Err;
8580b57cec5SDimitry Andric   return Error::success();
8590b57cec5SDimitry Andric }
8600b57cec5SDimitry Andric 
8610b57cec5SDimitry Andric static Error
parseBuildVersionCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,SmallVectorImpl<const char * > & BuildTools,uint32_t LoadCommandIndex)8620b57cec5SDimitry Andric parseBuildVersionCommand(const MachOObjectFile &Obj,
8630b57cec5SDimitry Andric                          const MachOObjectFile::LoadCommandInfo &Load,
8640b57cec5SDimitry Andric                          SmallVectorImpl<const char*> &BuildTools,
8650b57cec5SDimitry Andric                          uint32_t LoadCommandIndex) {
8660b57cec5SDimitry Andric   auto BVCOrErr =
8670b57cec5SDimitry Andric     getStructOrErr<MachO::build_version_command>(Obj, Load.Ptr);
8680b57cec5SDimitry Andric   if (!BVCOrErr)
8690b57cec5SDimitry Andric     return BVCOrErr.takeError();
8700b57cec5SDimitry Andric   MachO::build_version_command BVC = BVCOrErr.get();
8710b57cec5SDimitry Andric   if (Load.C.cmdsize !=
8720b57cec5SDimitry Andric       sizeof(MachO::build_version_command) +
8730b57cec5SDimitry Andric           BVC.ntools * sizeof(MachO::build_tool_version))
8740b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
8750b57cec5SDimitry Andric                           " LC_BUILD_VERSION_COMMAND has incorrect cmdsize");
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric   auto Start = Load.Ptr + sizeof(MachO::build_version_command);
8780b57cec5SDimitry Andric   BuildTools.resize(BVC.ntools);
8790b57cec5SDimitry Andric   for (unsigned i = 0; i < BVC.ntools; ++i)
8800b57cec5SDimitry Andric     BuildTools[i] = Start + i * sizeof(MachO::build_tool_version);
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric   return Error::success();
8830b57cec5SDimitry Andric }
8840b57cec5SDimitry Andric 
checkRpathCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex)8850b57cec5SDimitry Andric static Error checkRpathCommand(const MachOObjectFile &Obj,
8860b57cec5SDimitry Andric                                const MachOObjectFile::LoadCommandInfo &Load,
8870b57cec5SDimitry Andric                                uint32_t LoadCommandIndex) {
8880b57cec5SDimitry Andric   if (Load.C.cmdsize < sizeof(MachO::rpath_command))
8890b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
8900b57cec5SDimitry Andric                           " LC_RPATH cmdsize too small");
8910b57cec5SDimitry Andric   auto ROrErr = getStructOrErr<MachO::rpath_command>(Obj, Load.Ptr);
8920b57cec5SDimitry Andric   if (!ROrErr)
8930b57cec5SDimitry Andric     return ROrErr.takeError();
8940b57cec5SDimitry Andric   MachO::rpath_command R = ROrErr.get();
8950b57cec5SDimitry Andric   if (R.path < sizeof(MachO::rpath_command))
8960b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
8970b57cec5SDimitry Andric                           " LC_RPATH path.offset field too small, not past "
8980b57cec5SDimitry Andric                           "the end of the rpath_command struct");
8990b57cec5SDimitry Andric   if (R.path >= R.cmdsize)
9000b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
9010b57cec5SDimitry Andric                           " LC_RPATH path.offset field extends past the end "
9020b57cec5SDimitry Andric                           "of the load command");
9030b57cec5SDimitry Andric   // Make sure there is a null between the starting offset of the path and
9040b57cec5SDimitry Andric   // the end of the load command.
9050b57cec5SDimitry Andric   uint32_t i;
9060b57cec5SDimitry Andric   const char *P = (const char *)Load.Ptr;
9070b57cec5SDimitry Andric   for (i = R.path; i < R.cmdsize; i++)
9080b57cec5SDimitry Andric     if (P[i] == '\0')
9090b57cec5SDimitry Andric       break;
9100b57cec5SDimitry Andric   if (i >= R.cmdsize)
9110b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
9120b57cec5SDimitry Andric                           " LC_RPATH library name extends past the end of the "
9130b57cec5SDimitry Andric                           "load command");
9140b57cec5SDimitry Andric   return Error::success();
9150b57cec5SDimitry Andric }
9160b57cec5SDimitry Andric 
checkEncryptCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,uint64_t cryptoff,uint64_t cryptsize,const char ** LoadCmd,const char * CmdName)9170b57cec5SDimitry Andric static Error checkEncryptCommand(const MachOObjectFile &Obj,
9180b57cec5SDimitry Andric                                  const MachOObjectFile::LoadCommandInfo &Load,
9190b57cec5SDimitry Andric                                  uint32_t LoadCommandIndex,
9200b57cec5SDimitry Andric                                  uint64_t cryptoff, uint64_t cryptsize,
9210b57cec5SDimitry Andric                                  const char **LoadCmd, const char *CmdName) {
9220b57cec5SDimitry Andric   if (*LoadCmd != nullptr)
9230b57cec5SDimitry Andric     return malformedError("more than one LC_ENCRYPTION_INFO and or "
9240b57cec5SDimitry Andric                           "LC_ENCRYPTION_INFO_64 command");
9250b57cec5SDimitry Andric   uint64_t FileSize = Obj.getData().size();
9260b57cec5SDimitry Andric   if (cryptoff > FileSize)
9270b57cec5SDimitry Andric     return malformedError("cryptoff field of " + Twine(CmdName) +
9280b57cec5SDimitry Andric                           " command " + Twine(LoadCommandIndex) + " extends "
9290b57cec5SDimitry Andric                           "past the end of the file");
9300b57cec5SDimitry Andric   uint64_t BigSize = cryptoff;
9310b57cec5SDimitry Andric   BigSize += cryptsize;
9320b57cec5SDimitry Andric   if (BigSize > FileSize)
9330b57cec5SDimitry Andric     return malformedError("cryptoff field plus cryptsize field of " +
9340b57cec5SDimitry Andric                           Twine(CmdName) + " command " +
9350b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
9360b57cec5SDimitry Andric                           "the file");
9370b57cec5SDimitry Andric   *LoadCmd = Load.Ptr;
9380b57cec5SDimitry Andric   return Error::success();
9390b57cec5SDimitry Andric }
9400b57cec5SDimitry Andric 
checkLinkerOptCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex)9410b57cec5SDimitry Andric static Error checkLinkerOptCommand(const MachOObjectFile &Obj,
9420b57cec5SDimitry Andric                                    const MachOObjectFile::LoadCommandInfo &Load,
9430b57cec5SDimitry Andric                                    uint32_t LoadCommandIndex) {
9440b57cec5SDimitry Andric   if (Load.C.cmdsize < sizeof(MachO::linker_option_command))
9450b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
9460b57cec5SDimitry Andric                           " LC_LINKER_OPTION cmdsize too small");
9470b57cec5SDimitry Andric   auto LinkOptionOrErr =
9480b57cec5SDimitry Andric     getStructOrErr<MachO::linker_option_command>(Obj, Load.Ptr);
9490b57cec5SDimitry Andric   if (!LinkOptionOrErr)
9500b57cec5SDimitry Andric     return LinkOptionOrErr.takeError();
9510b57cec5SDimitry Andric   MachO::linker_option_command L = LinkOptionOrErr.get();
9520b57cec5SDimitry Andric   // Make sure the count of strings is correct.
9530b57cec5SDimitry Andric   const char *string = (const char *)Load.Ptr +
9540b57cec5SDimitry Andric                        sizeof(struct MachO::linker_option_command);
9550b57cec5SDimitry Andric   uint32_t left = L.cmdsize - sizeof(struct MachO::linker_option_command);
9560b57cec5SDimitry Andric   uint32_t i = 0;
9570b57cec5SDimitry Andric   while (left > 0) {
9580b57cec5SDimitry Andric     while (*string == '\0' && left > 0) {
9590b57cec5SDimitry Andric       string++;
9600b57cec5SDimitry Andric       left--;
9610b57cec5SDimitry Andric     }
9620b57cec5SDimitry Andric     if (left > 0) {
9630b57cec5SDimitry Andric       i++;
9640b57cec5SDimitry Andric       uint32_t NullPos = StringRef(string, left).find('\0');
9650b57cec5SDimitry Andric       if (0xffffffff == NullPos)
9660b57cec5SDimitry Andric         return malformedError("load command " + Twine(LoadCommandIndex) +
9670b57cec5SDimitry Andric                               " LC_LINKER_OPTION string #" + Twine(i) +
9680b57cec5SDimitry Andric                               " is not NULL terminated");
9690b57cec5SDimitry Andric       uint32_t len = std::min(NullPos, left) + 1;
9700b57cec5SDimitry Andric       string += len;
9710b57cec5SDimitry Andric       left -= len;
9720b57cec5SDimitry Andric     }
9730b57cec5SDimitry Andric   }
9740b57cec5SDimitry Andric   if (L.count != i)
9750b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
9760b57cec5SDimitry Andric                           " LC_LINKER_OPTION string count " + Twine(L.count) +
9770b57cec5SDimitry Andric                           " does not match number of strings");
9780b57cec5SDimitry Andric   return Error::success();
9790b57cec5SDimitry Andric }
9800b57cec5SDimitry Andric 
checkSubCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char * CmdName,size_t SizeOfCmd,const char * CmdStructName,uint32_t PathOffset,const char * PathFieldName)9810b57cec5SDimitry Andric static Error checkSubCommand(const MachOObjectFile &Obj,
9820b57cec5SDimitry Andric                              const MachOObjectFile::LoadCommandInfo &Load,
9830b57cec5SDimitry Andric                              uint32_t LoadCommandIndex, const char *CmdName,
9840b57cec5SDimitry Andric                              size_t SizeOfCmd, const char *CmdStructName,
9850b57cec5SDimitry Andric                              uint32_t PathOffset, const char *PathFieldName) {
9860b57cec5SDimitry Andric   if (PathOffset < SizeOfCmd)
9870b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
9880b57cec5SDimitry Andric                           CmdName + " " + PathFieldName + ".offset field too "
9890b57cec5SDimitry Andric                           "small, not past the end of the " + CmdStructName);
9900b57cec5SDimitry Andric   if (PathOffset >= Load.C.cmdsize)
9910b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
9920b57cec5SDimitry Andric                           CmdName + " " + PathFieldName + ".offset field "
9930b57cec5SDimitry Andric                           "extends past the end of the load command");
9940b57cec5SDimitry Andric   // Make sure there is a null between the starting offset of the path and
9950b57cec5SDimitry Andric   // the end of the load command.
9960b57cec5SDimitry Andric   uint32_t i;
9970b57cec5SDimitry Andric   const char *P = (const char *)Load.Ptr;
9980b57cec5SDimitry Andric   for (i = PathOffset; i < Load.C.cmdsize; i++)
9990b57cec5SDimitry Andric     if (P[i] == '\0')
10000b57cec5SDimitry Andric       break;
10010b57cec5SDimitry Andric   if (i >= Load.C.cmdsize)
10020b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) + " " +
10030b57cec5SDimitry Andric                           CmdName + " " + PathFieldName + " name extends past "
10040b57cec5SDimitry Andric                           "the end of the load command");
10050b57cec5SDimitry Andric   return Error::success();
10060b57cec5SDimitry Andric }
10070b57cec5SDimitry Andric 
checkThreadCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char * CmdName)10080b57cec5SDimitry Andric static Error checkThreadCommand(const MachOObjectFile &Obj,
10090b57cec5SDimitry Andric                                 const MachOObjectFile::LoadCommandInfo &Load,
10100b57cec5SDimitry Andric                                 uint32_t LoadCommandIndex,
10110b57cec5SDimitry Andric                                 const char *CmdName) {
10120b57cec5SDimitry Andric   if (Load.C.cmdsize < sizeof(MachO::thread_command))
10130b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
10140b57cec5SDimitry Andric                           CmdName + " cmdsize too small");
10150b57cec5SDimitry Andric   auto ThreadCommandOrErr =
10160b57cec5SDimitry Andric     getStructOrErr<MachO::thread_command>(Obj, Load.Ptr);
10170b57cec5SDimitry Andric   if (!ThreadCommandOrErr)
10180b57cec5SDimitry Andric     return ThreadCommandOrErr.takeError();
10190b57cec5SDimitry Andric   MachO::thread_command T = ThreadCommandOrErr.get();
10200b57cec5SDimitry Andric   const char *state = Load.Ptr + sizeof(MachO::thread_command);
10210b57cec5SDimitry Andric   const char *end = Load.Ptr + T.cmdsize;
10220b57cec5SDimitry Andric   uint32_t nflavor = 0;
10230b57cec5SDimitry Andric   uint32_t cputype = getCPUType(Obj);
10240b57cec5SDimitry Andric   while (state < end) {
10250b57cec5SDimitry Andric     if(state + sizeof(uint32_t) > end)
10260b57cec5SDimitry Andric       return malformedError("load command " + Twine(LoadCommandIndex) +
10270b57cec5SDimitry Andric                             "flavor in " + CmdName + " extends past end of "
10280b57cec5SDimitry Andric                             "command");
10290b57cec5SDimitry Andric     uint32_t flavor;
10300b57cec5SDimitry Andric     memcpy(&flavor, state, sizeof(uint32_t));
10310b57cec5SDimitry Andric     if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
10320b57cec5SDimitry Andric       sys::swapByteOrder(flavor);
10330b57cec5SDimitry Andric     state += sizeof(uint32_t);
10340b57cec5SDimitry Andric 
10350b57cec5SDimitry Andric     if(state + sizeof(uint32_t) > end)
10360b57cec5SDimitry Andric       return malformedError("load command " + Twine(LoadCommandIndex) +
10370b57cec5SDimitry Andric                             " count in " + CmdName + " extends past end of "
10380b57cec5SDimitry Andric                             "command");
10390b57cec5SDimitry Andric     uint32_t count;
10400b57cec5SDimitry Andric     memcpy(&count, state, sizeof(uint32_t));
10410b57cec5SDimitry Andric     if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
10420b57cec5SDimitry Andric       sys::swapByteOrder(count);
10430b57cec5SDimitry Andric     state += sizeof(uint32_t);
10440b57cec5SDimitry Andric 
10450b57cec5SDimitry Andric     if (cputype == MachO::CPU_TYPE_I386) {
10460b57cec5SDimitry Andric       if (flavor == MachO::x86_THREAD_STATE32) {
10470b57cec5SDimitry Andric         if (count != MachO::x86_THREAD_STATE32_COUNT)
10480b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
10490b57cec5SDimitry Andric                                 " count not x86_THREAD_STATE32_COUNT for "
10500b57cec5SDimitry Andric                                 "flavor number " + Twine(nflavor) + " which is "
10510b57cec5SDimitry Andric                                 "a x86_THREAD_STATE32 flavor in " + CmdName +
10520b57cec5SDimitry Andric                                 " command");
10530b57cec5SDimitry Andric         if (state + sizeof(MachO::x86_thread_state32_t) > end)
10540b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
10550b57cec5SDimitry Andric                                 " x86_THREAD_STATE32 extends past end of "
10560b57cec5SDimitry Andric                                 "command in " + CmdName + " command");
10570b57cec5SDimitry Andric         state += sizeof(MachO::x86_thread_state32_t);
10580b57cec5SDimitry Andric       } else {
10590b57cec5SDimitry Andric         return malformedError("load command " + Twine(LoadCommandIndex) +
10600b57cec5SDimitry Andric                               " unknown flavor (" + Twine(flavor) + ") for "
10610b57cec5SDimitry Andric                               "flavor number " + Twine(nflavor) + " in " +
10620b57cec5SDimitry Andric                               CmdName + " command");
10630b57cec5SDimitry Andric       }
10640b57cec5SDimitry Andric     } else if (cputype == MachO::CPU_TYPE_X86_64) {
10650b57cec5SDimitry Andric       if (flavor == MachO::x86_THREAD_STATE) {
10660b57cec5SDimitry Andric         if (count != MachO::x86_THREAD_STATE_COUNT)
10670b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
10680b57cec5SDimitry Andric                                 " count not x86_THREAD_STATE_COUNT for "
10690b57cec5SDimitry Andric                                 "flavor number " + Twine(nflavor) + " which is "
10700b57cec5SDimitry Andric                                 "a x86_THREAD_STATE flavor in " + CmdName +
10710b57cec5SDimitry Andric                                 " command");
10720b57cec5SDimitry Andric         if (state + sizeof(MachO::x86_thread_state_t) > end)
10730b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
10740b57cec5SDimitry Andric                                 " x86_THREAD_STATE extends past end of "
10750b57cec5SDimitry Andric                                 "command in " + CmdName + " command");
10760b57cec5SDimitry Andric         state += sizeof(MachO::x86_thread_state_t);
10770b57cec5SDimitry Andric       } else if (flavor == MachO::x86_FLOAT_STATE) {
10780b57cec5SDimitry Andric         if (count != MachO::x86_FLOAT_STATE_COUNT)
10790b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
10800b57cec5SDimitry Andric                                 " count not x86_FLOAT_STATE_COUNT for "
10810b57cec5SDimitry Andric                                 "flavor number " + Twine(nflavor) + " which is "
10820b57cec5SDimitry Andric                                 "a x86_FLOAT_STATE flavor in " + CmdName +
10830b57cec5SDimitry Andric                                 " command");
10840b57cec5SDimitry Andric         if (state + sizeof(MachO::x86_float_state_t) > end)
10850b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
10860b57cec5SDimitry Andric                                 " x86_FLOAT_STATE extends past end of "
10870b57cec5SDimitry Andric                                 "command in " + CmdName + " command");
10880b57cec5SDimitry Andric         state += sizeof(MachO::x86_float_state_t);
10890b57cec5SDimitry Andric       } else if (flavor == MachO::x86_EXCEPTION_STATE) {
10900b57cec5SDimitry Andric         if (count != MachO::x86_EXCEPTION_STATE_COUNT)
10910b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
10920b57cec5SDimitry Andric                                 " count not x86_EXCEPTION_STATE_COUNT for "
10930b57cec5SDimitry Andric                                 "flavor number " + Twine(nflavor) + " which is "
10940b57cec5SDimitry Andric                                 "a x86_EXCEPTION_STATE flavor in " + CmdName +
10950b57cec5SDimitry Andric                                 " command");
10960b57cec5SDimitry Andric         if (state + sizeof(MachO::x86_exception_state_t) > end)
10970b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
10980b57cec5SDimitry Andric                                 " x86_EXCEPTION_STATE extends past end of "
10990b57cec5SDimitry Andric                                 "command in " + CmdName + " command");
11000b57cec5SDimitry Andric         state += sizeof(MachO::x86_exception_state_t);
11010b57cec5SDimitry Andric       } else if (flavor == MachO::x86_THREAD_STATE64) {
11020b57cec5SDimitry Andric         if (count != MachO::x86_THREAD_STATE64_COUNT)
11030b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11040b57cec5SDimitry Andric                                 " count not x86_THREAD_STATE64_COUNT for "
11050b57cec5SDimitry Andric                                 "flavor number " + Twine(nflavor) + " which is "
11060b57cec5SDimitry Andric                                 "a x86_THREAD_STATE64 flavor in " + CmdName +
11070b57cec5SDimitry Andric                                 " command");
11080b57cec5SDimitry Andric         if (state + sizeof(MachO::x86_thread_state64_t) > end)
11090b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11100b57cec5SDimitry Andric                                 " x86_THREAD_STATE64 extends past end of "
11110b57cec5SDimitry Andric                                 "command in " + CmdName + " command");
11120b57cec5SDimitry Andric         state += sizeof(MachO::x86_thread_state64_t);
11130b57cec5SDimitry Andric       } else if (flavor == MachO::x86_EXCEPTION_STATE64) {
11140b57cec5SDimitry Andric         if (count != MachO::x86_EXCEPTION_STATE64_COUNT)
11150b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11160b57cec5SDimitry Andric                                 " count not x86_EXCEPTION_STATE64_COUNT for "
11170b57cec5SDimitry Andric                                 "flavor number " + Twine(nflavor) + " which is "
11180b57cec5SDimitry Andric                                 "a x86_EXCEPTION_STATE64 flavor in " + CmdName +
11190b57cec5SDimitry Andric                                 " command");
11200b57cec5SDimitry Andric         if (state + sizeof(MachO::x86_exception_state64_t) > end)
11210b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11220b57cec5SDimitry Andric                                 " x86_EXCEPTION_STATE64 extends past end of "
11230b57cec5SDimitry Andric                                 "command in " + CmdName + " command");
11240b57cec5SDimitry Andric         state += sizeof(MachO::x86_exception_state64_t);
11250b57cec5SDimitry Andric       } else {
11260b57cec5SDimitry Andric         return malformedError("load command " + Twine(LoadCommandIndex) +
11270b57cec5SDimitry Andric                               " unknown flavor (" + Twine(flavor) + ") for "
11280b57cec5SDimitry Andric                               "flavor number " + Twine(nflavor) + " in " +
11290b57cec5SDimitry Andric                               CmdName + " command");
11300b57cec5SDimitry Andric       }
11310b57cec5SDimitry Andric     } else if (cputype == MachO::CPU_TYPE_ARM) {
11320b57cec5SDimitry Andric       if (flavor == MachO::ARM_THREAD_STATE) {
11330b57cec5SDimitry Andric         if (count != MachO::ARM_THREAD_STATE_COUNT)
11340b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11350b57cec5SDimitry Andric                                 " count not ARM_THREAD_STATE_COUNT for "
11360b57cec5SDimitry Andric                                 "flavor number " + Twine(nflavor) + " which is "
11370b57cec5SDimitry Andric                                 "a ARM_THREAD_STATE flavor in " + CmdName +
11380b57cec5SDimitry Andric                                 " command");
11390b57cec5SDimitry Andric         if (state + sizeof(MachO::arm_thread_state32_t) > end)
11400b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11410b57cec5SDimitry Andric                                 " ARM_THREAD_STATE extends past end of "
11420b57cec5SDimitry Andric                                 "command in " + CmdName + " command");
11430b57cec5SDimitry Andric         state += sizeof(MachO::arm_thread_state32_t);
11440b57cec5SDimitry Andric       } else {
11450b57cec5SDimitry Andric         return malformedError("load command " + Twine(LoadCommandIndex) +
11460b57cec5SDimitry Andric                               " unknown flavor (" + Twine(flavor) + ") for "
11470b57cec5SDimitry Andric                               "flavor number " + Twine(nflavor) + " in " +
11480b57cec5SDimitry Andric                               CmdName + " command");
11490b57cec5SDimitry Andric       }
11500b57cec5SDimitry Andric     } else if (cputype == MachO::CPU_TYPE_ARM64 ||
11510b57cec5SDimitry Andric                cputype == MachO::CPU_TYPE_ARM64_32) {
11520b57cec5SDimitry Andric       if (flavor == MachO::ARM_THREAD_STATE64) {
11530b57cec5SDimitry Andric         if (count != MachO::ARM_THREAD_STATE64_COUNT)
11540b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11550b57cec5SDimitry Andric                                 " count not ARM_THREAD_STATE64_COUNT for "
11560b57cec5SDimitry Andric                                 "flavor number " + Twine(nflavor) + " which is "
11570b57cec5SDimitry Andric                                 "a ARM_THREAD_STATE64 flavor in " + CmdName +
11580b57cec5SDimitry Andric                                 " command");
11590b57cec5SDimitry Andric         if (state + sizeof(MachO::arm_thread_state64_t) > end)
11600b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11610b57cec5SDimitry Andric                                 " ARM_THREAD_STATE64 extends past end of "
11620b57cec5SDimitry Andric                                 "command in " + CmdName + " command");
11630b57cec5SDimitry Andric         state += sizeof(MachO::arm_thread_state64_t);
11640b57cec5SDimitry Andric       } else {
11650b57cec5SDimitry Andric         return malformedError("load command " + Twine(LoadCommandIndex) +
11660b57cec5SDimitry Andric                               " unknown flavor (" + Twine(flavor) + ") for "
11670b57cec5SDimitry Andric                               "flavor number " + Twine(nflavor) + " in " +
11680b57cec5SDimitry Andric                               CmdName + " command");
11690b57cec5SDimitry Andric       }
11700b57cec5SDimitry Andric     } else if (cputype == MachO::CPU_TYPE_POWERPC) {
11710b57cec5SDimitry Andric       if (flavor == MachO::PPC_THREAD_STATE) {
11720b57cec5SDimitry Andric         if (count != MachO::PPC_THREAD_STATE_COUNT)
11730b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11740b57cec5SDimitry Andric                                 " count not PPC_THREAD_STATE_COUNT for "
11750b57cec5SDimitry Andric                                 "flavor number " + Twine(nflavor) + " which is "
11760b57cec5SDimitry Andric                                 "a PPC_THREAD_STATE flavor in " + CmdName +
11770b57cec5SDimitry Andric                                 " command");
11780b57cec5SDimitry Andric         if (state + sizeof(MachO::ppc_thread_state32_t) > end)
11790b57cec5SDimitry Andric           return malformedError("load command " + Twine(LoadCommandIndex) +
11800b57cec5SDimitry Andric                                 " PPC_THREAD_STATE extends past end of "
11810b57cec5SDimitry Andric                                 "command in " + CmdName + " command");
11820b57cec5SDimitry Andric         state += sizeof(MachO::ppc_thread_state32_t);
11830b57cec5SDimitry Andric       } else {
11840b57cec5SDimitry Andric         return malformedError("load command " + Twine(LoadCommandIndex) +
11850b57cec5SDimitry Andric                               " unknown flavor (" + Twine(flavor) + ") for "
11860b57cec5SDimitry Andric                               "flavor number " + Twine(nflavor) + " in " +
11870b57cec5SDimitry Andric                               CmdName + " command");
11880b57cec5SDimitry Andric       }
11890b57cec5SDimitry Andric     } else {
11900b57cec5SDimitry Andric       return malformedError("unknown cputype (" + Twine(cputype) + ") load "
11910b57cec5SDimitry Andric                             "command " + Twine(LoadCommandIndex) + " for " +
11920b57cec5SDimitry Andric                             CmdName + " command can't be checked");
11930b57cec5SDimitry Andric     }
11940b57cec5SDimitry Andric     nflavor++;
11950b57cec5SDimitry Andric   }
11960b57cec5SDimitry Andric   return Error::success();
11970b57cec5SDimitry Andric }
11980b57cec5SDimitry Andric 
checkTwoLevelHintsCommand(const MachOObjectFile & Obj,const MachOObjectFile::LoadCommandInfo & Load,uint32_t LoadCommandIndex,const char ** LoadCmd,std::list<MachOElement> & Elements)11990b57cec5SDimitry Andric static Error checkTwoLevelHintsCommand(const MachOObjectFile &Obj,
12000b57cec5SDimitry Andric                                        const MachOObjectFile::LoadCommandInfo
12010b57cec5SDimitry Andric                                          &Load,
12020b57cec5SDimitry Andric                                        uint32_t LoadCommandIndex,
12030b57cec5SDimitry Andric                                        const char **LoadCmd,
12040b57cec5SDimitry Andric                                        std::list<MachOElement> &Elements) {
12050b57cec5SDimitry Andric   if (Load.C.cmdsize != sizeof(MachO::twolevel_hints_command))
12060b57cec5SDimitry Andric     return malformedError("load command " + Twine(LoadCommandIndex) +
12070b57cec5SDimitry Andric                           " LC_TWOLEVEL_HINTS has incorrect cmdsize");
12080b57cec5SDimitry Andric   if (*LoadCmd != nullptr)
12090b57cec5SDimitry Andric     return malformedError("more than one LC_TWOLEVEL_HINTS command");
12100b57cec5SDimitry Andric   auto HintsOrErr = getStructOrErr<MachO::twolevel_hints_command>(Obj, Load.Ptr);
12110b57cec5SDimitry Andric   if(!HintsOrErr)
12120b57cec5SDimitry Andric     return HintsOrErr.takeError();
12130b57cec5SDimitry Andric   MachO::twolevel_hints_command Hints = HintsOrErr.get();
12140b57cec5SDimitry Andric   uint64_t FileSize = Obj.getData().size();
12150b57cec5SDimitry Andric   if (Hints.offset > FileSize)
12160b57cec5SDimitry Andric     return malformedError("offset field of LC_TWOLEVEL_HINTS command " +
12170b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
12180b57cec5SDimitry Andric                           "the file");
12190b57cec5SDimitry Andric   uint64_t BigSize = Hints.nhints;
12200b57cec5SDimitry Andric   BigSize *= sizeof(MachO::twolevel_hint);
12210b57cec5SDimitry Andric   BigSize += Hints.offset;
12220b57cec5SDimitry Andric   if (BigSize > FileSize)
12230b57cec5SDimitry Andric     return malformedError("offset field plus nhints times sizeof(struct "
12240b57cec5SDimitry Andric                           "twolevel_hint) field of LC_TWOLEVEL_HINTS command " +
12250b57cec5SDimitry Andric                           Twine(LoadCommandIndex) + " extends past the end of "
12260b57cec5SDimitry Andric                           "the file");
12270b57cec5SDimitry Andric   if (Error Err = checkOverlappingElement(Elements, Hints.offset, Hints.nhints *
12280b57cec5SDimitry Andric                                           sizeof(MachO::twolevel_hint),
12290b57cec5SDimitry Andric                                           "two level hints"))
12300b57cec5SDimitry Andric     return Err;
12310b57cec5SDimitry Andric   *LoadCmd = Load.Ptr;
12320b57cec5SDimitry Andric   return Error::success();
12330b57cec5SDimitry Andric }
12340b57cec5SDimitry Andric 
12350b57cec5SDimitry Andric // Returns true if the libObject code does not support the load command and its
12360b57cec5SDimitry Andric // contents.  The cmd value it is treated as an unknown load command but with
12370b57cec5SDimitry Andric // an error message that says the cmd value is obsolete.
isLoadCommandObsolete(uint32_t cmd)12380b57cec5SDimitry Andric static bool isLoadCommandObsolete(uint32_t cmd) {
12390b57cec5SDimitry Andric   if (cmd == MachO::LC_SYMSEG ||
12400b57cec5SDimitry Andric       cmd == MachO::LC_LOADFVMLIB ||
12410b57cec5SDimitry Andric       cmd == MachO::LC_IDFVMLIB ||
12420b57cec5SDimitry Andric       cmd == MachO::LC_IDENT ||
12430b57cec5SDimitry Andric       cmd == MachO::LC_FVMFILE ||
12440b57cec5SDimitry Andric       cmd == MachO::LC_PREPAGE ||
12450b57cec5SDimitry Andric       cmd == MachO::LC_PREBOUND_DYLIB ||
12460b57cec5SDimitry Andric       cmd == MachO::LC_TWOLEVEL_HINTS ||
12470b57cec5SDimitry Andric       cmd == MachO::LC_PREBIND_CKSUM)
12480b57cec5SDimitry Andric     return true;
12490b57cec5SDimitry Andric   return false;
12500b57cec5SDimitry Andric }
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric Expected<std::unique_ptr<MachOObjectFile>>
create(MemoryBufferRef Object,bool IsLittleEndian,bool Is64Bits,uint32_t UniversalCputype,uint32_t UniversalIndex,size_t MachOFilesetEntryOffset)12530b57cec5SDimitry Andric MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,
12540b57cec5SDimitry Andric                         bool Is64Bits, uint32_t UniversalCputype,
1255*c9157d92SDimitry Andric                         uint32_t UniversalIndex,
1256*c9157d92SDimitry Andric                         size_t MachOFilesetEntryOffset) {
12570b57cec5SDimitry Andric   Error Err = Error::success();
1258*c9157d92SDimitry Andric   std::unique_ptr<MachOObjectFile> Obj(new MachOObjectFile(
1259*c9157d92SDimitry Andric       std::move(Object), IsLittleEndian, Is64Bits, Err, UniversalCputype,
1260*c9157d92SDimitry Andric       UniversalIndex, MachOFilesetEntryOffset));
12610b57cec5SDimitry Andric   if (Err)
12620b57cec5SDimitry Andric     return std::move(Err);
12630b57cec5SDimitry Andric   return std::move(Obj);
12640b57cec5SDimitry Andric }
12650b57cec5SDimitry Andric 
MachOObjectFile(MemoryBufferRef Object,bool IsLittleEndian,bool Is64bits,Error & Err,uint32_t UniversalCputype,uint32_t UniversalIndex,size_t MachOFilesetEntryOffset)12660b57cec5SDimitry Andric MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
12670b57cec5SDimitry Andric                                  bool Is64bits, Error &Err,
12680b57cec5SDimitry Andric                                  uint32_t UniversalCputype,
1269*c9157d92SDimitry Andric                                  uint32_t UniversalIndex,
1270*c9157d92SDimitry Andric                                  size_t MachOFilesetEntryOffset)
1271*c9157d92SDimitry Andric     : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object),
1272*c9157d92SDimitry Andric       MachOFilesetEntryOffset(MachOFilesetEntryOffset) {
12730b57cec5SDimitry Andric   ErrorAsOutParameter ErrAsOutParam(&Err);
12740b57cec5SDimitry Andric   uint64_t SizeOfHeaders;
12750b57cec5SDimitry Andric   uint32_t cputype;
12760b57cec5SDimitry Andric   if (is64Bit()) {
12770b57cec5SDimitry Andric     parseHeader(*this, Header64, Err);
12780b57cec5SDimitry Andric     SizeOfHeaders = sizeof(MachO::mach_header_64);
12790b57cec5SDimitry Andric     cputype = Header64.cputype;
12800b57cec5SDimitry Andric   } else {
12810b57cec5SDimitry Andric     parseHeader(*this, Header, Err);
12820b57cec5SDimitry Andric     SizeOfHeaders = sizeof(MachO::mach_header);
12830b57cec5SDimitry Andric     cputype = Header.cputype;
12840b57cec5SDimitry Andric   }
12850b57cec5SDimitry Andric   if (Err)
12860b57cec5SDimitry Andric     return;
12870b57cec5SDimitry Andric   SizeOfHeaders += getHeader().sizeofcmds;
12880b57cec5SDimitry Andric   if (getData().data() + SizeOfHeaders > getData().end()) {
12890b57cec5SDimitry Andric     Err = malformedError("load commands extend past the end of the file");
12900b57cec5SDimitry Andric     return;
12910b57cec5SDimitry Andric   }
12920b57cec5SDimitry Andric   if (UniversalCputype != 0 && cputype != UniversalCputype) {
12930b57cec5SDimitry Andric     Err = malformedError("universal header architecture: " +
12940b57cec5SDimitry Andric                          Twine(UniversalIndex) + "'s cputype does not match "
12950b57cec5SDimitry Andric                          "object file's mach header");
12960b57cec5SDimitry Andric     return;
12970b57cec5SDimitry Andric   }
12980b57cec5SDimitry Andric   std::list<MachOElement> Elements;
12990b57cec5SDimitry Andric   Elements.push_back({0, SizeOfHeaders, "Mach-O headers"});
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric   uint32_t LoadCommandCount = getHeader().ncmds;
13020b57cec5SDimitry Andric   LoadCommandInfo Load;
13030b57cec5SDimitry Andric   if (LoadCommandCount != 0) {
13040b57cec5SDimitry Andric     if (auto LoadOrErr = getFirstLoadCommandInfo(*this))
13050b57cec5SDimitry Andric       Load = *LoadOrErr;
13060b57cec5SDimitry Andric     else {
13070b57cec5SDimitry Andric       Err = LoadOrErr.takeError();
13080b57cec5SDimitry Andric       return;
13090b57cec5SDimitry Andric     }
13100b57cec5SDimitry Andric   }
13110b57cec5SDimitry Andric 
13120b57cec5SDimitry Andric   const char *DyldIdLoadCmd = nullptr;
13130b57cec5SDimitry Andric   const char *SplitInfoLoadCmd = nullptr;
13140b57cec5SDimitry Andric   const char *CodeSignDrsLoadCmd = nullptr;
13150b57cec5SDimitry Andric   const char *CodeSignLoadCmd = nullptr;
13160b57cec5SDimitry Andric   const char *VersLoadCmd = nullptr;
13170b57cec5SDimitry Andric   const char *SourceLoadCmd = nullptr;
13180b57cec5SDimitry Andric   const char *EntryPointLoadCmd = nullptr;
13190b57cec5SDimitry Andric   const char *EncryptLoadCmd = nullptr;
13200b57cec5SDimitry Andric   const char *RoutinesLoadCmd = nullptr;
13210b57cec5SDimitry Andric   const char *UnixThreadLoadCmd = nullptr;
13220b57cec5SDimitry Andric   const char *TwoLevelHintsLoadCmd = nullptr;
13230b57cec5SDimitry Andric   for (unsigned I = 0; I < LoadCommandCount; ++I) {
13240b57cec5SDimitry Andric     if (is64Bit()) {
13250b57cec5SDimitry Andric       if (Load.C.cmdsize % 8 != 0) {
13260b57cec5SDimitry Andric         // We have a hack here to allow 64-bit Mach-O core files to have
13270b57cec5SDimitry Andric         // LC_THREAD commands that are only a multiple of 4 and not 8 to be
13280b57cec5SDimitry Andric         // allowed since the macOS kernel produces them.
13290b57cec5SDimitry Andric         if (getHeader().filetype != MachO::MH_CORE ||
13300b57cec5SDimitry Andric             Load.C.cmd != MachO::LC_THREAD || Load.C.cmdsize % 4) {
13310b57cec5SDimitry Andric           Err = malformedError("load command " + Twine(I) + " cmdsize not a "
13320b57cec5SDimitry Andric                                "multiple of 8");
13330b57cec5SDimitry Andric           return;
13340b57cec5SDimitry Andric         }
13350b57cec5SDimitry Andric       }
13360b57cec5SDimitry Andric     } else {
13370b57cec5SDimitry Andric       if (Load.C.cmdsize % 4 != 0) {
13380b57cec5SDimitry Andric         Err = malformedError("load command " + Twine(I) + " cmdsize not a "
13390b57cec5SDimitry Andric                              "multiple of 4");
13400b57cec5SDimitry Andric         return;
13410b57cec5SDimitry Andric       }
13420b57cec5SDimitry Andric     }
13430b57cec5SDimitry Andric     LoadCommands.push_back(Load);
13440b57cec5SDimitry Andric     if (Load.C.cmd == MachO::LC_SYMTAB) {
13450b57cec5SDimitry Andric       if ((Err = checkSymtabCommand(*this, Load, I, &SymtabLoadCmd, Elements)))
13460b57cec5SDimitry Andric         return;
13470b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_DYSYMTAB) {
13480b57cec5SDimitry Andric       if ((Err = checkDysymtabCommand(*this, Load, I, &DysymtabLoadCmd,
13490b57cec5SDimitry Andric                                       Elements)))
13500b57cec5SDimitry Andric         return;
13510b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) {
13520b57cec5SDimitry Andric       if ((Err = checkLinkeditDataCommand(*this, Load, I, &DataInCodeLoadCmd,
13530b57cec5SDimitry Andric                                           "LC_DATA_IN_CODE", Elements,
13540b57cec5SDimitry Andric                                           "data in code info")))
13550b57cec5SDimitry Andric         return;
13560b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) {
13570b57cec5SDimitry Andric       if ((Err = checkLinkeditDataCommand(*this, Load, I, &LinkOptHintsLoadCmd,
13580b57cec5SDimitry Andric                                           "LC_LINKER_OPTIMIZATION_HINT",
13590b57cec5SDimitry Andric                                           Elements, "linker optimization "
13600b57cec5SDimitry Andric                                           "hints")))
13610b57cec5SDimitry Andric         return;
13620b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_FUNCTION_STARTS) {
13630b57cec5SDimitry Andric       if ((Err = checkLinkeditDataCommand(*this, Load, I, &FuncStartsLoadCmd,
13640b57cec5SDimitry Andric                                           "LC_FUNCTION_STARTS", Elements,
13650b57cec5SDimitry Andric                                           "function starts data")))
13660b57cec5SDimitry Andric         return;
13670b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO) {
13680b57cec5SDimitry Andric       if ((Err = checkLinkeditDataCommand(*this, Load, I, &SplitInfoLoadCmd,
13690b57cec5SDimitry Andric                                           "LC_SEGMENT_SPLIT_INFO", Elements,
13700b57cec5SDimitry Andric                                           "split info data")))
13710b57cec5SDimitry Andric         return;
13720b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS) {
13730b57cec5SDimitry Andric       if ((Err = checkLinkeditDataCommand(*this, Load, I, &CodeSignDrsLoadCmd,
13740b57cec5SDimitry Andric                                           "LC_DYLIB_CODE_SIGN_DRS", Elements,
13750b57cec5SDimitry Andric                                           "code signing RDs data")))
13760b57cec5SDimitry Andric         return;
13770b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_CODE_SIGNATURE) {
13780b57cec5SDimitry Andric       if ((Err = checkLinkeditDataCommand(*this, Load, I, &CodeSignLoadCmd,
13790b57cec5SDimitry Andric                                           "LC_CODE_SIGNATURE", Elements,
13800b57cec5SDimitry Andric                                           "code signature data")))
13810b57cec5SDimitry Andric         return;
13820b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_DYLD_INFO) {
13830b57cec5SDimitry Andric       if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd,
13840b57cec5SDimitry Andric                                       "LC_DYLD_INFO", Elements)))
13850b57cec5SDimitry Andric         return;
13860b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
13870b57cec5SDimitry Andric       if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd,
13880b57cec5SDimitry Andric                                       "LC_DYLD_INFO_ONLY", Elements)))
13890b57cec5SDimitry Andric         return;
139081ad6265SDimitry Andric     } else if (Load.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS) {
139181ad6265SDimitry Andric       if ((Err = checkLinkeditDataCommand(
139281ad6265SDimitry Andric                *this, Load, I, &DyldChainedFixupsLoadCmd,
139381ad6265SDimitry Andric                "LC_DYLD_CHAINED_FIXUPS", Elements, "chained fixups")))
139481ad6265SDimitry Andric         return;
1395bdd1243dSDimitry Andric     } else if (Load.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE) {
1396bdd1243dSDimitry Andric       if ((Err = checkLinkeditDataCommand(
1397bdd1243dSDimitry Andric                *this, Load, I, &DyldExportsTrieLoadCmd, "LC_DYLD_EXPORTS_TRIE",
1398bdd1243dSDimitry Andric                Elements, "exports trie")))
1399bdd1243dSDimitry Andric         return;
14000b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_UUID) {
14010b57cec5SDimitry Andric       if (Load.C.cmdsize != sizeof(MachO::uuid_command)) {
14020b57cec5SDimitry Andric         Err = malformedError("LC_UUID command " + Twine(I) + " has incorrect "
14030b57cec5SDimitry Andric                              "cmdsize");
14040b57cec5SDimitry Andric         return;
14050b57cec5SDimitry Andric       }
14060b57cec5SDimitry Andric       if (UuidLoadCmd) {
14070b57cec5SDimitry Andric         Err = malformedError("more than one LC_UUID command");
14080b57cec5SDimitry Andric         return;
14090b57cec5SDimitry Andric       }
14100b57cec5SDimitry Andric       UuidLoadCmd = Load.Ptr;
14110b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SEGMENT_64) {
14120b57cec5SDimitry Andric       if ((Err = parseSegmentLoadCommand<MachO::segment_command_64,
14130b57cec5SDimitry Andric                                          MachO::section_64>(
14140b57cec5SDimitry Andric                    *this, Load, Sections, HasPageZeroSegment, I,
14150b57cec5SDimitry Andric                    "LC_SEGMENT_64", SizeOfHeaders, Elements)))
14160b57cec5SDimitry Andric         return;
14170b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SEGMENT) {
14180b57cec5SDimitry Andric       if ((Err = parseSegmentLoadCommand<MachO::segment_command,
14190b57cec5SDimitry Andric                                          MachO::section>(
14200b57cec5SDimitry Andric                    *this, Load, Sections, HasPageZeroSegment, I,
14210b57cec5SDimitry Andric                    "LC_SEGMENT", SizeOfHeaders, Elements)))
14220b57cec5SDimitry Andric         return;
14230b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_ID_DYLIB) {
14240b57cec5SDimitry Andric       if ((Err = checkDylibIdCommand(*this, Load, I, &DyldIdLoadCmd)))
14250b57cec5SDimitry Andric         return;
14260b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB) {
14270b57cec5SDimitry Andric       if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_DYLIB")))
14280b57cec5SDimitry Andric         return;
14290b57cec5SDimitry Andric       Libraries.push_back(Load.Ptr);
14300b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB) {
14310b57cec5SDimitry Andric       if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_WEAK_DYLIB")))
14320b57cec5SDimitry Andric         return;
14330b57cec5SDimitry Andric       Libraries.push_back(Load.Ptr);
14340b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB) {
14350b57cec5SDimitry Andric       if ((Err = checkDylibCommand(*this, Load, I, "LC_LAZY_LOAD_DYLIB")))
14360b57cec5SDimitry Andric         return;
14370b57cec5SDimitry Andric       Libraries.push_back(Load.Ptr);
14380b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB) {
14390b57cec5SDimitry Andric       if ((Err = checkDylibCommand(*this, Load, I, "LC_REEXPORT_DYLIB")))
14400b57cec5SDimitry Andric         return;
14410b57cec5SDimitry Andric       Libraries.push_back(Load.Ptr);
14420b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
14430b57cec5SDimitry Andric       if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_UPWARD_DYLIB")))
14440b57cec5SDimitry Andric         return;
14450b57cec5SDimitry Andric       Libraries.push_back(Load.Ptr);
14460b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_ID_DYLINKER) {
14470b57cec5SDimitry Andric       if ((Err = checkDyldCommand(*this, Load, I, "LC_ID_DYLINKER")))
14480b57cec5SDimitry Andric         return;
14490b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_LOAD_DYLINKER) {
14500b57cec5SDimitry Andric       if ((Err = checkDyldCommand(*this, Load, I, "LC_LOAD_DYLINKER")))
14510b57cec5SDimitry Andric         return;
14520b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {
14530b57cec5SDimitry Andric       if ((Err = checkDyldCommand(*this, Load, I, "LC_DYLD_ENVIRONMENT")))
14540b57cec5SDimitry Andric         return;
14550b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_VERSION_MIN_MACOSX) {
14560b57cec5SDimitry Andric       if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
14570b57cec5SDimitry Andric                                   "LC_VERSION_MIN_MACOSX")))
14580b57cec5SDimitry Andric         return;
14590b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS) {
14600b57cec5SDimitry Andric       if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
14610b57cec5SDimitry Andric                                   "LC_VERSION_MIN_IPHONEOS")))
14620b57cec5SDimitry Andric         return;
14630b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_VERSION_MIN_TVOS) {
14640b57cec5SDimitry Andric       if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
14650b57cec5SDimitry Andric                                   "LC_VERSION_MIN_TVOS")))
14660b57cec5SDimitry Andric         return;
14670b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
14680b57cec5SDimitry Andric       if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
14690b57cec5SDimitry Andric                                   "LC_VERSION_MIN_WATCHOS")))
14700b57cec5SDimitry Andric         return;
14710b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_NOTE) {
14720b57cec5SDimitry Andric       if ((Err = checkNoteCommand(*this, Load, I, Elements)))
14730b57cec5SDimitry Andric         return;
14740b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_BUILD_VERSION) {
14750b57cec5SDimitry Andric       if ((Err = parseBuildVersionCommand(*this, Load, BuildTools, I)))
14760b57cec5SDimitry Andric         return;
14770b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_RPATH) {
14780b57cec5SDimitry Andric       if ((Err = checkRpathCommand(*this, Load, I)))
14790b57cec5SDimitry Andric         return;
14800b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SOURCE_VERSION) {
14810b57cec5SDimitry Andric       if (Load.C.cmdsize != sizeof(MachO::source_version_command)) {
14820b57cec5SDimitry Andric         Err = malformedError("LC_SOURCE_VERSION command " + Twine(I) +
14830b57cec5SDimitry Andric                              " has incorrect cmdsize");
14840b57cec5SDimitry Andric         return;
14850b57cec5SDimitry Andric       }
14860b57cec5SDimitry Andric       if (SourceLoadCmd) {
14870b57cec5SDimitry Andric         Err = malformedError("more than one LC_SOURCE_VERSION command");
14880b57cec5SDimitry Andric         return;
14890b57cec5SDimitry Andric       }
14900b57cec5SDimitry Andric       SourceLoadCmd = Load.Ptr;
14910b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_MAIN) {
14920b57cec5SDimitry Andric       if (Load.C.cmdsize != sizeof(MachO::entry_point_command)) {
14930b57cec5SDimitry Andric         Err = malformedError("LC_MAIN command " + Twine(I) +
14940b57cec5SDimitry Andric                              " has incorrect cmdsize");
14950b57cec5SDimitry Andric         return;
14960b57cec5SDimitry Andric       }
14970b57cec5SDimitry Andric       if (EntryPointLoadCmd) {
14980b57cec5SDimitry Andric         Err = malformedError("more than one LC_MAIN command");
14990b57cec5SDimitry Andric         return;
15000b57cec5SDimitry Andric       }
15010b57cec5SDimitry Andric       EntryPointLoadCmd = Load.Ptr;
15020b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO) {
15030b57cec5SDimitry Andric       if (Load.C.cmdsize != sizeof(MachO::encryption_info_command)) {
15040b57cec5SDimitry Andric         Err = malformedError("LC_ENCRYPTION_INFO command " + Twine(I) +
15050b57cec5SDimitry Andric                              " has incorrect cmdsize");
15060b57cec5SDimitry Andric         return;
15070b57cec5SDimitry Andric       }
15080b57cec5SDimitry Andric       MachO::encryption_info_command E =
15090b57cec5SDimitry Andric         getStruct<MachO::encryption_info_command>(*this, Load.Ptr);
15100b57cec5SDimitry Andric       if ((Err = checkEncryptCommand(*this, Load, I, E.cryptoff, E.cryptsize,
15110b57cec5SDimitry Andric                                      &EncryptLoadCmd, "LC_ENCRYPTION_INFO")))
15120b57cec5SDimitry Andric         return;
15130b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
15140b57cec5SDimitry Andric       if (Load.C.cmdsize != sizeof(MachO::encryption_info_command_64)) {
15150b57cec5SDimitry Andric         Err = malformedError("LC_ENCRYPTION_INFO_64 command " + Twine(I) +
15160b57cec5SDimitry Andric                              " has incorrect cmdsize");
15170b57cec5SDimitry Andric         return;
15180b57cec5SDimitry Andric       }
15190b57cec5SDimitry Andric       MachO::encryption_info_command_64 E =
15200b57cec5SDimitry Andric         getStruct<MachO::encryption_info_command_64>(*this, Load.Ptr);
15210b57cec5SDimitry Andric       if ((Err = checkEncryptCommand(*this, Load, I, E.cryptoff, E.cryptsize,
15220b57cec5SDimitry Andric                                      &EncryptLoadCmd, "LC_ENCRYPTION_INFO_64")))
15230b57cec5SDimitry Andric         return;
15240b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_LINKER_OPTION) {
15250b57cec5SDimitry Andric       if ((Err = checkLinkerOptCommand(*this, Load, I)))
15260b57cec5SDimitry Andric         return;
15270b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SUB_FRAMEWORK) {
15280b57cec5SDimitry Andric       if (Load.C.cmdsize < sizeof(MachO::sub_framework_command)) {
15290b57cec5SDimitry Andric         Err =  malformedError("load command " + Twine(I) +
15300b57cec5SDimitry Andric                               " LC_SUB_FRAMEWORK cmdsize too small");
15310b57cec5SDimitry Andric         return;
15320b57cec5SDimitry Andric       }
15330b57cec5SDimitry Andric       MachO::sub_framework_command S =
15340b57cec5SDimitry Andric         getStruct<MachO::sub_framework_command>(*this, Load.Ptr);
15350b57cec5SDimitry Andric       if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_FRAMEWORK",
15360b57cec5SDimitry Andric                                  sizeof(MachO::sub_framework_command),
15370b57cec5SDimitry Andric                                  "sub_framework_command", S.umbrella,
15380b57cec5SDimitry Andric                                  "umbrella")))
15390b57cec5SDimitry Andric         return;
15400b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SUB_UMBRELLA) {
15410b57cec5SDimitry Andric       if (Load.C.cmdsize < sizeof(MachO::sub_umbrella_command)) {
15420b57cec5SDimitry Andric         Err =  malformedError("load command " + Twine(I) +
15430b57cec5SDimitry Andric                               " LC_SUB_UMBRELLA cmdsize too small");
15440b57cec5SDimitry Andric         return;
15450b57cec5SDimitry Andric       }
15460b57cec5SDimitry Andric       MachO::sub_umbrella_command S =
15470b57cec5SDimitry Andric         getStruct<MachO::sub_umbrella_command>(*this, Load.Ptr);
15480b57cec5SDimitry Andric       if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_UMBRELLA",
15490b57cec5SDimitry Andric                                  sizeof(MachO::sub_umbrella_command),
15500b57cec5SDimitry Andric                                  "sub_umbrella_command", S.sub_umbrella,
15510b57cec5SDimitry Andric                                  "sub_umbrella")))
15520b57cec5SDimitry Andric         return;
15530b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SUB_LIBRARY) {
15540b57cec5SDimitry Andric       if (Load.C.cmdsize < sizeof(MachO::sub_library_command)) {
15550b57cec5SDimitry Andric         Err =  malformedError("load command " + Twine(I) +
15560b57cec5SDimitry Andric                               " LC_SUB_LIBRARY cmdsize too small");
15570b57cec5SDimitry Andric         return;
15580b57cec5SDimitry Andric       }
15590b57cec5SDimitry Andric       MachO::sub_library_command S =
15600b57cec5SDimitry Andric         getStruct<MachO::sub_library_command>(*this, Load.Ptr);
15610b57cec5SDimitry Andric       if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_LIBRARY",
15620b57cec5SDimitry Andric                                  sizeof(MachO::sub_library_command),
15630b57cec5SDimitry Andric                                  "sub_library_command", S.sub_library,
15640b57cec5SDimitry Andric                                  "sub_library")))
15650b57cec5SDimitry Andric         return;
15660b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_SUB_CLIENT) {
15670b57cec5SDimitry Andric       if (Load.C.cmdsize < sizeof(MachO::sub_client_command)) {
15680b57cec5SDimitry Andric         Err =  malformedError("load command " + Twine(I) +
15690b57cec5SDimitry Andric                               " LC_SUB_CLIENT cmdsize too small");
15700b57cec5SDimitry Andric         return;
15710b57cec5SDimitry Andric       }
15720b57cec5SDimitry Andric       MachO::sub_client_command S =
15730b57cec5SDimitry Andric         getStruct<MachO::sub_client_command>(*this, Load.Ptr);
15740b57cec5SDimitry Andric       if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_CLIENT",
15750b57cec5SDimitry Andric                                  sizeof(MachO::sub_client_command),
15760b57cec5SDimitry Andric                                  "sub_client_command", S.client, "client")))
15770b57cec5SDimitry Andric         return;
15780b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_ROUTINES) {
15790b57cec5SDimitry Andric       if (Load.C.cmdsize != sizeof(MachO::routines_command)) {
15800b57cec5SDimitry Andric         Err = malformedError("LC_ROUTINES command " + Twine(I) +
15810b57cec5SDimitry Andric                              " has incorrect cmdsize");
15820b57cec5SDimitry Andric         return;
15830b57cec5SDimitry Andric       }
15840b57cec5SDimitry Andric       if (RoutinesLoadCmd) {
15850b57cec5SDimitry Andric         Err = malformedError("more than one LC_ROUTINES and or LC_ROUTINES_64 "
15860b57cec5SDimitry Andric                              "command");
15870b57cec5SDimitry Andric         return;
15880b57cec5SDimitry Andric       }
15890b57cec5SDimitry Andric       RoutinesLoadCmd = Load.Ptr;
15900b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_ROUTINES_64) {
15910b57cec5SDimitry Andric       if (Load.C.cmdsize != sizeof(MachO::routines_command_64)) {
15920b57cec5SDimitry Andric         Err = malformedError("LC_ROUTINES_64 command " + Twine(I) +
15930b57cec5SDimitry Andric                              " has incorrect cmdsize");
15940b57cec5SDimitry Andric         return;
15950b57cec5SDimitry Andric       }
15960b57cec5SDimitry Andric       if (RoutinesLoadCmd) {
15970b57cec5SDimitry Andric         Err = malformedError("more than one LC_ROUTINES_64 and or LC_ROUTINES "
15980b57cec5SDimitry Andric                              "command");
15990b57cec5SDimitry Andric         return;
16000b57cec5SDimitry Andric       }
16010b57cec5SDimitry Andric       RoutinesLoadCmd = Load.Ptr;
16020b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_UNIXTHREAD) {
16030b57cec5SDimitry Andric       if ((Err = checkThreadCommand(*this, Load, I, "LC_UNIXTHREAD")))
16040b57cec5SDimitry Andric         return;
16050b57cec5SDimitry Andric       if (UnixThreadLoadCmd) {
16060b57cec5SDimitry Andric         Err = malformedError("more than one LC_UNIXTHREAD command");
16070b57cec5SDimitry Andric         return;
16080b57cec5SDimitry Andric       }
16090b57cec5SDimitry Andric       UnixThreadLoadCmd = Load.Ptr;
16100b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_THREAD) {
16110b57cec5SDimitry Andric       if ((Err = checkThreadCommand(*this, Load, I, "LC_THREAD")))
16120b57cec5SDimitry Andric         return;
16130b57cec5SDimitry Andric     // Note: LC_TWOLEVEL_HINTS is really obsolete and is not supported.
16140b57cec5SDimitry Andric     } else if (Load.C.cmd == MachO::LC_TWOLEVEL_HINTS) {
16150b57cec5SDimitry Andric       if ((Err = checkTwoLevelHintsCommand(*this, Load, I,
16160b57cec5SDimitry Andric                                            &TwoLevelHintsLoadCmd, Elements)))
16170b57cec5SDimitry Andric         return;
1618e8d8bef9SDimitry Andric     } else if (Load.C.cmd == MachO::LC_IDENT) {
1619e8d8bef9SDimitry Andric       // Note: LC_IDENT is ignored.
1620e8d8bef9SDimitry Andric       continue;
16210b57cec5SDimitry Andric     } else if (isLoadCommandObsolete(Load.C.cmd)) {
16220b57cec5SDimitry Andric       Err = malformedError("load command " + Twine(I) + " for cmd value of: " +
16230b57cec5SDimitry Andric                            Twine(Load.C.cmd) + " is obsolete and not "
16240b57cec5SDimitry Andric                            "supported");
16250b57cec5SDimitry Andric       return;
16260b57cec5SDimitry Andric     }
16270b57cec5SDimitry Andric     // TODO: generate a error for unknown load commands by default.  But still
16280b57cec5SDimitry Andric     // need work out an approach to allow or not allow unknown values like this
16290b57cec5SDimitry Andric     // as an option for some uses like lldb.
16300b57cec5SDimitry Andric     if (I < LoadCommandCount - 1) {
16310b57cec5SDimitry Andric       if (auto LoadOrErr = getNextLoadCommandInfo(*this, I, Load))
16320b57cec5SDimitry Andric         Load = *LoadOrErr;
16330b57cec5SDimitry Andric       else {
16340b57cec5SDimitry Andric         Err = LoadOrErr.takeError();
16350b57cec5SDimitry Andric         return;
16360b57cec5SDimitry Andric       }
16370b57cec5SDimitry Andric     }
16380b57cec5SDimitry Andric   }
16390b57cec5SDimitry Andric   if (!SymtabLoadCmd) {
16400b57cec5SDimitry Andric     if (DysymtabLoadCmd) {
16410b57cec5SDimitry Andric       Err = malformedError("contains LC_DYSYMTAB load command without a "
16420b57cec5SDimitry Andric                            "LC_SYMTAB load command");
16430b57cec5SDimitry Andric       return;
16440b57cec5SDimitry Andric     }
16450b57cec5SDimitry Andric   } else if (DysymtabLoadCmd) {
16460b57cec5SDimitry Andric     MachO::symtab_command Symtab =
16470b57cec5SDimitry Andric       getStruct<MachO::symtab_command>(*this, SymtabLoadCmd);
16480b57cec5SDimitry Andric     MachO::dysymtab_command Dysymtab =
16490b57cec5SDimitry Andric       getStruct<MachO::dysymtab_command>(*this, DysymtabLoadCmd);
16500b57cec5SDimitry Andric     if (Dysymtab.nlocalsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) {
16510b57cec5SDimitry Andric       Err = malformedError("ilocalsym in LC_DYSYMTAB load command "
16520b57cec5SDimitry Andric                            "extends past the end of the symbol table");
16530b57cec5SDimitry Andric       return;
16540b57cec5SDimitry Andric     }
16550b57cec5SDimitry Andric     uint64_t BigSize = Dysymtab.ilocalsym;
16560b57cec5SDimitry Andric     BigSize += Dysymtab.nlocalsym;
16570b57cec5SDimitry Andric     if (Dysymtab.nlocalsym != 0 && BigSize > Symtab.nsyms) {
16580b57cec5SDimitry Andric       Err = malformedError("ilocalsym plus nlocalsym in LC_DYSYMTAB load "
16590b57cec5SDimitry Andric                            "command extends past the end of the symbol table");
16600b57cec5SDimitry Andric       return;
16610b57cec5SDimitry Andric     }
16620b57cec5SDimitry Andric     if (Dysymtab.nextdefsym != 0 && Dysymtab.iextdefsym > Symtab.nsyms) {
16630b57cec5SDimitry Andric       Err = malformedError("iextdefsym in LC_DYSYMTAB load command "
16640b57cec5SDimitry Andric                            "extends past the end of the symbol table");
16650b57cec5SDimitry Andric       return;
16660b57cec5SDimitry Andric     }
16670b57cec5SDimitry Andric     BigSize = Dysymtab.iextdefsym;
16680b57cec5SDimitry Andric     BigSize += Dysymtab.nextdefsym;
16690b57cec5SDimitry Andric     if (Dysymtab.nextdefsym != 0 && BigSize > Symtab.nsyms) {
16700b57cec5SDimitry Andric       Err = malformedError("iextdefsym plus nextdefsym in LC_DYSYMTAB "
16710b57cec5SDimitry Andric                            "load command extends past the end of the symbol "
16720b57cec5SDimitry Andric                            "table");
16730b57cec5SDimitry Andric       return;
16740b57cec5SDimitry Andric     }
16750b57cec5SDimitry Andric     if (Dysymtab.nundefsym != 0 && Dysymtab.iundefsym > Symtab.nsyms) {
16760b57cec5SDimitry Andric       Err = malformedError("iundefsym in LC_DYSYMTAB load command "
16770b57cec5SDimitry Andric                            "extends past the end of the symbol table");
16780b57cec5SDimitry Andric       return;
16790b57cec5SDimitry Andric     }
16800b57cec5SDimitry Andric     BigSize = Dysymtab.iundefsym;
16810b57cec5SDimitry Andric     BigSize += Dysymtab.nundefsym;
16820b57cec5SDimitry Andric     if (Dysymtab.nundefsym != 0 && BigSize > Symtab.nsyms) {
16830b57cec5SDimitry Andric       Err = malformedError("iundefsym plus nundefsym in LC_DYSYMTAB load "
16840b57cec5SDimitry Andric                            " command extends past the end of the symbol table");
16850b57cec5SDimitry Andric       return;
16860b57cec5SDimitry Andric     }
16870b57cec5SDimitry Andric   }
16880b57cec5SDimitry Andric   if ((getHeader().filetype == MachO::MH_DYLIB ||
16890b57cec5SDimitry Andric        getHeader().filetype == MachO::MH_DYLIB_STUB) &&
16900b57cec5SDimitry Andric        DyldIdLoadCmd == nullptr) {
16910b57cec5SDimitry Andric     Err = malformedError("no LC_ID_DYLIB load command in dynamic library "
16920b57cec5SDimitry Andric                          "filetype");
16930b57cec5SDimitry Andric     return;
16940b57cec5SDimitry Andric   }
16950b57cec5SDimitry Andric   assert(LoadCommands.size() == LoadCommandCount);
16960b57cec5SDimitry Andric 
16970b57cec5SDimitry Andric   Err = Error::success();
16980b57cec5SDimitry Andric }
16990b57cec5SDimitry Andric 
checkSymbolTable() const17000b57cec5SDimitry Andric Error MachOObjectFile::checkSymbolTable() const {
17010b57cec5SDimitry Andric   uint32_t Flags = 0;
17020b57cec5SDimitry Andric   if (is64Bit()) {
17030b57cec5SDimitry Andric     MachO::mach_header_64 H_64 = MachOObjectFile::getHeader64();
17040b57cec5SDimitry Andric     Flags = H_64.flags;
17050b57cec5SDimitry Andric   } else {
17060b57cec5SDimitry Andric     MachO::mach_header H = MachOObjectFile::getHeader();
17070b57cec5SDimitry Andric     Flags = H.flags;
17080b57cec5SDimitry Andric   }
17090b57cec5SDimitry Andric   uint8_t NType = 0;
17100b57cec5SDimitry Andric   uint8_t NSect = 0;
17110b57cec5SDimitry Andric   uint16_t NDesc = 0;
17120b57cec5SDimitry Andric   uint32_t NStrx = 0;
17130b57cec5SDimitry Andric   uint64_t NValue = 0;
17140b57cec5SDimitry Andric   uint32_t SymbolIndex = 0;
17150b57cec5SDimitry Andric   MachO::symtab_command S = getSymtabLoadCommand();
17160b57cec5SDimitry Andric   for (const SymbolRef &Symbol : symbols()) {
17170b57cec5SDimitry Andric     DataRefImpl SymDRI = Symbol.getRawDataRefImpl();
17180b57cec5SDimitry Andric     if (is64Bit()) {
17190b57cec5SDimitry Andric       MachO::nlist_64 STE_64 = getSymbol64TableEntry(SymDRI);
17200b57cec5SDimitry Andric       NType = STE_64.n_type;
17210b57cec5SDimitry Andric       NSect = STE_64.n_sect;
17220b57cec5SDimitry Andric       NDesc = STE_64.n_desc;
17230b57cec5SDimitry Andric       NStrx = STE_64.n_strx;
17240b57cec5SDimitry Andric       NValue = STE_64.n_value;
17250b57cec5SDimitry Andric     } else {
17260b57cec5SDimitry Andric       MachO::nlist STE = getSymbolTableEntry(SymDRI);
17270b57cec5SDimitry Andric       NType = STE.n_type;
17280b57cec5SDimitry Andric       NSect = STE.n_sect;
17290b57cec5SDimitry Andric       NDesc = STE.n_desc;
17300b57cec5SDimitry Andric       NStrx = STE.n_strx;
17310b57cec5SDimitry Andric       NValue = STE.n_value;
17320b57cec5SDimitry Andric     }
17330b57cec5SDimitry Andric     if ((NType & MachO::N_STAB) == 0) {
17340b57cec5SDimitry Andric       if ((NType & MachO::N_TYPE) == MachO::N_SECT) {
17350b57cec5SDimitry Andric         if (NSect == 0 || NSect > Sections.size())
17360b57cec5SDimitry Andric           return malformedError("bad section index: " + Twine((int)NSect) +
17370b57cec5SDimitry Andric                                 " for symbol at index " + Twine(SymbolIndex));
17380b57cec5SDimitry Andric       }
17390b57cec5SDimitry Andric       if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
17400b57cec5SDimitry Andric         if (NValue >= S.strsize)
17410b57cec5SDimitry Andric           return malformedError("bad n_value: " + Twine((int)NValue) + " past "
17420b57cec5SDimitry Andric                                 "the end of string table, for N_INDR symbol at "
17430b57cec5SDimitry Andric                                 "index " + Twine(SymbolIndex));
17440b57cec5SDimitry Andric       }
17450b57cec5SDimitry Andric       if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
17460b57cec5SDimitry Andric           (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
17470b57cec5SDimitry Andric            (NType & MachO::N_TYPE) == MachO::N_PBUD)) {
17480b57cec5SDimitry Andric             uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc);
17490b57cec5SDimitry Andric             if (LibraryOrdinal != 0 &&
17500b57cec5SDimitry Andric                 LibraryOrdinal != MachO::EXECUTABLE_ORDINAL &&
17510b57cec5SDimitry Andric                 LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL &&
17520b57cec5SDimitry Andric                 LibraryOrdinal - 1 >= Libraries.size() ) {
17530b57cec5SDimitry Andric               return malformedError("bad library ordinal: " + Twine(LibraryOrdinal) +
17540b57cec5SDimitry Andric                                     " for symbol at index " + Twine(SymbolIndex));
17550b57cec5SDimitry Andric             }
17560b57cec5SDimitry Andric           }
17570b57cec5SDimitry Andric     }
17580b57cec5SDimitry Andric     if (NStrx >= S.strsize)
17590b57cec5SDimitry Andric       return malformedError("bad string table index: " + Twine((int)NStrx) +
17600b57cec5SDimitry Andric                             " past the end of string table, for symbol at "
17610b57cec5SDimitry Andric                             "index " + Twine(SymbolIndex));
17620b57cec5SDimitry Andric     SymbolIndex++;
17630b57cec5SDimitry Andric   }
17640b57cec5SDimitry Andric   return Error::success();
17650b57cec5SDimitry Andric }
17660b57cec5SDimitry Andric 
moveSymbolNext(DataRefImpl & Symb) const17670b57cec5SDimitry Andric void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
17680b57cec5SDimitry Andric   unsigned SymbolTableEntrySize = is64Bit() ?
17690b57cec5SDimitry Andric     sizeof(MachO::nlist_64) :
17700b57cec5SDimitry Andric     sizeof(MachO::nlist);
17710b57cec5SDimitry Andric   Symb.p += SymbolTableEntrySize;
17720b57cec5SDimitry Andric }
17730b57cec5SDimitry Andric 
getSymbolName(DataRefImpl Symb) const17740b57cec5SDimitry Andric Expected<StringRef> MachOObjectFile::getSymbolName(DataRefImpl Symb) const {
17750b57cec5SDimitry Andric   StringRef StringTable = getStringTableData();
17760b57cec5SDimitry Andric   MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
17770b57cec5SDimitry Andric   if (Entry.n_strx == 0)
17780b57cec5SDimitry Andric     // A n_strx value of 0 indicates that no name is associated with a
17790b57cec5SDimitry Andric     // particular symbol table entry.
17800b57cec5SDimitry Andric     return StringRef();
17810b57cec5SDimitry Andric   const char *Start = &StringTable.data()[Entry.n_strx];
17820b57cec5SDimitry Andric   if (Start < getData().begin() || Start >= getData().end()) {
17830b57cec5SDimitry Andric     return malformedError("bad string index: " + Twine(Entry.n_strx) +
17840b57cec5SDimitry Andric                           " for symbol at index " + Twine(getSymbolIndex(Symb)));
17850b57cec5SDimitry Andric   }
17860b57cec5SDimitry Andric   return StringRef(Start);
17870b57cec5SDimitry Andric }
17880b57cec5SDimitry Andric 
getSectionType(SectionRef Sec) const17890b57cec5SDimitry Andric unsigned MachOObjectFile::getSectionType(SectionRef Sec) const {
17900b57cec5SDimitry Andric   DataRefImpl DRI = Sec.getRawDataRefImpl();
17910b57cec5SDimitry Andric   uint32_t Flags = getSectionFlags(*this, DRI);
17920b57cec5SDimitry Andric   return Flags & MachO::SECTION_TYPE;
17930b57cec5SDimitry Andric }
17940b57cec5SDimitry Andric 
getNValue(DataRefImpl Sym) const17950b57cec5SDimitry Andric uint64_t MachOObjectFile::getNValue(DataRefImpl Sym) const {
17960b57cec5SDimitry Andric   if (is64Bit()) {
17970b57cec5SDimitry Andric     MachO::nlist_64 Entry = getSymbol64TableEntry(Sym);
17980b57cec5SDimitry Andric     return Entry.n_value;
17990b57cec5SDimitry Andric   }
18000b57cec5SDimitry Andric   MachO::nlist Entry = getSymbolTableEntry(Sym);
18010b57cec5SDimitry Andric   return Entry.n_value;
18020b57cec5SDimitry Andric }
18030b57cec5SDimitry Andric 
18040b57cec5SDimitry Andric // getIndirectName() returns the name of the alias'ed symbol who's string table
18050b57cec5SDimitry Andric // index is in the n_value field.
getIndirectName(DataRefImpl Symb,StringRef & Res) const18060b57cec5SDimitry Andric std::error_code MachOObjectFile::getIndirectName(DataRefImpl Symb,
18070b57cec5SDimitry Andric                                                  StringRef &Res) const {
18080b57cec5SDimitry Andric   StringRef StringTable = getStringTableData();
18090b57cec5SDimitry Andric   MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
18100b57cec5SDimitry Andric   if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR)
18110b57cec5SDimitry Andric     return object_error::parse_failed;
18120b57cec5SDimitry Andric   uint64_t NValue = getNValue(Symb);
18130b57cec5SDimitry Andric   if (NValue >= StringTable.size())
18140b57cec5SDimitry Andric     return object_error::parse_failed;
18150b57cec5SDimitry Andric   const char *Start = &StringTable.data()[NValue];
18160b57cec5SDimitry Andric   Res = StringRef(Start);
18170b57cec5SDimitry Andric   return std::error_code();
18180b57cec5SDimitry Andric }
18190b57cec5SDimitry Andric 
getSymbolValueImpl(DataRefImpl Sym) const18200b57cec5SDimitry Andric uint64_t MachOObjectFile::getSymbolValueImpl(DataRefImpl Sym) const {
18210b57cec5SDimitry Andric   return getNValue(Sym);
18220b57cec5SDimitry Andric }
18230b57cec5SDimitry Andric 
getSymbolAddress(DataRefImpl Sym) const18240b57cec5SDimitry Andric Expected<uint64_t> MachOObjectFile::getSymbolAddress(DataRefImpl Sym) const {
18250b57cec5SDimitry Andric   return getSymbolValue(Sym);
18260b57cec5SDimitry Andric }
18270b57cec5SDimitry Andric 
getSymbolAlignment(DataRefImpl DRI) const18280b57cec5SDimitry Andric uint32_t MachOObjectFile::getSymbolAlignment(DataRefImpl DRI) const {
18295ffd83dbSDimitry Andric   uint32_t Flags = cantFail(getSymbolFlags(DRI));
18305ffd83dbSDimitry Andric   if (Flags & SymbolRef::SF_Common) {
18310b57cec5SDimitry Andric     MachO::nlist_base Entry = getSymbolTableEntryBase(*this, DRI);
18320b57cec5SDimitry Andric     return 1 << MachO::GET_COMM_ALIGN(Entry.n_desc);
18330b57cec5SDimitry Andric   }
18340b57cec5SDimitry Andric   return 0;
18350b57cec5SDimitry Andric }
18360b57cec5SDimitry Andric 
getCommonSymbolSizeImpl(DataRefImpl DRI) const18370b57cec5SDimitry Andric uint64_t MachOObjectFile::getCommonSymbolSizeImpl(DataRefImpl DRI) const {
18380b57cec5SDimitry Andric   return getNValue(DRI);
18390b57cec5SDimitry Andric }
18400b57cec5SDimitry Andric 
18410b57cec5SDimitry Andric Expected<SymbolRef::Type>
getSymbolType(DataRefImpl Symb) const18420b57cec5SDimitry Andric MachOObjectFile::getSymbolType(DataRefImpl Symb) const {
18430b57cec5SDimitry Andric   MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
18440b57cec5SDimitry Andric   uint8_t n_type = Entry.n_type;
18450b57cec5SDimitry Andric 
18460b57cec5SDimitry Andric   // If this is a STAB debugging symbol, we can do nothing more.
18470b57cec5SDimitry Andric   if (n_type & MachO::N_STAB)
18480b57cec5SDimitry Andric     return SymbolRef::ST_Debug;
18490b57cec5SDimitry Andric 
18500b57cec5SDimitry Andric   switch (n_type & MachO::N_TYPE) {
18510b57cec5SDimitry Andric     case MachO::N_UNDF :
18520b57cec5SDimitry Andric       return SymbolRef::ST_Unknown;
18530b57cec5SDimitry Andric     case MachO::N_SECT :
18540b57cec5SDimitry Andric       Expected<section_iterator> SecOrError = getSymbolSection(Symb);
18550b57cec5SDimitry Andric       if (!SecOrError)
18560b57cec5SDimitry Andric         return SecOrError.takeError();
18570b57cec5SDimitry Andric       section_iterator Sec = *SecOrError;
1858fe6060f1SDimitry Andric       if (Sec == section_end())
1859fe6060f1SDimitry Andric         return SymbolRef::ST_Other;
18600b57cec5SDimitry Andric       if (Sec->isData() || Sec->isBSS())
18610b57cec5SDimitry Andric         return SymbolRef::ST_Data;
18620b57cec5SDimitry Andric       return SymbolRef::ST_Function;
18630b57cec5SDimitry Andric   }
18640b57cec5SDimitry Andric   return SymbolRef::ST_Other;
18650b57cec5SDimitry Andric }
18660b57cec5SDimitry Andric 
getSymbolFlags(DataRefImpl DRI) const18675ffd83dbSDimitry Andric Expected<uint32_t> MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const {
18680b57cec5SDimitry Andric   MachO::nlist_base Entry = getSymbolTableEntryBase(*this, DRI);
18690b57cec5SDimitry Andric 
18700b57cec5SDimitry Andric   uint8_t MachOType = Entry.n_type;
18710b57cec5SDimitry Andric   uint16_t MachOFlags = Entry.n_desc;
18720b57cec5SDimitry Andric 
18730b57cec5SDimitry Andric   uint32_t Result = SymbolRef::SF_None;
18740b57cec5SDimitry Andric 
18750b57cec5SDimitry Andric   if ((MachOType & MachO::N_TYPE) == MachO::N_INDR)
18760b57cec5SDimitry Andric     Result |= SymbolRef::SF_Indirect;
18770b57cec5SDimitry Andric 
18780b57cec5SDimitry Andric   if (MachOType & MachO::N_STAB)
18790b57cec5SDimitry Andric     Result |= SymbolRef::SF_FormatSpecific;
18800b57cec5SDimitry Andric 
18810b57cec5SDimitry Andric   if (MachOType & MachO::N_EXT) {
18820b57cec5SDimitry Andric     Result |= SymbolRef::SF_Global;
18830b57cec5SDimitry Andric     if ((MachOType & MachO::N_TYPE) == MachO::N_UNDF) {
18840b57cec5SDimitry Andric       if (getNValue(DRI))
18850b57cec5SDimitry Andric         Result |= SymbolRef::SF_Common;
18860b57cec5SDimitry Andric       else
18870b57cec5SDimitry Andric         Result |= SymbolRef::SF_Undefined;
18880b57cec5SDimitry Andric     }
18890b57cec5SDimitry Andric 
1890bdd1243dSDimitry Andric     if (MachOType & MachO::N_PEXT)
1891bdd1243dSDimitry Andric       Result |= SymbolRef::SF_Hidden;
1892bdd1243dSDimitry Andric     else
18930b57cec5SDimitry Andric       Result |= SymbolRef::SF_Exported;
1894bdd1243dSDimitry Andric 
1895bdd1243dSDimitry Andric   } else if (MachOType & MachO::N_PEXT)
1896bdd1243dSDimitry Andric     Result |= SymbolRef::SF_Hidden;
18970b57cec5SDimitry Andric 
18980b57cec5SDimitry Andric   if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
18990b57cec5SDimitry Andric     Result |= SymbolRef::SF_Weak;
19000b57cec5SDimitry Andric 
19010b57cec5SDimitry Andric   if (MachOFlags & (MachO::N_ARM_THUMB_DEF))
19020b57cec5SDimitry Andric     Result |= SymbolRef::SF_Thumb;
19030b57cec5SDimitry Andric 
19040b57cec5SDimitry Andric   if ((MachOType & MachO::N_TYPE) == MachO::N_ABS)
19050b57cec5SDimitry Andric     Result |= SymbolRef::SF_Absolute;
19060b57cec5SDimitry Andric 
19070b57cec5SDimitry Andric   return Result;
19080b57cec5SDimitry Andric }
19090b57cec5SDimitry Andric 
19100b57cec5SDimitry Andric Expected<section_iterator>
getSymbolSection(DataRefImpl Symb) const19110b57cec5SDimitry Andric MachOObjectFile::getSymbolSection(DataRefImpl Symb) const {
19120b57cec5SDimitry Andric   MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
19130b57cec5SDimitry Andric   uint8_t index = Entry.n_sect;
19140b57cec5SDimitry Andric 
19150b57cec5SDimitry Andric   if (index == 0)
19160b57cec5SDimitry Andric     return section_end();
19170b57cec5SDimitry Andric   DataRefImpl DRI;
19180b57cec5SDimitry Andric   DRI.d.a = index - 1;
19190b57cec5SDimitry Andric   if (DRI.d.a >= Sections.size()){
19200b57cec5SDimitry Andric     return malformedError("bad section index: " + Twine((int)index) +
19210b57cec5SDimitry Andric                           " for symbol at index " + Twine(getSymbolIndex(Symb)));
19220b57cec5SDimitry Andric   }
19230b57cec5SDimitry Andric   return section_iterator(SectionRef(DRI, this));
19240b57cec5SDimitry Andric }
19250b57cec5SDimitry Andric 
getSymbolSectionID(SymbolRef Sym) const19260b57cec5SDimitry Andric unsigned MachOObjectFile::getSymbolSectionID(SymbolRef Sym) const {
19270b57cec5SDimitry Andric   MachO::nlist_base Entry =
19280b57cec5SDimitry Andric       getSymbolTableEntryBase(*this, Sym.getRawDataRefImpl());
19290b57cec5SDimitry Andric   return Entry.n_sect - 1;
19300b57cec5SDimitry Andric }
19310b57cec5SDimitry Andric 
moveSectionNext(DataRefImpl & Sec) const19320b57cec5SDimitry Andric void MachOObjectFile::moveSectionNext(DataRefImpl &Sec) const {
19330b57cec5SDimitry Andric   Sec.d.a++;
19340b57cec5SDimitry Andric }
19350b57cec5SDimitry Andric 
getSectionName(DataRefImpl Sec) const19360b57cec5SDimitry Andric Expected<StringRef> MachOObjectFile::getSectionName(DataRefImpl Sec) const {
19370b57cec5SDimitry Andric   ArrayRef<char> Raw = getSectionRawName(Sec);
19380b57cec5SDimitry Andric   return parseSegmentOrSectionName(Raw.data());
19390b57cec5SDimitry Andric }
19400b57cec5SDimitry Andric 
getSectionAddress(DataRefImpl Sec) const19410b57cec5SDimitry Andric uint64_t MachOObjectFile::getSectionAddress(DataRefImpl Sec) const {
19420b57cec5SDimitry Andric   if (is64Bit())
19430b57cec5SDimitry Andric     return getSection64(Sec).addr;
19440b57cec5SDimitry Andric   return getSection(Sec).addr;
19450b57cec5SDimitry Andric }
19460b57cec5SDimitry Andric 
getSectionIndex(DataRefImpl Sec) const19470b57cec5SDimitry Andric uint64_t MachOObjectFile::getSectionIndex(DataRefImpl Sec) const {
19480b57cec5SDimitry Andric   return Sec.d.a;
19490b57cec5SDimitry Andric }
19500b57cec5SDimitry Andric 
getSectionSize(DataRefImpl Sec) const19510b57cec5SDimitry Andric uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const {
19520b57cec5SDimitry Andric   // In the case if a malformed Mach-O file where the section offset is past
19530b57cec5SDimitry Andric   // the end of the file or some part of the section size is past the end of
19540b57cec5SDimitry Andric   // the file return a size of zero or a size that covers the rest of the file
19550b57cec5SDimitry Andric   // but does not extend past the end of the file.
19560b57cec5SDimitry Andric   uint32_t SectOffset, SectType;
19570b57cec5SDimitry Andric   uint64_t SectSize;
19580b57cec5SDimitry Andric 
19590b57cec5SDimitry Andric   if (is64Bit()) {
19600b57cec5SDimitry Andric     MachO::section_64 Sect = getSection64(Sec);
19610b57cec5SDimitry Andric     SectOffset = Sect.offset;
19620b57cec5SDimitry Andric     SectSize = Sect.size;
19630b57cec5SDimitry Andric     SectType = Sect.flags & MachO::SECTION_TYPE;
19640b57cec5SDimitry Andric   } else {
19650b57cec5SDimitry Andric     MachO::section Sect = getSection(Sec);
19660b57cec5SDimitry Andric     SectOffset = Sect.offset;
19670b57cec5SDimitry Andric     SectSize = Sect.size;
19680b57cec5SDimitry Andric     SectType = Sect.flags & MachO::SECTION_TYPE;
19690b57cec5SDimitry Andric   }
19700b57cec5SDimitry Andric   if (SectType == MachO::S_ZEROFILL || SectType == MachO::S_GB_ZEROFILL)
19710b57cec5SDimitry Andric     return SectSize;
19720b57cec5SDimitry Andric   uint64_t FileSize = getData().size();
19730b57cec5SDimitry Andric   if (SectOffset > FileSize)
19740b57cec5SDimitry Andric     return 0;
19750b57cec5SDimitry Andric   if (FileSize - SectOffset < SectSize)
19760b57cec5SDimitry Andric     return FileSize - SectOffset;
19770b57cec5SDimitry Andric   return SectSize;
19780b57cec5SDimitry Andric }
19790b57cec5SDimitry Andric 
getSectionContents(uint32_t Offset,uint64_t Size) const19808bcb0991SDimitry Andric ArrayRef<uint8_t> MachOObjectFile::getSectionContents(uint32_t Offset,
19818bcb0991SDimitry Andric                                                       uint64_t Size) const {
19828bcb0991SDimitry Andric   return arrayRefFromStringRef(getData().substr(Offset, Size));
19838bcb0991SDimitry Andric }
19848bcb0991SDimitry Andric 
19850b57cec5SDimitry Andric Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Sec) const19860b57cec5SDimitry Andric MachOObjectFile::getSectionContents(DataRefImpl Sec) const {
19870b57cec5SDimitry Andric   uint32_t Offset;
19880b57cec5SDimitry Andric   uint64_t Size;
19890b57cec5SDimitry Andric 
19900b57cec5SDimitry Andric   if (is64Bit()) {
19910b57cec5SDimitry Andric     MachO::section_64 Sect = getSection64(Sec);
19920b57cec5SDimitry Andric     Offset = Sect.offset;
19930b57cec5SDimitry Andric     Size = Sect.size;
19940b57cec5SDimitry Andric   } else {
19950b57cec5SDimitry Andric     MachO::section Sect = getSection(Sec);
19960b57cec5SDimitry Andric     Offset = Sect.offset;
19970b57cec5SDimitry Andric     Size = Sect.size;
19980b57cec5SDimitry Andric   }
19990b57cec5SDimitry Andric 
20008bcb0991SDimitry Andric   return getSectionContents(Offset, Size);
20010b57cec5SDimitry Andric }
20020b57cec5SDimitry Andric 
getSectionAlignment(DataRefImpl Sec) const20030b57cec5SDimitry Andric uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const {
20040b57cec5SDimitry Andric   uint32_t Align;
20050b57cec5SDimitry Andric   if (is64Bit()) {
20060b57cec5SDimitry Andric     MachO::section_64 Sect = getSection64(Sec);
20070b57cec5SDimitry Andric     Align = Sect.align;
20080b57cec5SDimitry Andric   } else {
20090b57cec5SDimitry Andric     MachO::section Sect = getSection(Sec);
20100b57cec5SDimitry Andric     Align = Sect.align;
20110b57cec5SDimitry Andric   }
20120b57cec5SDimitry Andric 
20130b57cec5SDimitry Andric   return uint64_t(1) << Align;
20140b57cec5SDimitry Andric }
20150b57cec5SDimitry Andric 
getSection(unsigned SectionIndex) const20160b57cec5SDimitry Andric Expected<SectionRef> MachOObjectFile::getSection(unsigned SectionIndex) const {
20170b57cec5SDimitry Andric   if (SectionIndex < 1 || SectionIndex > Sections.size())
20180b57cec5SDimitry Andric     return malformedError("bad section index: " + Twine((int)SectionIndex));
20190b57cec5SDimitry Andric 
20200b57cec5SDimitry Andric   DataRefImpl DRI;
20210b57cec5SDimitry Andric   DRI.d.a = SectionIndex - 1;
20220b57cec5SDimitry Andric   return SectionRef(DRI, this);
20230b57cec5SDimitry Andric }
20240b57cec5SDimitry Andric 
getSection(StringRef SectionName) const20250b57cec5SDimitry Andric Expected<SectionRef> MachOObjectFile::getSection(StringRef SectionName) const {
20260b57cec5SDimitry Andric   for (const SectionRef &Section : sections()) {
20278bcb0991SDimitry Andric     auto NameOrErr = Section.getName();
20288bcb0991SDimitry Andric     if (!NameOrErr)
20298bcb0991SDimitry Andric       return NameOrErr.takeError();
20308bcb0991SDimitry Andric     if (*NameOrErr == SectionName)
20310b57cec5SDimitry Andric       return Section;
20320b57cec5SDimitry Andric   }
20330b57cec5SDimitry Andric   return errorCodeToError(object_error::parse_failed);
20340b57cec5SDimitry Andric }
20350b57cec5SDimitry Andric 
isSectionCompressed(DataRefImpl Sec) const20360b57cec5SDimitry Andric bool MachOObjectFile::isSectionCompressed(DataRefImpl Sec) const {
20370b57cec5SDimitry Andric   return false;
20380b57cec5SDimitry Andric }
20390b57cec5SDimitry Andric 
isSectionText(DataRefImpl Sec) const20400b57cec5SDimitry Andric bool MachOObjectFile::isSectionText(DataRefImpl Sec) const {
20410b57cec5SDimitry Andric   uint32_t Flags = getSectionFlags(*this, Sec);
20420b57cec5SDimitry Andric   return Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;
20430b57cec5SDimitry Andric }
20440b57cec5SDimitry Andric 
isSectionData(DataRefImpl Sec) const20450b57cec5SDimitry Andric bool MachOObjectFile::isSectionData(DataRefImpl Sec) const {
20460b57cec5SDimitry Andric   uint32_t Flags = getSectionFlags(*this, Sec);
20470b57cec5SDimitry Andric   unsigned SectionType = Flags & MachO::SECTION_TYPE;
20480b57cec5SDimitry Andric   return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) &&
20490b57cec5SDimitry Andric          !(SectionType == MachO::S_ZEROFILL ||
20500b57cec5SDimitry Andric            SectionType == MachO::S_GB_ZEROFILL);
20510b57cec5SDimitry Andric }
20520b57cec5SDimitry Andric 
isSectionBSS(DataRefImpl Sec) const20530b57cec5SDimitry Andric bool MachOObjectFile::isSectionBSS(DataRefImpl Sec) const {
20540b57cec5SDimitry Andric   uint32_t Flags = getSectionFlags(*this, Sec);
20550b57cec5SDimitry Andric   unsigned SectionType = Flags & MachO::SECTION_TYPE;
20560b57cec5SDimitry Andric   return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) &&
20570b57cec5SDimitry Andric          (SectionType == MachO::S_ZEROFILL ||
20580b57cec5SDimitry Andric           SectionType == MachO::S_GB_ZEROFILL);
20590b57cec5SDimitry Andric }
20600b57cec5SDimitry Andric 
isDebugSection(DataRefImpl Sec) const2061fe6060f1SDimitry Andric bool MachOObjectFile::isDebugSection(DataRefImpl Sec) const {
2062fe6060f1SDimitry Andric   Expected<StringRef> SectionNameOrErr = getSectionName(Sec);
2063fe6060f1SDimitry Andric   if (!SectionNameOrErr) {
2064fe6060f1SDimitry Andric     // TODO: Report the error message properly.
2065fe6060f1SDimitry Andric     consumeError(SectionNameOrErr.takeError());
2066fe6060f1SDimitry Andric     return false;
2067fe6060f1SDimitry Andric   }
2068fe6060f1SDimitry Andric   StringRef SectionName = SectionNameOrErr.get();
2069*c9157d92SDimitry Andric   return SectionName.starts_with("__debug") ||
2070*c9157d92SDimitry Andric          SectionName.starts_with("__zdebug") ||
2071*c9157d92SDimitry Andric          SectionName.starts_with("__apple") || SectionName == "__gdb_index" ||
2072e8d8bef9SDimitry Andric          SectionName == "__swift_ast";
20735ffd83dbSDimitry Andric }
20745ffd83dbSDimitry Andric 
2075349cc55cSDimitry Andric namespace {
2076349cc55cSDimitry Andric template <typename LoadCommandType>
getSegmentContents(const MachOObjectFile & Obj,MachOObjectFile::LoadCommandInfo LoadCmd,StringRef SegmentName)2077349cc55cSDimitry Andric ArrayRef<uint8_t> getSegmentContents(const MachOObjectFile &Obj,
2078349cc55cSDimitry Andric                                      MachOObjectFile::LoadCommandInfo LoadCmd,
2079349cc55cSDimitry Andric                                      StringRef SegmentName) {
2080349cc55cSDimitry Andric   auto SegmentOrErr = getStructOrErr<LoadCommandType>(Obj, LoadCmd.Ptr);
2081349cc55cSDimitry Andric   if (!SegmentOrErr) {
2082349cc55cSDimitry Andric     consumeError(SegmentOrErr.takeError());
2083349cc55cSDimitry Andric     return {};
2084349cc55cSDimitry Andric   }
2085349cc55cSDimitry Andric   auto &Segment = SegmentOrErr.get();
2086*c9157d92SDimitry Andric   if (StringRef(Segment.segname, 16).starts_with(SegmentName))
2087349cc55cSDimitry Andric     return arrayRefFromStringRef(Obj.getData().slice(
2088349cc55cSDimitry Andric         Segment.fileoff, Segment.fileoff + Segment.filesize));
2089349cc55cSDimitry Andric   return {};
2090349cc55cSDimitry Andric }
2091bdd1243dSDimitry Andric 
2092bdd1243dSDimitry Andric template <typename LoadCommandType>
getSegmentContents(const MachOObjectFile & Obj,MachOObjectFile::LoadCommandInfo LoadCmd)2093bdd1243dSDimitry Andric ArrayRef<uint8_t> getSegmentContents(const MachOObjectFile &Obj,
2094bdd1243dSDimitry Andric                                      MachOObjectFile::LoadCommandInfo LoadCmd) {
2095bdd1243dSDimitry Andric   auto SegmentOrErr = getStructOrErr<LoadCommandType>(Obj, LoadCmd.Ptr);
2096bdd1243dSDimitry Andric   if (!SegmentOrErr) {
2097bdd1243dSDimitry Andric     consumeError(SegmentOrErr.takeError());
2098bdd1243dSDimitry Andric     return {};
2099bdd1243dSDimitry Andric   }
2100bdd1243dSDimitry Andric   auto &Segment = SegmentOrErr.get();
2101bdd1243dSDimitry Andric   return arrayRefFromStringRef(
2102bdd1243dSDimitry Andric       Obj.getData().slice(Segment.fileoff, Segment.fileoff + Segment.filesize));
2103bdd1243dSDimitry Andric }
2104349cc55cSDimitry Andric } // namespace
2105349cc55cSDimitry Andric 
2106349cc55cSDimitry Andric ArrayRef<uint8_t>
getSegmentContents(StringRef SegmentName) const2107349cc55cSDimitry Andric MachOObjectFile::getSegmentContents(StringRef SegmentName) const {
2108349cc55cSDimitry Andric   for (auto LoadCmd : load_commands()) {
2109349cc55cSDimitry Andric     ArrayRef<uint8_t> Contents;
2110349cc55cSDimitry Andric     switch (LoadCmd.C.cmd) {
2111349cc55cSDimitry Andric     case MachO::LC_SEGMENT:
2112349cc55cSDimitry Andric       Contents = ::getSegmentContents<MachO::segment_command>(*this, LoadCmd,
2113349cc55cSDimitry Andric                                                               SegmentName);
2114349cc55cSDimitry Andric       break;
2115349cc55cSDimitry Andric     case MachO::LC_SEGMENT_64:
2116349cc55cSDimitry Andric       Contents = ::getSegmentContents<MachO::segment_command_64>(*this, LoadCmd,
2117349cc55cSDimitry Andric                                                                  SegmentName);
2118349cc55cSDimitry Andric       break;
2119349cc55cSDimitry Andric     default:
2120349cc55cSDimitry Andric       continue;
2121349cc55cSDimitry Andric     }
2122349cc55cSDimitry Andric     if (!Contents.empty())
2123349cc55cSDimitry Andric       return Contents;
2124349cc55cSDimitry Andric   }
2125349cc55cSDimitry Andric   return {};
2126349cc55cSDimitry Andric }
2127349cc55cSDimitry Andric 
2128bdd1243dSDimitry Andric ArrayRef<uint8_t>
getSegmentContents(size_t SegmentIndex) const2129bdd1243dSDimitry Andric MachOObjectFile::getSegmentContents(size_t SegmentIndex) const {
2130bdd1243dSDimitry Andric   size_t Idx = 0;
2131bdd1243dSDimitry Andric   for (auto LoadCmd : load_commands()) {
2132bdd1243dSDimitry Andric     switch (LoadCmd.C.cmd) {
2133bdd1243dSDimitry Andric     case MachO::LC_SEGMENT:
2134bdd1243dSDimitry Andric       if (Idx == SegmentIndex)
2135bdd1243dSDimitry Andric         return ::getSegmentContents<MachO::segment_command>(*this, LoadCmd);
2136bdd1243dSDimitry Andric       ++Idx;
2137bdd1243dSDimitry Andric       break;
2138bdd1243dSDimitry Andric     case MachO::LC_SEGMENT_64:
2139bdd1243dSDimitry Andric       if (Idx == SegmentIndex)
2140bdd1243dSDimitry Andric         return ::getSegmentContents<MachO::segment_command_64>(*this, LoadCmd);
2141bdd1243dSDimitry Andric       ++Idx;
2142bdd1243dSDimitry Andric       break;
2143bdd1243dSDimitry Andric     default:
2144bdd1243dSDimitry Andric       continue;
2145bdd1243dSDimitry Andric     }
2146bdd1243dSDimitry Andric   }
2147bdd1243dSDimitry Andric   return {};
2148bdd1243dSDimitry Andric }
2149bdd1243dSDimitry Andric 
getSectionID(SectionRef Sec) const21500b57cec5SDimitry Andric unsigned MachOObjectFile::getSectionID(SectionRef Sec) const {
21510b57cec5SDimitry Andric   return Sec.getRawDataRefImpl().d.a;
21520b57cec5SDimitry Andric }
21530b57cec5SDimitry Andric 
isSectionVirtual(DataRefImpl Sec) const21540b57cec5SDimitry Andric bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const {
21550b57cec5SDimitry Andric   uint32_t Flags = getSectionFlags(*this, Sec);
21560b57cec5SDimitry Andric   unsigned SectionType = Flags & MachO::SECTION_TYPE;
21570b57cec5SDimitry Andric   return SectionType == MachO::S_ZEROFILL ||
21580b57cec5SDimitry Andric          SectionType == MachO::S_GB_ZEROFILL;
21590b57cec5SDimitry Andric }
21600b57cec5SDimitry Andric 
isSectionBitcode(DataRefImpl Sec) const21610b57cec5SDimitry Andric bool MachOObjectFile::isSectionBitcode(DataRefImpl Sec) const {
21620b57cec5SDimitry Andric   StringRef SegmentName = getSectionFinalSegmentName(Sec);
21630b57cec5SDimitry Andric   if (Expected<StringRef> NameOrErr = getSectionName(Sec))
21640b57cec5SDimitry Andric     return (SegmentName == "__LLVM" && *NameOrErr == "__bitcode");
21650b57cec5SDimitry Andric   return false;
21660b57cec5SDimitry Andric }
21670b57cec5SDimitry Andric 
isSectionStripped(DataRefImpl Sec) const21680b57cec5SDimitry Andric bool MachOObjectFile::isSectionStripped(DataRefImpl Sec) const {
21690b57cec5SDimitry Andric   if (is64Bit())
21700b57cec5SDimitry Andric     return getSection64(Sec).offset == 0;
21710b57cec5SDimitry Andric   return getSection(Sec).offset == 0;
21720b57cec5SDimitry Andric }
21730b57cec5SDimitry Andric 
section_rel_begin(DataRefImpl Sec) const21740b57cec5SDimitry Andric relocation_iterator MachOObjectFile::section_rel_begin(DataRefImpl Sec) const {
21750b57cec5SDimitry Andric   DataRefImpl Ret;
21760b57cec5SDimitry Andric   Ret.d.a = Sec.d.a;
21770b57cec5SDimitry Andric   Ret.d.b = 0;
21780b57cec5SDimitry Andric   return relocation_iterator(RelocationRef(Ret, this));
21790b57cec5SDimitry Andric }
21800b57cec5SDimitry Andric 
21810b57cec5SDimitry Andric relocation_iterator
section_rel_end(DataRefImpl Sec) const21820b57cec5SDimitry Andric MachOObjectFile::section_rel_end(DataRefImpl Sec) const {
21830b57cec5SDimitry Andric   uint32_t Num;
21840b57cec5SDimitry Andric   if (is64Bit()) {
21850b57cec5SDimitry Andric     MachO::section_64 Sect = getSection64(Sec);
21860b57cec5SDimitry Andric     Num = Sect.nreloc;
21870b57cec5SDimitry Andric   } else {
21880b57cec5SDimitry Andric     MachO::section Sect = getSection(Sec);
21890b57cec5SDimitry Andric     Num = Sect.nreloc;
21900b57cec5SDimitry Andric   }
21910b57cec5SDimitry Andric 
21920b57cec5SDimitry Andric   DataRefImpl Ret;
21930b57cec5SDimitry Andric   Ret.d.a = Sec.d.a;
21940b57cec5SDimitry Andric   Ret.d.b = Num;
21950b57cec5SDimitry Andric   return relocation_iterator(RelocationRef(Ret, this));
21960b57cec5SDimitry Andric }
21970b57cec5SDimitry Andric 
extrel_begin() const21980b57cec5SDimitry Andric relocation_iterator MachOObjectFile::extrel_begin() const {
21990b57cec5SDimitry Andric   DataRefImpl Ret;
22000b57cec5SDimitry Andric   // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations
22010b57cec5SDimitry Andric   Ret.d.a = 0; // Would normally be a section index.
22020b57cec5SDimitry Andric   Ret.d.b = 0; // Index into the external relocations
22030b57cec5SDimitry Andric   return relocation_iterator(RelocationRef(Ret, this));
22040b57cec5SDimitry Andric }
22050b57cec5SDimitry Andric 
extrel_end() const22060b57cec5SDimitry Andric relocation_iterator MachOObjectFile::extrel_end() const {
22070b57cec5SDimitry Andric   MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();
22080b57cec5SDimitry Andric   DataRefImpl Ret;
22090b57cec5SDimitry Andric   // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations
22100b57cec5SDimitry Andric   Ret.d.a = 0; // Would normally be a section index.
22110b57cec5SDimitry Andric   Ret.d.b = DysymtabLoadCmd.nextrel; // Index into the external relocations
22120b57cec5SDimitry Andric   return relocation_iterator(RelocationRef(Ret, this));
22130b57cec5SDimitry Andric }
22140b57cec5SDimitry Andric 
locrel_begin() const22150b57cec5SDimitry Andric relocation_iterator MachOObjectFile::locrel_begin() const {
22160b57cec5SDimitry Andric   DataRefImpl Ret;
22170b57cec5SDimitry Andric   // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations
22180b57cec5SDimitry Andric   Ret.d.a = 1; // Would normally be a section index.
22190b57cec5SDimitry Andric   Ret.d.b = 0; // Index into the local relocations
22200b57cec5SDimitry Andric   return relocation_iterator(RelocationRef(Ret, this));
22210b57cec5SDimitry Andric }
22220b57cec5SDimitry Andric 
locrel_end() const22230b57cec5SDimitry Andric relocation_iterator MachOObjectFile::locrel_end() const {
22240b57cec5SDimitry Andric   MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();
22250b57cec5SDimitry Andric   DataRefImpl Ret;
22260b57cec5SDimitry Andric   // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations
22270b57cec5SDimitry Andric   Ret.d.a = 1; // Would normally be a section index.
22280b57cec5SDimitry Andric   Ret.d.b = DysymtabLoadCmd.nlocrel; // Index into the local relocations
22290b57cec5SDimitry Andric   return relocation_iterator(RelocationRef(Ret, this));
22300b57cec5SDimitry Andric }
22310b57cec5SDimitry Andric 
moveRelocationNext(DataRefImpl & Rel) const22320b57cec5SDimitry Andric void MachOObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
22330b57cec5SDimitry Andric   ++Rel.d.b;
22340b57cec5SDimitry Andric }
22350b57cec5SDimitry Andric 
getRelocationOffset(DataRefImpl Rel) const22360b57cec5SDimitry Andric uint64_t MachOObjectFile::getRelocationOffset(DataRefImpl Rel) const {
22370b57cec5SDimitry Andric   assert((getHeader().filetype == MachO::MH_OBJECT ||
22380b57cec5SDimitry Andric           getHeader().filetype == MachO::MH_KEXT_BUNDLE) &&
22390b57cec5SDimitry Andric          "Only implemented for MH_OBJECT && MH_KEXT_BUNDLE");
22400b57cec5SDimitry Andric   MachO::any_relocation_info RE = getRelocation(Rel);
22410b57cec5SDimitry Andric   return getAnyRelocationAddress(RE);
22420b57cec5SDimitry Andric }
22430b57cec5SDimitry Andric 
22440b57cec5SDimitry Andric symbol_iterator
getRelocationSymbol(DataRefImpl Rel) const22450b57cec5SDimitry Andric MachOObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
22460b57cec5SDimitry Andric   MachO::any_relocation_info RE = getRelocation(Rel);
22470b57cec5SDimitry Andric   if (isRelocationScattered(RE))
22480b57cec5SDimitry Andric     return symbol_end();
22490b57cec5SDimitry Andric 
22500b57cec5SDimitry Andric   uint32_t SymbolIdx = getPlainRelocationSymbolNum(RE);
22510b57cec5SDimitry Andric   bool isExtern = getPlainRelocationExternal(RE);
22520b57cec5SDimitry Andric   if (!isExtern)
22530b57cec5SDimitry Andric     return symbol_end();
22540b57cec5SDimitry Andric 
22550b57cec5SDimitry Andric   MachO::symtab_command S = getSymtabLoadCommand();
22560b57cec5SDimitry Andric   unsigned SymbolTableEntrySize = is64Bit() ?
22570b57cec5SDimitry Andric     sizeof(MachO::nlist_64) :
22580b57cec5SDimitry Andric     sizeof(MachO::nlist);
22590b57cec5SDimitry Andric   uint64_t Offset = S.symoff + SymbolIdx * SymbolTableEntrySize;
22600b57cec5SDimitry Andric   DataRefImpl Sym;
22610b57cec5SDimitry Andric   Sym.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));
22620b57cec5SDimitry Andric   return symbol_iterator(SymbolRef(Sym, this));
22630b57cec5SDimitry Andric }
22640b57cec5SDimitry Andric 
22650b57cec5SDimitry Andric section_iterator
getRelocationSection(DataRefImpl Rel) const22660b57cec5SDimitry Andric MachOObjectFile::getRelocationSection(DataRefImpl Rel) const {
22670b57cec5SDimitry Andric   return section_iterator(getAnyRelocationSection(getRelocation(Rel)));
22680b57cec5SDimitry Andric }
22690b57cec5SDimitry Andric 
getRelocationType(DataRefImpl Rel) const22700b57cec5SDimitry Andric uint64_t MachOObjectFile::getRelocationType(DataRefImpl Rel) const {
22710b57cec5SDimitry Andric   MachO::any_relocation_info RE = getRelocation(Rel);
22720b57cec5SDimitry Andric   return getAnyRelocationType(RE);
22730b57cec5SDimitry Andric }
22740b57cec5SDimitry Andric 
getRelocationTypeName(DataRefImpl Rel,SmallVectorImpl<char> & Result) const22750b57cec5SDimitry Andric void MachOObjectFile::getRelocationTypeName(
22760b57cec5SDimitry Andric     DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
22770b57cec5SDimitry Andric   StringRef res;
22780b57cec5SDimitry Andric   uint64_t RType = getRelocationType(Rel);
22790b57cec5SDimitry Andric 
22800b57cec5SDimitry Andric   unsigned Arch = this->getArch();
22810b57cec5SDimitry Andric 
22820b57cec5SDimitry Andric   switch (Arch) {
22830b57cec5SDimitry Andric     case Triple::x86: {
22840b57cec5SDimitry Andric       static const char *const Table[] =  {
22850b57cec5SDimitry Andric         "GENERIC_RELOC_VANILLA",
22860b57cec5SDimitry Andric         "GENERIC_RELOC_PAIR",
22870b57cec5SDimitry Andric         "GENERIC_RELOC_SECTDIFF",
22880b57cec5SDimitry Andric         "GENERIC_RELOC_PB_LA_PTR",
22890b57cec5SDimitry Andric         "GENERIC_RELOC_LOCAL_SECTDIFF",
22900b57cec5SDimitry Andric         "GENERIC_RELOC_TLV" };
22910b57cec5SDimitry Andric 
22920b57cec5SDimitry Andric       if (RType > 5)
22930b57cec5SDimitry Andric         res = "Unknown";
22940b57cec5SDimitry Andric       else
22950b57cec5SDimitry Andric         res = Table[RType];
22960b57cec5SDimitry Andric       break;
22970b57cec5SDimitry Andric     }
22980b57cec5SDimitry Andric     case Triple::x86_64: {
22990b57cec5SDimitry Andric       static const char *const Table[] =  {
23000b57cec5SDimitry Andric         "X86_64_RELOC_UNSIGNED",
23010b57cec5SDimitry Andric         "X86_64_RELOC_SIGNED",
23020b57cec5SDimitry Andric         "X86_64_RELOC_BRANCH",
23030b57cec5SDimitry Andric         "X86_64_RELOC_GOT_LOAD",
23040b57cec5SDimitry Andric         "X86_64_RELOC_GOT",
23050b57cec5SDimitry Andric         "X86_64_RELOC_SUBTRACTOR",
23060b57cec5SDimitry Andric         "X86_64_RELOC_SIGNED_1",
23070b57cec5SDimitry Andric         "X86_64_RELOC_SIGNED_2",
23080b57cec5SDimitry Andric         "X86_64_RELOC_SIGNED_4",
23090b57cec5SDimitry Andric         "X86_64_RELOC_TLV" };
23100b57cec5SDimitry Andric 
23110b57cec5SDimitry Andric       if (RType > 9)
23120b57cec5SDimitry Andric         res = "Unknown";
23130b57cec5SDimitry Andric       else
23140b57cec5SDimitry Andric         res = Table[RType];
23150b57cec5SDimitry Andric       break;
23160b57cec5SDimitry Andric     }
23170b57cec5SDimitry Andric     case Triple::arm: {
23180b57cec5SDimitry Andric       static const char *const Table[] =  {
23190b57cec5SDimitry Andric         "ARM_RELOC_VANILLA",
23200b57cec5SDimitry Andric         "ARM_RELOC_PAIR",
23210b57cec5SDimitry Andric         "ARM_RELOC_SECTDIFF",
23220b57cec5SDimitry Andric         "ARM_RELOC_LOCAL_SECTDIFF",
23230b57cec5SDimitry Andric         "ARM_RELOC_PB_LA_PTR",
23240b57cec5SDimitry Andric         "ARM_RELOC_BR24",
23250b57cec5SDimitry Andric         "ARM_THUMB_RELOC_BR22",
23260b57cec5SDimitry Andric         "ARM_THUMB_32BIT_BRANCH",
23270b57cec5SDimitry Andric         "ARM_RELOC_HALF",
23280b57cec5SDimitry Andric         "ARM_RELOC_HALF_SECTDIFF" };
23290b57cec5SDimitry Andric 
23300b57cec5SDimitry Andric       if (RType > 9)
23310b57cec5SDimitry Andric         res = "Unknown";
23320b57cec5SDimitry Andric       else
23330b57cec5SDimitry Andric         res = Table[RType];
23340b57cec5SDimitry Andric       break;
23350b57cec5SDimitry Andric     }
23360b57cec5SDimitry Andric     case Triple::aarch64:
23370b57cec5SDimitry Andric     case Triple::aarch64_32: {
23380b57cec5SDimitry Andric       static const char *const Table[] = {
23390b57cec5SDimitry Andric         "ARM64_RELOC_UNSIGNED",           "ARM64_RELOC_SUBTRACTOR",
23400b57cec5SDimitry Andric         "ARM64_RELOC_BRANCH26",           "ARM64_RELOC_PAGE21",
23410b57cec5SDimitry Andric         "ARM64_RELOC_PAGEOFF12",          "ARM64_RELOC_GOT_LOAD_PAGE21",
23420b57cec5SDimitry Andric         "ARM64_RELOC_GOT_LOAD_PAGEOFF12", "ARM64_RELOC_POINTER_TO_GOT",
23430b57cec5SDimitry Andric         "ARM64_RELOC_TLVP_LOAD_PAGE21",   "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
23440b57cec5SDimitry Andric         "ARM64_RELOC_ADDEND"
23450b57cec5SDimitry Andric       };
23460b57cec5SDimitry Andric 
2347bdd1243dSDimitry Andric       if (RType >= std::size(Table))
23480b57cec5SDimitry Andric         res = "Unknown";
23490b57cec5SDimitry Andric       else
23500b57cec5SDimitry Andric         res = Table[RType];
23510b57cec5SDimitry Andric       break;
23520b57cec5SDimitry Andric     }
23530b57cec5SDimitry Andric     case Triple::ppc: {
23540b57cec5SDimitry Andric       static const char *const Table[] =  {
23550b57cec5SDimitry Andric         "PPC_RELOC_VANILLA",
23560b57cec5SDimitry Andric         "PPC_RELOC_PAIR",
23570b57cec5SDimitry Andric         "PPC_RELOC_BR14",
23580b57cec5SDimitry Andric         "PPC_RELOC_BR24",
23590b57cec5SDimitry Andric         "PPC_RELOC_HI16",
23600b57cec5SDimitry Andric         "PPC_RELOC_LO16",
23610b57cec5SDimitry Andric         "PPC_RELOC_HA16",
23620b57cec5SDimitry Andric         "PPC_RELOC_LO14",
23630b57cec5SDimitry Andric         "PPC_RELOC_SECTDIFF",
23640b57cec5SDimitry Andric         "PPC_RELOC_PB_LA_PTR",
23650b57cec5SDimitry Andric         "PPC_RELOC_HI16_SECTDIFF",
23660b57cec5SDimitry Andric         "PPC_RELOC_LO16_SECTDIFF",
23670b57cec5SDimitry Andric         "PPC_RELOC_HA16_SECTDIFF",
23680b57cec5SDimitry Andric         "PPC_RELOC_JBSR",
23690b57cec5SDimitry Andric         "PPC_RELOC_LO14_SECTDIFF",
23700b57cec5SDimitry Andric         "PPC_RELOC_LOCAL_SECTDIFF" };
23710b57cec5SDimitry Andric 
23720b57cec5SDimitry Andric       if (RType > 15)
23730b57cec5SDimitry Andric         res = "Unknown";
23740b57cec5SDimitry Andric       else
23750b57cec5SDimitry Andric         res = Table[RType];
23760b57cec5SDimitry Andric       break;
23770b57cec5SDimitry Andric     }
23780b57cec5SDimitry Andric     case Triple::UnknownArch:
23790b57cec5SDimitry Andric       res = "Unknown";
23800b57cec5SDimitry Andric       break;
23810b57cec5SDimitry Andric   }
23820b57cec5SDimitry Andric   Result.append(res.begin(), res.end());
23830b57cec5SDimitry Andric }
23840b57cec5SDimitry Andric 
getRelocationLength(DataRefImpl Rel) const23850b57cec5SDimitry Andric uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const {
23860b57cec5SDimitry Andric   MachO::any_relocation_info RE = getRelocation(Rel);
23870b57cec5SDimitry Andric   return getAnyRelocationLength(RE);
23880b57cec5SDimitry Andric }
23890b57cec5SDimitry Andric 
23900b57cec5SDimitry Andric //
23910b57cec5SDimitry Andric // guessLibraryShortName() is passed a name of a dynamic library and returns a
23920b57cec5SDimitry Andric // guess on what the short name is.  Then name is returned as a substring of the
23930b57cec5SDimitry Andric // StringRef Name passed in.  The name of the dynamic library is recognized as
23940b57cec5SDimitry Andric // a framework if it has one of the two following forms:
23950b57cec5SDimitry Andric //      Foo.framework/Versions/A/Foo
23960b57cec5SDimitry Andric //      Foo.framework/Foo
23970b57cec5SDimitry Andric // Where A and Foo can be any string.  And may contain a trailing suffix
23980b57cec5SDimitry Andric // starting with an underbar.  If the Name is recognized as a framework then
23990b57cec5SDimitry Andric // isFramework is set to true else it is set to false.  If the Name has a
24000b57cec5SDimitry Andric // suffix then Suffix is set to the substring in Name that contains the suffix
24010b57cec5SDimitry Andric // else it is set to a NULL StringRef.
24020b57cec5SDimitry Andric //
24030b57cec5SDimitry Andric // The Name of the dynamic library is recognized as a library name if it has
24040b57cec5SDimitry Andric // one of the two following forms:
24050b57cec5SDimitry Andric //      libFoo.A.dylib
24060b57cec5SDimitry Andric //      libFoo.dylib
24070b57cec5SDimitry Andric //
24080b57cec5SDimitry Andric // The library may have a suffix trailing the name Foo of the form:
24090b57cec5SDimitry Andric //      libFoo_profile.A.dylib
24100b57cec5SDimitry Andric //      libFoo_profile.dylib
24110b57cec5SDimitry Andric // These dyld image suffixes are separated from the short name by a '_'
24120b57cec5SDimitry Andric // character. Because the '_' character is commonly used to separate words in
24130b57cec5SDimitry Andric // filenames guessLibraryShortName() cannot reliably separate a dylib's short
24140b57cec5SDimitry Andric // name from an arbitrary image suffix; imagine if both the short name and the
24150b57cec5SDimitry Andric // suffix contains an '_' character! To better deal with this ambiguity,
24160b57cec5SDimitry Andric // guessLibraryShortName() will recognize only "_debug" and "_profile" as valid
24170b57cec5SDimitry Andric // Suffix values. Calling code needs to be tolerant of guessLibraryShortName()
24180b57cec5SDimitry Andric // guessing incorrectly.
24190b57cec5SDimitry Andric //
24200b57cec5SDimitry Andric // The Name of the dynamic library is also recognized as a library name if it
24210b57cec5SDimitry Andric // has the following form:
24220b57cec5SDimitry Andric //      Foo.qtx
24230b57cec5SDimitry Andric //
24240b57cec5SDimitry Andric // If the Name of the dynamic library is none of the forms above then a NULL
24250b57cec5SDimitry Andric // StringRef is returned.
guessLibraryShortName(StringRef Name,bool & isFramework,StringRef & Suffix)24260b57cec5SDimitry Andric StringRef MachOObjectFile::guessLibraryShortName(StringRef Name,
24270b57cec5SDimitry Andric                                                  bool &isFramework,
24280b57cec5SDimitry Andric                                                  StringRef &Suffix) {
24290b57cec5SDimitry Andric   StringRef Foo, F, DotFramework, V, Dylib, Lib, Dot, Qtx;
24300b57cec5SDimitry Andric   size_t a, b, c, d, Idx;
24310b57cec5SDimitry Andric 
24320b57cec5SDimitry Andric   isFramework = false;
24330b57cec5SDimitry Andric   Suffix = StringRef();
24340b57cec5SDimitry Andric 
24350b57cec5SDimitry Andric   // Pull off the last component and make Foo point to it
24360b57cec5SDimitry Andric   a = Name.rfind('/');
24370b57cec5SDimitry Andric   if (a == Name.npos || a == 0)
24380b57cec5SDimitry Andric     goto guess_library;
24390b57cec5SDimitry Andric   Foo = Name.slice(a+1, Name.npos);
24400b57cec5SDimitry Andric 
24410b57cec5SDimitry Andric   // Look for a suffix starting with a '_'
24420b57cec5SDimitry Andric   Idx = Foo.rfind('_');
24430b57cec5SDimitry Andric   if (Idx != Foo.npos && Foo.size() >= 2) {
24440b57cec5SDimitry Andric     Suffix = Foo.slice(Idx, Foo.npos);
24450b57cec5SDimitry Andric     if (Suffix != "_debug" && Suffix != "_profile")
24460b57cec5SDimitry Andric       Suffix = StringRef();
24470b57cec5SDimitry Andric     else
24480b57cec5SDimitry Andric       Foo = Foo.slice(0, Idx);
24490b57cec5SDimitry Andric   }
24500b57cec5SDimitry Andric 
24510b57cec5SDimitry Andric   // First look for the form Foo.framework/Foo
24520b57cec5SDimitry Andric   b = Name.rfind('/', a);
24530b57cec5SDimitry Andric   if (b == Name.npos)
24540b57cec5SDimitry Andric     Idx = 0;
24550b57cec5SDimitry Andric   else
24560b57cec5SDimitry Andric     Idx = b+1;
24570b57cec5SDimitry Andric   F = Name.slice(Idx, Idx + Foo.size());
24580b57cec5SDimitry Andric   DotFramework = Name.slice(Idx + Foo.size(),
24590b57cec5SDimitry Andric                             Idx + Foo.size() + sizeof(".framework/")-1);
24600b57cec5SDimitry Andric   if (F == Foo && DotFramework == ".framework/") {
24610b57cec5SDimitry Andric     isFramework = true;
24620b57cec5SDimitry Andric     return Foo;
24630b57cec5SDimitry Andric   }
24640b57cec5SDimitry Andric 
24650b57cec5SDimitry Andric   // Next look for the form Foo.framework/Versions/A/Foo
24660b57cec5SDimitry Andric   if (b == Name.npos)
24670b57cec5SDimitry Andric     goto guess_library;
24680b57cec5SDimitry Andric   c =  Name.rfind('/', b);
24690b57cec5SDimitry Andric   if (c == Name.npos || c == 0)
24700b57cec5SDimitry Andric     goto guess_library;
24710b57cec5SDimitry Andric   V = Name.slice(c+1, Name.npos);
2472*c9157d92SDimitry Andric   if (!V.starts_with("Versions/"))
24730b57cec5SDimitry Andric     goto guess_library;
24740b57cec5SDimitry Andric   d =  Name.rfind('/', c);
24750b57cec5SDimitry Andric   if (d == Name.npos)
24760b57cec5SDimitry Andric     Idx = 0;
24770b57cec5SDimitry Andric   else
24780b57cec5SDimitry Andric     Idx = d+1;
24790b57cec5SDimitry Andric   F = Name.slice(Idx, Idx + Foo.size());
24800b57cec5SDimitry Andric   DotFramework = Name.slice(Idx + Foo.size(),
24810b57cec5SDimitry Andric                             Idx + Foo.size() + sizeof(".framework/")-1);
24820b57cec5SDimitry Andric   if (F == Foo && DotFramework == ".framework/") {
24830b57cec5SDimitry Andric     isFramework = true;
24840b57cec5SDimitry Andric     return Foo;
24850b57cec5SDimitry Andric   }
24860b57cec5SDimitry Andric 
24870b57cec5SDimitry Andric guess_library:
24880b57cec5SDimitry Andric   // pull off the suffix after the "." and make a point to it
24890b57cec5SDimitry Andric   a = Name.rfind('.');
24900b57cec5SDimitry Andric   if (a == Name.npos || a == 0)
24910b57cec5SDimitry Andric     return StringRef();
24920b57cec5SDimitry Andric   Dylib = Name.slice(a, Name.npos);
24930b57cec5SDimitry Andric   if (Dylib != ".dylib")
24940b57cec5SDimitry Andric     goto guess_qtx;
24950b57cec5SDimitry Andric 
24960b57cec5SDimitry Andric   // First pull off the version letter for the form Foo.A.dylib if any.
24970b57cec5SDimitry Andric   if (a >= 3) {
24980b57cec5SDimitry Andric     Dot = Name.slice(a-2, a-1);
24990b57cec5SDimitry Andric     if (Dot == ".")
25000b57cec5SDimitry Andric       a = a - 2;
25010b57cec5SDimitry Andric   }
25020b57cec5SDimitry Andric 
25030b57cec5SDimitry Andric   b = Name.rfind('/', a);
25040b57cec5SDimitry Andric   if (b == Name.npos)
25050b57cec5SDimitry Andric     b = 0;
25060b57cec5SDimitry Andric   else
25070b57cec5SDimitry Andric     b = b+1;
25080b57cec5SDimitry Andric   // ignore any suffix after an underbar like Foo_profile.A.dylib
25090b57cec5SDimitry Andric   Idx = Name.rfind('_');
25100b57cec5SDimitry Andric   if (Idx != Name.npos && Idx != b) {
25110b57cec5SDimitry Andric     Lib = Name.slice(b, Idx);
25120b57cec5SDimitry Andric     Suffix = Name.slice(Idx, a);
25130b57cec5SDimitry Andric     if (Suffix != "_debug" && Suffix != "_profile") {
25140b57cec5SDimitry Andric       Suffix = StringRef();
25150b57cec5SDimitry Andric       Lib = Name.slice(b, a);
25160b57cec5SDimitry Andric     }
25170b57cec5SDimitry Andric   }
25180b57cec5SDimitry Andric   else
25190b57cec5SDimitry Andric     Lib = Name.slice(b, a);
25200b57cec5SDimitry Andric   // There are incorrect library names of the form:
25210b57cec5SDimitry Andric   // libATS.A_profile.dylib so check for these.
25220b57cec5SDimitry Andric   if (Lib.size() >= 3) {
25230b57cec5SDimitry Andric     Dot = Lib.slice(Lib.size()-2, Lib.size()-1);
25240b57cec5SDimitry Andric     if (Dot == ".")
25250b57cec5SDimitry Andric       Lib = Lib.slice(0, Lib.size()-2);
25260b57cec5SDimitry Andric   }
25270b57cec5SDimitry Andric   return Lib;
25280b57cec5SDimitry Andric 
25290b57cec5SDimitry Andric guess_qtx:
25300b57cec5SDimitry Andric   Qtx = Name.slice(a, Name.npos);
25310b57cec5SDimitry Andric   if (Qtx != ".qtx")
25320b57cec5SDimitry Andric     return StringRef();
25330b57cec5SDimitry Andric   b = Name.rfind('/', a);
25340b57cec5SDimitry Andric   if (b == Name.npos)
25350b57cec5SDimitry Andric     Lib = Name.slice(0, a);
25360b57cec5SDimitry Andric   else
25370b57cec5SDimitry Andric     Lib = Name.slice(b+1, a);
25380b57cec5SDimitry Andric   // There are library names of the form: QT.A.qtx so check for these.
25390b57cec5SDimitry Andric   if (Lib.size() >= 3) {
25400b57cec5SDimitry Andric     Dot = Lib.slice(Lib.size()-2, Lib.size()-1);
25410b57cec5SDimitry Andric     if (Dot == ".")
25420b57cec5SDimitry Andric       Lib = Lib.slice(0, Lib.size()-2);
25430b57cec5SDimitry Andric   }
25440b57cec5SDimitry Andric   return Lib;
25450b57cec5SDimitry Andric }
25460b57cec5SDimitry Andric 
25470b57cec5SDimitry Andric // getLibraryShortNameByIndex() is used to get the short name of the library
25480b57cec5SDimitry Andric // for an undefined symbol in a linked Mach-O binary that was linked with the
25490b57cec5SDimitry Andric // normal two-level namespace default (that is MH_TWOLEVEL in the header).
25500b57cec5SDimitry Andric // It is passed the index (0 - based) of the library as translated from
25510b57cec5SDimitry Andric // GET_LIBRARY_ORDINAL (1 - based).
getLibraryShortNameByIndex(unsigned Index,StringRef & Res) const25520b57cec5SDimitry Andric std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index,
25530b57cec5SDimitry Andric                                                          StringRef &Res) const {
25540b57cec5SDimitry Andric   if (Index >= Libraries.size())
25550b57cec5SDimitry Andric     return object_error::parse_failed;
25560b57cec5SDimitry Andric 
25570b57cec5SDimitry Andric   // If the cache of LibrariesShortNames is not built up do that first for
25580b57cec5SDimitry Andric   // all the Libraries.
25590b57cec5SDimitry Andric   if (LibrariesShortNames.size() == 0) {
25600b57cec5SDimitry Andric     for (unsigned i = 0; i < Libraries.size(); i++) {
25610b57cec5SDimitry Andric       auto CommandOrErr =
25620b57cec5SDimitry Andric         getStructOrErr<MachO::dylib_command>(*this, Libraries[i]);
25630b57cec5SDimitry Andric       if (!CommandOrErr)
25640b57cec5SDimitry Andric         return object_error::parse_failed;
25650b57cec5SDimitry Andric       MachO::dylib_command D = CommandOrErr.get();
25660b57cec5SDimitry Andric       if (D.dylib.name >= D.cmdsize)
25670b57cec5SDimitry Andric         return object_error::parse_failed;
25680b57cec5SDimitry Andric       const char *P = (const char *)(Libraries[i]) + D.dylib.name;
25690b57cec5SDimitry Andric       StringRef Name = StringRef(P);
25700b57cec5SDimitry Andric       if (D.dylib.name+Name.size() >= D.cmdsize)
25710b57cec5SDimitry Andric         return object_error::parse_failed;
25720b57cec5SDimitry Andric       StringRef Suffix;
25730b57cec5SDimitry Andric       bool isFramework;
25740b57cec5SDimitry Andric       StringRef shortName = guessLibraryShortName(Name, isFramework, Suffix);
25750b57cec5SDimitry Andric       if (shortName.empty())
25760b57cec5SDimitry Andric         LibrariesShortNames.push_back(Name);
25770b57cec5SDimitry Andric       else
25780b57cec5SDimitry Andric         LibrariesShortNames.push_back(shortName);
25790b57cec5SDimitry Andric     }
25800b57cec5SDimitry Andric   }
25810b57cec5SDimitry Andric 
25820b57cec5SDimitry Andric   Res = LibrariesShortNames[Index];
25830b57cec5SDimitry Andric   return std::error_code();
25840b57cec5SDimitry Andric }
25850b57cec5SDimitry Andric 
getLibraryCount() const25860b57cec5SDimitry Andric uint32_t MachOObjectFile::getLibraryCount() const {
25870b57cec5SDimitry Andric   return Libraries.size();
25880b57cec5SDimitry Andric }
25890b57cec5SDimitry Andric 
25900b57cec5SDimitry Andric section_iterator
getRelocationRelocatedSection(relocation_iterator Rel) const25910b57cec5SDimitry Andric MachOObjectFile::getRelocationRelocatedSection(relocation_iterator Rel) const {
25920b57cec5SDimitry Andric   DataRefImpl Sec;
25930b57cec5SDimitry Andric   Sec.d.a = Rel->getRawDataRefImpl().d.a;
25940b57cec5SDimitry Andric   return section_iterator(SectionRef(Sec, this));
25950b57cec5SDimitry Andric }
25960b57cec5SDimitry Andric 
symbol_begin() const25970b57cec5SDimitry Andric basic_symbol_iterator MachOObjectFile::symbol_begin() const {
25980b57cec5SDimitry Andric   DataRefImpl DRI;
25990b57cec5SDimitry Andric   MachO::symtab_command Symtab = getSymtabLoadCommand();
26000b57cec5SDimitry Andric   if (!SymtabLoadCmd || Symtab.nsyms == 0)
26010b57cec5SDimitry Andric     return basic_symbol_iterator(SymbolRef(DRI, this));
26020b57cec5SDimitry Andric 
26030b57cec5SDimitry Andric   return getSymbolByIndex(0);
26040b57cec5SDimitry Andric }
26050b57cec5SDimitry Andric 
symbol_end() const26060b57cec5SDimitry Andric basic_symbol_iterator MachOObjectFile::symbol_end() const {
26070b57cec5SDimitry Andric   DataRefImpl DRI;
26080b57cec5SDimitry Andric   MachO::symtab_command Symtab = getSymtabLoadCommand();
26090b57cec5SDimitry Andric   if (!SymtabLoadCmd || Symtab.nsyms == 0)
26100b57cec5SDimitry Andric     return basic_symbol_iterator(SymbolRef(DRI, this));
26110b57cec5SDimitry Andric 
26120b57cec5SDimitry Andric   unsigned SymbolTableEntrySize = is64Bit() ?
26130b57cec5SDimitry Andric     sizeof(MachO::nlist_64) :
26140b57cec5SDimitry Andric     sizeof(MachO::nlist);
26150b57cec5SDimitry Andric   unsigned Offset = Symtab.symoff +
26160b57cec5SDimitry Andric     Symtab.nsyms * SymbolTableEntrySize;
26170b57cec5SDimitry Andric   DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));
26180b57cec5SDimitry Andric   return basic_symbol_iterator(SymbolRef(DRI, this));
26190b57cec5SDimitry Andric }
26200b57cec5SDimitry Andric 
getSymbolByIndex(unsigned Index) const26210b57cec5SDimitry Andric symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const {
26220b57cec5SDimitry Andric   MachO::symtab_command Symtab = getSymtabLoadCommand();
26230b57cec5SDimitry Andric   if (!SymtabLoadCmd || Index >= Symtab.nsyms)
26240b57cec5SDimitry Andric     report_fatal_error("Requested symbol index is out of range.");
26250b57cec5SDimitry Andric   unsigned SymbolTableEntrySize =
26260b57cec5SDimitry Andric     is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
26270b57cec5SDimitry Andric   DataRefImpl DRI;
26280b57cec5SDimitry Andric   DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Symtab.symoff));
26290b57cec5SDimitry Andric   DRI.p += Index * SymbolTableEntrySize;
26300b57cec5SDimitry Andric   return basic_symbol_iterator(SymbolRef(DRI, this));
26310b57cec5SDimitry Andric }
26320b57cec5SDimitry Andric 
getSymbolIndex(DataRefImpl Symb) const26330b57cec5SDimitry Andric uint64_t MachOObjectFile::getSymbolIndex(DataRefImpl Symb) const {
26340b57cec5SDimitry Andric   MachO::symtab_command Symtab = getSymtabLoadCommand();
26350b57cec5SDimitry Andric   if (!SymtabLoadCmd)
26360b57cec5SDimitry Andric     report_fatal_error("getSymbolIndex() called with no symbol table symbol");
26370b57cec5SDimitry Andric   unsigned SymbolTableEntrySize =
26380b57cec5SDimitry Andric     is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
26390b57cec5SDimitry Andric   DataRefImpl DRIstart;
26400b57cec5SDimitry Andric   DRIstart.p = reinterpret_cast<uintptr_t>(getPtr(*this, Symtab.symoff));
26410b57cec5SDimitry Andric   uint64_t Index = (Symb.p - DRIstart.p) / SymbolTableEntrySize;
26420b57cec5SDimitry Andric   return Index;
26430b57cec5SDimitry Andric }
26440b57cec5SDimitry Andric 
section_begin() const26450b57cec5SDimitry Andric section_iterator MachOObjectFile::section_begin() const {
26460b57cec5SDimitry Andric   DataRefImpl DRI;
26470b57cec5SDimitry Andric   return section_iterator(SectionRef(DRI, this));
26480b57cec5SDimitry Andric }
26490b57cec5SDimitry Andric 
section_end() const26500b57cec5SDimitry Andric section_iterator MachOObjectFile::section_end() const {
26510b57cec5SDimitry Andric   DataRefImpl DRI;
26520b57cec5SDimitry Andric   DRI.d.a = Sections.size();
26530b57cec5SDimitry Andric   return section_iterator(SectionRef(DRI, this));
26540b57cec5SDimitry Andric }
26550b57cec5SDimitry Andric 
getBytesInAddress() const26560b57cec5SDimitry Andric uint8_t MachOObjectFile::getBytesInAddress() const {
26570b57cec5SDimitry Andric   return is64Bit() ? 8 : 4;
26580b57cec5SDimitry Andric }
26590b57cec5SDimitry Andric 
getFileFormatName() const26600b57cec5SDimitry Andric StringRef MachOObjectFile::getFileFormatName() const {
26610b57cec5SDimitry Andric   unsigned CPUType = getCPUType(*this);
26620b57cec5SDimitry Andric   if (!is64Bit()) {
26630b57cec5SDimitry Andric     switch (CPUType) {
26640b57cec5SDimitry Andric     case MachO::CPU_TYPE_I386:
26650b57cec5SDimitry Andric       return "Mach-O 32-bit i386";
26660b57cec5SDimitry Andric     case MachO::CPU_TYPE_ARM:
26670b57cec5SDimitry Andric       return "Mach-O arm";
26680b57cec5SDimitry Andric     case MachO::CPU_TYPE_ARM64_32:
26690b57cec5SDimitry Andric       return "Mach-O arm64 (ILP32)";
26700b57cec5SDimitry Andric     case MachO::CPU_TYPE_POWERPC:
26710b57cec5SDimitry Andric       return "Mach-O 32-bit ppc";
26720b57cec5SDimitry Andric     default:
26730b57cec5SDimitry Andric       return "Mach-O 32-bit unknown";
26740b57cec5SDimitry Andric     }
26750b57cec5SDimitry Andric   }
26760b57cec5SDimitry Andric 
26770b57cec5SDimitry Andric   switch (CPUType) {
26780b57cec5SDimitry Andric   case MachO::CPU_TYPE_X86_64:
26790b57cec5SDimitry Andric     return "Mach-O 64-bit x86-64";
26800b57cec5SDimitry Andric   case MachO::CPU_TYPE_ARM64:
26810b57cec5SDimitry Andric     return "Mach-O arm64";
26820b57cec5SDimitry Andric   case MachO::CPU_TYPE_POWERPC64:
26830b57cec5SDimitry Andric     return "Mach-O 64-bit ppc64";
26840b57cec5SDimitry Andric   default:
26850b57cec5SDimitry Andric     return "Mach-O 64-bit unknown";
26860b57cec5SDimitry Andric   }
26870b57cec5SDimitry Andric }
26880b57cec5SDimitry Andric 
getArch(uint32_t CPUType,uint32_t CPUSubType)2689480093f4SDimitry Andric Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) {
26900b57cec5SDimitry Andric   switch (CPUType) {
26910b57cec5SDimitry Andric   case MachO::CPU_TYPE_I386:
26920b57cec5SDimitry Andric     return Triple::x86;
26930b57cec5SDimitry Andric   case MachO::CPU_TYPE_X86_64:
26940b57cec5SDimitry Andric     return Triple::x86_64;
26950b57cec5SDimitry Andric   case MachO::CPU_TYPE_ARM:
26960b57cec5SDimitry Andric     return Triple::arm;
26970b57cec5SDimitry Andric   case MachO::CPU_TYPE_ARM64:
26980b57cec5SDimitry Andric     return Triple::aarch64;
26990b57cec5SDimitry Andric   case MachO::CPU_TYPE_ARM64_32:
27000b57cec5SDimitry Andric     return Triple::aarch64_32;
27010b57cec5SDimitry Andric   case MachO::CPU_TYPE_POWERPC:
27020b57cec5SDimitry Andric     return Triple::ppc;
27030b57cec5SDimitry Andric   case MachO::CPU_TYPE_POWERPC64:
27040b57cec5SDimitry Andric     return Triple::ppc64;
27050b57cec5SDimitry Andric   default:
27060b57cec5SDimitry Andric     return Triple::UnknownArch;
27070b57cec5SDimitry Andric   }
27080b57cec5SDimitry Andric }
27090b57cec5SDimitry Andric 
getArchTriple(uint32_t CPUType,uint32_t CPUSubType,const char ** McpuDefault,const char ** ArchFlag)27100b57cec5SDimitry Andric Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType,
27110b57cec5SDimitry Andric                                       const char **McpuDefault,
27120b57cec5SDimitry Andric                                       const char **ArchFlag) {
27130b57cec5SDimitry Andric   if (McpuDefault)
27140b57cec5SDimitry Andric     *McpuDefault = nullptr;
27150b57cec5SDimitry Andric   if (ArchFlag)
27160b57cec5SDimitry Andric     *ArchFlag = nullptr;
27170b57cec5SDimitry Andric 
27180b57cec5SDimitry Andric   switch (CPUType) {
27190b57cec5SDimitry Andric   case MachO::CPU_TYPE_I386:
27200b57cec5SDimitry Andric     switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
27210b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_I386_ALL:
27220b57cec5SDimitry Andric       if (ArchFlag)
27230b57cec5SDimitry Andric         *ArchFlag = "i386";
27240b57cec5SDimitry Andric       return Triple("i386-apple-darwin");
27250b57cec5SDimitry Andric     default:
27260b57cec5SDimitry Andric       return Triple();
27270b57cec5SDimitry Andric     }
27280b57cec5SDimitry Andric   case MachO::CPU_TYPE_X86_64:
27290b57cec5SDimitry Andric     switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
27300b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_X86_64_ALL:
27310b57cec5SDimitry Andric       if (ArchFlag)
27320b57cec5SDimitry Andric         *ArchFlag = "x86_64";
27330b57cec5SDimitry Andric       return Triple("x86_64-apple-darwin");
27340b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_X86_64_H:
27350b57cec5SDimitry Andric       if (ArchFlag)
27360b57cec5SDimitry Andric         *ArchFlag = "x86_64h";
27370b57cec5SDimitry Andric       return Triple("x86_64h-apple-darwin");
27380b57cec5SDimitry Andric     default:
27390b57cec5SDimitry Andric       return Triple();
27400b57cec5SDimitry Andric     }
27410b57cec5SDimitry Andric   case MachO::CPU_TYPE_ARM:
27420b57cec5SDimitry Andric     switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
27430b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_V4T:
27440b57cec5SDimitry Andric       if (ArchFlag)
27450b57cec5SDimitry Andric         *ArchFlag = "armv4t";
27460b57cec5SDimitry Andric       return Triple("armv4t-apple-darwin");
27470b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_V5TEJ:
27480b57cec5SDimitry Andric       if (ArchFlag)
27490b57cec5SDimitry Andric         *ArchFlag = "armv5e";
27500b57cec5SDimitry Andric       return Triple("armv5e-apple-darwin");
27510b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_XSCALE:
27520b57cec5SDimitry Andric       if (ArchFlag)
27530b57cec5SDimitry Andric         *ArchFlag = "xscale";
27540b57cec5SDimitry Andric       return Triple("xscale-apple-darwin");
27550b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_V6:
27560b57cec5SDimitry Andric       if (ArchFlag)
27570b57cec5SDimitry Andric         *ArchFlag = "armv6";
27580b57cec5SDimitry Andric       return Triple("armv6-apple-darwin");
27590b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_V6M:
27600b57cec5SDimitry Andric       if (McpuDefault)
27610b57cec5SDimitry Andric         *McpuDefault = "cortex-m0";
27620b57cec5SDimitry Andric       if (ArchFlag)
27630b57cec5SDimitry Andric         *ArchFlag = "armv6m";
27640b57cec5SDimitry Andric       return Triple("armv6m-apple-darwin");
27650b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_V7:
27660b57cec5SDimitry Andric       if (ArchFlag)
27670b57cec5SDimitry Andric         *ArchFlag = "armv7";
27680b57cec5SDimitry Andric       return Triple("armv7-apple-darwin");
27690b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_V7EM:
27700b57cec5SDimitry Andric       if (McpuDefault)
27710b57cec5SDimitry Andric         *McpuDefault = "cortex-m4";
27720b57cec5SDimitry Andric       if (ArchFlag)
27730b57cec5SDimitry Andric         *ArchFlag = "armv7em";
27740b57cec5SDimitry Andric       return Triple("thumbv7em-apple-darwin");
27750b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_V7K:
27760b57cec5SDimitry Andric       if (McpuDefault)
27770b57cec5SDimitry Andric         *McpuDefault = "cortex-a7";
27780b57cec5SDimitry Andric       if (ArchFlag)
27790b57cec5SDimitry Andric         *ArchFlag = "armv7k";
27800b57cec5SDimitry Andric       return Triple("armv7k-apple-darwin");
27810b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_V7M:
27820b57cec5SDimitry Andric       if (McpuDefault)
27830b57cec5SDimitry Andric         *McpuDefault = "cortex-m3";
27840b57cec5SDimitry Andric       if (ArchFlag)
27850b57cec5SDimitry Andric         *ArchFlag = "armv7m";
27860b57cec5SDimitry Andric       return Triple("thumbv7m-apple-darwin");
27870b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM_V7S:
27880b57cec5SDimitry Andric       if (McpuDefault)
27890b57cec5SDimitry Andric         *McpuDefault = "cortex-a7";
27900b57cec5SDimitry Andric       if (ArchFlag)
27910b57cec5SDimitry Andric         *ArchFlag = "armv7s";
27920b57cec5SDimitry Andric       return Triple("armv7s-apple-darwin");
27930b57cec5SDimitry Andric     default:
27940b57cec5SDimitry Andric       return Triple();
27950b57cec5SDimitry Andric     }
27960b57cec5SDimitry Andric   case MachO::CPU_TYPE_ARM64:
27970b57cec5SDimitry Andric     switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
27980b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM64_ALL:
27990b57cec5SDimitry Andric       if (McpuDefault)
28000b57cec5SDimitry Andric         *McpuDefault = "cyclone";
28010b57cec5SDimitry Andric       if (ArchFlag)
28020b57cec5SDimitry Andric         *ArchFlag = "arm64";
28030b57cec5SDimitry Andric       return Triple("arm64-apple-darwin");
2804e8d8bef9SDimitry Andric     case MachO::CPU_SUBTYPE_ARM64E:
2805e8d8bef9SDimitry Andric       if (McpuDefault)
2806e8d8bef9SDimitry Andric         *McpuDefault = "apple-a12";
2807e8d8bef9SDimitry Andric       if (ArchFlag)
2808e8d8bef9SDimitry Andric         *ArchFlag = "arm64e";
2809e8d8bef9SDimitry Andric       return Triple("arm64e-apple-darwin");
28100b57cec5SDimitry Andric     default:
28110b57cec5SDimitry Andric       return Triple();
28120b57cec5SDimitry Andric     }
28130b57cec5SDimitry Andric   case MachO::CPU_TYPE_ARM64_32:
28140b57cec5SDimitry Andric     switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
28150b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_ARM64_32_V8:
28160b57cec5SDimitry Andric       if (McpuDefault)
28170b57cec5SDimitry Andric         *McpuDefault = "cyclone";
28180b57cec5SDimitry Andric       if (ArchFlag)
28190b57cec5SDimitry Andric         *ArchFlag = "arm64_32";
28200b57cec5SDimitry Andric       return Triple("arm64_32-apple-darwin");
28210b57cec5SDimitry Andric     default:
28220b57cec5SDimitry Andric       return Triple();
28230b57cec5SDimitry Andric     }
28240b57cec5SDimitry Andric   case MachO::CPU_TYPE_POWERPC:
28250b57cec5SDimitry Andric     switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
28260b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_POWERPC_ALL:
28270b57cec5SDimitry Andric       if (ArchFlag)
28280b57cec5SDimitry Andric         *ArchFlag = "ppc";
28290b57cec5SDimitry Andric       return Triple("ppc-apple-darwin");
28300b57cec5SDimitry Andric     default:
28310b57cec5SDimitry Andric       return Triple();
28320b57cec5SDimitry Andric     }
28330b57cec5SDimitry Andric   case MachO::CPU_TYPE_POWERPC64:
28340b57cec5SDimitry Andric     switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
28350b57cec5SDimitry Andric     case MachO::CPU_SUBTYPE_POWERPC_ALL:
28360b57cec5SDimitry Andric       if (ArchFlag)
28370b57cec5SDimitry Andric         *ArchFlag = "ppc64";
28380b57cec5SDimitry Andric       return Triple("ppc64-apple-darwin");
28390b57cec5SDimitry Andric     default:
28400b57cec5SDimitry Andric       return Triple();
28410b57cec5SDimitry Andric     }
28420b57cec5SDimitry Andric   default:
28430b57cec5SDimitry Andric     return Triple();
28440b57cec5SDimitry Andric   }
28450b57cec5SDimitry Andric }
28460b57cec5SDimitry Andric 
getHostArch()28470b57cec5SDimitry Andric Triple MachOObjectFile::getHostArch() {
28480b57cec5SDimitry Andric   return Triple(sys::getDefaultTargetTriple());
28490b57cec5SDimitry Andric }
28500b57cec5SDimitry Andric 
isValidArch(StringRef ArchFlag)28510b57cec5SDimitry Andric bool MachOObjectFile::isValidArch(StringRef ArchFlag) {
28528bcb0991SDimitry Andric   auto validArchs = getValidArchs();
2853e8d8bef9SDimitry Andric   return llvm::is_contained(validArchs, ArchFlag);
28540b57cec5SDimitry Andric }
28550b57cec5SDimitry Andric 
getValidArchs()28568bcb0991SDimitry Andric ArrayRef<StringRef> MachOObjectFile::getValidArchs() {
2857e8d8bef9SDimitry Andric   static const std::array<StringRef, 18> ValidArchs = {{
2858e8d8bef9SDimitry Andric       "i386",
2859e8d8bef9SDimitry Andric       "x86_64",
2860e8d8bef9SDimitry Andric       "x86_64h",
2861e8d8bef9SDimitry Andric       "armv4t",
2862e8d8bef9SDimitry Andric       "arm",
2863e8d8bef9SDimitry Andric       "armv5e",
2864e8d8bef9SDimitry Andric       "armv6",
2865e8d8bef9SDimitry Andric       "armv6m",
2866e8d8bef9SDimitry Andric       "armv7",
2867e8d8bef9SDimitry Andric       "armv7em",
2868e8d8bef9SDimitry Andric       "armv7k",
2869e8d8bef9SDimitry Andric       "armv7m",
2870e8d8bef9SDimitry Andric       "armv7s",
2871e8d8bef9SDimitry Andric       "arm64",
2872e8d8bef9SDimitry Andric       "arm64e",
2873e8d8bef9SDimitry Andric       "arm64_32",
2874e8d8bef9SDimitry Andric       "ppc",
2875e8d8bef9SDimitry Andric       "ppc64",
28768bcb0991SDimitry Andric   }};
28778bcb0991SDimitry Andric 
2878e8d8bef9SDimitry Andric   return ValidArchs;
28798bcb0991SDimitry Andric }
28800b57cec5SDimitry Andric 
getArch() const28810b57cec5SDimitry Andric Triple::ArchType MachOObjectFile::getArch() const {
2882480093f4SDimitry Andric   return getArch(getCPUType(*this), getCPUSubType(*this));
28830b57cec5SDimitry Andric }
28840b57cec5SDimitry Andric 
getArchTriple(const char ** McpuDefault) const28850b57cec5SDimitry Andric Triple MachOObjectFile::getArchTriple(const char **McpuDefault) const {
28860b57cec5SDimitry Andric   return getArchTriple(Header.cputype, Header.cpusubtype, McpuDefault);
28870b57cec5SDimitry Andric }
28880b57cec5SDimitry Andric 
section_rel_begin(unsigned Index) const28890b57cec5SDimitry Andric relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const {
28900b57cec5SDimitry Andric   DataRefImpl DRI;
28910b57cec5SDimitry Andric   DRI.d.a = Index;
28920b57cec5SDimitry Andric   return section_rel_begin(DRI);
28930b57cec5SDimitry Andric }
28940b57cec5SDimitry Andric 
section_rel_end(unsigned Index) const28950b57cec5SDimitry Andric relocation_iterator MachOObjectFile::section_rel_end(unsigned Index) const {
28960b57cec5SDimitry Andric   DataRefImpl DRI;
28970b57cec5SDimitry Andric   DRI.d.a = Index;
28980b57cec5SDimitry Andric   return section_rel_end(DRI);
28990b57cec5SDimitry Andric }
29000b57cec5SDimitry Andric 
begin_dices() const29010b57cec5SDimitry Andric dice_iterator MachOObjectFile::begin_dices() const {
29020b57cec5SDimitry Andric   DataRefImpl DRI;
29030b57cec5SDimitry Andric   if (!DataInCodeLoadCmd)
29040b57cec5SDimitry Andric     return dice_iterator(DiceRef(DRI, this));
29050b57cec5SDimitry Andric 
29060b57cec5SDimitry Andric   MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();
29070b57cec5SDimitry Andric   DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, DicLC.dataoff));
29080b57cec5SDimitry Andric   return dice_iterator(DiceRef(DRI, this));
29090b57cec5SDimitry Andric }
29100b57cec5SDimitry Andric 
end_dices() const29110b57cec5SDimitry Andric dice_iterator MachOObjectFile::end_dices() const {
29120b57cec5SDimitry Andric   DataRefImpl DRI;
29130b57cec5SDimitry Andric   if (!DataInCodeLoadCmd)
29140b57cec5SDimitry Andric     return dice_iterator(DiceRef(DRI, this));
29150b57cec5SDimitry Andric 
29160b57cec5SDimitry Andric   MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();
29170b57cec5SDimitry Andric   unsigned Offset = DicLC.dataoff + DicLC.datasize;
29180b57cec5SDimitry Andric   DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));
29190b57cec5SDimitry Andric   return dice_iterator(DiceRef(DRI, this));
29200b57cec5SDimitry Andric }
29210b57cec5SDimitry Andric 
ExportEntry(Error * E,const MachOObjectFile * O,ArrayRef<uint8_t> T)29220b57cec5SDimitry Andric ExportEntry::ExportEntry(Error *E, const MachOObjectFile *O,
29230b57cec5SDimitry Andric                          ArrayRef<uint8_t> T) : E(E), O(O), Trie(T) {}
29240b57cec5SDimitry Andric 
moveToFirst()29250b57cec5SDimitry Andric void ExportEntry::moveToFirst() {
29260b57cec5SDimitry Andric   ErrorAsOutParameter ErrAsOutParam(E);
29270b57cec5SDimitry Andric   pushNode(0);
29280b57cec5SDimitry Andric   if (*E)
29290b57cec5SDimitry Andric     return;
29300b57cec5SDimitry Andric   pushDownUntilBottom();
29310b57cec5SDimitry Andric }
29320b57cec5SDimitry Andric 
moveToEnd()29330b57cec5SDimitry Andric void ExportEntry::moveToEnd() {
29340b57cec5SDimitry Andric   Stack.clear();
29350b57cec5SDimitry Andric   Done = true;
29360b57cec5SDimitry Andric }
29370b57cec5SDimitry Andric 
operator ==(const ExportEntry & Other) const29380b57cec5SDimitry Andric bool ExportEntry::operator==(const ExportEntry &Other) const {
29390b57cec5SDimitry Andric   // Common case, one at end, other iterating from begin.
29400b57cec5SDimitry Andric   if (Done || Other.Done)
29410b57cec5SDimitry Andric     return (Done == Other.Done);
29420b57cec5SDimitry Andric   // Not equal if different stack sizes.
29430b57cec5SDimitry Andric   if (Stack.size() != Other.Stack.size())
29440b57cec5SDimitry Andric     return false;
29450b57cec5SDimitry Andric   // Not equal if different cumulative strings.
29460b57cec5SDimitry Andric   if (!CumulativeString.equals(Other.CumulativeString))
29470b57cec5SDimitry Andric     return false;
29480b57cec5SDimitry Andric   // Equal if all nodes in both stacks match.
29490b57cec5SDimitry Andric   for (unsigned i=0; i < Stack.size(); ++i) {
29500b57cec5SDimitry Andric     if (Stack[i].Start != Other.Stack[i].Start)
29510b57cec5SDimitry Andric       return false;
29520b57cec5SDimitry Andric   }
29530b57cec5SDimitry Andric   return true;
29540b57cec5SDimitry Andric }
29550b57cec5SDimitry Andric 
readULEB128(const uint8_t * & Ptr,const char ** error)29560b57cec5SDimitry Andric uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr, const char **error) {
29570b57cec5SDimitry Andric   unsigned Count;
29580b57cec5SDimitry Andric   uint64_t Result = decodeULEB128(Ptr, &Count, Trie.end(), error);
29590b57cec5SDimitry Andric   Ptr += Count;
29600b57cec5SDimitry Andric   if (Ptr > Trie.end())
29610b57cec5SDimitry Andric     Ptr = Trie.end();
29620b57cec5SDimitry Andric   return Result;
29630b57cec5SDimitry Andric }
29640b57cec5SDimitry Andric 
name() const29650b57cec5SDimitry Andric StringRef ExportEntry::name() const {
29660b57cec5SDimitry Andric   return CumulativeString;
29670b57cec5SDimitry Andric }
29680b57cec5SDimitry Andric 
flags() const29690b57cec5SDimitry Andric uint64_t ExportEntry::flags() const {
29700b57cec5SDimitry Andric   return Stack.back().Flags;
29710b57cec5SDimitry Andric }
29720b57cec5SDimitry Andric 
address() const29730b57cec5SDimitry Andric uint64_t ExportEntry::address() const {
29740b57cec5SDimitry Andric   return Stack.back().Address;
29750b57cec5SDimitry Andric }
29760b57cec5SDimitry Andric 
other() const29770b57cec5SDimitry Andric uint64_t ExportEntry::other() const {
29780b57cec5SDimitry Andric   return Stack.back().Other;
29790b57cec5SDimitry Andric }
29800b57cec5SDimitry Andric 
otherName() const29810b57cec5SDimitry Andric StringRef ExportEntry::otherName() const {
29820b57cec5SDimitry Andric   const char* ImportName = Stack.back().ImportName;
29830b57cec5SDimitry Andric   if (ImportName)
29840b57cec5SDimitry Andric     return StringRef(ImportName);
29850b57cec5SDimitry Andric   return StringRef();
29860b57cec5SDimitry Andric }
29870b57cec5SDimitry Andric 
nodeOffset() const29880b57cec5SDimitry Andric uint32_t ExportEntry::nodeOffset() const {
29890b57cec5SDimitry Andric   return Stack.back().Start - Trie.begin();
29900b57cec5SDimitry Andric }
29910b57cec5SDimitry Andric 
NodeState(const uint8_t * Ptr)29920b57cec5SDimitry Andric ExportEntry::NodeState::NodeState(const uint8_t *Ptr)
29930b57cec5SDimitry Andric     : Start(Ptr), Current(Ptr) {}
29940b57cec5SDimitry Andric 
pushNode(uint64_t offset)29950b57cec5SDimitry Andric void ExportEntry::pushNode(uint64_t offset) {
29960b57cec5SDimitry Andric   ErrorAsOutParameter ErrAsOutParam(E);
29970b57cec5SDimitry Andric   const uint8_t *Ptr = Trie.begin() + offset;
29980b57cec5SDimitry Andric   NodeState State(Ptr);
2999*c9157d92SDimitry Andric   const char *error = nullptr;
30000b57cec5SDimitry Andric   uint64_t ExportInfoSize = readULEB128(State.Current, &error);
30010b57cec5SDimitry Andric   if (error) {
30020b57cec5SDimitry Andric     *E = malformedError("export info size " + Twine(error) +
30030b57cec5SDimitry Andric                         " in export trie data at node: 0x" +
30040b57cec5SDimitry Andric                         Twine::utohexstr(offset));
30050b57cec5SDimitry Andric     moveToEnd();
30060b57cec5SDimitry Andric     return;
30070b57cec5SDimitry Andric   }
30080b57cec5SDimitry Andric   State.IsExportNode = (ExportInfoSize != 0);
30090b57cec5SDimitry Andric   const uint8_t* Children = State.Current + ExportInfoSize;
30100b57cec5SDimitry Andric   if (Children > Trie.end()) {
30110b57cec5SDimitry Andric     *E = malformedError(
30120b57cec5SDimitry Andric         "export info size: 0x" + Twine::utohexstr(ExportInfoSize) +
30130b57cec5SDimitry Andric         " in export trie data at node: 0x" + Twine::utohexstr(offset) +
30140b57cec5SDimitry Andric         " too big and extends past end of trie data");
30150b57cec5SDimitry Andric     moveToEnd();
30160b57cec5SDimitry Andric     return;
30170b57cec5SDimitry Andric   }
30180b57cec5SDimitry Andric   if (State.IsExportNode) {
30190b57cec5SDimitry Andric     const uint8_t *ExportStart = State.Current;
30200b57cec5SDimitry Andric     State.Flags = readULEB128(State.Current, &error);
30210b57cec5SDimitry Andric     if (error) {
30220b57cec5SDimitry Andric       *E = malformedError("flags " + Twine(error) +
30230b57cec5SDimitry Andric                           " in export trie data at node: 0x" +
30240b57cec5SDimitry Andric                           Twine::utohexstr(offset));
30250b57cec5SDimitry Andric       moveToEnd();
30260b57cec5SDimitry Andric       return;
30270b57cec5SDimitry Andric     }
30280b57cec5SDimitry Andric     uint64_t Kind = State.Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK;
30290b57cec5SDimitry Andric     if (State.Flags != 0 &&
30300b57cec5SDimitry Andric         (Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR &&
30310b57cec5SDimitry Andric          Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE &&
30320b57cec5SDimitry Andric          Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)) {
30330b57cec5SDimitry Andric       *E = malformedError(
30340b57cec5SDimitry Andric           "unsupported exported symbol kind: " + Twine((int)Kind) +
30350b57cec5SDimitry Andric           " in flags: 0x" + Twine::utohexstr(State.Flags) +
30360b57cec5SDimitry Andric           " in export trie data at node: 0x" + Twine::utohexstr(offset));
30370b57cec5SDimitry Andric       moveToEnd();
30380b57cec5SDimitry Andric       return;
30390b57cec5SDimitry Andric     }
30400b57cec5SDimitry Andric     if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) {
30410b57cec5SDimitry Andric       State.Address = 0;
30420b57cec5SDimitry Andric       State.Other = readULEB128(State.Current, &error); // dylib ordinal
30430b57cec5SDimitry Andric       if (error) {
30440b57cec5SDimitry Andric         *E = malformedError("dylib ordinal of re-export " + Twine(error) +
30450b57cec5SDimitry Andric                             " in export trie data at node: 0x" +
30460b57cec5SDimitry Andric                             Twine::utohexstr(offset));
30470b57cec5SDimitry Andric         moveToEnd();
30480b57cec5SDimitry Andric         return;
30490b57cec5SDimitry Andric       }
30500b57cec5SDimitry Andric       if (O != nullptr) {
305181ad6265SDimitry Andric         // Only positive numbers represent library ordinals. Zero and negative
305281ad6265SDimitry Andric         // numbers have special meaning (see BindSpecialDylib).
305381ad6265SDimitry Andric         if ((int64_t)State.Other > 0 && State.Other > O->getLibraryCount()) {
30540b57cec5SDimitry Andric           *E = malformedError(
30550b57cec5SDimitry Andric               "bad library ordinal: " + Twine((int)State.Other) + " (max " +
30560b57cec5SDimitry Andric               Twine((int)O->getLibraryCount()) +
30570b57cec5SDimitry Andric               ") in export trie data at node: 0x" + Twine::utohexstr(offset));
30580b57cec5SDimitry Andric           moveToEnd();
30590b57cec5SDimitry Andric           return;
30600b57cec5SDimitry Andric         }
30610b57cec5SDimitry Andric       }
30620b57cec5SDimitry Andric       State.ImportName = reinterpret_cast<const char*>(State.Current);
30630b57cec5SDimitry Andric       if (*State.ImportName == '\0') {
30640b57cec5SDimitry Andric         State.Current++;
30650b57cec5SDimitry Andric       } else {
30660b57cec5SDimitry Andric         const uint8_t *End = State.Current + 1;
30670b57cec5SDimitry Andric         if (End >= Trie.end()) {
30680b57cec5SDimitry Andric           *E = malformedError("import name of re-export in export trie data at "
30690b57cec5SDimitry Andric                               "node: 0x" +
30700b57cec5SDimitry Andric                               Twine::utohexstr(offset) +
30710b57cec5SDimitry Andric                               " starts past end of trie data");
30720b57cec5SDimitry Andric           moveToEnd();
30730b57cec5SDimitry Andric           return;
30740b57cec5SDimitry Andric         }
30750b57cec5SDimitry Andric         while(*End != '\0' && End < Trie.end())
30760b57cec5SDimitry Andric           End++;
30770b57cec5SDimitry Andric         if (*End != '\0') {
30780b57cec5SDimitry Andric           *E = malformedError("import name of re-export in export trie data at "
30790b57cec5SDimitry Andric                               "node: 0x" +
30800b57cec5SDimitry Andric                               Twine::utohexstr(offset) +
30810b57cec5SDimitry Andric                               " extends past end of trie data");
30820b57cec5SDimitry Andric           moveToEnd();
30830b57cec5SDimitry Andric           return;
30840b57cec5SDimitry Andric         }
30850b57cec5SDimitry Andric         State.Current = End + 1;
30860b57cec5SDimitry Andric       }
30870b57cec5SDimitry Andric     } else {
30880b57cec5SDimitry Andric       State.Address = readULEB128(State.Current, &error);
30890b57cec5SDimitry Andric       if (error) {
30900b57cec5SDimitry Andric         *E = malformedError("address " + Twine(error) +
30910b57cec5SDimitry Andric                             " in export trie data at node: 0x" +
30920b57cec5SDimitry Andric                             Twine::utohexstr(offset));
30930b57cec5SDimitry Andric         moveToEnd();
30940b57cec5SDimitry Andric         return;
30950b57cec5SDimitry Andric       }
30960b57cec5SDimitry Andric       if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {
30970b57cec5SDimitry Andric         State.Other = readULEB128(State.Current, &error);
30980b57cec5SDimitry Andric         if (error) {
30990b57cec5SDimitry Andric           *E = malformedError("resolver of stub and resolver " + Twine(error) +
31000b57cec5SDimitry Andric                               " in export trie data at node: 0x" +
31010b57cec5SDimitry Andric                               Twine::utohexstr(offset));
31020b57cec5SDimitry Andric           moveToEnd();
31030b57cec5SDimitry Andric           return;
31040b57cec5SDimitry Andric         }
31050b57cec5SDimitry Andric       }
31060b57cec5SDimitry Andric     }
31070b57cec5SDimitry Andric     if(ExportStart + ExportInfoSize != State.Current) {
31080b57cec5SDimitry Andric       *E = malformedError(
3109bdd1243dSDimitry Andric           "inconsistent export info size: 0x" +
31100b57cec5SDimitry Andric           Twine::utohexstr(ExportInfoSize) + " where actual size was: 0x" +
31110b57cec5SDimitry Andric           Twine::utohexstr(State.Current - ExportStart) +
31120b57cec5SDimitry Andric           " in export trie data at node: 0x" + Twine::utohexstr(offset));
31130b57cec5SDimitry Andric       moveToEnd();
31140b57cec5SDimitry Andric       return;
31150b57cec5SDimitry Andric     }
31160b57cec5SDimitry Andric   }
31170b57cec5SDimitry Andric   State.ChildCount = *Children;
31180b57cec5SDimitry Andric   if (State.ChildCount != 0 && Children + 1 >= Trie.end()) {
31190b57cec5SDimitry Andric     *E = malformedError("byte for count of childern in export trie data at "
31200b57cec5SDimitry Andric                         "node: 0x" +
31210b57cec5SDimitry Andric                         Twine::utohexstr(offset) +
31220b57cec5SDimitry Andric                         " extends past end of trie data");
31230b57cec5SDimitry Andric     moveToEnd();
31240b57cec5SDimitry Andric     return;
31250b57cec5SDimitry Andric   }
31260b57cec5SDimitry Andric   State.Current = Children + 1;
31270b57cec5SDimitry Andric   State.NextChildIndex = 0;
31280b57cec5SDimitry Andric   State.ParentStringLength = CumulativeString.size();
31290b57cec5SDimitry Andric   Stack.push_back(State);
31300b57cec5SDimitry Andric }
31310b57cec5SDimitry Andric 
pushDownUntilBottom()31320b57cec5SDimitry Andric void ExportEntry::pushDownUntilBottom() {
31330b57cec5SDimitry Andric   ErrorAsOutParameter ErrAsOutParam(E);
3134*c9157d92SDimitry Andric   const char *error = nullptr;
31350b57cec5SDimitry Andric   while (Stack.back().NextChildIndex < Stack.back().ChildCount) {
31360b57cec5SDimitry Andric     NodeState &Top = Stack.back();
31370b57cec5SDimitry Andric     CumulativeString.resize(Top.ParentStringLength);
31380b57cec5SDimitry Andric     for (;*Top.Current != 0 && Top.Current < Trie.end(); Top.Current++) {
31390b57cec5SDimitry Andric       char C = *Top.Current;
31400b57cec5SDimitry Andric       CumulativeString.push_back(C);
31410b57cec5SDimitry Andric     }
31420b57cec5SDimitry Andric     if (Top.Current >= Trie.end()) {
31430b57cec5SDimitry Andric       *E = malformedError("edge sub-string in export trie data at node: 0x" +
31440b57cec5SDimitry Andric                           Twine::utohexstr(Top.Start - Trie.begin()) +
31450b57cec5SDimitry Andric                           " for child #" + Twine((int)Top.NextChildIndex) +
31460b57cec5SDimitry Andric                           " extends past end of trie data");
31470b57cec5SDimitry Andric       moveToEnd();
31480b57cec5SDimitry Andric       return;
31490b57cec5SDimitry Andric     }
31500b57cec5SDimitry Andric     Top.Current += 1;
31510b57cec5SDimitry Andric     uint64_t childNodeIndex = readULEB128(Top.Current, &error);
31520b57cec5SDimitry Andric     if (error) {
31530b57cec5SDimitry Andric       *E = malformedError("child node offset " + Twine(error) +
31540b57cec5SDimitry Andric                           " in export trie data at node: 0x" +
31550b57cec5SDimitry Andric                           Twine::utohexstr(Top.Start - Trie.begin()));
31560b57cec5SDimitry Andric       moveToEnd();
31570b57cec5SDimitry Andric       return;
31580b57cec5SDimitry Andric     }
31590b57cec5SDimitry Andric     for (const NodeState &node : nodes()) {
31600b57cec5SDimitry Andric       if (node.Start == Trie.begin() + childNodeIndex){
31610b57cec5SDimitry Andric         *E = malformedError("loop in childern in export trie data at node: 0x" +
31620b57cec5SDimitry Andric                             Twine::utohexstr(Top.Start - Trie.begin()) +
31630b57cec5SDimitry Andric                             " back to node: 0x" +
31640b57cec5SDimitry Andric                             Twine::utohexstr(childNodeIndex));
31650b57cec5SDimitry Andric         moveToEnd();
31660b57cec5SDimitry Andric         return;
31670b57cec5SDimitry Andric       }
31680b57cec5SDimitry Andric     }
31690b57cec5SDimitry Andric     Top.NextChildIndex += 1;
31700b57cec5SDimitry Andric     pushNode(childNodeIndex);
31710b57cec5SDimitry Andric     if (*E)
31720b57cec5SDimitry Andric       return;
31730b57cec5SDimitry Andric   }
31740b57cec5SDimitry Andric   if (!Stack.back().IsExportNode) {
31750b57cec5SDimitry Andric     *E = malformedError("node is not an export node in export trie data at "
31760b57cec5SDimitry Andric                         "node: 0x" +
31770b57cec5SDimitry Andric                         Twine::utohexstr(Stack.back().Start - Trie.begin()));
31780b57cec5SDimitry Andric     moveToEnd();
31790b57cec5SDimitry Andric     return;
31800b57cec5SDimitry Andric   }
31810b57cec5SDimitry Andric }
31820b57cec5SDimitry Andric 
31830b57cec5SDimitry Andric // We have a trie data structure and need a way to walk it that is compatible
31840b57cec5SDimitry Andric // with the C++ iterator model. The solution is a non-recursive depth first
31850b57cec5SDimitry Andric // traversal where the iterator contains a stack of parent nodes along with a
31860b57cec5SDimitry Andric // string that is the accumulation of all edge strings along the parent chain
31870b57cec5SDimitry Andric // to this point.
31880b57cec5SDimitry Andric //
31890b57cec5SDimitry Andric // There is one "export" node for each exported symbol.  But because some
31900b57cec5SDimitry Andric // symbols may be a prefix of another symbol (e.g. _dup and _dup2), an export
31910b57cec5SDimitry Andric // node may have child nodes too.
31920b57cec5SDimitry Andric //
31930b57cec5SDimitry Andric // The algorithm for moveNext() is to keep moving down the leftmost unvisited
31940b57cec5SDimitry Andric // child until hitting a node with no children (which is an export node or
31950b57cec5SDimitry Andric // else the trie is malformed). On the way down, each node is pushed on the
31960b57cec5SDimitry Andric // stack ivar.  If there is no more ways down, it pops up one and tries to go
31970b57cec5SDimitry Andric // down a sibling path until a childless node is reached.
moveNext()31980b57cec5SDimitry Andric void ExportEntry::moveNext() {
31990b57cec5SDimitry Andric   assert(!Stack.empty() && "ExportEntry::moveNext() with empty node stack");
32000b57cec5SDimitry Andric   if (!Stack.back().IsExportNode) {
32010b57cec5SDimitry Andric     *E = malformedError("node is not an export node in export trie data at "
32020b57cec5SDimitry Andric                         "node: 0x" +
32030b57cec5SDimitry Andric                         Twine::utohexstr(Stack.back().Start - Trie.begin()));
32040b57cec5SDimitry Andric     moveToEnd();
32050b57cec5SDimitry Andric     return;
32060b57cec5SDimitry Andric   }
32070b57cec5SDimitry Andric 
32080b57cec5SDimitry Andric   Stack.pop_back();
32090b57cec5SDimitry Andric   while (!Stack.empty()) {
32100b57cec5SDimitry Andric     NodeState &Top = Stack.back();
32110b57cec5SDimitry Andric     if (Top.NextChildIndex < Top.ChildCount) {
32120b57cec5SDimitry Andric       pushDownUntilBottom();
32130b57cec5SDimitry Andric       // Now at the next export node.
32140b57cec5SDimitry Andric       return;
32150b57cec5SDimitry Andric     } else {
32160b57cec5SDimitry Andric       if (Top.IsExportNode) {
32170b57cec5SDimitry Andric         // This node has no children but is itself an export node.
32180b57cec5SDimitry Andric         CumulativeString.resize(Top.ParentStringLength);
32190b57cec5SDimitry Andric         return;
32200b57cec5SDimitry Andric       }
32210b57cec5SDimitry Andric       Stack.pop_back();
32220b57cec5SDimitry Andric     }
32230b57cec5SDimitry Andric   }
32240b57cec5SDimitry Andric   Done = true;
32250b57cec5SDimitry Andric }
32260b57cec5SDimitry Andric 
32270b57cec5SDimitry Andric iterator_range<export_iterator>
exports(Error & E,ArrayRef<uint8_t> Trie,const MachOObjectFile * O)32280b57cec5SDimitry Andric MachOObjectFile::exports(Error &E, ArrayRef<uint8_t> Trie,
32290b57cec5SDimitry Andric                          const MachOObjectFile *O) {
32300b57cec5SDimitry Andric   ExportEntry Start(&E, O, Trie);
32310b57cec5SDimitry Andric   if (Trie.empty())
32320b57cec5SDimitry Andric     Start.moveToEnd();
32330b57cec5SDimitry Andric   else
32340b57cec5SDimitry Andric     Start.moveToFirst();
32350b57cec5SDimitry Andric 
32360b57cec5SDimitry Andric   ExportEntry Finish(&E, O, Trie);
32370b57cec5SDimitry Andric   Finish.moveToEnd();
32380b57cec5SDimitry Andric 
32390b57cec5SDimitry Andric   return make_range(export_iterator(Start), export_iterator(Finish));
32400b57cec5SDimitry Andric }
32410b57cec5SDimitry Andric 
exports(Error & Err) const32420b57cec5SDimitry Andric iterator_range<export_iterator> MachOObjectFile::exports(Error &Err) const {
3243bdd1243dSDimitry Andric   ArrayRef<uint8_t> Trie;
3244bdd1243dSDimitry Andric   if (DyldInfoLoadCmd)
3245bdd1243dSDimitry Andric     Trie = getDyldInfoExportsTrie();
3246bdd1243dSDimitry Andric   else if (DyldExportsTrieLoadCmd)
3247bdd1243dSDimitry Andric     Trie = getDyldExportsTrie();
3248bdd1243dSDimitry Andric 
3249bdd1243dSDimitry Andric   return exports(Err, Trie, this);
32500b57cec5SDimitry Andric }
32510b57cec5SDimitry Andric 
MachOAbstractFixupEntry(Error * E,const MachOObjectFile * O)325281ad6265SDimitry Andric MachOAbstractFixupEntry::MachOAbstractFixupEntry(Error *E,
325381ad6265SDimitry Andric                                                  const MachOObjectFile *O)
325481ad6265SDimitry Andric     : E(E), O(O) {
325581ad6265SDimitry Andric   // Cache the vmaddress of __TEXT
325681ad6265SDimitry Andric   for (const auto &Command : O->load_commands()) {
325781ad6265SDimitry Andric     if (Command.C.cmd == MachO::LC_SEGMENT) {
325881ad6265SDimitry Andric       MachO::segment_command SLC = O->getSegmentLoadCommand(Command);
325981ad6265SDimitry Andric       if (StringRef(SLC.segname) == StringRef("__TEXT")) {
326081ad6265SDimitry Andric         TextAddress = SLC.vmaddr;
326181ad6265SDimitry Andric         break;
326281ad6265SDimitry Andric       }
326381ad6265SDimitry Andric     } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
326481ad6265SDimitry Andric       MachO::segment_command_64 SLC_64 = O->getSegment64LoadCommand(Command);
326581ad6265SDimitry Andric       if (StringRef(SLC_64.segname) == StringRef("__TEXT")) {
326681ad6265SDimitry Andric         TextAddress = SLC_64.vmaddr;
326781ad6265SDimitry Andric         break;
326881ad6265SDimitry Andric       }
326981ad6265SDimitry Andric     }
327081ad6265SDimitry Andric   }
327181ad6265SDimitry Andric }
327281ad6265SDimitry Andric 
segmentIndex() const327381ad6265SDimitry Andric int32_t MachOAbstractFixupEntry::segmentIndex() const { return SegmentIndex; }
327481ad6265SDimitry Andric 
segmentOffset() const327581ad6265SDimitry Andric uint64_t MachOAbstractFixupEntry::segmentOffset() const {
327681ad6265SDimitry Andric   return SegmentOffset;
327781ad6265SDimitry Andric }
327881ad6265SDimitry Andric 
segmentAddress() const327981ad6265SDimitry Andric uint64_t MachOAbstractFixupEntry::segmentAddress() const {
328081ad6265SDimitry Andric   return O->BindRebaseAddress(SegmentIndex, 0);
328181ad6265SDimitry Andric }
328281ad6265SDimitry Andric 
segmentName() const328381ad6265SDimitry Andric StringRef MachOAbstractFixupEntry::segmentName() const {
328481ad6265SDimitry Andric   return O->BindRebaseSegmentName(SegmentIndex);
328581ad6265SDimitry Andric }
328681ad6265SDimitry Andric 
sectionName() const328781ad6265SDimitry Andric StringRef MachOAbstractFixupEntry::sectionName() const {
328881ad6265SDimitry Andric   return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);
328981ad6265SDimitry Andric }
329081ad6265SDimitry Andric 
address() const329181ad6265SDimitry Andric uint64_t MachOAbstractFixupEntry::address() const {
329281ad6265SDimitry Andric   return O->BindRebaseAddress(SegmentIndex, SegmentOffset);
329381ad6265SDimitry Andric }
329481ad6265SDimitry Andric 
symbolName() const329581ad6265SDimitry Andric StringRef MachOAbstractFixupEntry::symbolName() const { return SymbolName; }
329681ad6265SDimitry Andric 
addend() const329781ad6265SDimitry Andric int64_t MachOAbstractFixupEntry::addend() const { return Addend; }
329881ad6265SDimitry Andric 
flags() const329981ad6265SDimitry Andric uint32_t MachOAbstractFixupEntry::flags() const { return Flags; }
330081ad6265SDimitry Andric 
ordinal() const330181ad6265SDimitry Andric int MachOAbstractFixupEntry::ordinal() const { return Ordinal; }
330281ad6265SDimitry Andric 
typeName() const330381ad6265SDimitry Andric StringRef MachOAbstractFixupEntry::typeName() const { return "unknown"; }
330481ad6265SDimitry Andric 
moveToFirst()330581ad6265SDimitry Andric void MachOAbstractFixupEntry::moveToFirst() {
330681ad6265SDimitry Andric   SegmentOffset = 0;
330781ad6265SDimitry Andric   SegmentIndex = -1;
330881ad6265SDimitry Andric   Ordinal = 0;
330981ad6265SDimitry Andric   Flags = 0;
331081ad6265SDimitry Andric   Addend = 0;
331181ad6265SDimitry Andric   Done = false;
331281ad6265SDimitry Andric }
331381ad6265SDimitry Andric 
moveToEnd()331481ad6265SDimitry Andric void MachOAbstractFixupEntry::moveToEnd() { Done = true; }
331581ad6265SDimitry Andric 
moveNext()3316bdd1243dSDimitry Andric void MachOAbstractFixupEntry::moveNext() {}
3317bdd1243dSDimitry Andric 
MachOChainedFixupEntry(Error * E,const MachOObjectFile * O,bool Parse)331881ad6265SDimitry Andric MachOChainedFixupEntry::MachOChainedFixupEntry(Error *E,
331981ad6265SDimitry Andric                                                const MachOObjectFile *O,
332081ad6265SDimitry Andric                                                bool Parse)
332181ad6265SDimitry Andric     : MachOAbstractFixupEntry(E, O) {
332281ad6265SDimitry Andric   ErrorAsOutParameter e(E);
332381ad6265SDimitry Andric   if (!Parse)
332481ad6265SDimitry Andric     return;
3325bdd1243dSDimitry Andric 
3326bdd1243dSDimitry Andric   if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets()) {
332781ad6265SDimitry Andric     FixupTargets = *FixupTargetsOrErr;
3328bdd1243dSDimitry Andric   } else {
332981ad6265SDimitry Andric     *E = FixupTargetsOrErr.takeError();
333081ad6265SDimitry Andric     return;
333181ad6265SDimitry Andric   }
3332bdd1243dSDimitry Andric 
3333bdd1243dSDimitry Andric   if (auto SegmentsOrErr = O->getChainedFixupsSegments()) {
3334bdd1243dSDimitry Andric     Segments = std::move(SegmentsOrErr->second);
3335bdd1243dSDimitry Andric   } else {
3336bdd1243dSDimitry Andric     *E = SegmentsOrErr.takeError();
3337bdd1243dSDimitry Andric     return;
3338bdd1243dSDimitry Andric   }
3339bdd1243dSDimitry Andric }
3340bdd1243dSDimitry Andric 
findNextPageWithFixups()3341bdd1243dSDimitry Andric void MachOChainedFixupEntry::findNextPageWithFixups() {
3342bdd1243dSDimitry Andric   auto FindInSegment = [this]() {
3343bdd1243dSDimitry Andric     const ChainedFixupsSegment &SegInfo = Segments[InfoSegIndex];
3344bdd1243dSDimitry Andric     while (PageIndex < SegInfo.PageStarts.size() &&
3345bdd1243dSDimitry Andric            SegInfo.PageStarts[PageIndex] == MachO::DYLD_CHAINED_PTR_START_NONE)
3346bdd1243dSDimitry Andric       ++PageIndex;
3347bdd1243dSDimitry Andric     return PageIndex < SegInfo.PageStarts.size();
3348bdd1243dSDimitry Andric   };
3349bdd1243dSDimitry Andric 
3350bdd1243dSDimitry Andric   while (InfoSegIndex < Segments.size()) {
3351bdd1243dSDimitry Andric     if (FindInSegment()) {
3352bdd1243dSDimitry Andric       PageOffset = Segments[InfoSegIndex].PageStarts[PageIndex];
3353bdd1243dSDimitry Andric       SegmentData = O->getSegmentContents(Segments[InfoSegIndex].SegIdx);
3354bdd1243dSDimitry Andric       return;
3355bdd1243dSDimitry Andric     }
3356bdd1243dSDimitry Andric 
3357bdd1243dSDimitry Andric     InfoSegIndex++;
3358bdd1243dSDimitry Andric     PageIndex = 0;
3359bdd1243dSDimitry Andric   }
336081ad6265SDimitry Andric }
336181ad6265SDimitry Andric 
moveToFirst()336281ad6265SDimitry Andric void MachOChainedFixupEntry::moveToFirst() {
336381ad6265SDimitry Andric   MachOAbstractFixupEntry::moveToFirst();
3364bdd1243dSDimitry Andric   if (Segments.empty()) {
3365bdd1243dSDimitry Andric     Done = true;
3366bdd1243dSDimitry Andric     return;
3367bdd1243dSDimitry Andric   }
3368bdd1243dSDimitry Andric 
3369bdd1243dSDimitry Andric   InfoSegIndex = 0;
3370bdd1243dSDimitry Andric   PageIndex = 0;
3371bdd1243dSDimitry Andric 
3372bdd1243dSDimitry Andric   findNextPageWithFixups();
337381ad6265SDimitry Andric   moveNext();
337481ad6265SDimitry Andric }
337581ad6265SDimitry Andric 
moveToEnd()337681ad6265SDimitry Andric void MachOChainedFixupEntry::moveToEnd() {
337781ad6265SDimitry Andric   MachOAbstractFixupEntry::moveToEnd();
337881ad6265SDimitry Andric }
337981ad6265SDimitry Andric 
moveNext()3380bdd1243dSDimitry Andric void MachOChainedFixupEntry::moveNext() {
3381bdd1243dSDimitry Andric   ErrorAsOutParameter ErrAsOutParam(E);
3382bdd1243dSDimitry Andric 
3383bdd1243dSDimitry Andric   if (InfoSegIndex == Segments.size()) {
3384bdd1243dSDimitry Andric     Done = true;
3385bdd1243dSDimitry Andric     return;
3386bdd1243dSDimitry Andric   }
3387bdd1243dSDimitry Andric 
3388bdd1243dSDimitry Andric   const ChainedFixupsSegment &SegInfo = Segments[InfoSegIndex];
3389bdd1243dSDimitry Andric   SegmentIndex = SegInfo.SegIdx;
3390bdd1243dSDimitry Andric   SegmentOffset = SegInfo.Header.page_size * PageIndex + PageOffset;
3391bdd1243dSDimitry Andric 
3392bdd1243dSDimitry Andric   // FIXME: Handle other pointer formats.
3393bdd1243dSDimitry Andric   uint16_t PointerFormat = SegInfo.Header.pointer_format;
3394bdd1243dSDimitry Andric   if (PointerFormat != MachO::DYLD_CHAINED_PTR_64 &&
3395bdd1243dSDimitry Andric       PointerFormat != MachO::DYLD_CHAINED_PTR_64_OFFSET) {
3396bdd1243dSDimitry Andric     *E = createError("segment " + Twine(SegmentIndex) +
3397bdd1243dSDimitry Andric                      " has unsupported chained fixup pointer_format " +
3398bdd1243dSDimitry Andric                      Twine(PointerFormat));
3399bdd1243dSDimitry Andric     moveToEnd();
3400bdd1243dSDimitry Andric     return;
3401bdd1243dSDimitry Andric   }
3402bdd1243dSDimitry Andric 
3403bdd1243dSDimitry Andric   Ordinal = 0;
3404bdd1243dSDimitry Andric   Flags = 0;
3405bdd1243dSDimitry Andric   Addend = 0;
3406bdd1243dSDimitry Andric   PointerValue = 0;
3407bdd1243dSDimitry Andric   SymbolName = {};
3408bdd1243dSDimitry Andric 
3409bdd1243dSDimitry Andric   if (SegmentOffset + sizeof(RawValue) > SegmentData.size()) {
3410bdd1243dSDimitry Andric     *E = malformedError("fixup in segment " + Twine(SegmentIndex) +
3411bdd1243dSDimitry Andric                         " at offset " + Twine(SegmentOffset) +
3412bdd1243dSDimitry Andric                         " extends past segment's end");
3413bdd1243dSDimitry Andric     moveToEnd();
3414bdd1243dSDimitry Andric     return;
3415bdd1243dSDimitry Andric   }
3416bdd1243dSDimitry Andric 
3417bdd1243dSDimitry Andric   static_assert(sizeof(RawValue) == sizeof(MachO::dyld_chained_import_addend));
3418bdd1243dSDimitry Andric   memcpy(&RawValue, SegmentData.data() + SegmentOffset, sizeof(RawValue));
3419bdd1243dSDimitry Andric   if (O->isLittleEndian() != sys::IsLittleEndianHost)
3420bdd1243dSDimitry Andric     sys::swapByteOrder(RawValue);
3421bdd1243dSDimitry Andric 
3422bdd1243dSDimitry Andric   // The bit extraction below assumes little-endian fixup entries.
3423bdd1243dSDimitry Andric   assert(O->isLittleEndian() && "big-endian object should have been rejected "
3424bdd1243dSDimitry Andric                                 "by getDyldChainedFixupTargets()");
3425bdd1243dSDimitry Andric   auto Field = [this](uint8_t Right, uint8_t Count) {
3426bdd1243dSDimitry Andric     return (RawValue >> Right) & ((1ULL << Count) - 1);
3427bdd1243dSDimitry Andric   };
3428bdd1243dSDimitry Andric 
3429bdd1243dSDimitry Andric   // The `bind` field (most significant bit) of the encoded fixup determines
3430bdd1243dSDimitry Andric   // whether it is dyld_chained_ptr_64_bind or dyld_chained_ptr_64_rebase.
3431bdd1243dSDimitry Andric   bool IsBind = Field(63, 1);
3432bdd1243dSDimitry Andric   Kind = IsBind ? FixupKind::Bind : FixupKind::Rebase;
3433bdd1243dSDimitry Andric   uint32_t Next = Field(51, 12);
3434bdd1243dSDimitry Andric   if (IsBind) {
3435bdd1243dSDimitry Andric     uint32_t ImportOrdinal = Field(0, 24);
3436bdd1243dSDimitry Andric     uint8_t InlineAddend = Field(24, 8);
3437bdd1243dSDimitry Andric 
3438bdd1243dSDimitry Andric     if (ImportOrdinal >= FixupTargets.size()) {
3439bdd1243dSDimitry Andric       *E = malformedError("fixup in segment " + Twine(SegmentIndex) +
3440bdd1243dSDimitry Andric                           " at offset " + Twine(SegmentOffset) +
3441bdd1243dSDimitry Andric                           "  has out-of range import ordinal " +
3442bdd1243dSDimitry Andric                           Twine(ImportOrdinal));
3443bdd1243dSDimitry Andric       moveToEnd();
3444bdd1243dSDimitry Andric       return;
3445bdd1243dSDimitry Andric     }
3446bdd1243dSDimitry Andric 
3447bdd1243dSDimitry Andric     ChainedFixupTarget &Target = FixupTargets[ImportOrdinal];
3448bdd1243dSDimitry Andric     Ordinal = Target.libOrdinal();
3449bdd1243dSDimitry Andric     Addend = InlineAddend ? InlineAddend : Target.addend();
3450bdd1243dSDimitry Andric     Flags = Target.weakImport() ? MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0;
3451bdd1243dSDimitry Andric     SymbolName = Target.symbolName();
3452bdd1243dSDimitry Andric   } else {
3453bdd1243dSDimitry Andric     uint64_t Target = Field(0, 36);
3454bdd1243dSDimitry Andric     uint64_t High8 = Field(36, 8);
3455bdd1243dSDimitry Andric 
3456bdd1243dSDimitry Andric     PointerValue = Target | (High8 << 56);
3457bdd1243dSDimitry Andric     if (PointerFormat == MachO::DYLD_CHAINED_PTR_64_OFFSET)
3458bdd1243dSDimitry Andric       PointerValue += textAddress();
3459bdd1243dSDimitry Andric   }
3460bdd1243dSDimitry Andric 
3461bdd1243dSDimitry Andric   // The stride is 4 bytes for DYLD_CHAINED_PTR_64(_OFFSET).
3462bdd1243dSDimitry Andric   if (Next != 0) {
3463bdd1243dSDimitry Andric     PageOffset += 4 * Next;
3464bdd1243dSDimitry Andric   } else {
3465bdd1243dSDimitry Andric     ++PageIndex;
3466bdd1243dSDimitry Andric     findNextPageWithFixups();
3467bdd1243dSDimitry Andric   }
3468bdd1243dSDimitry Andric }
346981ad6265SDimitry Andric 
operator ==(const MachOChainedFixupEntry & Other) const347081ad6265SDimitry Andric bool MachOChainedFixupEntry::operator==(
347181ad6265SDimitry Andric     const MachOChainedFixupEntry &Other) const {
3472bdd1243dSDimitry Andric   if (Done && Other.Done)
347381ad6265SDimitry Andric     return true;
3474bdd1243dSDimitry Andric   if (Done != Other.Done)
347581ad6265SDimitry Andric     return false;
3476bdd1243dSDimitry Andric   return InfoSegIndex == Other.InfoSegIndex && PageIndex == Other.PageIndex &&
3477bdd1243dSDimitry Andric          PageOffset == Other.PageOffset;
347881ad6265SDimitry Andric }
347981ad6265SDimitry Andric 
MachORebaseEntry(Error * E,const MachOObjectFile * O,ArrayRef<uint8_t> Bytes,bool is64Bit)34800b57cec5SDimitry Andric MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O,
34810b57cec5SDimitry Andric                                    ArrayRef<uint8_t> Bytes, bool is64Bit)
34820b57cec5SDimitry Andric     : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()),
34830b57cec5SDimitry Andric       PointerSize(is64Bit ? 8 : 4) {}
34840b57cec5SDimitry Andric 
moveToFirst()34850b57cec5SDimitry Andric void MachORebaseEntry::moveToFirst() {
34860b57cec5SDimitry Andric   Ptr = Opcodes.begin();
34870b57cec5SDimitry Andric   moveNext();
34880b57cec5SDimitry Andric }
34890b57cec5SDimitry Andric 
moveToEnd()34900b57cec5SDimitry Andric void MachORebaseEntry::moveToEnd() {
34910b57cec5SDimitry Andric   Ptr = Opcodes.end();
34920b57cec5SDimitry Andric   RemainingLoopCount = 0;
34930b57cec5SDimitry Andric   Done = true;
34940b57cec5SDimitry Andric }
34950b57cec5SDimitry Andric 
moveNext()34960b57cec5SDimitry Andric void MachORebaseEntry::moveNext() {
34970b57cec5SDimitry Andric   ErrorAsOutParameter ErrAsOutParam(E);
34980b57cec5SDimitry Andric   // If in the middle of some loop, move to next rebasing in loop.
34990b57cec5SDimitry Andric   SegmentOffset += AdvanceAmount;
35000b57cec5SDimitry Andric   if (RemainingLoopCount) {
35010b57cec5SDimitry Andric     --RemainingLoopCount;
35020b57cec5SDimitry Andric     return;
35030b57cec5SDimitry Andric   }
35040b57cec5SDimitry Andric   // REBASE_OPCODE_DONE is only used for padding if we are not aligned to
35050b57cec5SDimitry Andric   // pointer size. Therefore it is possible to reach the end without ever having
35060b57cec5SDimitry Andric   // seen REBASE_OPCODE_DONE.
35070b57cec5SDimitry Andric   if (Ptr == Opcodes.end()) {
35080b57cec5SDimitry Andric     Done = true;
35090b57cec5SDimitry Andric     return;
35100b57cec5SDimitry Andric   }
35110b57cec5SDimitry Andric   bool More = true;
35120b57cec5SDimitry Andric   while (More) {
35130b57cec5SDimitry Andric     // Parse next opcode and set up next loop.
35140b57cec5SDimitry Andric     const uint8_t *OpcodeStart = Ptr;
35150b57cec5SDimitry Andric     uint8_t Byte = *Ptr++;
35160b57cec5SDimitry Andric     uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK;
35170b57cec5SDimitry Andric     uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK;
35180b57cec5SDimitry Andric     uint32_t Count, Skip;
35190b57cec5SDimitry Andric     const char *error = nullptr;
35200b57cec5SDimitry Andric     switch (Opcode) {
35210b57cec5SDimitry Andric     case MachO::REBASE_OPCODE_DONE:
35220b57cec5SDimitry Andric       More = false;
35230b57cec5SDimitry Andric       Done = true;
35240b57cec5SDimitry Andric       moveToEnd();
35250b57cec5SDimitry Andric       DEBUG_WITH_TYPE("mach-o-rebase", dbgs() << "REBASE_OPCODE_DONE\n");
35260b57cec5SDimitry Andric       break;
35270b57cec5SDimitry Andric     case MachO::REBASE_OPCODE_SET_TYPE_IMM:
35280b57cec5SDimitry Andric       RebaseType = ImmValue;
35290b57cec5SDimitry Andric       if (RebaseType > MachO::REBASE_TYPE_TEXT_PCREL32) {
35300b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_SET_TYPE_IMM bad bind type: " +
35310b57cec5SDimitry Andric                             Twine((int)RebaseType) + " for opcode at: 0x" +
35320b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
35330b57cec5SDimitry Andric         moveToEnd();
35340b57cec5SDimitry Andric         return;
35350b57cec5SDimitry Andric       }
35360b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
35370b57cec5SDimitry Andric           "mach-o-rebase",
35380b57cec5SDimitry Andric           dbgs() << "REBASE_OPCODE_SET_TYPE_IMM: "
35390b57cec5SDimitry Andric                  << "RebaseType=" << (int) RebaseType << "\n");
35400b57cec5SDimitry Andric       break;
35410b57cec5SDimitry Andric     case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
35420b57cec5SDimitry Andric       SegmentIndex = ImmValue;
35430b57cec5SDimitry Andric       SegmentOffset = readULEB128(&error);
35440b57cec5SDimitry Andric       if (error) {
35450b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
35460b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
35470b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
35480b57cec5SDimitry Andric         moveToEnd();
35490b57cec5SDimitry Andric         return;
35500b57cec5SDimitry Andric       }
35510b57cec5SDimitry Andric       error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
35520b57cec5SDimitry Andric                                                PointerSize);
35530b57cec5SDimitry Andric       if (error) {
35540b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
35550b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
35560b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
35570b57cec5SDimitry Andric         moveToEnd();
35580b57cec5SDimitry Andric         return;
35590b57cec5SDimitry Andric       }
35600b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
35610b57cec5SDimitry Andric           "mach-o-rebase",
35620b57cec5SDimitry Andric           dbgs() << "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "
35630b57cec5SDimitry Andric                  << "SegmentIndex=" << SegmentIndex << ", "
35640b57cec5SDimitry Andric                  << format("SegmentOffset=0x%06X", SegmentOffset)
35650b57cec5SDimitry Andric                  << "\n");
35660b57cec5SDimitry Andric       break;
35670b57cec5SDimitry Andric     case MachO::REBASE_OPCODE_ADD_ADDR_ULEB:
35680b57cec5SDimitry Andric       SegmentOffset += readULEB128(&error);
35690b57cec5SDimitry Andric       if (error) {
35700b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) +
35710b57cec5SDimitry Andric                             " for opcode at: 0x" +
35720b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
35730b57cec5SDimitry Andric         moveToEnd();
35740b57cec5SDimitry Andric         return;
35750b57cec5SDimitry Andric       }
35760b57cec5SDimitry Andric       error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
35770b57cec5SDimitry Andric                                                PointerSize);
35780b57cec5SDimitry Andric       if (error) {
35790b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) +
35800b57cec5SDimitry Andric                             " for opcode at: 0x" +
35810b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
35820b57cec5SDimitry Andric         moveToEnd();
35830b57cec5SDimitry Andric         return;
35840b57cec5SDimitry Andric       }
35850b57cec5SDimitry Andric       DEBUG_WITH_TYPE("mach-o-rebase",
35860b57cec5SDimitry Andric                       dbgs() << "REBASE_OPCODE_ADD_ADDR_ULEB: "
35870b57cec5SDimitry Andric                              << format("SegmentOffset=0x%06X",
35880b57cec5SDimitry Andric                                        SegmentOffset) << "\n");
35890b57cec5SDimitry Andric       break;
35900b57cec5SDimitry Andric     case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
35910b57cec5SDimitry Andric       SegmentOffset += ImmValue * PointerSize;
35920b57cec5SDimitry Andric       error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
35930b57cec5SDimitry Andric                                                PointerSize);
35940b57cec5SDimitry Andric       if (error) {
35955ffd83dbSDimitry Andric         *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " +
35960b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
35970b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
35980b57cec5SDimitry Andric         moveToEnd();
35990b57cec5SDimitry Andric         return;
36000b57cec5SDimitry Andric       }
36010b57cec5SDimitry Andric       DEBUG_WITH_TYPE("mach-o-rebase",
36020b57cec5SDimitry Andric                       dbgs() << "REBASE_OPCODE_ADD_ADDR_IMM_SCALED: "
36030b57cec5SDimitry Andric                              << format("SegmentOffset=0x%06X",
36040b57cec5SDimitry Andric                                        SegmentOffset) << "\n");
36050b57cec5SDimitry Andric       break;
36060b57cec5SDimitry Andric     case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES:
36070b57cec5SDimitry Andric       AdvanceAmount = PointerSize;
36080b57cec5SDimitry Andric       Skip = 0;
36090b57cec5SDimitry Andric       Count = ImmValue;
36100b57cec5SDimitry Andric       if (ImmValue != 0)
36110b57cec5SDimitry Andric         RemainingLoopCount = ImmValue - 1;
36120b57cec5SDimitry Andric       else
36130b57cec5SDimitry Andric         RemainingLoopCount = 0;
36140b57cec5SDimitry Andric       error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
36150b57cec5SDimitry Andric                                                PointerSize, Count, Skip);
36160b57cec5SDimitry Andric       if (error) {
36170b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " +
36180b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
36190b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
36200b57cec5SDimitry Andric         moveToEnd();
36210b57cec5SDimitry Andric         return;
36220b57cec5SDimitry Andric       }
36230b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
36240b57cec5SDimitry Andric           "mach-o-rebase",
36250b57cec5SDimitry Andric           dbgs() << "REBASE_OPCODE_DO_REBASE_IMM_TIMES: "
36260b57cec5SDimitry Andric                  << format("SegmentOffset=0x%06X", SegmentOffset)
36270b57cec5SDimitry Andric                  << ", AdvanceAmount=" << AdvanceAmount
36280b57cec5SDimitry Andric                  << ", RemainingLoopCount=" << RemainingLoopCount
36290b57cec5SDimitry Andric                  << "\n");
36300b57cec5SDimitry Andric       return;
36310b57cec5SDimitry Andric     case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
36320b57cec5SDimitry Andric       AdvanceAmount = PointerSize;
36330b57cec5SDimitry Andric       Skip = 0;
36340b57cec5SDimitry Andric       Count = readULEB128(&error);
36350b57cec5SDimitry Andric       if (error) {
36360b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +
36370b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
36380b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
36390b57cec5SDimitry Andric         moveToEnd();
36400b57cec5SDimitry Andric         return;
36410b57cec5SDimitry Andric       }
36420b57cec5SDimitry Andric       if (Count != 0)
36430b57cec5SDimitry Andric         RemainingLoopCount = Count - 1;
36440b57cec5SDimitry Andric       else
36450b57cec5SDimitry Andric         RemainingLoopCount = 0;
36460b57cec5SDimitry Andric       error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
36470b57cec5SDimitry Andric                                                PointerSize, Count, Skip);
36480b57cec5SDimitry Andric       if (error) {
36490b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +
36500b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
36510b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
36520b57cec5SDimitry Andric         moveToEnd();
36530b57cec5SDimitry Andric         return;
36540b57cec5SDimitry Andric       }
36550b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
36560b57cec5SDimitry Andric           "mach-o-rebase",
36570b57cec5SDimitry Andric           dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES: "
36580b57cec5SDimitry Andric                  << format("SegmentOffset=0x%06X", SegmentOffset)
36590b57cec5SDimitry Andric                  << ", AdvanceAmount=" << AdvanceAmount
36600b57cec5SDimitry Andric                  << ", RemainingLoopCount=" << RemainingLoopCount
36610b57cec5SDimitry Andric                  << "\n");
36620b57cec5SDimitry Andric       return;
36630b57cec5SDimitry Andric     case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
36640b57cec5SDimitry Andric       Skip = readULEB128(&error);
36650b57cec5SDimitry Andric       if (error) {
36660b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +
36670b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
36680b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
36690b57cec5SDimitry Andric         moveToEnd();
36700b57cec5SDimitry Andric         return;
36710b57cec5SDimitry Andric       }
36720b57cec5SDimitry Andric       AdvanceAmount = Skip + PointerSize;
36730b57cec5SDimitry Andric       Count = 1;
36740b57cec5SDimitry Andric       RemainingLoopCount = 0;
36750b57cec5SDimitry Andric       error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
36760b57cec5SDimitry Andric                                                PointerSize, Count, Skip);
36770b57cec5SDimitry Andric       if (error) {
36780b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +
36790b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
36800b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
36810b57cec5SDimitry Andric         moveToEnd();
36820b57cec5SDimitry Andric         return;
36830b57cec5SDimitry Andric       }
36840b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
36850b57cec5SDimitry Andric           "mach-o-rebase",
36860b57cec5SDimitry Andric           dbgs() << "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: "
36870b57cec5SDimitry Andric                  << format("SegmentOffset=0x%06X", SegmentOffset)
36880b57cec5SDimitry Andric                  << ", AdvanceAmount=" << AdvanceAmount
36890b57cec5SDimitry Andric                  << ", RemainingLoopCount=" << RemainingLoopCount
36900b57cec5SDimitry Andric                  << "\n");
36910b57cec5SDimitry Andric       return;
36920b57cec5SDimitry Andric     case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
36930b57cec5SDimitry Andric       Count = readULEB128(&error);
36940b57cec5SDimitry Andric       if (error) {
36950b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
36960b57cec5SDimitry Andric                             "ULEB " +
36970b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
36980b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
36990b57cec5SDimitry Andric         moveToEnd();
37000b57cec5SDimitry Andric         return;
37010b57cec5SDimitry Andric       }
37020b57cec5SDimitry Andric       if (Count != 0)
37030b57cec5SDimitry Andric         RemainingLoopCount = Count - 1;
37040b57cec5SDimitry Andric       else
37050b57cec5SDimitry Andric         RemainingLoopCount = 0;
37060b57cec5SDimitry Andric       Skip = readULEB128(&error);
37070b57cec5SDimitry Andric       if (error) {
37080b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
37090b57cec5SDimitry Andric                             "ULEB " +
37100b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
37110b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
37120b57cec5SDimitry Andric         moveToEnd();
37130b57cec5SDimitry Andric         return;
37140b57cec5SDimitry Andric       }
37150b57cec5SDimitry Andric       AdvanceAmount = Skip + PointerSize;
37160b57cec5SDimitry Andric 
37170b57cec5SDimitry Andric       error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
37180b57cec5SDimitry Andric                                                PointerSize, Count, Skip);
37190b57cec5SDimitry Andric       if (error) {
37200b57cec5SDimitry Andric         *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
37210b57cec5SDimitry Andric                             "ULEB " +
37220b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
37230b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
37240b57cec5SDimitry Andric         moveToEnd();
37250b57cec5SDimitry Andric         return;
37260b57cec5SDimitry Andric       }
37270b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
37280b57cec5SDimitry Andric           "mach-o-rebase",
37290b57cec5SDimitry Andric           dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: "
37300b57cec5SDimitry Andric                  << format("SegmentOffset=0x%06X", SegmentOffset)
37310b57cec5SDimitry Andric                  << ", AdvanceAmount=" << AdvanceAmount
37320b57cec5SDimitry Andric                  << ", RemainingLoopCount=" << RemainingLoopCount
37330b57cec5SDimitry Andric                  << "\n");
37340b57cec5SDimitry Andric       return;
37350b57cec5SDimitry Andric     default:
37360b57cec5SDimitry Andric       *E = malformedError("bad rebase info (bad opcode value 0x" +
37370b57cec5SDimitry Andric                           Twine::utohexstr(Opcode) + " for opcode at: 0x" +
37380b57cec5SDimitry Andric                           Twine::utohexstr(OpcodeStart - Opcodes.begin()));
37390b57cec5SDimitry Andric       moveToEnd();
37400b57cec5SDimitry Andric       return;
37410b57cec5SDimitry Andric     }
37420b57cec5SDimitry Andric   }
37430b57cec5SDimitry Andric }
37440b57cec5SDimitry Andric 
readULEB128(const char ** error)37450b57cec5SDimitry Andric uint64_t MachORebaseEntry::readULEB128(const char **error) {
37460b57cec5SDimitry Andric   unsigned Count;
37470b57cec5SDimitry Andric   uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);
37480b57cec5SDimitry Andric   Ptr += Count;
37490b57cec5SDimitry Andric   if (Ptr > Opcodes.end())
37500b57cec5SDimitry Andric     Ptr = Opcodes.end();
37510b57cec5SDimitry Andric   return Result;
37520b57cec5SDimitry Andric }
37530b57cec5SDimitry Andric 
segmentIndex() const37540b57cec5SDimitry Andric int32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; }
37550b57cec5SDimitry Andric 
segmentOffset() const37560b57cec5SDimitry Andric uint64_t MachORebaseEntry::segmentOffset() const { return SegmentOffset; }
37570b57cec5SDimitry Andric 
typeName() const37580b57cec5SDimitry Andric StringRef MachORebaseEntry::typeName() const {
37590b57cec5SDimitry Andric   switch (RebaseType) {
37600b57cec5SDimitry Andric   case MachO::REBASE_TYPE_POINTER:
37610b57cec5SDimitry Andric     return "pointer";
37620b57cec5SDimitry Andric   case MachO::REBASE_TYPE_TEXT_ABSOLUTE32:
37630b57cec5SDimitry Andric     return "text abs32";
37640b57cec5SDimitry Andric   case MachO::REBASE_TYPE_TEXT_PCREL32:
37650b57cec5SDimitry Andric     return "text rel32";
37660b57cec5SDimitry Andric   }
37670b57cec5SDimitry Andric   return "unknown";
37680b57cec5SDimitry Andric }
37690b57cec5SDimitry Andric 
37700b57cec5SDimitry Andric // For use with the SegIndex of a checked Mach-O Rebase entry
37710b57cec5SDimitry Andric // to get the segment name.
segmentName() const37720b57cec5SDimitry Andric StringRef MachORebaseEntry::segmentName() const {
37730b57cec5SDimitry Andric   return O->BindRebaseSegmentName(SegmentIndex);
37740b57cec5SDimitry Andric }
37750b57cec5SDimitry Andric 
37760b57cec5SDimitry Andric // For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry
37770b57cec5SDimitry Andric // to get the section name.
sectionName() const37780b57cec5SDimitry Andric StringRef MachORebaseEntry::sectionName() const {
37790b57cec5SDimitry Andric   return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);
37800b57cec5SDimitry Andric }
37810b57cec5SDimitry Andric 
37820b57cec5SDimitry Andric // For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry
37830b57cec5SDimitry Andric // to get the address.
address() const37840b57cec5SDimitry Andric uint64_t MachORebaseEntry::address() const {
37850b57cec5SDimitry Andric   return O->BindRebaseAddress(SegmentIndex, SegmentOffset);
37860b57cec5SDimitry Andric }
37870b57cec5SDimitry Andric 
operator ==(const MachORebaseEntry & Other) const37880b57cec5SDimitry Andric bool MachORebaseEntry::operator==(const MachORebaseEntry &Other) const {
37890b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS
37900b57cec5SDimitry Andric   assert(Opcodes == Other.Opcodes && "compare iterators of different files");
37910b57cec5SDimitry Andric #else
37920b57cec5SDimitry Andric   assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files");
37930b57cec5SDimitry Andric #endif
37940b57cec5SDimitry Andric   return (Ptr == Other.Ptr) &&
37950b57cec5SDimitry Andric          (RemainingLoopCount == Other.RemainingLoopCount) &&
37960b57cec5SDimitry Andric          (Done == Other.Done);
37970b57cec5SDimitry Andric }
37980b57cec5SDimitry Andric 
37990b57cec5SDimitry Andric iterator_range<rebase_iterator>
rebaseTable(Error & Err,MachOObjectFile * O,ArrayRef<uint8_t> Opcodes,bool is64)38000b57cec5SDimitry Andric MachOObjectFile::rebaseTable(Error &Err, MachOObjectFile *O,
38010b57cec5SDimitry Andric                              ArrayRef<uint8_t> Opcodes, bool is64) {
38020b57cec5SDimitry Andric   if (O->BindRebaseSectionTable == nullptr)
38038bcb0991SDimitry Andric     O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);
38040b57cec5SDimitry Andric   MachORebaseEntry Start(&Err, O, Opcodes, is64);
38050b57cec5SDimitry Andric   Start.moveToFirst();
38060b57cec5SDimitry Andric 
38070b57cec5SDimitry Andric   MachORebaseEntry Finish(&Err, O, Opcodes, is64);
38080b57cec5SDimitry Andric   Finish.moveToEnd();
38090b57cec5SDimitry Andric 
38100b57cec5SDimitry Andric   return make_range(rebase_iterator(Start), rebase_iterator(Finish));
38110b57cec5SDimitry Andric }
38120b57cec5SDimitry Andric 
rebaseTable(Error & Err)38130b57cec5SDimitry Andric iterator_range<rebase_iterator> MachOObjectFile::rebaseTable(Error &Err) {
38140b57cec5SDimitry Andric   return rebaseTable(Err, this, getDyldInfoRebaseOpcodes(), is64Bit());
38150b57cec5SDimitry Andric }
38160b57cec5SDimitry Andric 
MachOBindEntry(Error * E,const MachOObjectFile * O,ArrayRef<uint8_t> Bytes,bool is64Bit,Kind BK)38170b57cec5SDimitry Andric MachOBindEntry::MachOBindEntry(Error *E, const MachOObjectFile *O,
38180b57cec5SDimitry Andric                                ArrayRef<uint8_t> Bytes, bool is64Bit, Kind BK)
38190b57cec5SDimitry Andric     : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()),
38200b57cec5SDimitry Andric       PointerSize(is64Bit ? 8 : 4), TableKind(BK) {}
38210b57cec5SDimitry Andric 
moveToFirst()38220b57cec5SDimitry Andric void MachOBindEntry::moveToFirst() {
38230b57cec5SDimitry Andric   Ptr = Opcodes.begin();
38240b57cec5SDimitry Andric   moveNext();
38250b57cec5SDimitry Andric }
38260b57cec5SDimitry Andric 
moveToEnd()38270b57cec5SDimitry Andric void MachOBindEntry::moveToEnd() {
38280b57cec5SDimitry Andric   Ptr = Opcodes.end();
38290b57cec5SDimitry Andric   RemainingLoopCount = 0;
38300b57cec5SDimitry Andric   Done = true;
38310b57cec5SDimitry Andric }
38320b57cec5SDimitry Andric 
moveNext()38330b57cec5SDimitry Andric void MachOBindEntry::moveNext() {
38340b57cec5SDimitry Andric   ErrorAsOutParameter ErrAsOutParam(E);
38350b57cec5SDimitry Andric   // If in the middle of some loop, move to next binding in loop.
38360b57cec5SDimitry Andric   SegmentOffset += AdvanceAmount;
38370b57cec5SDimitry Andric   if (RemainingLoopCount) {
38380b57cec5SDimitry Andric     --RemainingLoopCount;
38390b57cec5SDimitry Andric     return;
38400b57cec5SDimitry Andric   }
38410b57cec5SDimitry Andric   // BIND_OPCODE_DONE is only used for padding if we are not aligned to
38420b57cec5SDimitry Andric   // pointer size. Therefore it is possible to reach the end without ever having
38430b57cec5SDimitry Andric   // seen BIND_OPCODE_DONE.
38440b57cec5SDimitry Andric   if (Ptr == Opcodes.end()) {
38450b57cec5SDimitry Andric     Done = true;
38460b57cec5SDimitry Andric     return;
38470b57cec5SDimitry Andric   }
38480b57cec5SDimitry Andric   bool More = true;
38490b57cec5SDimitry Andric   while (More) {
38500b57cec5SDimitry Andric     // Parse next opcode and set up next loop.
38510b57cec5SDimitry Andric     const uint8_t *OpcodeStart = Ptr;
38520b57cec5SDimitry Andric     uint8_t Byte = *Ptr++;
38530b57cec5SDimitry Andric     uint8_t ImmValue = Byte & MachO::BIND_IMMEDIATE_MASK;
38540b57cec5SDimitry Andric     uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK;
38550b57cec5SDimitry Andric     int8_t SignExtended;
38560b57cec5SDimitry Andric     const uint8_t *SymStart;
38570b57cec5SDimitry Andric     uint32_t Count, Skip;
38580b57cec5SDimitry Andric     const char *error = nullptr;
38590b57cec5SDimitry Andric     switch (Opcode) {
38600b57cec5SDimitry Andric     case MachO::BIND_OPCODE_DONE:
38610b57cec5SDimitry Andric       if (TableKind == Kind::Lazy) {
38620b57cec5SDimitry Andric         // Lazying bindings have a DONE opcode between entries.  Need to ignore
38630b57cec5SDimitry Andric         // it to advance to next entry.  But need not if this is last entry.
38640b57cec5SDimitry Andric         bool NotLastEntry = false;
38650b57cec5SDimitry Andric         for (const uint8_t *P = Ptr; P < Opcodes.end(); ++P) {
38660b57cec5SDimitry Andric           if (*P) {
38670b57cec5SDimitry Andric             NotLastEntry = true;
38680b57cec5SDimitry Andric           }
38690b57cec5SDimitry Andric         }
38700b57cec5SDimitry Andric         if (NotLastEntry)
38710b57cec5SDimitry Andric           break;
38720b57cec5SDimitry Andric       }
38730b57cec5SDimitry Andric       More = false;
38740b57cec5SDimitry Andric       moveToEnd();
38750b57cec5SDimitry Andric       DEBUG_WITH_TYPE("mach-o-bind", dbgs() << "BIND_OPCODE_DONE\n");
38760b57cec5SDimitry Andric       break;
38770b57cec5SDimitry Andric     case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
38780b57cec5SDimitry Andric       if (TableKind == Kind::Weak) {
38790b57cec5SDimitry Andric         *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM not allowed in "
38800b57cec5SDimitry Andric                             "weak bind table for opcode at: 0x" +
38810b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
38820b57cec5SDimitry Andric         moveToEnd();
38830b57cec5SDimitry Andric         return;
38840b57cec5SDimitry Andric       }
38850b57cec5SDimitry Andric       Ordinal = ImmValue;
38860b57cec5SDimitry Andric       LibraryOrdinalSet = true;
38870b57cec5SDimitry Andric       if (ImmValue > O->getLibraryCount()) {
38880b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad "
38890b57cec5SDimitry Andric                             "library ordinal: " +
38900b57cec5SDimitry Andric                             Twine((int)ImmValue) + " (max " +
38910b57cec5SDimitry Andric                             Twine((int)O->getLibraryCount()) +
38920b57cec5SDimitry Andric                             ") for opcode at: 0x" +
38930b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
38940b57cec5SDimitry Andric         moveToEnd();
38950b57cec5SDimitry Andric         return;
38960b57cec5SDimitry Andric       }
38970b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
38980b57cec5SDimitry Andric           "mach-o-bind",
38990b57cec5SDimitry Andric           dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: "
39000b57cec5SDimitry Andric                  << "Ordinal=" << Ordinal << "\n");
39010b57cec5SDimitry Andric       break;
39020b57cec5SDimitry Andric     case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
39030b57cec5SDimitry Andric       if (TableKind == Kind::Weak) {
39040b57cec5SDimitry Andric         *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB not allowed in "
39050b57cec5SDimitry Andric                             "weak bind table for opcode at: 0x" +
39060b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
39070b57cec5SDimitry Andric         moveToEnd();
39080b57cec5SDimitry Andric         return;
39090b57cec5SDimitry Andric       }
39100b57cec5SDimitry Andric       Ordinal = readULEB128(&error);
39110b57cec5SDimitry Andric       LibraryOrdinalSet = true;
39120b57cec5SDimitry Andric       if (error) {
39130b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB " +
39140b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
39150b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
39160b57cec5SDimitry Andric         moveToEnd();
39170b57cec5SDimitry Andric         return;
39180b57cec5SDimitry Andric       }
39190b57cec5SDimitry Andric       if (Ordinal > (int)O->getLibraryCount()) {
39200b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad "
39210b57cec5SDimitry Andric                             "library ordinal: " +
39220b57cec5SDimitry Andric                             Twine((int)Ordinal) + " (max " +
39230b57cec5SDimitry Andric                             Twine((int)O->getLibraryCount()) +
39240b57cec5SDimitry Andric                             ") for opcode at: 0x" +
39250b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
39260b57cec5SDimitry Andric         moveToEnd();
39270b57cec5SDimitry Andric         return;
39280b57cec5SDimitry Andric       }
39290b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
39300b57cec5SDimitry Andric           "mach-o-bind",
39310b57cec5SDimitry Andric           dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: "
39320b57cec5SDimitry Andric                  << "Ordinal=" << Ordinal << "\n");
39330b57cec5SDimitry Andric       break;
39340b57cec5SDimitry Andric     case MachO::BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
39350b57cec5SDimitry Andric       if (TableKind == Kind::Weak) {
39360b57cec5SDimitry Andric         *E = malformedError("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM not allowed in "
39370b57cec5SDimitry Andric                             "weak bind table for opcode at: 0x" +
39380b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
39390b57cec5SDimitry Andric         moveToEnd();
39400b57cec5SDimitry Andric         return;
39410b57cec5SDimitry Andric       }
39420b57cec5SDimitry Andric       if (ImmValue) {
39430b57cec5SDimitry Andric         SignExtended = MachO::BIND_OPCODE_MASK | ImmValue;
39440b57cec5SDimitry Andric         Ordinal = SignExtended;
39450b57cec5SDimitry Andric         if (Ordinal < MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) {
39460b57cec5SDimitry Andric           *E = malformedError("for BIND_OPCODE_SET_DYLIB_SPECIAL_IMM unknown "
39470b57cec5SDimitry Andric                               "special ordinal: " +
39480b57cec5SDimitry Andric                               Twine((int)Ordinal) + " for opcode at: 0x" +
39490b57cec5SDimitry Andric                               Twine::utohexstr(OpcodeStart - Opcodes.begin()));
39500b57cec5SDimitry Andric           moveToEnd();
39510b57cec5SDimitry Andric           return;
39520b57cec5SDimitry Andric         }
39530b57cec5SDimitry Andric       } else
39540b57cec5SDimitry Andric         Ordinal = 0;
39550b57cec5SDimitry Andric       LibraryOrdinalSet = true;
39560b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
39570b57cec5SDimitry Andric           "mach-o-bind",
39580b57cec5SDimitry Andric           dbgs() << "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: "
39590b57cec5SDimitry Andric                  << "Ordinal=" << Ordinal << "\n");
39600b57cec5SDimitry Andric       break;
39610b57cec5SDimitry Andric     case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
39620b57cec5SDimitry Andric       Flags = ImmValue;
39630b57cec5SDimitry Andric       SymStart = Ptr;
39640b57cec5SDimitry Andric       while (*Ptr && (Ptr < Opcodes.end())) {
39650b57cec5SDimitry Andric         ++Ptr;
39660b57cec5SDimitry Andric       }
39670b57cec5SDimitry Andric       if (Ptr == Opcodes.end()) {
39680b57cec5SDimitry Andric         *E = malformedError(
39690b57cec5SDimitry Andric             "for BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM "
39700b57cec5SDimitry Andric             "symbol name extends past opcodes for opcode at: 0x" +
39710b57cec5SDimitry Andric             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
39720b57cec5SDimitry Andric         moveToEnd();
39730b57cec5SDimitry Andric         return;
39740b57cec5SDimitry Andric       }
39750b57cec5SDimitry Andric       SymbolName = StringRef(reinterpret_cast<const char*>(SymStart),
39760b57cec5SDimitry Andric                              Ptr-SymStart);
39770b57cec5SDimitry Andric       ++Ptr;
39780b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
39790b57cec5SDimitry Andric           "mach-o-bind",
39800b57cec5SDimitry Andric           dbgs() << "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: "
39810b57cec5SDimitry Andric                  << "SymbolName=" << SymbolName << "\n");
39820b57cec5SDimitry Andric       if (TableKind == Kind::Weak) {
39830b57cec5SDimitry Andric         if (ImmValue & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION)
39840b57cec5SDimitry Andric           return;
39850b57cec5SDimitry Andric       }
39860b57cec5SDimitry Andric       break;
39870b57cec5SDimitry Andric     case MachO::BIND_OPCODE_SET_TYPE_IMM:
39880b57cec5SDimitry Andric       BindType = ImmValue;
39890b57cec5SDimitry Andric       if (ImmValue > MachO::BIND_TYPE_TEXT_PCREL32) {
39900b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_SET_TYPE_IMM bad bind type: " +
39910b57cec5SDimitry Andric                             Twine((int)ImmValue) + " for opcode at: 0x" +
39920b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
39930b57cec5SDimitry Andric         moveToEnd();
39940b57cec5SDimitry Andric         return;
39950b57cec5SDimitry Andric       }
39960b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
39970b57cec5SDimitry Andric           "mach-o-bind",
39980b57cec5SDimitry Andric           dbgs() << "BIND_OPCODE_SET_TYPE_IMM: "
39990b57cec5SDimitry Andric                  << "BindType=" << (int)BindType << "\n");
40000b57cec5SDimitry Andric       break;
40010b57cec5SDimitry Andric     case MachO::BIND_OPCODE_SET_ADDEND_SLEB:
40020b57cec5SDimitry Andric       Addend = readSLEB128(&error);
40030b57cec5SDimitry Andric       if (error) {
40040b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_SET_ADDEND_SLEB " + Twine(error) +
40050b57cec5SDimitry Andric                             " for opcode at: 0x" +
40060b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
40070b57cec5SDimitry Andric         moveToEnd();
40080b57cec5SDimitry Andric         return;
40090b57cec5SDimitry Andric       }
40100b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
40110b57cec5SDimitry Andric           "mach-o-bind",
40120b57cec5SDimitry Andric           dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: "
40130b57cec5SDimitry Andric                  << "Addend=" << Addend << "\n");
40140b57cec5SDimitry Andric       break;
40150b57cec5SDimitry Andric     case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
40160b57cec5SDimitry Andric       SegmentIndex = ImmValue;
40170b57cec5SDimitry Andric       SegmentOffset = readULEB128(&error);
40180b57cec5SDimitry Andric       if (error) {
40190b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
40200b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
40210b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
40220b57cec5SDimitry Andric         moveToEnd();
40230b57cec5SDimitry Andric         return;
40240b57cec5SDimitry Andric       }
40250b57cec5SDimitry Andric       error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
40260b57cec5SDimitry Andric                                              PointerSize);
40270b57cec5SDimitry Andric       if (error) {
40280b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
40290b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
40300b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
40310b57cec5SDimitry Andric         moveToEnd();
40320b57cec5SDimitry Andric         return;
40330b57cec5SDimitry Andric       }
40340b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
40350b57cec5SDimitry Andric           "mach-o-bind",
40360b57cec5SDimitry Andric           dbgs() << "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "
40370b57cec5SDimitry Andric                  << "SegmentIndex=" << SegmentIndex << ", "
40380b57cec5SDimitry Andric                  << format("SegmentOffset=0x%06X", SegmentOffset)
40390b57cec5SDimitry Andric                  << "\n");
40400b57cec5SDimitry Andric       break;
40410b57cec5SDimitry Andric     case MachO::BIND_OPCODE_ADD_ADDR_ULEB:
40420b57cec5SDimitry Andric       SegmentOffset += readULEB128(&error);
40430b57cec5SDimitry Andric       if (error) {
40440b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) +
40450b57cec5SDimitry Andric                             " for opcode at: 0x" +
40460b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
40470b57cec5SDimitry Andric         moveToEnd();
40480b57cec5SDimitry Andric         return;
40490b57cec5SDimitry Andric       }
40500b57cec5SDimitry Andric       error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
40510b57cec5SDimitry Andric                                              PointerSize);
40520b57cec5SDimitry Andric       if (error) {
40530b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) +
40540b57cec5SDimitry Andric                             " for opcode at: 0x" +
40550b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
40560b57cec5SDimitry Andric         moveToEnd();
40570b57cec5SDimitry Andric         return;
40580b57cec5SDimitry Andric       }
40590b57cec5SDimitry Andric       DEBUG_WITH_TYPE("mach-o-bind",
40600b57cec5SDimitry Andric                       dbgs() << "BIND_OPCODE_ADD_ADDR_ULEB: "
40610b57cec5SDimitry Andric                              << format("SegmentOffset=0x%06X",
40620b57cec5SDimitry Andric                                        SegmentOffset) << "\n");
40630b57cec5SDimitry Andric       break;
40640b57cec5SDimitry Andric     case MachO::BIND_OPCODE_DO_BIND:
40650b57cec5SDimitry Andric       AdvanceAmount = PointerSize;
40660b57cec5SDimitry Andric       RemainingLoopCount = 0;
40670b57cec5SDimitry Andric       error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
40680b57cec5SDimitry Andric                                              PointerSize);
40690b57cec5SDimitry Andric       if (error) {
40700b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_DO_BIND " + Twine(error) +
40710b57cec5SDimitry Andric                             " for opcode at: 0x" +
40720b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
40730b57cec5SDimitry Andric         moveToEnd();
40740b57cec5SDimitry Andric         return;
40750b57cec5SDimitry Andric       }
40760b57cec5SDimitry Andric       if (SymbolName == StringRef()) {
40770b57cec5SDimitry Andric         *E = malformedError(
40780b57cec5SDimitry Andric             "for BIND_OPCODE_DO_BIND missing preceding "
40790b57cec5SDimitry Andric             "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode at: 0x" +
40800b57cec5SDimitry Andric             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
40810b57cec5SDimitry Andric         moveToEnd();
40820b57cec5SDimitry Andric         return;
40830b57cec5SDimitry Andric       }
40840b57cec5SDimitry Andric       if (!LibraryOrdinalSet && TableKind != Kind::Weak) {
40850b57cec5SDimitry Andric         *E =
40860b57cec5SDimitry Andric             malformedError("for BIND_OPCODE_DO_BIND missing preceding "
40870b57cec5SDimitry Andric                            "BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" +
40880b57cec5SDimitry Andric                            Twine::utohexstr(OpcodeStart - Opcodes.begin()));
40890b57cec5SDimitry Andric         moveToEnd();
40900b57cec5SDimitry Andric         return;
40910b57cec5SDimitry Andric       }
40920b57cec5SDimitry Andric       DEBUG_WITH_TYPE("mach-o-bind",
40930b57cec5SDimitry Andric                       dbgs() << "BIND_OPCODE_DO_BIND: "
40940b57cec5SDimitry Andric                              << format("SegmentOffset=0x%06X",
40950b57cec5SDimitry Andric                                        SegmentOffset) << "\n");
40960b57cec5SDimitry Andric       return;
40970b57cec5SDimitry Andric      case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
40980b57cec5SDimitry Andric       if (TableKind == Kind::Lazy) {
40990b57cec5SDimitry Andric         *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB not allowed in "
41000b57cec5SDimitry Andric                             "lazy bind table for opcode at: 0x" +
41010b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41020b57cec5SDimitry Andric         moveToEnd();
41030b57cec5SDimitry Andric         return;
41040b57cec5SDimitry Andric       }
41050b57cec5SDimitry Andric       error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
41060b57cec5SDimitry Andric                                              PointerSize);
41070b57cec5SDimitry Andric       if (error) {
41080b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " +
41090b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
41100b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41110b57cec5SDimitry Andric         moveToEnd();
41120b57cec5SDimitry Andric         return;
41130b57cec5SDimitry Andric       }
41140b57cec5SDimitry Andric       if (SymbolName == StringRef()) {
41150b57cec5SDimitry Andric         *E = malformedError(
41160b57cec5SDimitry Andric             "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing "
41170b57cec5SDimitry Andric             "preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode "
41180b57cec5SDimitry Andric             "at: 0x" +
41190b57cec5SDimitry Andric             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41200b57cec5SDimitry Andric         moveToEnd();
41210b57cec5SDimitry Andric         return;
41220b57cec5SDimitry Andric       }
41230b57cec5SDimitry Andric       if (!LibraryOrdinalSet && TableKind != Kind::Weak) {
41240b57cec5SDimitry Andric         *E = malformedError(
41250b57cec5SDimitry Andric             "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing "
41260b57cec5SDimitry Andric             "preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" +
41270b57cec5SDimitry Andric             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41280b57cec5SDimitry Andric         moveToEnd();
41290b57cec5SDimitry Andric         return;
41300b57cec5SDimitry Andric       }
41310b57cec5SDimitry Andric       AdvanceAmount = readULEB128(&error) + PointerSize;
41320b57cec5SDimitry Andric       if (error) {
41330b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " +
41340b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
41350b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41360b57cec5SDimitry Andric         moveToEnd();
41370b57cec5SDimitry Andric         return;
41380b57cec5SDimitry Andric       }
41390b57cec5SDimitry Andric       // Note, this is not really an error until the next bind but make no sense
41400b57cec5SDimitry Andric       // for a BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB to not be followed by another
41410b57cec5SDimitry Andric       // bind operation.
41420b57cec5SDimitry Andric       error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset +
41430b57cec5SDimitry Andric                                             AdvanceAmount, PointerSize);
41440b57cec5SDimitry Andric       if (error) {
41450b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB (after adding "
41460b57cec5SDimitry Andric                             "ULEB) " +
41470b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
41480b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41490b57cec5SDimitry Andric         moveToEnd();
41500b57cec5SDimitry Andric         return;
41510b57cec5SDimitry Andric       }
41520b57cec5SDimitry Andric       RemainingLoopCount = 0;
41530b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
41540b57cec5SDimitry Andric           "mach-o-bind",
41550b57cec5SDimitry Andric           dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: "
41560b57cec5SDimitry Andric                  << format("SegmentOffset=0x%06X", SegmentOffset)
41570b57cec5SDimitry Andric                  << ", AdvanceAmount=" << AdvanceAmount
41580b57cec5SDimitry Andric                  << ", RemainingLoopCount=" << RemainingLoopCount
41590b57cec5SDimitry Andric                  << "\n");
41600b57cec5SDimitry Andric       return;
41610b57cec5SDimitry Andric     case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
41620b57cec5SDimitry Andric       if (TableKind == Kind::Lazy) {
41630b57cec5SDimitry Andric         *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED not "
41640b57cec5SDimitry Andric                             "allowed in lazy bind table for opcode at: 0x" +
41650b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41660b57cec5SDimitry Andric         moveToEnd();
41670b57cec5SDimitry Andric         return;
41680b57cec5SDimitry Andric       }
41690b57cec5SDimitry Andric       if (SymbolName == StringRef()) {
41700b57cec5SDimitry Andric         *E = malformedError(
41710b57cec5SDimitry Andric             "for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED "
41720b57cec5SDimitry Andric             "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for "
41730b57cec5SDimitry Andric             "opcode at: 0x" +
41740b57cec5SDimitry Andric             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41750b57cec5SDimitry Andric         moveToEnd();
41760b57cec5SDimitry Andric         return;
41770b57cec5SDimitry Andric       }
41780b57cec5SDimitry Andric       if (!LibraryOrdinalSet && TableKind != Kind::Weak) {
41790b57cec5SDimitry Andric         *E = malformedError(
41800b57cec5SDimitry Andric             "for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED "
41810b57cec5SDimitry Andric             "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode "
41820b57cec5SDimitry Andric             "at: 0x" +
41830b57cec5SDimitry Andric             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41840b57cec5SDimitry Andric         moveToEnd();
41850b57cec5SDimitry Andric         return;
41860b57cec5SDimitry Andric       }
41870b57cec5SDimitry Andric       AdvanceAmount = ImmValue * PointerSize + PointerSize;
41880b57cec5SDimitry Andric       RemainingLoopCount = 0;
41890b57cec5SDimitry Andric       error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset +
41900b57cec5SDimitry Andric                                              AdvanceAmount, PointerSize);
41910b57cec5SDimitry Andric       if (error) {
41925ffd83dbSDimitry Andric         *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " +
41930b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
41940b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
41950b57cec5SDimitry Andric         moveToEnd();
41960b57cec5SDimitry Andric         return;
41970b57cec5SDimitry Andric       }
41980b57cec5SDimitry Andric       DEBUG_WITH_TYPE("mach-o-bind",
41990b57cec5SDimitry Andric                       dbgs()
42000b57cec5SDimitry Andric                       << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: "
42010b57cec5SDimitry Andric                       << format("SegmentOffset=0x%06X", SegmentOffset) << "\n");
42020b57cec5SDimitry Andric       return;
42030b57cec5SDimitry Andric     case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
42040b57cec5SDimitry Andric       if (TableKind == Kind::Lazy) {
42050b57cec5SDimitry Andric         *E = malformedError("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB not "
42060b57cec5SDimitry Andric                             "allowed in lazy bind table for opcode at: 0x" +
42070b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
42080b57cec5SDimitry Andric         moveToEnd();
42090b57cec5SDimitry Andric         return;
42100b57cec5SDimitry Andric       }
42110b57cec5SDimitry Andric       Count = readULEB128(&error);
42120b57cec5SDimitry Andric       if (Count != 0)
42130b57cec5SDimitry Andric         RemainingLoopCount = Count - 1;
42140b57cec5SDimitry Andric       else
42150b57cec5SDimitry Andric         RemainingLoopCount = 0;
42160b57cec5SDimitry Andric       if (error) {
42170b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "
42180b57cec5SDimitry Andric                             " (count value) " +
42190b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
42200b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
42210b57cec5SDimitry Andric         moveToEnd();
42220b57cec5SDimitry Andric         return;
42230b57cec5SDimitry Andric       }
42240b57cec5SDimitry Andric       Skip = readULEB128(&error);
42250b57cec5SDimitry Andric       AdvanceAmount = Skip + PointerSize;
42260b57cec5SDimitry Andric       if (error) {
42270b57cec5SDimitry Andric         *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "
42280b57cec5SDimitry Andric                             " (skip value) " +
42290b57cec5SDimitry Andric                             Twine(error) + " for opcode at: 0x" +
42300b57cec5SDimitry Andric                             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
42310b57cec5SDimitry Andric         moveToEnd();
42320b57cec5SDimitry Andric         return;
42330b57cec5SDimitry Andric       }
42340b57cec5SDimitry Andric       if (SymbolName == StringRef()) {
42350b57cec5SDimitry Andric         *E = malformedError(
42360b57cec5SDimitry Andric             "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "
42370b57cec5SDimitry Andric             "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for "
42380b57cec5SDimitry Andric             "opcode at: 0x" +
42390b57cec5SDimitry Andric             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
42400b57cec5SDimitry Andric         moveToEnd();
42410b57cec5SDimitry Andric         return;
42420b57cec5SDimitry Andric       }
42430b57cec5SDimitry Andric       if (!LibraryOrdinalSet && TableKind != Kind::Weak) {
42440b57cec5SDimitry Andric         *E = malformedError(
42450b57cec5SDimitry Andric             "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "
42460b57cec5SDimitry Andric             "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode "
42470b57cec5SDimitry Andric             "at: 0x" +
42480b57cec5SDimitry Andric             Twine::utohexstr(OpcodeStart - Opcodes.begin()));
42490b57cec5SDimitry Andric         moveToEnd();
42500b57cec5SDimitry Andric         return;
42510b57cec5SDimitry Andric       }
42520b57cec5SDimitry Andric       error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
42530b57cec5SDimitry Andric                                              PointerSize, Count, Skip);
42540b57cec5SDimitry Andric       if (error) {
42550b57cec5SDimitry Andric         *E =
42560b57cec5SDimitry Andric             malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " +
42570b57cec5SDimitry Andric                            Twine(error) + " for opcode at: 0x" +
42580b57cec5SDimitry Andric                            Twine::utohexstr(OpcodeStart - Opcodes.begin()));
42590b57cec5SDimitry Andric         moveToEnd();
42600b57cec5SDimitry Andric         return;
42610b57cec5SDimitry Andric       }
42620b57cec5SDimitry Andric       DEBUG_WITH_TYPE(
42630b57cec5SDimitry Andric           "mach-o-bind",
42640b57cec5SDimitry Andric           dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: "
42650b57cec5SDimitry Andric                  << format("SegmentOffset=0x%06X", SegmentOffset)
42660b57cec5SDimitry Andric                  << ", AdvanceAmount=" << AdvanceAmount
42670b57cec5SDimitry Andric                  << ", RemainingLoopCount=" << RemainingLoopCount
42680b57cec5SDimitry Andric                  << "\n");
42690b57cec5SDimitry Andric       return;
42700b57cec5SDimitry Andric     default:
42710b57cec5SDimitry Andric       *E = malformedError("bad bind info (bad opcode value 0x" +
42720b57cec5SDimitry Andric                           Twine::utohexstr(Opcode) + " for opcode at: 0x" +
42730b57cec5SDimitry Andric                           Twine::utohexstr(OpcodeStart - Opcodes.begin()));
42740b57cec5SDimitry Andric       moveToEnd();
42750b57cec5SDimitry Andric       return;
42760b57cec5SDimitry Andric     }
42770b57cec5SDimitry Andric   }
42780b57cec5SDimitry Andric }
42790b57cec5SDimitry Andric 
readULEB128(const char ** error)42800b57cec5SDimitry Andric uint64_t MachOBindEntry::readULEB128(const char **error) {
42810b57cec5SDimitry Andric   unsigned Count;
42820b57cec5SDimitry Andric   uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);
42830b57cec5SDimitry Andric   Ptr += Count;
42840b57cec5SDimitry Andric   if (Ptr > Opcodes.end())
42850b57cec5SDimitry Andric     Ptr = Opcodes.end();
42860b57cec5SDimitry Andric   return Result;
42870b57cec5SDimitry Andric }
42880b57cec5SDimitry Andric 
readSLEB128(const char ** error)42890b57cec5SDimitry Andric int64_t MachOBindEntry::readSLEB128(const char **error) {
42900b57cec5SDimitry Andric   unsigned Count;
42910b57cec5SDimitry Andric   int64_t Result = decodeSLEB128(Ptr, &Count, Opcodes.end(), error);
42920b57cec5SDimitry Andric   Ptr += Count;
42930b57cec5SDimitry Andric   if (Ptr > Opcodes.end())
42940b57cec5SDimitry Andric     Ptr = Opcodes.end();
42950b57cec5SDimitry Andric   return Result;
42960b57cec5SDimitry Andric }
42970b57cec5SDimitry Andric 
segmentIndex() const42980b57cec5SDimitry Andric int32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; }
42990b57cec5SDimitry Andric 
segmentOffset() const43000b57cec5SDimitry Andric uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; }
43010b57cec5SDimitry Andric 
typeName() const43020b57cec5SDimitry Andric StringRef MachOBindEntry::typeName() const {
43030b57cec5SDimitry Andric   switch (BindType) {
43040b57cec5SDimitry Andric   case MachO::BIND_TYPE_POINTER:
43050b57cec5SDimitry Andric     return "pointer";
43060b57cec5SDimitry Andric   case MachO::BIND_TYPE_TEXT_ABSOLUTE32:
43070b57cec5SDimitry Andric     return "text abs32";
43080b57cec5SDimitry Andric   case MachO::BIND_TYPE_TEXT_PCREL32:
43090b57cec5SDimitry Andric     return "text rel32";
43100b57cec5SDimitry Andric   }
43110b57cec5SDimitry Andric   return "unknown";
43120b57cec5SDimitry Andric }
43130b57cec5SDimitry Andric 
symbolName() const43140b57cec5SDimitry Andric StringRef MachOBindEntry::symbolName() const { return SymbolName; }
43150b57cec5SDimitry Andric 
addend() const43160b57cec5SDimitry Andric int64_t MachOBindEntry::addend() const { return Addend; }
43170b57cec5SDimitry Andric 
flags() const43180b57cec5SDimitry Andric uint32_t MachOBindEntry::flags() const { return Flags; }
43190b57cec5SDimitry Andric 
ordinal() const43200b57cec5SDimitry Andric int MachOBindEntry::ordinal() const { return Ordinal; }
43210b57cec5SDimitry Andric 
43220b57cec5SDimitry Andric // For use with the SegIndex of a checked Mach-O Bind entry
43230b57cec5SDimitry Andric // to get the segment name.
segmentName() const43240b57cec5SDimitry Andric StringRef MachOBindEntry::segmentName() const {
43250b57cec5SDimitry Andric   return O->BindRebaseSegmentName(SegmentIndex);
43260b57cec5SDimitry Andric }
43270b57cec5SDimitry Andric 
43280b57cec5SDimitry Andric // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry
43290b57cec5SDimitry Andric // to get the section name.
sectionName() const43300b57cec5SDimitry Andric StringRef MachOBindEntry::sectionName() const {
43310b57cec5SDimitry Andric   return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);
43320b57cec5SDimitry Andric }
43330b57cec5SDimitry Andric 
43340b57cec5SDimitry Andric // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry
43350b57cec5SDimitry Andric // to get the address.
address() const43360b57cec5SDimitry Andric uint64_t MachOBindEntry::address() const {
43370b57cec5SDimitry Andric   return O->BindRebaseAddress(SegmentIndex, SegmentOffset);
43380b57cec5SDimitry Andric }
43390b57cec5SDimitry Andric 
operator ==(const MachOBindEntry & Other) const43400b57cec5SDimitry Andric bool MachOBindEntry::operator==(const MachOBindEntry &Other) const {
43410b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS
43420b57cec5SDimitry Andric   assert(Opcodes == Other.Opcodes && "compare iterators of different files");
43430b57cec5SDimitry Andric #else
43440b57cec5SDimitry Andric   assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files");
43450b57cec5SDimitry Andric #endif
43460b57cec5SDimitry Andric   return (Ptr == Other.Ptr) &&
43470b57cec5SDimitry Andric          (RemainingLoopCount == Other.RemainingLoopCount) &&
43480b57cec5SDimitry Andric          (Done == Other.Done);
43490b57cec5SDimitry Andric }
43500b57cec5SDimitry Andric 
43510b57cec5SDimitry Andric // Build table of sections so SegIndex/SegOffset pairs can be translated.
BindRebaseSegInfo(const object::MachOObjectFile * Obj)43520b57cec5SDimitry Andric BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) {
43530b57cec5SDimitry Andric   uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0;
43540b57cec5SDimitry Andric   StringRef CurSegName;
43550b57cec5SDimitry Andric   uint64_t CurSegAddress;
43560b57cec5SDimitry Andric   for (const SectionRef &Section : Obj->sections()) {
43570b57cec5SDimitry Andric     SectionInfo Info;
43588bcb0991SDimitry Andric     Expected<StringRef> NameOrErr = Section.getName();
43598bcb0991SDimitry Andric     if (!NameOrErr)
43608bcb0991SDimitry Andric       consumeError(NameOrErr.takeError());
43618bcb0991SDimitry Andric     else
43628bcb0991SDimitry Andric       Info.SectionName = *NameOrErr;
43630b57cec5SDimitry Andric     Info.Address = Section.getAddress();
43640b57cec5SDimitry Andric     Info.Size = Section.getSize();
43650b57cec5SDimitry Andric     Info.SegmentName =
43660b57cec5SDimitry Andric         Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl());
43670b57cec5SDimitry Andric     if (!Info.SegmentName.equals(CurSegName)) {
43680b57cec5SDimitry Andric       ++CurSegIndex;
43690b57cec5SDimitry Andric       CurSegName = Info.SegmentName;
43700b57cec5SDimitry Andric       CurSegAddress = Info.Address;
43710b57cec5SDimitry Andric     }
43720b57cec5SDimitry Andric     Info.SegmentIndex = CurSegIndex - 1;
43730b57cec5SDimitry Andric     Info.OffsetInSegment = Info.Address - CurSegAddress;
43740b57cec5SDimitry Andric     Info.SegmentStartAddress = CurSegAddress;
43750b57cec5SDimitry Andric     Sections.push_back(Info);
43760b57cec5SDimitry Andric   }
43770b57cec5SDimitry Andric   MaxSegIndex = CurSegIndex;
43780b57cec5SDimitry Andric }
43790b57cec5SDimitry Andric 
43800b57cec5SDimitry Andric // For use with a SegIndex, SegOffset, and PointerSize triple in
43810b57cec5SDimitry Andric // MachOBindEntry::moveNext() to validate a MachOBindEntry or MachORebaseEntry.
43820b57cec5SDimitry Andric //
43830b57cec5SDimitry Andric // Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists
43840b57cec5SDimitry Andric // that fully contains a pointer at that location. Multiple fixups in a bind
43850b57cec5SDimitry Andric // (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can
43860b57cec5SDimitry Andric // be tested via the Count and Skip parameters.
checkSegAndOffsets(int32_t SegIndex,uint64_t SegOffset,uint8_t PointerSize,uint32_t Count,uint32_t Skip)43870b57cec5SDimitry Andric const char * BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex,
43880b57cec5SDimitry Andric                                                    uint64_t SegOffset,
43890b57cec5SDimitry Andric                                                    uint8_t PointerSize,
43900b57cec5SDimitry Andric                                                    uint32_t Count,
43910b57cec5SDimitry Andric                                                    uint32_t Skip) {
43920b57cec5SDimitry Andric   if (SegIndex == -1)
43930b57cec5SDimitry Andric     return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB";
43940b57cec5SDimitry Andric   if (SegIndex >= MaxSegIndex)
43950b57cec5SDimitry Andric     return "bad segIndex (too large)";
43960b57cec5SDimitry Andric   for (uint32_t i = 0; i < Count; ++i) {
43970b57cec5SDimitry Andric     uint32_t Start = SegOffset + i * (PointerSize + Skip);
43980b57cec5SDimitry Andric     uint32_t End = Start + PointerSize;
43990b57cec5SDimitry Andric     bool Found = false;
44000b57cec5SDimitry Andric     for (const SectionInfo &SI : Sections) {
44010b57cec5SDimitry Andric       if (SI.SegmentIndex != SegIndex)
44020b57cec5SDimitry Andric         continue;
44030b57cec5SDimitry Andric       if ((SI.OffsetInSegment<=Start) && (Start<(SI.OffsetInSegment+SI.Size))) {
44040b57cec5SDimitry Andric         if (End <= SI.OffsetInSegment + SI.Size) {
44050b57cec5SDimitry Andric           Found = true;
44060b57cec5SDimitry Andric           break;
44070b57cec5SDimitry Andric         }
44080b57cec5SDimitry Andric         else
44090b57cec5SDimitry Andric           return "bad offset, extends beyond section boundary";
44100b57cec5SDimitry Andric       }
44110b57cec5SDimitry Andric     }
44120b57cec5SDimitry Andric     if (!Found)
44130b57cec5SDimitry Andric       return "bad offset, not in section";
44140b57cec5SDimitry Andric   }
44150b57cec5SDimitry Andric   return nullptr;
44160b57cec5SDimitry Andric }
44170b57cec5SDimitry Andric 
44180b57cec5SDimitry Andric // For use with the SegIndex of a checked Mach-O Bind or Rebase entry
44190b57cec5SDimitry Andric // to get the segment name.
segmentName(int32_t SegIndex)44200b57cec5SDimitry Andric StringRef BindRebaseSegInfo::segmentName(int32_t SegIndex) {
44210b57cec5SDimitry Andric   for (const SectionInfo &SI : Sections) {
44220b57cec5SDimitry Andric     if (SI.SegmentIndex == SegIndex)
44230b57cec5SDimitry Andric       return SI.SegmentName;
44240b57cec5SDimitry Andric   }
44250b57cec5SDimitry Andric   llvm_unreachable("invalid SegIndex");
44260b57cec5SDimitry Andric }
44270b57cec5SDimitry Andric 
44280b57cec5SDimitry Andric // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase
44290b57cec5SDimitry Andric // to get the SectionInfo.
findSection(int32_t SegIndex,uint64_t SegOffset)44300b57cec5SDimitry Andric const BindRebaseSegInfo::SectionInfo &BindRebaseSegInfo::findSection(
44310b57cec5SDimitry Andric                                      int32_t SegIndex, uint64_t SegOffset) {
44320b57cec5SDimitry Andric   for (const SectionInfo &SI : Sections) {
44330b57cec5SDimitry Andric     if (SI.SegmentIndex != SegIndex)
44340b57cec5SDimitry Andric       continue;
44350b57cec5SDimitry Andric     if (SI.OffsetInSegment > SegOffset)
44360b57cec5SDimitry Andric       continue;
44370b57cec5SDimitry Andric     if (SegOffset >= (SI.OffsetInSegment + SI.Size))
44380b57cec5SDimitry Andric       continue;
44390b57cec5SDimitry Andric     return SI;
44400b57cec5SDimitry Andric   }
44410b57cec5SDimitry Andric   llvm_unreachable("SegIndex and SegOffset not in any section");
44420b57cec5SDimitry Andric }
44430b57cec5SDimitry Andric 
44440b57cec5SDimitry Andric // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase
44450b57cec5SDimitry Andric // entry to get the section name.
sectionName(int32_t SegIndex,uint64_t SegOffset)44460b57cec5SDimitry Andric StringRef BindRebaseSegInfo::sectionName(int32_t SegIndex,
44470b57cec5SDimitry Andric                                          uint64_t SegOffset) {
44480b57cec5SDimitry Andric   return findSection(SegIndex, SegOffset).SectionName;
44490b57cec5SDimitry Andric }
44500b57cec5SDimitry Andric 
44510b57cec5SDimitry Andric // For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase
44520b57cec5SDimitry Andric // entry to get the address.
address(uint32_t SegIndex,uint64_t OffsetInSeg)44530b57cec5SDimitry Andric uint64_t BindRebaseSegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) {
44540b57cec5SDimitry Andric   const SectionInfo &SI = findSection(SegIndex, OffsetInSeg);
44550b57cec5SDimitry Andric   return SI.SegmentStartAddress + OffsetInSeg;
44560b57cec5SDimitry Andric }
44570b57cec5SDimitry Andric 
44580b57cec5SDimitry Andric iterator_range<bind_iterator>
bindTable(Error & Err,MachOObjectFile * O,ArrayRef<uint8_t> Opcodes,bool is64,MachOBindEntry::Kind BKind)44590b57cec5SDimitry Andric MachOObjectFile::bindTable(Error &Err, MachOObjectFile *O,
44600b57cec5SDimitry Andric                            ArrayRef<uint8_t> Opcodes, bool is64,
44610b57cec5SDimitry Andric                            MachOBindEntry::Kind BKind) {
44620b57cec5SDimitry Andric   if (O->BindRebaseSectionTable == nullptr)
44638bcb0991SDimitry Andric     O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);
44640b57cec5SDimitry Andric   MachOBindEntry Start(&Err, O, Opcodes, is64, BKind);
44650b57cec5SDimitry Andric   Start.moveToFirst();
44660b57cec5SDimitry Andric 
44670b57cec5SDimitry Andric   MachOBindEntry Finish(&Err, O, Opcodes, is64, BKind);
44680b57cec5SDimitry Andric   Finish.moveToEnd();
44690b57cec5SDimitry Andric 
44700b57cec5SDimitry Andric   return make_range(bind_iterator(Start), bind_iterator(Finish));
44710b57cec5SDimitry Andric }
44720b57cec5SDimitry Andric 
bindTable(Error & Err)44730b57cec5SDimitry Andric iterator_range<bind_iterator> MachOObjectFile::bindTable(Error &Err) {
44740b57cec5SDimitry Andric   return bindTable(Err, this, getDyldInfoBindOpcodes(), is64Bit(),
44750b57cec5SDimitry Andric                    MachOBindEntry::Kind::Regular);
44760b57cec5SDimitry Andric }
44770b57cec5SDimitry Andric 
lazyBindTable(Error & Err)44780b57cec5SDimitry Andric iterator_range<bind_iterator> MachOObjectFile::lazyBindTable(Error &Err) {
44790b57cec5SDimitry Andric   return bindTable(Err, this, getDyldInfoLazyBindOpcodes(), is64Bit(),
44800b57cec5SDimitry Andric                    MachOBindEntry::Kind::Lazy);
44810b57cec5SDimitry Andric }
44820b57cec5SDimitry Andric 
weakBindTable(Error & Err)44830b57cec5SDimitry Andric iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) {
44840b57cec5SDimitry Andric   return bindTable(Err, this, getDyldInfoWeakBindOpcodes(), is64Bit(),
44850b57cec5SDimitry Andric                    MachOBindEntry::Kind::Weak);
44860b57cec5SDimitry Andric }
44870b57cec5SDimitry Andric 
fixupTable(Error & Err)448881ad6265SDimitry Andric iterator_range<fixup_iterator> MachOObjectFile::fixupTable(Error &Err) {
4489bdd1243dSDimitry Andric   if (BindRebaseSectionTable == nullptr)
4490bdd1243dSDimitry Andric     BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(this);
4491bdd1243dSDimitry Andric 
449281ad6265SDimitry Andric   MachOChainedFixupEntry Start(&Err, this, true);
449381ad6265SDimitry Andric   Start.moveToFirst();
449481ad6265SDimitry Andric 
449581ad6265SDimitry Andric   MachOChainedFixupEntry Finish(&Err, this, false);
449681ad6265SDimitry Andric   Finish.moveToEnd();
449781ad6265SDimitry Andric 
449881ad6265SDimitry Andric   return make_range(fixup_iterator(Start), fixup_iterator(Finish));
449981ad6265SDimitry Andric }
450081ad6265SDimitry Andric 
45010b57cec5SDimitry Andric MachOObjectFile::load_command_iterator
begin_load_commands() const45020b57cec5SDimitry Andric MachOObjectFile::begin_load_commands() const {
45030b57cec5SDimitry Andric   return LoadCommands.begin();
45040b57cec5SDimitry Andric }
45050b57cec5SDimitry Andric 
45060b57cec5SDimitry Andric MachOObjectFile::load_command_iterator
end_load_commands() const45070b57cec5SDimitry Andric MachOObjectFile::end_load_commands() const {
45080b57cec5SDimitry Andric   return LoadCommands.end();
45090b57cec5SDimitry Andric }
45100b57cec5SDimitry Andric 
45110b57cec5SDimitry Andric iterator_range<MachOObjectFile::load_command_iterator>
load_commands() const45120b57cec5SDimitry Andric MachOObjectFile::load_commands() const {
45130b57cec5SDimitry Andric   return make_range(begin_load_commands(), end_load_commands());
45140b57cec5SDimitry Andric }
45150b57cec5SDimitry Andric 
45160b57cec5SDimitry Andric StringRef
getSectionFinalSegmentName(DataRefImpl Sec) const45170b57cec5SDimitry Andric MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const {
45180b57cec5SDimitry Andric   ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec);
45190b57cec5SDimitry Andric   return parseSegmentOrSectionName(Raw.data());
45200b57cec5SDimitry Andric }
45210b57cec5SDimitry Andric 
45220b57cec5SDimitry Andric ArrayRef<char>
getSectionRawName(DataRefImpl Sec) const45230b57cec5SDimitry Andric MachOObjectFile::getSectionRawName(DataRefImpl Sec) const {
45240b57cec5SDimitry Andric   assert(Sec.d.a < Sections.size() && "Should have detected this earlier");
45250b57cec5SDimitry Andric   const section_base *Base =
45260b57cec5SDimitry Andric     reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
4527bdd1243dSDimitry Andric   return ArrayRef(Base->sectname);
45280b57cec5SDimitry Andric }
45290b57cec5SDimitry Andric 
45300b57cec5SDimitry Andric ArrayRef<char>
getSectionRawFinalSegmentName(DataRefImpl Sec) const45310b57cec5SDimitry Andric MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const {
45320b57cec5SDimitry Andric   assert(Sec.d.a < Sections.size() && "Should have detected this earlier");
45330b57cec5SDimitry Andric   const section_base *Base =
45340b57cec5SDimitry Andric     reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
4535bdd1243dSDimitry Andric   return ArrayRef(Base->segname);
45360b57cec5SDimitry Andric }
45370b57cec5SDimitry Andric 
45380b57cec5SDimitry Andric bool
isRelocationScattered(const MachO::any_relocation_info & RE) const45390b57cec5SDimitry Andric MachOObjectFile::isRelocationScattered(const MachO::any_relocation_info &RE)
45400b57cec5SDimitry Andric   const {
45410b57cec5SDimitry Andric   if (getCPUType(*this) == MachO::CPU_TYPE_X86_64)
45420b57cec5SDimitry Andric     return false;
45430b57cec5SDimitry Andric   return getPlainRelocationAddress(RE) & MachO::R_SCATTERED;
45440b57cec5SDimitry Andric }
45450b57cec5SDimitry Andric 
getPlainRelocationSymbolNum(const MachO::any_relocation_info & RE) const45460b57cec5SDimitry Andric unsigned MachOObjectFile::getPlainRelocationSymbolNum(
45470b57cec5SDimitry Andric     const MachO::any_relocation_info &RE) const {
45480b57cec5SDimitry Andric   if (isLittleEndian())
45490b57cec5SDimitry Andric     return RE.r_word1 & 0xffffff;
45500b57cec5SDimitry Andric   return RE.r_word1 >> 8;
45510b57cec5SDimitry Andric }
45520b57cec5SDimitry Andric 
getPlainRelocationExternal(const MachO::any_relocation_info & RE) const45530b57cec5SDimitry Andric bool MachOObjectFile::getPlainRelocationExternal(
45540b57cec5SDimitry Andric     const MachO::any_relocation_info &RE) const {
45550b57cec5SDimitry Andric   if (isLittleEndian())
45560b57cec5SDimitry Andric     return (RE.r_word1 >> 27) & 1;
45570b57cec5SDimitry Andric   return (RE.r_word1 >> 4) & 1;
45580b57cec5SDimitry Andric }
45590b57cec5SDimitry Andric 
getScatteredRelocationScattered(const MachO::any_relocation_info & RE) const45600b57cec5SDimitry Andric bool MachOObjectFile::getScatteredRelocationScattered(
45610b57cec5SDimitry Andric     const MachO::any_relocation_info &RE) const {
45620b57cec5SDimitry Andric   return RE.r_word0 >> 31;
45630b57cec5SDimitry Andric }
45640b57cec5SDimitry Andric 
getScatteredRelocationValue(const MachO::any_relocation_info & RE) const45650b57cec5SDimitry Andric uint32_t MachOObjectFile::getScatteredRelocationValue(
45660b57cec5SDimitry Andric     const MachO::any_relocation_info &RE) const {
45670b57cec5SDimitry Andric   return RE.r_word1;
45680b57cec5SDimitry Andric }
45690b57cec5SDimitry Andric 
getScatteredRelocationType(const MachO::any_relocation_info & RE) const45700b57cec5SDimitry Andric uint32_t MachOObjectFile::getScatteredRelocationType(
45710b57cec5SDimitry Andric     const MachO::any_relocation_info &RE) const {
45720b57cec5SDimitry Andric   return (RE.r_word0 >> 24) & 0xf;
45730b57cec5SDimitry Andric }
45740b57cec5SDimitry Andric 
getAnyRelocationAddress(const MachO::any_relocation_info & RE) const45750b57cec5SDimitry Andric unsigned MachOObjectFile::getAnyRelocationAddress(
45760b57cec5SDimitry Andric     const MachO::any_relocation_info &RE) const {
45770b57cec5SDimitry Andric   if (isRelocationScattered(RE))
45780b57cec5SDimitry Andric     return getScatteredRelocationAddress(RE);
45790b57cec5SDimitry Andric   return getPlainRelocationAddress(RE);
45800b57cec5SDimitry Andric }
45810b57cec5SDimitry Andric 
getAnyRelocationPCRel(const MachO::any_relocation_info & RE) const45820b57cec5SDimitry Andric unsigned MachOObjectFile::getAnyRelocationPCRel(
45830b57cec5SDimitry Andric     const MachO::any_relocation_info &RE) const {
45840b57cec5SDimitry Andric   if (isRelocationScattered(RE))
45850b57cec5SDimitry Andric     return getScatteredRelocationPCRel(RE);
45860b57cec5SDimitry Andric   return getPlainRelocationPCRel(*this, RE);
45870b57cec5SDimitry Andric }
45880b57cec5SDimitry Andric 
getAnyRelocationLength(const MachO::any_relocation_info & RE) const45890b57cec5SDimitry Andric unsigned MachOObjectFile::getAnyRelocationLength(
45900b57cec5SDimitry Andric     const MachO::any_relocation_info &RE) const {
45910b57cec5SDimitry Andric   if (isRelocationScattered(RE))
45920b57cec5SDimitry Andric     return getScatteredRelocationLength(RE);
45930b57cec5SDimitry Andric   return getPlainRelocationLength(*this, RE);
45940b57cec5SDimitry Andric }
45950b57cec5SDimitry Andric 
45960b57cec5SDimitry Andric unsigned
getAnyRelocationType(const MachO::any_relocation_info & RE) const45970b57cec5SDimitry Andric MachOObjectFile::getAnyRelocationType(
45980b57cec5SDimitry Andric                                    const MachO::any_relocation_info &RE) const {
45990b57cec5SDimitry Andric   if (isRelocationScattered(RE))
46000b57cec5SDimitry Andric     return getScatteredRelocationType(RE);
46010b57cec5SDimitry Andric   return getPlainRelocationType(*this, RE);
46020b57cec5SDimitry Andric }
46030b57cec5SDimitry Andric 
46040b57cec5SDimitry Andric SectionRef
getAnyRelocationSection(const MachO::any_relocation_info & RE) const46050b57cec5SDimitry Andric MachOObjectFile::getAnyRelocationSection(
46060b57cec5SDimitry Andric                                    const MachO::any_relocation_info &RE) const {
46070b57cec5SDimitry Andric   if (isRelocationScattered(RE) || getPlainRelocationExternal(RE))
46080b57cec5SDimitry Andric     return *section_end();
46090b57cec5SDimitry Andric   unsigned SecNum = getPlainRelocationSymbolNum(RE);
46100b57cec5SDimitry Andric   if (SecNum == MachO::R_ABS || SecNum > Sections.size())
46110b57cec5SDimitry Andric     return *section_end();
46120b57cec5SDimitry Andric   DataRefImpl DRI;
46130b57cec5SDimitry Andric   DRI.d.a = SecNum - 1;
46140b57cec5SDimitry Andric   return SectionRef(DRI, this);
46150b57cec5SDimitry Andric }
46160b57cec5SDimitry Andric 
getSection(DataRefImpl DRI) const46170b57cec5SDimitry Andric MachO::section MachOObjectFile::getSection(DataRefImpl DRI) const {
46180b57cec5SDimitry Andric   assert(DRI.d.a < Sections.size() && "Should have detected this earlier");
46190b57cec5SDimitry Andric   return getStruct<MachO::section>(*this, Sections[DRI.d.a]);
46200b57cec5SDimitry Andric }
46210b57cec5SDimitry Andric 
getSection64(DataRefImpl DRI) const46220b57cec5SDimitry Andric MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const {
46230b57cec5SDimitry Andric   assert(DRI.d.a < Sections.size() && "Should have detected this earlier");
46240b57cec5SDimitry Andric   return getStruct<MachO::section_64>(*this, Sections[DRI.d.a]);
46250b57cec5SDimitry Andric }
46260b57cec5SDimitry Andric 
getSection(const LoadCommandInfo & L,unsigned Index) const46270b57cec5SDimitry Andric MachO::section MachOObjectFile::getSection(const LoadCommandInfo &L,
46280b57cec5SDimitry Andric                                            unsigned Index) const {
46290b57cec5SDimitry Andric   const char *Sec = getSectionPtr(*this, L, Index);
46300b57cec5SDimitry Andric   return getStruct<MachO::section>(*this, Sec);
46310b57cec5SDimitry Andric }
46320b57cec5SDimitry Andric 
getSection64(const LoadCommandInfo & L,unsigned Index) const46330b57cec5SDimitry Andric MachO::section_64 MachOObjectFile::getSection64(const LoadCommandInfo &L,
46340b57cec5SDimitry Andric                                                 unsigned Index) const {
46350b57cec5SDimitry Andric   const char *Sec = getSectionPtr(*this, L, Index);
46360b57cec5SDimitry Andric   return getStruct<MachO::section_64>(*this, Sec);
46370b57cec5SDimitry Andric }
46380b57cec5SDimitry Andric 
46390b57cec5SDimitry Andric MachO::nlist
getSymbolTableEntry(DataRefImpl DRI) const46400b57cec5SDimitry Andric MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI) const {
46410b57cec5SDimitry Andric   const char *P = reinterpret_cast<const char *>(DRI.p);
46420b57cec5SDimitry Andric   return getStruct<MachO::nlist>(*this, P);
46430b57cec5SDimitry Andric }
46440b57cec5SDimitry Andric 
46450b57cec5SDimitry Andric MachO::nlist_64
getSymbol64TableEntry(DataRefImpl DRI) const46460b57cec5SDimitry Andric MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI) const {
46470b57cec5SDimitry Andric   const char *P = reinterpret_cast<const char *>(DRI.p);
46480b57cec5SDimitry Andric   return getStruct<MachO::nlist_64>(*this, P);
46490b57cec5SDimitry Andric }
46500b57cec5SDimitry Andric 
46510b57cec5SDimitry Andric MachO::linkedit_data_command
getLinkeditDataLoadCommand(const LoadCommandInfo & L) const46520b57cec5SDimitry Andric MachOObjectFile::getLinkeditDataLoadCommand(const LoadCommandInfo &L) const {
46530b57cec5SDimitry Andric   return getStruct<MachO::linkedit_data_command>(*this, L.Ptr);
46540b57cec5SDimitry Andric }
46550b57cec5SDimitry Andric 
46560b57cec5SDimitry Andric MachO::segment_command
getSegmentLoadCommand(const LoadCommandInfo & L) const46570b57cec5SDimitry Andric MachOObjectFile::getSegmentLoadCommand(const LoadCommandInfo &L) const {
46580b57cec5SDimitry Andric   return getStruct<MachO::segment_command>(*this, L.Ptr);
46590b57cec5SDimitry Andric }
46600b57cec5SDimitry Andric 
46610b57cec5SDimitry Andric MachO::segment_command_64
getSegment64LoadCommand(const LoadCommandInfo & L) const46620b57cec5SDimitry Andric MachOObjectFile::getSegment64LoadCommand(const LoadCommandInfo &L) const {
46630b57cec5SDimitry Andric   return getStruct<MachO::segment_command_64>(*this, L.Ptr);
46640b57cec5SDimitry Andric }
46650b57cec5SDimitry Andric 
46660b57cec5SDimitry Andric MachO::linker_option_command
getLinkerOptionLoadCommand(const LoadCommandInfo & L) const46670b57cec5SDimitry Andric MachOObjectFile::getLinkerOptionLoadCommand(const LoadCommandInfo &L) const {
46680b57cec5SDimitry Andric   return getStruct<MachO::linker_option_command>(*this, L.Ptr);
46690b57cec5SDimitry Andric }
46700b57cec5SDimitry Andric 
46710b57cec5SDimitry Andric MachO::version_min_command
getVersionMinLoadCommand(const LoadCommandInfo & L) const46720b57cec5SDimitry Andric MachOObjectFile::getVersionMinLoadCommand(const LoadCommandInfo &L) const {
46730b57cec5SDimitry Andric   return getStruct<MachO::version_min_command>(*this, L.Ptr);
46740b57cec5SDimitry Andric }
46750b57cec5SDimitry Andric 
46760b57cec5SDimitry Andric MachO::note_command
getNoteLoadCommand(const LoadCommandInfo & L) const46770b57cec5SDimitry Andric MachOObjectFile::getNoteLoadCommand(const LoadCommandInfo &L) const {
46780b57cec5SDimitry Andric   return getStruct<MachO::note_command>(*this, L.Ptr);
46790b57cec5SDimitry Andric }
46800b57cec5SDimitry Andric 
46810b57cec5SDimitry Andric MachO::build_version_command
getBuildVersionLoadCommand(const LoadCommandInfo & L) const46820b57cec5SDimitry Andric MachOObjectFile::getBuildVersionLoadCommand(const LoadCommandInfo &L) const {
46830b57cec5SDimitry Andric   return getStruct<MachO::build_version_command>(*this, L.Ptr);
46840b57cec5SDimitry Andric }
46850b57cec5SDimitry Andric 
46860b57cec5SDimitry Andric MachO::build_tool_version
getBuildToolVersion(unsigned index) const46870b57cec5SDimitry Andric MachOObjectFile::getBuildToolVersion(unsigned index) const {
46880b57cec5SDimitry Andric   return getStruct<MachO::build_tool_version>(*this, BuildTools[index]);
46890b57cec5SDimitry Andric }
46900b57cec5SDimitry Andric 
46910b57cec5SDimitry Andric MachO::dylib_command
getDylibIDLoadCommand(const LoadCommandInfo & L) const46920b57cec5SDimitry Andric MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const {
46930b57cec5SDimitry Andric   return getStruct<MachO::dylib_command>(*this, L.Ptr);
46940b57cec5SDimitry Andric }
46950b57cec5SDimitry Andric 
46960b57cec5SDimitry Andric MachO::dyld_info_command
getDyldInfoLoadCommand(const LoadCommandInfo & L) const46970b57cec5SDimitry Andric MachOObjectFile::getDyldInfoLoadCommand(const LoadCommandInfo &L) const {
46980b57cec5SDimitry Andric   return getStruct<MachO::dyld_info_command>(*this, L.Ptr);
46990b57cec5SDimitry Andric }
47000b57cec5SDimitry Andric 
47010b57cec5SDimitry Andric MachO::dylinker_command
getDylinkerCommand(const LoadCommandInfo & L) const47020b57cec5SDimitry Andric MachOObjectFile::getDylinkerCommand(const LoadCommandInfo &L) const {
47030b57cec5SDimitry Andric   return getStruct<MachO::dylinker_command>(*this, L.Ptr);
47040b57cec5SDimitry Andric }
47050b57cec5SDimitry Andric 
47060b57cec5SDimitry Andric MachO::uuid_command
getUuidCommand(const LoadCommandInfo & L) const47070b57cec5SDimitry Andric MachOObjectFile::getUuidCommand(const LoadCommandInfo &L) const {
47080b57cec5SDimitry Andric   return getStruct<MachO::uuid_command>(*this, L.Ptr);
47090b57cec5SDimitry Andric }
47100b57cec5SDimitry Andric 
47110b57cec5SDimitry Andric MachO::rpath_command
getRpathCommand(const LoadCommandInfo & L) const47120b57cec5SDimitry Andric MachOObjectFile::getRpathCommand(const LoadCommandInfo &L) const {
47130b57cec5SDimitry Andric   return getStruct<MachO::rpath_command>(*this, L.Ptr);
47140b57cec5SDimitry Andric }
47150b57cec5SDimitry Andric 
47160b57cec5SDimitry Andric MachO::source_version_command
getSourceVersionCommand(const LoadCommandInfo & L) const47170b57cec5SDimitry Andric MachOObjectFile::getSourceVersionCommand(const LoadCommandInfo &L) const {
47180b57cec5SDimitry Andric   return getStruct<MachO::source_version_command>(*this, L.Ptr);
47190b57cec5SDimitry Andric }
47200b57cec5SDimitry Andric 
47210b57cec5SDimitry Andric MachO::entry_point_command
getEntryPointCommand(const LoadCommandInfo & L) const47220b57cec5SDimitry Andric MachOObjectFile::getEntryPointCommand(const LoadCommandInfo &L) const {
47230b57cec5SDimitry Andric   return getStruct<MachO::entry_point_command>(*this, L.Ptr);
47240b57cec5SDimitry Andric }
47250b57cec5SDimitry Andric 
47260b57cec5SDimitry Andric MachO::encryption_info_command
getEncryptionInfoCommand(const LoadCommandInfo & L) const47270b57cec5SDimitry Andric MachOObjectFile::getEncryptionInfoCommand(const LoadCommandInfo &L) const {
47280b57cec5SDimitry Andric   return getStruct<MachO::encryption_info_command>(*this, L.Ptr);
47290b57cec5SDimitry Andric }
47300b57cec5SDimitry Andric 
47310b57cec5SDimitry Andric MachO::encryption_info_command_64
getEncryptionInfoCommand64(const LoadCommandInfo & L) const47320b57cec5SDimitry Andric MachOObjectFile::getEncryptionInfoCommand64(const LoadCommandInfo &L) const {
47330b57cec5SDimitry Andric   return getStruct<MachO::encryption_info_command_64>(*this, L.Ptr);
47340b57cec5SDimitry Andric }
47350b57cec5SDimitry Andric 
47360b57cec5SDimitry Andric MachO::sub_framework_command
getSubFrameworkCommand(const LoadCommandInfo & L) const47370b57cec5SDimitry Andric MachOObjectFile::getSubFrameworkCommand(const LoadCommandInfo &L) const {
47380b57cec5SDimitry Andric   return getStruct<MachO::sub_framework_command>(*this, L.Ptr);
47390b57cec5SDimitry Andric }
47400b57cec5SDimitry Andric 
47410b57cec5SDimitry Andric MachO::sub_umbrella_command
getSubUmbrellaCommand(const LoadCommandInfo & L) const47420b57cec5SDimitry Andric MachOObjectFile::getSubUmbrellaCommand(const LoadCommandInfo &L) const {
47430b57cec5SDimitry Andric   return getStruct<MachO::sub_umbrella_command>(*this, L.Ptr);
47440b57cec5SDimitry Andric }
47450b57cec5SDimitry Andric 
47460b57cec5SDimitry Andric MachO::sub_library_command
getSubLibraryCommand(const LoadCommandInfo & L) const47470b57cec5SDimitry Andric MachOObjectFile::getSubLibraryCommand(const LoadCommandInfo &L) const {
47480b57cec5SDimitry Andric   return getStruct<MachO::sub_library_command>(*this, L.Ptr);
47490b57cec5SDimitry Andric }
47500b57cec5SDimitry Andric 
47510b57cec5SDimitry Andric MachO::sub_client_command
getSubClientCommand(const LoadCommandInfo & L) const47520b57cec5SDimitry Andric MachOObjectFile::getSubClientCommand(const LoadCommandInfo &L) const {
47530b57cec5SDimitry Andric   return getStruct<MachO::sub_client_command>(*this, L.Ptr);
47540b57cec5SDimitry Andric }
47550b57cec5SDimitry Andric 
47560b57cec5SDimitry Andric MachO::routines_command
getRoutinesCommand(const LoadCommandInfo & L) const47570b57cec5SDimitry Andric MachOObjectFile::getRoutinesCommand(const LoadCommandInfo &L) const {
47580b57cec5SDimitry Andric   return getStruct<MachO::routines_command>(*this, L.Ptr);
47590b57cec5SDimitry Andric }
47600b57cec5SDimitry Andric 
47610b57cec5SDimitry Andric MachO::routines_command_64
getRoutinesCommand64(const LoadCommandInfo & L) const47620b57cec5SDimitry Andric MachOObjectFile::getRoutinesCommand64(const LoadCommandInfo &L) const {
47630b57cec5SDimitry Andric   return getStruct<MachO::routines_command_64>(*this, L.Ptr);
47640b57cec5SDimitry Andric }
47650b57cec5SDimitry Andric 
47660b57cec5SDimitry Andric MachO::thread_command
getThreadCommand(const LoadCommandInfo & L) const47670b57cec5SDimitry Andric MachOObjectFile::getThreadCommand(const LoadCommandInfo &L) const {
47680b57cec5SDimitry Andric   return getStruct<MachO::thread_command>(*this, L.Ptr);
47690b57cec5SDimitry Andric }
47700b57cec5SDimitry Andric 
4771*c9157d92SDimitry Andric MachO::fileset_entry_command
getFilesetEntryLoadCommand(const LoadCommandInfo & L) const4772*c9157d92SDimitry Andric MachOObjectFile::getFilesetEntryLoadCommand(const LoadCommandInfo &L) const {
4773*c9157d92SDimitry Andric   return getStruct<MachO::fileset_entry_command>(*this, L.Ptr);
4774*c9157d92SDimitry Andric }
4775*c9157d92SDimitry Andric 
47760b57cec5SDimitry Andric MachO::any_relocation_info
getRelocation(DataRefImpl Rel) const47770b57cec5SDimitry Andric MachOObjectFile::getRelocation(DataRefImpl Rel) const {
47780b57cec5SDimitry Andric   uint32_t Offset;
47790b57cec5SDimitry Andric   if (getHeader().filetype == MachO::MH_OBJECT) {
47800b57cec5SDimitry Andric     DataRefImpl Sec;
47810b57cec5SDimitry Andric     Sec.d.a = Rel.d.a;
47820b57cec5SDimitry Andric     if (is64Bit()) {
47830b57cec5SDimitry Andric       MachO::section_64 Sect = getSection64(Sec);
47840b57cec5SDimitry Andric       Offset = Sect.reloff;
47850b57cec5SDimitry Andric     } else {
47860b57cec5SDimitry Andric       MachO::section Sect = getSection(Sec);
47870b57cec5SDimitry Andric       Offset = Sect.reloff;
47880b57cec5SDimitry Andric     }
47890b57cec5SDimitry Andric   } else {
47900b57cec5SDimitry Andric     MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();
47910b57cec5SDimitry Andric     if (Rel.d.a == 0)
47920b57cec5SDimitry Andric       Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations
47930b57cec5SDimitry Andric     else
47940b57cec5SDimitry Andric       Offset = DysymtabLoadCmd.locreloff; // Offset to the local relocations
47950b57cec5SDimitry Andric   }
47960b57cec5SDimitry Andric 
47970b57cec5SDimitry Andric   auto P = reinterpret_cast<const MachO::any_relocation_info *>(
47980b57cec5SDimitry Andric       getPtr(*this, Offset)) + Rel.d.b;
47990b57cec5SDimitry Andric   return getStruct<MachO::any_relocation_info>(
48000b57cec5SDimitry Andric       *this, reinterpret_cast<const char *>(P));
48010b57cec5SDimitry Andric }
48020b57cec5SDimitry Andric 
48030b57cec5SDimitry Andric MachO::data_in_code_entry
getDice(DataRefImpl Rel) const48040b57cec5SDimitry Andric MachOObjectFile::getDice(DataRefImpl Rel) const {
48050b57cec5SDimitry Andric   const char *P = reinterpret_cast<const char *>(Rel.p);
48060b57cec5SDimitry Andric   return getStruct<MachO::data_in_code_entry>(*this, P);
48070b57cec5SDimitry Andric }
48080b57cec5SDimitry Andric 
getHeader() const48090b57cec5SDimitry Andric const MachO::mach_header &MachOObjectFile::getHeader() const {
48100b57cec5SDimitry Andric   return Header;
48110b57cec5SDimitry Andric }
48120b57cec5SDimitry Andric 
getHeader64() const48130b57cec5SDimitry Andric const MachO::mach_header_64 &MachOObjectFile::getHeader64() const {
48140b57cec5SDimitry Andric   assert(is64Bit());
48150b57cec5SDimitry Andric   return Header64;
48160b57cec5SDimitry Andric }
48170b57cec5SDimitry Andric 
getIndirectSymbolTableEntry(const MachO::dysymtab_command & DLC,unsigned Index) const48180b57cec5SDimitry Andric uint32_t MachOObjectFile::getIndirectSymbolTableEntry(
48190b57cec5SDimitry Andric                                              const MachO::dysymtab_command &DLC,
48200b57cec5SDimitry Andric                                              unsigned Index) const {
48210b57cec5SDimitry Andric   uint64_t Offset = DLC.indirectsymoff + Index * sizeof(uint32_t);
48220b57cec5SDimitry Andric   return getStruct<uint32_t>(*this, getPtr(*this, Offset));
48230b57cec5SDimitry Andric }
48240b57cec5SDimitry Andric 
48250b57cec5SDimitry Andric MachO::data_in_code_entry
getDataInCodeTableEntry(uint32_t DataOffset,unsigned Index) const48260b57cec5SDimitry Andric MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset,
48270b57cec5SDimitry Andric                                          unsigned Index) const {
48280b57cec5SDimitry Andric   uint64_t Offset = DataOffset + Index * sizeof(MachO::data_in_code_entry);
48290b57cec5SDimitry Andric   return getStruct<MachO::data_in_code_entry>(*this, getPtr(*this, Offset));
48300b57cec5SDimitry Andric }
48310b57cec5SDimitry Andric 
getSymtabLoadCommand() const48320b57cec5SDimitry Andric MachO::symtab_command MachOObjectFile::getSymtabLoadCommand() const {
48330b57cec5SDimitry Andric   if (SymtabLoadCmd)
48340b57cec5SDimitry Andric     return getStruct<MachO::symtab_command>(*this, SymtabLoadCmd);
48350b57cec5SDimitry Andric 
48360b57cec5SDimitry Andric   // If there is no SymtabLoadCmd return a load command with zero'ed fields.
48370b57cec5SDimitry Andric   MachO::symtab_command Cmd;
48380b57cec5SDimitry Andric   Cmd.cmd = MachO::LC_SYMTAB;
48390b57cec5SDimitry Andric   Cmd.cmdsize = sizeof(MachO::symtab_command);
48400b57cec5SDimitry Andric   Cmd.symoff = 0;
48410b57cec5SDimitry Andric   Cmd.nsyms = 0;
48420b57cec5SDimitry Andric   Cmd.stroff = 0;
48430b57cec5SDimitry Andric   Cmd.strsize = 0;
48440b57cec5SDimitry Andric   return Cmd;
48450b57cec5SDimitry Andric }
48460b57cec5SDimitry Andric 
getDysymtabLoadCommand() const48470b57cec5SDimitry Andric MachO::dysymtab_command MachOObjectFile::getDysymtabLoadCommand() const {
48480b57cec5SDimitry Andric   if (DysymtabLoadCmd)
48490b57cec5SDimitry Andric     return getStruct<MachO::dysymtab_command>(*this, DysymtabLoadCmd);
48500b57cec5SDimitry Andric 
48510b57cec5SDimitry Andric   // If there is no DysymtabLoadCmd return a load command with zero'ed fields.
48520b57cec5SDimitry Andric   MachO::dysymtab_command Cmd;
48530b57cec5SDimitry Andric   Cmd.cmd = MachO::LC_DYSYMTAB;
48540b57cec5SDimitry Andric   Cmd.cmdsize = sizeof(MachO::dysymtab_command);
48550b57cec5SDimitry Andric   Cmd.ilocalsym = 0;
48560b57cec5SDimitry Andric   Cmd.nlocalsym = 0;
48570b57cec5SDimitry Andric   Cmd.iextdefsym = 0;
48580b57cec5SDimitry Andric   Cmd.nextdefsym = 0;
48590b57cec5SDimitry Andric   Cmd.iundefsym = 0;
48600b57cec5SDimitry Andric   Cmd.nundefsym = 0;
48610b57cec5SDimitry Andric   Cmd.tocoff = 0;
48620b57cec5SDimitry Andric   Cmd.ntoc = 0;
48630b57cec5SDimitry Andric   Cmd.modtaboff = 0;
48640b57cec5SDimitry Andric   Cmd.nmodtab = 0;
48650b57cec5SDimitry Andric   Cmd.extrefsymoff = 0;
48660b57cec5SDimitry Andric   Cmd.nextrefsyms = 0;
48670b57cec5SDimitry Andric   Cmd.indirectsymoff = 0;
48680b57cec5SDimitry Andric   Cmd.nindirectsyms = 0;
48690b57cec5SDimitry Andric   Cmd.extreloff = 0;
48700b57cec5SDimitry Andric   Cmd.nextrel = 0;
48710b57cec5SDimitry Andric   Cmd.locreloff = 0;
48720b57cec5SDimitry Andric   Cmd.nlocrel = 0;
48730b57cec5SDimitry Andric   return Cmd;
48740b57cec5SDimitry Andric }
48750b57cec5SDimitry Andric 
48760b57cec5SDimitry Andric MachO::linkedit_data_command
getDataInCodeLoadCommand() const48770b57cec5SDimitry Andric MachOObjectFile::getDataInCodeLoadCommand() const {
48780b57cec5SDimitry Andric   if (DataInCodeLoadCmd)
48790b57cec5SDimitry Andric     return getStruct<MachO::linkedit_data_command>(*this, DataInCodeLoadCmd);
48800b57cec5SDimitry Andric 
48810b57cec5SDimitry Andric   // If there is no DataInCodeLoadCmd return a load command with zero'ed fields.
48820b57cec5SDimitry Andric   MachO::linkedit_data_command Cmd;
48830b57cec5SDimitry Andric   Cmd.cmd = MachO::LC_DATA_IN_CODE;
48840b57cec5SDimitry Andric   Cmd.cmdsize = sizeof(MachO::linkedit_data_command);
48850b57cec5SDimitry Andric   Cmd.dataoff = 0;
48860b57cec5SDimitry Andric   Cmd.datasize = 0;
48870b57cec5SDimitry Andric   return Cmd;
48880b57cec5SDimitry Andric }
48890b57cec5SDimitry Andric 
48900b57cec5SDimitry Andric MachO::linkedit_data_command
getLinkOptHintsLoadCommand() const48910b57cec5SDimitry Andric MachOObjectFile::getLinkOptHintsLoadCommand() const {
48920b57cec5SDimitry Andric   if (LinkOptHintsLoadCmd)
48930b57cec5SDimitry Andric     return getStruct<MachO::linkedit_data_command>(*this, LinkOptHintsLoadCmd);
48940b57cec5SDimitry Andric 
48950b57cec5SDimitry Andric   // If there is no LinkOptHintsLoadCmd return a load command with zero'ed
48960b57cec5SDimitry Andric   // fields.
48970b57cec5SDimitry Andric   MachO::linkedit_data_command Cmd;
48980b57cec5SDimitry Andric   Cmd.cmd = MachO::LC_LINKER_OPTIMIZATION_HINT;
48990b57cec5SDimitry Andric   Cmd.cmdsize = sizeof(MachO::linkedit_data_command);
49000b57cec5SDimitry Andric   Cmd.dataoff = 0;
49010b57cec5SDimitry Andric   Cmd.datasize = 0;
49020b57cec5SDimitry Andric   return Cmd;
49030b57cec5SDimitry Andric }
49040b57cec5SDimitry Andric 
getDyldInfoRebaseOpcodes() const49050b57cec5SDimitry Andric ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const {
49060b57cec5SDimitry Andric   if (!DyldInfoLoadCmd)
4907bdd1243dSDimitry Andric     return std::nullopt;
49080b57cec5SDimitry Andric 
49090b57cec5SDimitry Andric   auto DyldInfoOrErr =
49100b57cec5SDimitry Andric     getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
49110b57cec5SDimitry Andric   if (!DyldInfoOrErr)
4912bdd1243dSDimitry Andric     return std::nullopt;
49130b57cec5SDimitry Andric   MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
49140b57cec5SDimitry Andric   const uint8_t *Ptr =
49150b57cec5SDimitry Andric       reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.rebase_off));
4916bdd1243dSDimitry Andric   return ArrayRef(Ptr, DyldInfo.rebase_size);
49170b57cec5SDimitry Andric }
49180b57cec5SDimitry Andric 
getDyldInfoBindOpcodes() const49190b57cec5SDimitry Andric ArrayRef<uint8_t> MachOObjectFile::getDyldInfoBindOpcodes() const {
49200b57cec5SDimitry Andric   if (!DyldInfoLoadCmd)
4921bdd1243dSDimitry Andric     return std::nullopt;
49220b57cec5SDimitry Andric 
49230b57cec5SDimitry Andric   auto DyldInfoOrErr =
49240b57cec5SDimitry Andric     getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
49250b57cec5SDimitry Andric   if (!DyldInfoOrErr)
4926bdd1243dSDimitry Andric     return std::nullopt;
49270b57cec5SDimitry Andric   MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
49280b57cec5SDimitry Andric   const uint8_t *Ptr =
49290b57cec5SDimitry Andric       reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.bind_off));
4930bdd1243dSDimitry Andric   return ArrayRef(Ptr, DyldInfo.bind_size);
49310b57cec5SDimitry Andric }
49320b57cec5SDimitry Andric 
getDyldInfoWeakBindOpcodes() const49330b57cec5SDimitry Andric ArrayRef<uint8_t> MachOObjectFile::getDyldInfoWeakBindOpcodes() const {
49340b57cec5SDimitry Andric   if (!DyldInfoLoadCmd)
4935bdd1243dSDimitry Andric     return std::nullopt;
49360b57cec5SDimitry Andric 
49370b57cec5SDimitry Andric   auto DyldInfoOrErr =
49380b57cec5SDimitry Andric     getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
49390b57cec5SDimitry Andric   if (!DyldInfoOrErr)
4940bdd1243dSDimitry Andric     return std::nullopt;
49410b57cec5SDimitry Andric   MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
49420b57cec5SDimitry Andric   const uint8_t *Ptr =
49430b57cec5SDimitry Andric       reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.weak_bind_off));
4944bdd1243dSDimitry Andric   return ArrayRef(Ptr, DyldInfo.weak_bind_size);
49450b57cec5SDimitry Andric }
49460b57cec5SDimitry Andric 
getDyldInfoLazyBindOpcodes() const49470b57cec5SDimitry Andric ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
49480b57cec5SDimitry Andric   if (!DyldInfoLoadCmd)
4949bdd1243dSDimitry Andric     return std::nullopt;
49500b57cec5SDimitry Andric 
49510b57cec5SDimitry Andric   auto DyldInfoOrErr =
49520b57cec5SDimitry Andric       getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
49530b57cec5SDimitry Andric   if (!DyldInfoOrErr)
4954bdd1243dSDimitry Andric     return std::nullopt;
49550b57cec5SDimitry Andric   MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
49560b57cec5SDimitry Andric   const uint8_t *Ptr =
49570b57cec5SDimitry Andric       reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.lazy_bind_off));
4958bdd1243dSDimitry Andric   return ArrayRef(Ptr, DyldInfo.lazy_bind_size);
49590b57cec5SDimitry Andric }
49600b57cec5SDimitry Andric 
getDyldInfoExportsTrie() const4961bdd1243dSDimitry Andric ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {
4962bdd1243dSDimitry Andric   if (!DyldInfoLoadCmd)
4963bdd1243dSDimitry Andric     return std::nullopt;
4964bdd1243dSDimitry Andric 
4965bdd1243dSDimitry Andric   auto DyldInfoOrErr =
4966bdd1243dSDimitry Andric       getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
4967bdd1243dSDimitry Andric   if (!DyldInfoOrErr)
4968bdd1243dSDimitry Andric     return std::nullopt;
4969bdd1243dSDimitry Andric   MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
4970bdd1243dSDimitry Andric   const uint8_t *Ptr =
4971bdd1243dSDimitry Andric       reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.export_off));
4972bdd1243dSDimitry Andric   return ArrayRef(Ptr, DyldInfo.export_size);
4973bdd1243dSDimitry Andric }
4974bdd1243dSDimitry Andric 
4975bdd1243dSDimitry Andric Expected<std::optional<MachO::linkedit_data_command>>
getChainedFixupsLoadCommand() const4976bdd1243dSDimitry Andric MachOObjectFile::getChainedFixupsLoadCommand() const {
497781ad6265SDimitry Andric   // Load the dyld chained fixups load command.
497881ad6265SDimitry Andric   if (!DyldChainedFixupsLoadCmd)
4979bdd1243dSDimitry Andric     return std::nullopt;
498081ad6265SDimitry Andric   auto DyldChainedFixupsOrErr = getStructOrErr<MachO::linkedit_data_command>(
498181ad6265SDimitry Andric       *this, DyldChainedFixupsLoadCmd);
498281ad6265SDimitry Andric   if (!DyldChainedFixupsOrErr)
498381ad6265SDimitry Andric     return DyldChainedFixupsOrErr.takeError();
4984bdd1243dSDimitry Andric   const MachO::linkedit_data_command &DyldChainedFixups =
4985bdd1243dSDimitry Andric       *DyldChainedFixupsOrErr;
498681ad6265SDimitry Andric 
498781ad6265SDimitry Andric   // If the load command is present but the data offset has been zeroed out,
4988bdd1243dSDimitry Andric   // as is the case for dylib stubs, return std::nullopt (no error).
4989bdd1243dSDimitry Andric   if (!DyldChainedFixups.dataoff)
4990bdd1243dSDimitry Andric     return std::nullopt;
4991bdd1243dSDimitry Andric   return DyldChainedFixups;
4992bdd1243dSDimitry Andric }
4993bdd1243dSDimitry Andric 
4994bdd1243dSDimitry Andric Expected<std::optional<MachO::dyld_chained_fixups_header>>
getChainedFixupsHeader() const4995bdd1243dSDimitry Andric MachOObjectFile::getChainedFixupsHeader() const {
4996bdd1243dSDimitry Andric   auto CFOrErr = getChainedFixupsLoadCommand();
4997bdd1243dSDimitry Andric   if (!CFOrErr)
4998bdd1243dSDimitry Andric     return CFOrErr.takeError();
4999bdd1243dSDimitry Andric   if (!CFOrErr->has_value())
5000bdd1243dSDimitry Andric     return std::nullopt;
5001bdd1243dSDimitry Andric 
5002bdd1243dSDimitry Andric   const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr;
5003bdd1243dSDimitry Andric 
500481ad6265SDimitry Andric   uint64_t CFHeaderOffset = DyldChainedFixups.dataoff;
5005bdd1243dSDimitry Andric   uint64_t CFSize = DyldChainedFixups.datasize;
500681ad6265SDimitry Andric 
500781ad6265SDimitry Andric   // Load the dyld chained fixups header.
500881ad6265SDimitry Andric   const char *CFHeaderPtr = getPtr(*this, CFHeaderOffset);
500981ad6265SDimitry Andric   auto CFHeaderOrErr =
501081ad6265SDimitry Andric       getStructOrErr<MachO::dyld_chained_fixups_header>(*this, CFHeaderPtr);
501181ad6265SDimitry Andric   if (!CFHeaderOrErr)
501281ad6265SDimitry Andric     return CFHeaderOrErr.takeError();
501381ad6265SDimitry Andric   MachO::dyld_chained_fixups_header CFHeader = CFHeaderOrErr.get();
501481ad6265SDimitry Andric 
501581ad6265SDimitry Andric   // Reject unknown chained fixup formats.
501681ad6265SDimitry Andric   if (CFHeader.fixups_version != 0)
501781ad6265SDimitry Andric     return malformedError(Twine("bad chained fixups: unknown version: ") +
501881ad6265SDimitry Andric                           Twine(CFHeader.fixups_version));
501981ad6265SDimitry Andric   if (CFHeader.imports_format < 1 || CFHeader.imports_format > 3)
502081ad6265SDimitry Andric     return malformedError(
502181ad6265SDimitry Andric         Twine("bad chained fixups: unknown imports format: ") +
502281ad6265SDimitry Andric         Twine(CFHeader.imports_format));
502381ad6265SDimitry Andric 
502481ad6265SDimitry Andric   // Validate the image format.
502581ad6265SDimitry Andric   //
502681ad6265SDimitry Andric   // Load the image starts.
502781ad6265SDimitry Andric   uint64_t CFImageStartsOffset = (CFHeaderOffset + CFHeader.starts_offset);
502881ad6265SDimitry Andric   if (CFHeader.starts_offset < sizeof(MachO::dyld_chained_fixups_header)) {
502981ad6265SDimitry Andric     return malformedError(Twine("bad chained fixups: image starts offset ") +
503081ad6265SDimitry Andric                           Twine(CFHeader.starts_offset) +
503181ad6265SDimitry Andric                           " overlaps with chained fixups header");
503281ad6265SDimitry Andric   }
5033bdd1243dSDimitry Andric   uint32_t EndOffset = CFHeaderOffset + CFSize;
503481ad6265SDimitry Andric   if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) >
503581ad6265SDimitry Andric       EndOffset) {
503681ad6265SDimitry Andric     return malformedError(Twine("bad chained fixups: image starts end ") +
503781ad6265SDimitry Andric                           Twine(CFImageStartsOffset +
503881ad6265SDimitry Andric                                 sizeof(MachO::dyld_chained_starts_in_image)) +
503981ad6265SDimitry Andric                           " extends past end " + Twine(EndOffset));
504081ad6265SDimitry Andric   }
504181ad6265SDimitry Andric 
504281ad6265SDimitry Andric   return CFHeader;
504381ad6265SDimitry Andric }
504481ad6265SDimitry Andric 
5045bdd1243dSDimitry Andric Expected<std::pair<size_t, std::vector<ChainedFixupsSegment>>>
getChainedFixupsSegments() const5046bdd1243dSDimitry Andric MachOObjectFile::getChainedFixupsSegments() const {
5047bdd1243dSDimitry Andric   auto CFOrErr = getChainedFixupsLoadCommand();
5048bdd1243dSDimitry Andric   if (!CFOrErr)
5049bdd1243dSDimitry Andric     return CFOrErr.takeError();
5050bdd1243dSDimitry Andric 
5051bdd1243dSDimitry Andric   std::vector<ChainedFixupsSegment> Segments;
5052bdd1243dSDimitry Andric   if (!CFOrErr->has_value())
5053bdd1243dSDimitry Andric     return std::make_pair(0, Segments);
5054bdd1243dSDimitry Andric 
5055bdd1243dSDimitry Andric   const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr;
5056bdd1243dSDimitry Andric 
5057bdd1243dSDimitry Andric   auto HeaderOrErr = getChainedFixupsHeader();
5058bdd1243dSDimitry Andric   if (!HeaderOrErr)
5059bdd1243dSDimitry Andric     return HeaderOrErr.takeError();
5060bdd1243dSDimitry Andric   if (!HeaderOrErr->has_value())
5061bdd1243dSDimitry Andric     return std::make_pair(0, Segments);
5062bdd1243dSDimitry Andric   const MachO::dyld_chained_fixups_header &Header = **HeaderOrErr;
5063bdd1243dSDimitry Andric 
5064bdd1243dSDimitry Andric   const char *Contents = getPtr(*this, DyldChainedFixups.dataoff);
5065bdd1243dSDimitry Andric 
5066bdd1243dSDimitry Andric   auto ImageStartsOrErr = getStructOrErr<MachO::dyld_chained_starts_in_image>(
5067bdd1243dSDimitry Andric       *this, Contents + Header.starts_offset);
5068bdd1243dSDimitry Andric   if (!ImageStartsOrErr)
5069bdd1243dSDimitry Andric     return ImageStartsOrErr.takeError();
5070bdd1243dSDimitry Andric   const MachO::dyld_chained_starts_in_image &ImageStarts = *ImageStartsOrErr;
5071bdd1243dSDimitry Andric 
5072bdd1243dSDimitry Andric   const char *SegOffsPtr =
5073bdd1243dSDimitry Andric       Contents + Header.starts_offset +
5074bdd1243dSDimitry Andric       offsetof(MachO::dyld_chained_starts_in_image, seg_info_offset);
5075bdd1243dSDimitry Andric   const char *SegOffsEnd =
5076bdd1243dSDimitry Andric       SegOffsPtr + ImageStarts.seg_count * sizeof(uint32_t);
5077bdd1243dSDimitry Andric   if (SegOffsEnd > Contents + DyldChainedFixups.datasize)
5078bdd1243dSDimitry Andric     return malformedError(
5079bdd1243dSDimitry Andric         "bad chained fixups: seg_info_offset extends past end");
5080bdd1243dSDimitry Andric 
5081bdd1243dSDimitry Andric   const char *LastSegEnd = nullptr;
5082bdd1243dSDimitry Andric   for (size_t I = 0, N = ImageStarts.seg_count; I < N; ++I) {
5083bdd1243dSDimitry Andric     auto OffOrErr =
5084bdd1243dSDimitry Andric         getStructOrErr<uint32_t>(*this, SegOffsPtr + I * sizeof(uint32_t));
5085bdd1243dSDimitry Andric     if (!OffOrErr)
5086bdd1243dSDimitry Andric       return OffOrErr.takeError();
5087bdd1243dSDimitry Andric     // seg_info_offset == 0 means there is no associated starts_in_segment
5088bdd1243dSDimitry Andric     // entry.
5089bdd1243dSDimitry Andric     if (!*OffOrErr)
5090bdd1243dSDimitry Andric       continue;
5091bdd1243dSDimitry Andric 
5092bdd1243dSDimitry Andric     auto Fail = [&](Twine Message) {
5093bdd1243dSDimitry Andric       return malformedError("bad chained fixups: segment info" + Twine(I) +
5094bdd1243dSDimitry Andric                             " at offset " + Twine(*OffOrErr) + Message);
5095bdd1243dSDimitry Andric     };
5096bdd1243dSDimitry Andric 
5097bdd1243dSDimitry Andric     const char *SegPtr = Contents + Header.starts_offset + *OffOrErr;
5098bdd1243dSDimitry Andric     if (LastSegEnd && SegPtr < LastSegEnd)
5099bdd1243dSDimitry Andric       return Fail(" overlaps with previous segment info");
5100bdd1243dSDimitry Andric 
5101bdd1243dSDimitry Andric     auto SegOrErr =
5102bdd1243dSDimitry Andric         getStructOrErr<MachO::dyld_chained_starts_in_segment>(*this, SegPtr);
5103bdd1243dSDimitry Andric     if (!SegOrErr)
5104bdd1243dSDimitry Andric       return SegOrErr.takeError();
5105bdd1243dSDimitry Andric     const MachO::dyld_chained_starts_in_segment &Seg = *SegOrErr;
5106bdd1243dSDimitry Andric 
5107bdd1243dSDimitry Andric     LastSegEnd = SegPtr + Seg.size;
5108bdd1243dSDimitry Andric     if (Seg.pointer_format < 1 || Seg.pointer_format > 12)
5109bdd1243dSDimitry Andric       return Fail(" has unknown pointer format: " + Twine(Seg.pointer_format));
5110bdd1243dSDimitry Andric 
5111bdd1243dSDimitry Andric     const char *PageStart =
5112bdd1243dSDimitry Andric         SegPtr + offsetof(MachO::dyld_chained_starts_in_segment, page_start);
5113bdd1243dSDimitry Andric     const char *PageEnd = PageStart + Seg.page_count * sizeof(uint16_t);
5114bdd1243dSDimitry Andric     if (PageEnd > SegPtr + Seg.size)
5115bdd1243dSDimitry Andric       return Fail(" : page_starts extend past seg_info size");
5116bdd1243dSDimitry Andric 
5117bdd1243dSDimitry Andric     // FIXME: This does not account for multiple offsets on a single page
5118bdd1243dSDimitry Andric     //        (DYLD_CHAINED_PTR_START_MULTI; 32-bit only).
5119bdd1243dSDimitry Andric     std::vector<uint16_t> PageStarts;
5120bdd1243dSDimitry Andric     for (size_t PageIdx = 0; PageIdx < Seg.page_count; ++PageIdx) {
5121bdd1243dSDimitry Andric       uint16_t Start;
5122bdd1243dSDimitry Andric       memcpy(&Start, PageStart + PageIdx * sizeof(uint16_t), sizeof(uint16_t));
5123bdd1243dSDimitry Andric       if (isLittleEndian() != sys::IsLittleEndianHost)
5124bdd1243dSDimitry Andric         sys::swapByteOrder(Start);
5125bdd1243dSDimitry Andric       PageStarts.push_back(Start);
5126bdd1243dSDimitry Andric     }
5127bdd1243dSDimitry Andric 
5128bdd1243dSDimitry Andric     Segments.emplace_back(I, *OffOrErr, Seg, std::move(PageStarts));
5129bdd1243dSDimitry Andric   }
5130bdd1243dSDimitry Andric 
5131bdd1243dSDimitry Andric   return std::make_pair(ImageStarts.seg_count, Segments);
5132bdd1243dSDimitry Andric }
5133bdd1243dSDimitry Andric 
5134bdd1243dSDimitry Andric // The special library ordinals have a negative value, but they are encoded in
5135bdd1243dSDimitry Andric // an unsigned bitfield, so we need to sign extend the value.
getEncodedOrdinal(T Value)5136bdd1243dSDimitry Andric template <typename T> static int getEncodedOrdinal(T Value) {
5137bdd1243dSDimitry Andric   if (Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE) ||
5138bdd1243dSDimitry Andric       Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) ||
5139bdd1243dSDimitry Andric       Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP))
5140bdd1243dSDimitry Andric     return SignExtend32<sizeof(T) * CHAR_BIT>(Value);
5141bdd1243dSDimitry Andric   return Value;
5142bdd1243dSDimitry Andric }
5143bdd1243dSDimitry Andric 
5144bdd1243dSDimitry Andric template <typename T, unsigned N>
getArray(const MachOObjectFile & O,const void * Ptr)5145bdd1243dSDimitry Andric static std::array<T, N> getArray(const MachOObjectFile &O, const void *Ptr) {
5146bdd1243dSDimitry Andric   std::array<T, N> RawValue;
5147bdd1243dSDimitry Andric   memcpy(RawValue.data(), Ptr, N * sizeof(T));
5148bdd1243dSDimitry Andric   if (O.isLittleEndian() != sys::IsLittleEndianHost)
5149bdd1243dSDimitry Andric     for (auto &Element : RawValue)
5150bdd1243dSDimitry Andric       sys::swapByteOrder(Element);
5151bdd1243dSDimitry Andric   return RawValue;
5152bdd1243dSDimitry Andric }
5153bdd1243dSDimitry Andric 
515481ad6265SDimitry Andric Expected<std::vector<ChainedFixupTarget>>
getDyldChainedFixupTargets() const515581ad6265SDimitry Andric MachOObjectFile::getDyldChainedFixupTargets() const {
5156bdd1243dSDimitry Andric   auto CFOrErr = getChainedFixupsLoadCommand();
5157bdd1243dSDimitry Andric   if (!CFOrErr)
5158bdd1243dSDimitry Andric     return CFOrErr.takeError();
5159bdd1243dSDimitry Andric 
5160bdd1243dSDimitry Andric   std::vector<ChainedFixupTarget> Targets;
5161bdd1243dSDimitry Andric   if (!CFOrErr->has_value())
5162bdd1243dSDimitry Andric     return Targets;
5163bdd1243dSDimitry Andric 
5164bdd1243dSDimitry Andric   const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr;
5165bdd1243dSDimitry Andric 
516681ad6265SDimitry Andric   auto CFHeaderOrErr = getChainedFixupsHeader();
516781ad6265SDimitry Andric   if (!CFHeaderOrErr)
516881ad6265SDimitry Andric     return CFHeaderOrErr.takeError();
516981ad6265SDimitry Andric   if (!(*CFHeaderOrErr))
517081ad6265SDimitry Andric     return Targets;
5171bdd1243dSDimitry Andric   const MachO::dyld_chained_fixups_header &Header = **CFHeaderOrErr;
5172bdd1243dSDimitry Andric 
5173bdd1243dSDimitry Andric   size_t ImportSize = 0;
5174bdd1243dSDimitry Andric   if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT)
5175bdd1243dSDimitry Andric     ImportSize = sizeof(MachO::dyld_chained_import);
5176bdd1243dSDimitry Andric   else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND)
5177bdd1243dSDimitry Andric     ImportSize = sizeof(MachO::dyld_chained_import_addend);
5178bdd1243dSDimitry Andric   else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)
5179bdd1243dSDimitry Andric     ImportSize = sizeof(MachO::dyld_chained_import_addend64);
5180bdd1243dSDimitry Andric   else
5181bdd1243dSDimitry Andric     return malformedError("bad chained fixups: unknown imports format: " +
5182bdd1243dSDimitry Andric                           Twine(Header.imports_format));
5183bdd1243dSDimitry Andric 
5184bdd1243dSDimitry Andric   const char *Contents = getPtr(*this, DyldChainedFixups.dataoff);
5185bdd1243dSDimitry Andric   const char *Imports = Contents + Header.imports_offset;
5186bdd1243dSDimitry Andric   size_t ImportsEndOffset =
5187bdd1243dSDimitry Andric       Header.imports_offset + ImportSize * Header.imports_count;
5188bdd1243dSDimitry Andric   const char *ImportsEnd = Contents + ImportsEndOffset;
5189bdd1243dSDimitry Andric   const char *Symbols = Contents + Header.symbols_offset;
5190bdd1243dSDimitry Andric   const char *SymbolsEnd = Contents + DyldChainedFixups.datasize;
5191bdd1243dSDimitry Andric 
5192bdd1243dSDimitry Andric   if (ImportsEnd > Symbols)
5193bdd1243dSDimitry Andric     return malformedError("bad chained fixups: imports end " +
5194bdd1243dSDimitry Andric                           Twine(ImportsEndOffset) + " extends past end " +
5195bdd1243dSDimitry Andric                           Twine(DyldChainedFixups.datasize));
5196bdd1243dSDimitry Andric 
5197bdd1243dSDimitry Andric   if (ImportsEnd > Symbols)
5198bdd1243dSDimitry Andric     return malformedError("bad chained fixups: imports end " +
5199bdd1243dSDimitry Andric                           Twine(ImportsEndOffset) + " overlaps with symbols");
5200bdd1243dSDimitry Andric 
5201bdd1243dSDimitry Andric   // We use bit manipulation to extract data from the bitfields. This is correct
5202bdd1243dSDimitry Andric   // for both LE and BE hosts, but we assume that the object is little-endian.
5203bdd1243dSDimitry Andric   if (!isLittleEndian())
5204bdd1243dSDimitry Andric     return createError("parsing big-endian chained fixups is not implemented");
5205bdd1243dSDimitry Andric   for (const char *ImportPtr = Imports; ImportPtr < ImportsEnd;
5206bdd1243dSDimitry Andric        ImportPtr += ImportSize) {
5207bdd1243dSDimitry Andric     int LibOrdinal;
5208bdd1243dSDimitry Andric     bool WeakImport;
5209bdd1243dSDimitry Andric     uint32_t NameOffset;
5210bdd1243dSDimitry Andric     uint64_t Addend;
5211bdd1243dSDimitry Andric     if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT) {
5212bdd1243dSDimitry Andric       static_assert(sizeof(uint32_t) == sizeof(MachO::dyld_chained_import));
5213bdd1243dSDimitry Andric       auto RawValue = getArray<uint32_t, 1>(*this, ImportPtr);
5214bdd1243dSDimitry Andric 
5215bdd1243dSDimitry Andric       LibOrdinal = getEncodedOrdinal<uint8_t>(RawValue[0] & 0xFF);
5216bdd1243dSDimitry Andric       WeakImport = (RawValue[0] >> 8) & 1;
5217bdd1243dSDimitry Andric       NameOffset = RawValue[0] >> 9;
5218bdd1243dSDimitry Andric       Addend = 0;
5219bdd1243dSDimitry Andric     } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND) {
5220bdd1243dSDimitry Andric       static_assert(sizeof(uint64_t) ==
5221bdd1243dSDimitry Andric                     sizeof(MachO::dyld_chained_import_addend));
5222bdd1243dSDimitry Andric       auto RawValue = getArray<uint32_t, 2>(*this, ImportPtr);
5223bdd1243dSDimitry Andric 
5224bdd1243dSDimitry Andric       LibOrdinal = getEncodedOrdinal<uint8_t>(RawValue[0] & 0xFF);
5225bdd1243dSDimitry Andric       WeakImport = (RawValue[0] >> 8) & 1;
5226bdd1243dSDimitry Andric       NameOffset = RawValue[0] >> 9;
5227bdd1243dSDimitry Andric       Addend = bit_cast<int32_t>(RawValue[1]);
5228bdd1243dSDimitry Andric     } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) {
5229bdd1243dSDimitry Andric       static_assert(2 * sizeof(uint64_t) ==
5230bdd1243dSDimitry Andric                     sizeof(MachO::dyld_chained_import_addend64));
5231bdd1243dSDimitry Andric       auto RawValue = getArray<uint64_t, 2>(*this, ImportPtr);
5232bdd1243dSDimitry Andric 
5233bdd1243dSDimitry Andric       LibOrdinal = getEncodedOrdinal<uint16_t>(RawValue[0] & 0xFFFF);
5234bdd1243dSDimitry Andric       NameOffset = (RawValue[0] >> 16) & 1;
5235bdd1243dSDimitry Andric       WeakImport = RawValue[0] >> 17;
5236bdd1243dSDimitry Andric       Addend = RawValue[1];
5237bdd1243dSDimitry Andric     } else {
5238bdd1243dSDimitry Andric       llvm_unreachable("Import format should have been checked");
523981ad6265SDimitry Andric     }
524081ad6265SDimitry Andric 
5241bdd1243dSDimitry Andric     const char *Str = Symbols + NameOffset;
5242bdd1243dSDimitry Andric     if (Str >= SymbolsEnd)
5243bdd1243dSDimitry Andric       return malformedError("bad chained fixups: symbol offset " +
5244bdd1243dSDimitry Andric                             Twine(NameOffset) + " extends past end " +
5245bdd1243dSDimitry Andric                             Twine(DyldChainedFixups.datasize));
5246bdd1243dSDimitry Andric     Targets.emplace_back(LibOrdinal, NameOffset, Str, Addend, WeakImport);
5247bdd1243dSDimitry Andric   }
52480b57cec5SDimitry Andric 
5249bdd1243dSDimitry Andric   return std::move(Targets);
5250bdd1243dSDimitry Andric }
5251bdd1243dSDimitry Andric 
getDyldExportsTrie() const5252bdd1243dSDimitry Andric ArrayRef<uint8_t> MachOObjectFile::getDyldExportsTrie() const {
5253bdd1243dSDimitry Andric   if (!DyldExportsTrieLoadCmd)
5254bdd1243dSDimitry Andric     return std::nullopt;
5255bdd1243dSDimitry Andric 
5256bdd1243dSDimitry Andric   auto DyldExportsTrieOrError = getStructOrErr<MachO::linkedit_data_command>(
5257bdd1243dSDimitry Andric       *this, DyldExportsTrieLoadCmd);
5258bdd1243dSDimitry Andric   if (!DyldExportsTrieOrError)
5259bdd1243dSDimitry Andric     return std::nullopt;
5260bdd1243dSDimitry Andric   MachO::linkedit_data_command DyldExportsTrie = DyldExportsTrieOrError.get();
52610b57cec5SDimitry Andric   const uint8_t *Ptr =
5262bdd1243dSDimitry Andric       reinterpret_cast<const uint8_t *>(getPtr(*this, DyldExportsTrie.dataoff));
5263bdd1243dSDimitry Andric   return ArrayRef(Ptr, DyldExportsTrie.datasize);
52640b57cec5SDimitry Andric }
52650b57cec5SDimitry Andric 
getFunctionStarts() const526681ad6265SDimitry Andric SmallVector<uint64_t> MachOObjectFile::getFunctionStarts() const {
526781ad6265SDimitry Andric   if (!FuncStartsLoadCmd)
526881ad6265SDimitry Andric     return {};
526981ad6265SDimitry Andric 
527081ad6265SDimitry Andric   auto InfoOrErr =
527181ad6265SDimitry Andric       getStructOrErr<MachO::linkedit_data_command>(*this, FuncStartsLoadCmd);
527281ad6265SDimitry Andric   if (!InfoOrErr)
527381ad6265SDimitry Andric     return {};
527481ad6265SDimitry Andric 
527581ad6265SDimitry Andric   MachO::linkedit_data_command Info = InfoOrErr.get();
527681ad6265SDimitry Andric   SmallVector<uint64_t, 8> FunctionStarts;
527781ad6265SDimitry Andric   this->ReadULEB128s(Info.dataoff, FunctionStarts);
527881ad6265SDimitry Andric   return std::move(FunctionStarts);
527981ad6265SDimitry Andric }
528081ad6265SDimitry Andric 
getUuid() const52810b57cec5SDimitry Andric ArrayRef<uint8_t> MachOObjectFile::getUuid() const {
52820b57cec5SDimitry Andric   if (!UuidLoadCmd)
5283bdd1243dSDimitry Andric     return std::nullopt;
52840b57cec5SDimitry Andric   // Returning a pointer is fine as uuid doesn't need endian swapping.
52850b57cec5SDimitry Andric   const char *Ptr = UuidLoadCmd + offsetof(MachO::uuid_command, uuid);
5286bdd1243dSDimitry Andric   return ArrayRef(reinterpret_cast<const uint8_t *>(Ptr), 16);
52870b57cec5SDimitry Andric }
52880b57cec5SDimitry Andric 
getStringTableData() const52890b57cec5SDimitry Andric StringRef MachOObjectFile::getStringTableData() const {
52900b57cec5SDimitry Andric   MachO::symtab_command S = getSymtabLoadCommand();
52910b57cec5SDimitry Andric   return getData().substr(S.stroff, S.strsize);
52920b57cec5SDimitry Andric }
52930b57cec5SDimitry Andric 
is64Bit() const52940b57cec5SDimitry Andric bool MachOObjectFile::is64Bit() const {
52950b57cec5SDimitry Andric   return getType() == getMachOType(false, true) ||
52960b57cec5SDimitry Andric     getType() == getMachOType(true, true);
52970b57cec5SDimitry Andric }
52980b57cec5SDimitry Andric 
ReadULEB128s(uint64_t Index,SmallVectorImpl<uint64_t> & Out) const52990b57cec5SDimitry Andric void MachOObjectFile::ReadULEB128s(uint64_t Index,
53000b57cec5SDimitry Andric                                    SmallVectorImpl<uint64_t> &Out) const {
53010b57cec5SDimitry Andric   DataExtractor extractor(ObjectFile::getData(), true, 0);
53020b57cec5SDimitry Andric 
53038bcb0991SDimitry Andric   uint64_t offset = Index;
53040b57cec5SDimitry Andric   uint64_t data = 0;
53050b57cec5SDimitry Andric   while (uint64_t delta = extractor.getULEB128(&offset)) {
53060b57cec5SDimitry Andric     data += delta;
53070b57cec5SDimitry Andric     Out.push_back(data);
53080b57cec5SDimitry Andric   }
53090b57cec5SDimitry Andric }
53100b57cec5SDimitry Andric 
isRelocatableObject() const53110b57cec5SDimitry Andric bool MachOObjectFile::isRelocatableObject() const {
53120b57cec5SDimitry Andric   return getHeader().filetype == MachO::MH_OBJECT;
53130b57cec5SDimitry Andric }
53140b57cec5SDimitry Andric 
5315*c9157d92SDimitry Andric /// Create a MachOObjectFile instance from a given buffer.
5316*c9157d92SDimitry Andric ///
5317*c9157d92SDimitry Andric /// \param Buffer Memory buffer containing the MachO binary data.
5318*c9157d92SDimitry Andric /// \param UniversalCputype CPU type when the MachO part of a universal binary.
5319*c9157d92SDimitry Andric /// \param UniversalIndex Index of the MachO within a universal binary.
5320*c9157d92SDimitry Andric /// \param MachOFilesetEntryOffset Offset of the MachO entry in a fileset MachO.
5321*c9157d92SDimitry Andric /// \returns A std::unique_ptr to a MachOObjectFile instance on success.
createMachOObjectFile(MemoryBufferRef Buffer,uint32_t UniversalCputype,uint32_t UniversalIndex,size_t MachOFilesetEntryOffset)5322*c9157d92SDimitry Andric Expected<std::unique_ptr<MachOObjectFile>> ObjectFile::createMachOObjectFile(
5323*c9157d92SDimitry Andric     MemoryBufferRef Buffer, uint32_t UniversalCputype, uint32_t UniversalIndex,
5324*c9157d92SDimitry Andric     size_t MachOFilesetEntryOffset) {
53250b57cec5SDimitry Andric   StringRef Magic = Buffer.getBuffer().slice(0, 4);
53260b57cec5SDimitry Andric   if (Magic == "\xFE\xED\xFA\xCE")
5327*c9157d92SDimitry Andric     return MachOObjectFile::create(Buffer, false, false, UniversalCputype,
5328*c9157d92SDimitry Andric                                    UniversalIndex, MachOFilesetEntryOffset);
53290b57cec5SDimitry Andric   if (Magic == "\xCE\xFA\xED\xFE")
5330*c9157d92SDimitry Andric     return MachOObjectFile::create(Buffer, true, false, UniversalCputype,
5331*c9157d92SDimitry Andric                                    UniversalIndex, MachOFilesetEntryOffset);
53320b57cec5SDimitry Andric   if (Magic == "\xFE\xED\xFA\xCF")
5333*c9157d92SDimitry Andric     return MachOObjectFile::create(Buffer, false, true, UniversalCputype,
5334*c9157d92SDimitry Andric                                    UniversalIndex, MachOFilesetEntryOffset);
53350b57cec5SDimitry Andric   if (Magic == "\xCF\xFA\xED\xFE")
5336*c9157d92SDimitry Andric     return MachOObjectFile::create(Buffer, true, true, UniversalCputype,
5337*c9157d92SDimitry Andric                                    UniversalIndex, MachOFilesetEntryOffset);
53380b57cec5SDimitry Andric   return make_error<GenericBinaryError>("Unrecognized MachO magic number",
53390b57cec5SDimitry Andric                                         object_error::invalid_file_type);
53400b57cec5SDimitry Andric }
53410b57cec5SDimitry Andric 
mapDebugSectionName(StringRef Name) const53420b57cec5SDimitry Andric StringRef MachOObjectFile::mapDebugSectionName(StringRef Name) const {
53430b57cec5SDimitry Andric   return StringSwitch<StringRef>(Name)
53440b57cec5SDimitry Andric       .Case("debug_str_offs", "debug_str_offsets")
53450b57cec5SDimitry Andric       .Default(Name);
53460b57cec5SDimitry Andric }
53470eae32dcSDimitry Andric 
53480eae32dcSDimitry Andric Expected<std::vector<std::string>>
findDsymObjectMembers(StringRef Path)53490eae32dcSDimitry Andric MachOObjectFile::findDsymObjectMembers(StringRef Path) {
53500eae32dcSDimitry Andric   SmallString<256> BundlePath(Path);
53510eae32dcSDimitry Andric   // Normalize input path. This is necessary to accept `bundle.dSYM/`.
53520eae32dcSDimitry Andric   sys::path::remove_dots(BundlePath);
53530eae32dcSDimitry Andric   if (!sys::fs::is_directory(BundlePath) ||
53540eae32dcSDimitry Andric       sys::path::extension(BundlePath) != ".dSYM")
53550eae32dcSDimitry Andric     return std::vector<std::string>();
53560eae32dcSDimitry Andric   sys::path::append(BundlePath, "Contents", "Resources", "DWARF");
53570eae32dcSDimitry Andric   bool IsDir;
53580eae32dcSDimitry Andric   auto EC = sys::fs::is_directory(BundlePath, IsDir);
53590eae32dcSDimitry Andric   if (EC == errc::no_such_file_or_directory || (!EC && !IsDir))
53600eae32dcSDimitry Andric     return createStringError(
53610eae32dcSDimitry Andric         EC, "%s: expected directory 'Contents/Resources/DWARF' in dSYM bundle",
53620eae32dcSDimitry Andric         Path.str().c_str());
53630eae32dcSDimitry Andric   if (EC)
53640eae32dcSDimitry Andric     return createFileError(BundlePath, errorCodeToError(EC));
53650eae32dcSDimitry Andric 
53660eae32dcSDimitry Andric   std::vector<std::string> ObjectPaths;
53670eae32dcSDimitry Andric   for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd;
53680eae32dcSDimitry Andric        Dir != DirEnd && !EC; Dir.increment(EC)) {
53690eae32dcSDimitry Andric     StringRef ObjectPath = Dir->path();
53700eae32dcSDimitry Andric     sys::fs::file_status Status;
53710eae32dcSDimitry Andric     if (auto EC = sys::fs::status(ObjectPath, Status))
53720eae32dcSDimitry Andric       return createFileError(ObjectPath, errorCodeToError(EC));
53730eae32dcSDimitry Andric     switch (Status.type()) {
53740eae32dcSDimitry Andric     case sys::fs::file_type::regular_file:
53750eae32dcSDimitry Andric     case sys::fs::file_type::symlink_file:
53760eae32dcSDimitry Andric     case sys::fs::file_type::type_unknown:
53770eae32dcSDimitry Andric       ObjectPaths.push_back(ObjectPath.str());
53780eae32dcSDimitry Andric       break;
53790eae32dcSDimitry Andric     default: /*ignore*/;
53800eae32dcSDimitry Andric     }
53810eae32dcSDimitry Andric   }
53820eae32dcSDimitry Andric   if (EC)
53830eae32dcSDimitry Andric     return createFileError(BundlePath, errorCodeToError(EC));
53840eae32dcSDimitry Andric   if (ObjectPaths.empty())
53850eae32dcSDimitry Andric     return createStringError(std::error_code(),
53860eae32dcSDimitry Andric                              "%s: no objects found in dSYM bundle",
53870eae32dcSDimitry Andric                              Path.str().c_str());
53880eae32dcSDimitry Andric   return ObjectPaths;
53890eae32dcSDimitry Andric }
53901fd87a68SDimitry Andric 
53911fd87a68SDimitry Andric llvm::binaryformat::Swift5ReflectionSectionKind
mapReflectionSectionNameToEnumValue(StringRef SectionName) const53921fd87a68SDimitry Andric MachOObjectFile::mapReflectionSectionNameToEnumValue(
53931fd87a68SDimitry Andric     StringRef SectionName) const {
53941fd87a68SDimitry Andric #define HANDLE_SWIFT_SECTION(KIND, MACHO, ELF, COFF)                           \
53951fd87a68SDimitry Andric   .Case(MACHO, llvm::binaryformat::Swift5ReflectionSectionKind::KIND)
53961fd87a68SDimitry Andric   return StringSwitch<llvm::binaryformat::Swift5ReflectionSectionKind>(
53971fd87a68SDimitry Andric              SectionName)
53981fd87a68SDimitry Andric #include "llvm/BinaryFormat/Swift.def"
53991fd87a68SDimitry Andric       .Default(llvm::binaryformat::Swift5ReflectionSectionKind::unknown);
54001fd87a68SDimitry Andric #undef HANDLE_SWIFT_SECTION
54011fd87a68SDimitry Andric }
540281ad6265SDimitry Andric 
isMachOPairedReloc(uint64_t RelocType,uint64_t Arch)540381ad6265SDimitry Andric bool MachOObjectFile::isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) {
540481ad6265SDimitry Andric   switch (Arch) {
540581ad6265SDimitry Andric   case Triple::x86:
540681ad6265SDimitry Andric     return RelocType == MachO::GENERIC_RELOC_SECTDIFF ||
540781ad6265SDimitry Andric            RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF;
540881ad6265SDimitry Andric   case Triple::x86_64:
540981ad6265SDimitry Andric     return RelocType == MachO::X86_64_RELOC_SUBTRACTOR;
541081ad6265SDimitry Andric   case Triple::arm:
541181ad6265SDimitry Andric   case Triple::thumb:
541281ad6265SDimitry Andric     return RelocType == MachO::ARM_RELOC_SECTDIFF ||
541381ad6265SDimitry Andric            RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
541481ad6265SDimitry Andric            RelocType == MachO::ARM_RELOC_HALF ||
541581ad6265SDimitry Andric            RelocType == MachO::ARM_RELOC_HALF_SECTDIFF;
541681ad6265SDimitry Andric   case Triple::aarch64:
541781ad6265SDimitry Andric     return RelocType == MachO::ARM64_RELOC_SUBTRACTOR;
541881ad6265SDimitry Andric   default:
541981ad6265SDimitry Andric     return false;
542081ad6265SDimitry Andric   }
542181ad6265SDimitry Andric }
5422