Loading...
--- 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[];
};