Loading...
common/MachOFile.h dyld-1340 dyld-960
--- dyld/dyld-1340/common/MachOFile.h
+++ dyld/dyld-960/common/MachOFile.h
@@ -29,17 +29,7 @@
 #include <mach-o/fat.h>
 #include <uuid/uuid.h>
 
-#include <array>
-#include <optional>
-#include <string_view>
-
-#include "Defines.h"
-#include "GradedArchitectures.h"
-#include "Header.h"
-#include "UUID.h"
 #include "Diagnostics.h"
-#include "MachOLayout.h"
-#include "Platform.h"
 #include "SupportedArchs.h"
 #include <mach-o/fixup-chains.h>
 #include <mach-o/loader.h>
@@ -88,31 +78,84 @@
     #define MH_FILESET              0xc     /* set of mach-o's */
 #endif
 
-namespace objc_visitor {
-struct Visitor;
-}
-
 namespace dyld3 {
-
-using lsl::UUID;
 
 // 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;
-int fstatat(int fd, const char *path, struct stat *buf, int flag) VIS_HIDDEN;
 
 
 /// Returns true if (addLHS + addRHS) > b, or if the add overflowed
 template<typename T>
-VIS_HIDDEN inline bool greaterThanAddOrOverflow(uint32_t addLHS, uint32_t addRHS, T b) {
+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<typename T>
-VIS_HIDDEN inline bool greaterThanAddOrOverflow(uint64_t addLHS, uint64_t addRHS, T b) {
+inline bool greaterThanAddOrOverflow(uint64_t addLHS, uint64_t addRHS, T b) {
     return (addLHS > b) || (addRHS > (b-addLHS));
 }
+
+
+// Note, this should match PLATFORM_* values in <mach-o/loader.h>
+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;
+    bool                    checksOSBinary() const;
+
+    // pre-built lists for existing hardware
+#ifdef i386
+#undef i386
+#endif
+    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
@@ -120,7 +163,8 @@
 {
     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;
-    const char*            archNames(char strBuf[256], uint64_t fileLen) const;
+    bool                   isFatFileWithSlice(Diagnostics& diag, uint64_t fileLen, const GradedArchs& archs, bool osBinary, uint64_t& sliceOffset, uint64_t& sliceLen, bool& missingSlice) const;
+    const char*            archNames(char strBuf[256]) 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;
@@ -133,12 +177,19 @@
 // Only info from mach_header or load commands is accessible (no LINKEDIT info)
 struct VIS_HIDDEN MachOFile : mach_header
 {
-    typedef mach_o::ChainedFixupPointerOnDisk ChainedFixupPointerOnDisk;
-
+    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 Platform         basePlatform(dyld3::Platform reqPlatform);
     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 const MachOFile* compatibleSlice(Diagnostics& diag, uint64_t& sliceOffsetOut, uint64_t& sliceLenOut, const void* content, size_t size, const char* path, mach_o::Platform platform, bool isOSBinary, const mach_o::GradedArchitectures&, bool internalInstall=false);
-    static const MachOFile* isMachO(const void* content);
+    static bool             isSimulatorPlatform(Platform platform, Platform* basePlatform=nullptr);
+    static bool             isSharedCacheEligiblePath(const char* path);
+    static const MachOFile* compatibleSlice(Diagnostics& diag, const void* content, size_t size, const char* path, Platform, bool isOSBinary, const GradedArchs&);
 
     bool            hasMachOMagic() const;
     bool            isMachO(Diagnostics& diag, uint64_t fileSize) const;
@@ -151,7 +202,6 @@
     bool            isKextBundle() const;
     bool            isFileSet() const;
     bool            isPreload() const;
-    bool            isDyld() const;
     bool            isPIE() const;
     bool            isArch(const char* archName) const;
     const char*     archName() const;
@@ -160,117 +210,100 @@
     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            usesWeakDefs() 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;
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS || BUILDING_UNIT_TESTS || BUILDING_DYLD_SYMBOLS_CACHE
-    bool            addendsExceedPatchTableLimit(Diagnostics& diag, mach_o::Fixups fixups) const;
-    bool            canBePlacedInDyldCache(const char* path, bool checkObjC, void (^failureReason)(const char* format, ...)) const;
-    bool            canHavePrebuiltExecutableLoader(mach_o::Platform platform, const std::string_view& path,
-                                                    void (^failureReason)(const char*)) const;
-#endif
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-    // Note this is only for binaries in file layout, so can only be used by the cache builder
-    objc_visitor::Visitor makeObjCVisitor(Diagnostics& diag) const;
-#endif
-
+    void            forEachInterposingSection(Diagnostics& diag, void (^handler)(uint64_t vmOffset, uint64_t vmSize, 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
-#if BUILDING_APP_CACHE_UTIL || BUILDING_DYLDINFO
-    bool            usesClassicRelocationsInKernelCollection() 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;
     bool            hasOpcodeFixups() const;
-    void            removeLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& remove, bool& stop));
-    bool            hasSection(const char* segName, const char* sectName) const;
-    bool            inCodeSection(uint32_t runtimeOffset) const;
-    uint32_t        dependentDylibCount(bool* allDepsAreNormal = nullptr) const;
-    uint32_t        getFixupsLoadCommandFileOffset() const;
-    bool            hasInitializer(Diagnostics& diag) const;
-    void            forEachInitializerPointerSection(Diagnostics& diag, void (^callback)(uint32_t sectionOffset, uint32_t sectionSize, bool& stop)) const;
-    bool            hasObjC() const;
-    bool            hasConstObjCSection() const;
-    uint64_t        mappedSize() const;
-    void            forEachDOFSection(Diagnostics& diag, void (^callback)(uint32_t offset)) const;
-    enum class Malformed { linkeditOrder, linkeditAlignment, linkeditPermissions, dyldInfoAndlocalRelocs, segmentOrder,
-                            textPermissions, executableData, writableData, codeSigAlignment, sectionsAddrRangeWithinSegment,
-                            noLinkedDylibs, loaderPathsAreReal, mainExecInDyldCache, noUUID, zerofillSwiftMetadata, sdkOnOrAfter2021, sdkOnOrAfter2022 };
-    bool            enforceFormat(Malformed) const;
-
-    bool            validSegments(Diagnostics& diag, const char* path, size_t fileLen) const;
-
-    // used at runtime to validate loaded image matches closure
-    void            forEachCDHashOfCodeSignature(const void* codeSigStart, size_t codeSignLen,
-                                                 void (^callback)(const uint8_t cdHash[20])) const;
-
-    static void     forEachTreatAsWeakDef(void (^handler)(const char* symbolName));
-
-    // used by closure builder to find the offset and size of the trie.
-    bool            hasExportTrie(uint32_t& runtimeOffset, uint32_t& size) const;
-
-    uint32_t                        entryAddrRegisterIndexForThreadCmd() const;
-    bool                            use64BitEntryRegs() const;
-    uint64_t                        entryAddrFromThreadCmd(const thread_command* cmd) const;
-
-    // used by DyldSharedCache to find closure
-    static const uint8_t*   trieWalk(Diagnostics& diag, const uint8_t* start, const uint8_t* end, const char* symbol);
-
-#if !SUPPORT_VM_LAYOUT || BUILDING_UNIT_TESTS || BUILDING_DYLD_SYMBOLS_CACHE
-    // Get the layout information for this MachOFile.  Requires that the file is in file layout, not VM layout.
-    // If you have a MachOLoaded/MachOAnalyzer, do not use this method
-    bool                    getLinkeditLayout(Diagnostics& diag, mach_o::LinkeditLayout& layout) const;
-    void                    withFileLayout(Diagnostics &diag, void (^callback)(const mach_o::Layout& layout)) const;
-#endif
-
+    void            forDyldEnv(void (^callback)(const char* envVar, bool& stop)) const;
+    bool            enforceCompatVersion() const;
+    bool            hasInterposingTuples() const;
+    bool            isRestricted() const;
+
+    const thread_command*   unixThreadLoadCommand() const;
+    uint32_t                entryAddrRegisterIndexForThreadCmd() const;
+    uint64_t                entryAddrFromThreadCmd(const thread_command* cmd) const;
+    uint64_t                preferredLoadAddress() 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
+                    hasZeroFill   :  1,  // fileSize < vmSize
+                    segIndex      : 12,
+                    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;
     void            forEachLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& stop)) const;
-
-    struct PointerMetaData
-    {
-                    PointerMetaData();
-                    PointerMetaData(const ChainedFixupPointerOnDisk* fixupLoc, uint16_t pointer_format);
-
-        bool        operator==(const PointerMetaData& other) const;
-
-        uint32_t    diversity         : 16,
-                    high8             :  8,
-                    authenticated     :  1,
-                    key               :  2,
-                    usesAddrDiversity :  1,
-                    padding           :  4 = 0;
-    };
-
-    static uint16_t chainedPointerFormat(const dyld_chained_fixups_header* chainHeader);
-    static void     withChainStarts(Diagnostics& diag, const dyld_chained_fixups_header* chainHeader, void (^callback)(const dyld_chained_starts_in_image*));
-
-    static void     forEachFixupChainSegment(Diagnostics& diag, const dyld_chained_starts_in_image* starts,
-                                             void (^handler)(const dyld_chained_starts_in_segment* segInfo, uint32_t segIndex, bool& stop));
-    static void     forEachFixupInSegmentChains(Diagnostics& diag, const dyld_chained_starts_in_segment* segInfo,
-                                                bool notifyNonPointers, uint8_t* segmentContent,
-                                                void (^handler)(ChainedFixupPointerOnDisk* fixupLocation, bool& stop));
-    static bool     walkChain(Diagnostics& diag, ChainedFixupPointerOnDisk* start, uint16_t pointer_format,
-                              bool notifyNonPointers, uint32_t max_valid_pointer,
-                              void (^handler)(ChainedFixupPointerOnDisk* fixupLocation, bool& stop));
-    static void     forEachChainedFixupTarget(Diagnostics& diag, const dyld_chained_fixups_header* chainHeader, const linkedit_data_command* chainedFixups,
-                                              void (^callback)(int libOrdinal, const char* symbolName, uint64_t addend, bool weakImport, bool& stop));
 
 protected:
     bool            hasMachOBigEndianMagic() const;
+    void            removeLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& remove, bool& stop));
     bool            hasLoadCommand(uint32_t) const;
 
-    void    analyzeSegmentsLayout(uint64_t& vmSpace, bool& hasZeroFill) const;
-
-    // This calls the callback for all code directories required for a given platform/binary combination.
-    // On watchOS main executables this is all cd hashes.
-    // On watchOS dylibs this is only the single cd hash we need (by rank defined by dyld, not the kernel).
-    // On all other platforms this always returns a single best cd hash (ranked to match the kernel).
-    // Note the callback parameter is really a CS_CodeDirectory.
-    void    forEachCodeDirectoryBlob(const void* codeSigStart, size_t codeSignLen, void (^callback)(const void* cd)) const;
-    void    forEachSection(void (^callback)(const mach_o::Header::SectionInfo&, bool& stop)) const;
-    void    forEachSection(void (^callback)(const mach_o::Header::SegmentInfo&, const mach_o::Header::SectionInfo&, bool& stop)) 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[];
 };