Loading...
--- dyld/dyld-1340/common/MachOFile.h
+++ dyld/dyld-1162/common/MachOFile.h
@@ -34,12 +34,9 @@
#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>
@@ -87,10 +84,6 @@
#ifndef MH_FILESET
#define MH_FILESET 0xc /* set of mach-o's */
#endif
-
-namespace objc_visitor {
-struct Visitor;
-}
namespace dyld3 {
@@ -104,15 +97,91 @@
/// 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
+};
+
+// A prioritized list of architectures
+class VIS_HIDDEN GradedArchs {
+public:
+ struct CpuGrade { uint32_t type = 0; uint32_t subtype = 0; bool osBinary = false; uint16_t grade = 0; };
+ // never construct new ones - just use existing static instances
+ GradedArchs() = delete;
+ GradedArchs(const GradedArchs&) = delete;
+ constexpr GradedArchs(const CpuGrade& cg0, const CpuGrade& cg1 = {0,0,false,0} , const CpuGrade& cg2 = {0,0,false,0}) : _orderedCpuTypes({cg0, cg1, cg2, CpuGrade()}) {}
+
+#if BUILDING_LIBDYLD || BUILDING_UNIT_TESTS
+ static const GradedArchs& launchCurrentOS(const char* simArches); // for emulating how the kernel chooses which slice to exec()
+#endif
+ 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;
+ bool supports64() const;
+ void forEachArch(bool platformBinariesOnly, void (^handler)(const char* name)) 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
+ static const GradedArchs armv6m; // firmware
+ static const GradedArchs armv7m; // firmware
+ static const GradedArchs armv7em; // firmware
+ static const GradedArchs armv8m; // firmware
+
+#if SUPPORT_ARCH_arm64_32
+ static const GradedArchs arm64_32; // watch series 4 and later
+#endif
+#if BUILDING_LIBDYLD || BUILDING_UNIT_TESTS
+ static const GradedArchs launch_AS; // Apple Silicon macs
+ static const GradedArchs launch_AS_Sim; // iOS simulator for Apple Silicon macs
+ static const GradedArchs launch_Intel_h; // Intel macs with haswell cpu
+ static const GradedArchs launch_Intel; // Intel macs
+ static const GradedArchs launch_Intel_Sim; // iOS simulator for Intel macs
+#endif
+
+// private:
+// should be private, but compiler won't statically initialize static members above
+ const std::array<CpuGrade, 4> _orderedCpuTypes; // zero terminated
+};
// A file read/mapped into memory
@@ -120,6 +189,7 @@
{
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;
const char* archNames(char strBuf[256], uint64_t fileLen) const;
private:
bool isValidSlice(Diagnostics& diag, uint64_t fileLen, uint32_t sliceIndex,
@@ -135,9 +205,19 @@
{
typedef mach_o::ChainedFixupPointerOnDisk ChainedFixupPointerOnDisk;
+ static const char* archName(uint32_t cputype, uint32_t cpusubtype);
+ static const char* platformName(Platform platform);
+ static bool cpuTypeFromArchName(const char* archName, cpu_type_t* cputype, cpu_subtype_t* cpusubtype);
+ 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 bool isExclaveKitPlatform(Platform platform, Platform* basePlatform=nullptr);
+ 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 internalInstall=false);
static const MachOFile* isMachO(const void* content);
bool hasMachOMagic() const;
@@ -160,42 +240,68 @@
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, bool internalInstall=false) const;
+ bool isZippered() const;
bool inDyldCache() const;
+ bool getUuid(uuid_t uuid) const;
+ UUID uuid() const;
bool hasWeakDefs() const;
bool usesWeakDefs() const;
+ bool isBuiltForSimulator() 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;
+ void forEachSupportedBuildTool(void (^callback)(Platform platform, uint32_t tool, uint32_t version)) 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 forEachInterposingSection(Diagnostics& diag, void (^handler)(uint64_t vmOffset, uint64_t vmSize, bool& stop)) const;
+#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
+ bool canBePlacedInDyldCache(const char* path, void (^failureReason)(const char* format, ...)) const;
+ bool canHavePrebuiltExecutableLoader(dyld3::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
-
#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 forDyldEnv(void (^callback)(const char* envVar, bool& stop)) const;
+ bool enforceCompatVersion() const;
+ bool hasInterposingTuples() const;
+ bool isRestricted() const;
void removeLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& remove, bool& stop));
bool hasSection(const char* segName, const char* sectName) const;
+ void forEachRPath(void (^callback)(const char* rPath, bool& stop)) const;
bool inCodeSection(uint32_t runtimeOffset) const;
uint32_t dependentDylibCount(bool* allDepsAreNormal = nullptr) const;
+ bool hasPlusLoadMethod(Diagnostics& diag) 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 hasCodeSignature() const;
+ bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const;
bool hasObjC() const;
bool hasConstObjCSection() const;
uint64_t mappedSize() const;
+ uint32_t segmentCount() const;
void forEachDOFSection(Diagnostics& diag, void (^callback)(uint32_t offset)) const;
+ bool hasObjCMessageReferences() const;
+ uint32_t loadCommandsFreeSpace() const;
+
+ // Looks for the given section in the segments in order: __DATA, __DATA_CONST, __DATA_DIRTY.
+ // Returns true if it finds a section, and sets the out parameters to the first section it found.
+ // Returns false if the given section doesn't exist in any of the given segments.
+ bool findObjCDataSection(const char* sectionName, uint64_t& sectionRuntimeOffset, uint64_t& sectionSize) const;
+
enum class Malformed { linkeditOrder, linkeditAlignment, linkeditPermissions, dyldInfoAndlocalRelocs, segmentOrder,
textPermissions, executableData, writableData, codeSigAlignment, sectionsAddrRangeWithinSegment,
noLinkedDylibs, loaderPathsAreReal, mainExecInDyldCache, noUUID, zerofillSwiftMetadata, sdkOnOrAfter2021, sdkOnOrAfter2022 };
@@ -212,20 +318,72 @@
// used by closure builder to find the offset and size of the trie.
bool hasExportTrie(uint32_t& runtimeOffset, uint32_t& size) const;
+ const thread_command* unixThreadLoadCommand() const;
+ const linkedit_data_command* chainedFixupsCmd() const;
uint32_t entryAddrRegisterIndexForThreadCmd() const;
bool use64BitEntryRegs() const;
uint64_t entryAddrFromThreadCmd(const thread_command* cmd) const;
+ uint64_t preferredLoadAddress() const;
+ bool getEntry(uint64_t& offset, bool& usesCRT) 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
+#if !SUPPORT_VM_LAYOUT
// 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
+ // Note all kinds have the low bit set, and all offsets to values don't
+ enum class SingletonPatchKind : uint32_t
+ {
+ unknown = 0,
+
+ // An ISA, followed by a uintptr_t of constant data
+ cfObj2 = 1
+ };
+
+ void forEachSingletonPatch(Diagnostics& diag, void (^handler)(SingletonPatchKind kind,
+ uint64_t runtimeOffset)) 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
@@ -239,8 +397,7 @@
high8 : 8,
authenticated : 1,
key : 2,
- usesAddrDiversity : 1,
- padding : 4 = 0;
+ usesAddrDiversity : 1;
};
static uint16_t chainedPointerFormat(const dyld_chained_fixups_header* chainHeader);
@@ -261,6 +418,24 @@
bool hasMachOBigEndianMagic() const;
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[];
+
void analyzeSegmentsLayout(uint64_t& vmSpace, bool& hasZeroFill) const;
// This calls the callback for all code directories required for a given platform/binary combination.
@@ -269,8 +444,6 @@
// 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;
};