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