/* * Copyright (c) 2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef MachOFile_h #define MachOFile_h #include #include #include #include "Diagnostics.h" #include "SupportedArchs.h" #include #include // needed until dyld builds with a newer SDK #ifndef CPU_SUBTYPE_ARM64E #define CPU_SUBTYPE_ARM64E 2 #endif #ifndef CPU_TYPE_ARM64_32 #define CPU_TYPE_ARM64_32 0x0200000C #endif #ifndef CPU_SUBTYPE_ARM64_32_V8 #define CPU_SUBTYPE_ARM64_32_V8 1 #endif #ifndef BIND_OPCODE_THREADED #define BIND_OPCODE_THREADED 0xD0 #endif #ifndef BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB #define BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB 0x00 #endif #ifndef BIND_SUBOPCODE_THREADED_APPLY #define BIND_SUBOPCODE_THREADED_APPLY 0x01 #endif #ifndef BIND_SPECIAL_DYLIB_WEAK_LOOKUP #define BIND_SPECIAL_DYLIB_WEAK_LOOKUP (-3) #endif #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02 #endif #ifndef SG_READ_ONLY #define SG_READ_ONLY 0x10 #endif #ifndef LC_DYLD_EXPORTS_TRIE #define LC_DYLD_EXPORTS_TRIE 0x80000033 #endif #ifndef LC_DYLD_CHAINED_FIXUPS #define LC_DYLD_CHAINED_FIXUPS 0x80000034 #endif #ifndef S_INIT_FUNC_OFFSETS #define S_INIT_FUNC_OFFSETS 0x16 #endif #ifndef MH_FILESET #define MH_FILESET 0xc /* set of mach-o's */ #endif namespace dyld3 { // replacements for posix that handle EINTR int stat(const char* path, struct stat* buf) VIS_HIDDEN; int open(const char* path, int flag, int other) VIS_HIDDEN; /// Returns true if (addLHS + addRHS) > b, or if the add overflowed template inline bool greaterThanAddOrOverflow(uint32_t addLHS, uint32_t addRHS, T b) { return (addLHS > b) || (addRHS > (b-addLHS)); } /// Returns true if (addLHS + addRHS) > b, or if the add overflowed template inline bool greaterThanAddOrOverflow(uint64_t addLHS, uint64_t addRHS, T b) { return (addLHS > b) || (addRHS > (b-addLHS)); } // Note, this should match PLATFORM_* values in enum class Platform { unknown = 0, macOS = 1, // PLATFORM_MACOS iOS = 2, // PLATFORM_IOS tvOS = 3, // PLATFORM_TVOS watchOS = 4, // PLATFORM_WATCHOS bridgeOS = 5, // PLATFORM_BRIDGEOS iOSMac = 6, // PLATFORM_MACCATALYST iOS_simulator = 7, // PLATFORM_IOSSIMULATOR tvOS_simulator = 8, // PLATFORM_TVOSSIMULATOR watchOS_simulator = 9, // PLATFORM_WATCHOSSIMULATOR driverKit = 10, // PLATFORM_DRIVERKIT }; struct MachOFile; // forward ref // A prioritized list of architectures class VIS_HIDDEN GradedArchs { public: // never construct new ones - just use existing static instances GradedArchs() = delete; GradedArchs(const GradedArchs&) = delete; static const GradedArchs& forCurrentOS(bool keysOff, bool platformBinariesOnly); static const GradedArchs& forName(const char* archName, bool keysOff = false); int grade(uint32_t cputype, uint32_t cpusubtype, bool platformBinariesOnly) const; const char* name() const; // pre-built lists for existing hardware static const GradedArchs i386; // 32-bit Mac static const GradedArchs x86_64; // older Mac static const GradedArchs x86_64h; // haswell Mac static const GradedArchs arm64; // A11 or earlier iPhone or iPad #if SUPPORT_ARCH_arm64e static const GradedArchs arm64e; // A12 or later iPhone or iPad static const GradedArchs arm64e_keysoff; // A12 running with signing keys disabled static const GradedArchs arm64e_pb; // macOS Apple Silicon running platform binary static const GradedArchs arm64e_keysoff_pb; // macOS Apple Silicon running with signing keys disabled #endif static const GradedArchs armv7k; // watch thru series 3 static const GradedArchs armv7s; // deprecated static const GradedArchs armv7; // deprecated #if SUPPORT_ARCH_arm64_32 static const GradedArchs arm64_32; // watch series 4 and later #endif // private: // should be private, but compiler won't statically initialize static members above struct CpuGrade { uint32_t type; uint32_t subtype; bool osBinary; uint16_t grade; }; const CpuGrade _orderedCpuTypes[3]; // zero terminated }; // A file read/mapped into memory struct VIS_HIDDEN FatFile : fat_header { static const FatFile* isFatFile(const void* fileContent); void forEachSlice(Diagnostics& diag, uint64_t fileLen, void (^callback)(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, uint64_t sliceSize, bool& stop)) const; bool isFatFileWithSlice(Diagnostics& diag, uint64_t fileLen, const GradedArchs& archs, bool osBinary, uint64_t& sliceOffset, uint64_t& sliceLen, bool& missingSlice) const; private: bool isValidSlice(Diagnostics& diag, uint64_t fileLen, uint32_t sliceIndex, uint32_t sliceCpuType, uint32_t sliceCpuSubType, uint64_t sliceOffset, uint64_t sliceLen) const; }; // A mach-o file read/mapped into memory // Only info from mach_header or load commands is accessible (no LINKEDIT info) struct VIS_HIDDEN MachOFile : mach_header { static const char* archName(uint32_t cputype, uint32_t cpusubtype); static const char* platformName(Platform platform); static uint32_t cpuTypeFromArchName(const char* archName); static uint32_t cpuSubtypeFromArchName(const char* archName); static void packedVersionToString(uint32_t packedVersion, char versionString[32]); static const char* currentArchName(); static Platform currentPlatform(); static uint64_t read_uleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end); static int64_t read_sleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end); static bool isSimulatorPlatform(Platform platform); static bool isSharedCacheEligiblePath(const char* path); bool hasMachOMagic() const; bool isMachO(Diagnostics& diag, uint64_t fileSize) const; bool isDylib() const; bool isBundle() const; bool isMainExecutable() const; bool isDynamicExecutable() const; bool isStaticExecutable() const; bool isKextBundle() const; bool isFileSet() const; bool isPreload() const; bool isPIE() const; bool isArch(const char* archName) const; const char* archName() const; bool is64() const; uint32_t maskedCpuSubtype() const; size_t machHeaderSize() const; uint32_t pointerSize() const; bool uses16KPages() const; bool builtForPlatform(Platform, bool onlyOnePlatform=false) const; bool loadableIntoProcess(Platform processPlatform, const char* path) const; bool isZippered() const; bool inDyldCache() const; bool getUuid(uuid_t uuid) const; bool hasWeakDefs() const; bool hasThreadLocalVariables() const; bool getDylibInstallName(const char** installName, uint32_t* compatVersion, uint32_t* currentVersion) const; void forEachSupportedPlatform(void (^callback)(Platform platform, uint32_t minOS, uint32_t sdk)) const; const char* installName() const; // returns nullptr is no install name void forEachDependentDylib(void (^callback)(const char* loadPath, bool isWeak, bool isReExport, bool isUpward, uint32_t compatVersion, uint32_t curVersion, bool& stop)) const; bool canBePlacedInDyldCache(const char* path, void (^failureReason)(const char*)) const; #if BUILDING_APP_CACHE_UTIL bool canBePlacedInKernelCollection(const char* path, void (^failureReason)(const char*)) const; #endif bool canHavePrecomputedDlopenClosure(const char* path, void (^failureReason)(const char*)) const; bool canBeFairPlayEncrypted() const; bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const; bool allowsAlternatePlatform() const; bool hasChainedFixups() const; bool hasChainedFixupsLoadCommand() const; void forDyldEnv(void (^callback)(const char* envVar, bool& stop)) const; bool enforceCompatVersion() const; bool hasInterposingTuples() const; const thread_command* unixThreadLoadCommand() const; uint32_t entryAddrRegisterIndexForThreadCmd() const; uint64_t entryAddrFromThreadCmd(const thread_command* cmd) const; struct SegmentInfo { uint64_t fileOffset; uint64_t fileSize; uint64_t vmAddr; uint64_t vmSize; uint64_t sizeOfSections; const char* segName; uint32_t loadCommandOffset; uint32_t protections; uint32_t textRelocs : 1, // segment has text relocs (i386 only) readOnlyData : 1, isProtected : 1, // segment is protected segIndex : 13, p2align : 16; bool readable() const { return protections & VM_PROT_READ; } bool writable() const { return protections & VM_PROT_WRITE; } bool executable() const { return protections & VM_PROT_EXECUTE; } }; struct SectionInfo { SegmentInfo segInfo; uint64_t sectAddr; uint64_t sectSize; const char* sectName; uint32_t sectFileOffset; uint32_t sectFlags; uint32_t sectAlignP2; uint32_t reserved1; uint32_t reserved2; }; void forEachSegment(void (^callback)(const SegmentInfo& info, bool& stop)) const; void forEachSection(void (^callback)(const SectionInfo& sectInfo, bool malformedSectionRange, bool& stop)) const; protected: bool hasMachOBigEndianMagic() const; void forEachLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& stop)) const; void removeLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& remove, bool& stop)); bool hasLoadCommand(uint32_t) const; const encryption_info_command* findFairPlayEncryptionLoadCommand() const; struct ArchInfo { const char* name; uint32_t cputype; uint32_t cpusubtype; }; static const ArchInfo _s_archInfos[]; struct PlatformInfo { const char* name; Platform platform; uint32_t loadCommand; }; static const PlatformInfo _s_platformInfos[]; }; } // namespace dyld3 #endif /* MachOFile_h */