Loading...
--- dyld/dyld-750.5/dyld3/MachOFile.cpp
+++ dyld/dyld-625.13/dyld3/MachOFile.cpp
@@ -30,10 +30,27 @@
#include <mach/mach.h>
#include <mach/mach_host.h>
-#include "Array.h"
#include "MachOFile.h"
#include "SupportedArchs.h"
+#ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
+ #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
+#endif
+
+#ifndef CPU_SUBTYPE_ARM64_E
+ #define CPU_SUBTYPE_ARM64_E 2
+#endif
+
+#ifndef CPU_SUBTYPE_ARM64_32_V8
+ #define CPU_SUBTYPE_ARM64_32_V8 1
+#endif
+
+#ifndef CPU_TYPE_ARM64_32
+ #ifndef CPU_ARCH_ABI64_32
+ #define CPU_ARCH_ABI64_32 0x02000000
+ #endif
+ #define CPU_TYPE_ARM64_32 (CPU_TYPE_ARM | CPU_ARCH_ABI64_32)
+#endif
namespace dyld3 {
@@ -48,63 +65,27 @@
return nullptr;
}
-bool FatFile::isValidSlice(Diagnostics& diag, uint64_t fileLen, uint32_t sliceIndex,
- uint32_t sliceCpuType, uint32_t sliceCpuSubType, uint64_t sliceOffset, uint64_t sliceLen) const {
- if ( greaterThanAddOrOverflow(sliceOffset, sliceLen, fileLen) ) {
- diag.error("slice %d extends beyond end of file", sliceIndex);
- return false;
- }
- const dyld3::MachOFile* mf = (const dyld3::MachOFile*)((uint8_t*)this+sliceOffset);
- if (!mf->isMachO(diag, sliceLen))
- return false;
- if ( (mf->cputype != (cpu_type_t)sliceCpuType) || (mf->cpusubtype != (cpu_subtype_t)sliceCpuSubType) ) {
- diag.error("cpu type/subtype mismatch");
- return false;
- }
- uint32_t pageSizeMask = mf->uses16KPages() ? 0x3FFF : 0xFFF;
- if ( (sliceOffset & pageSizeMask) != 0 ) {
- // slice not page aligned
- if ( strncmp((char*)this+sliceOffset, "!<arch>", 7) == 0 )
- diag.error("file is static library");
- else
- diag.error("slice is not page aligned");
- return false;
- }
- return true;
-}
-
void FatFile::forEachSlice(Diagnostics& diag, uint64_t fileLen, void (^callback)(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, uint64_t sliceSize, bool& stop)) const
{
if ( this->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
- const uint64_t maxArchs = ((4096 - sizeof(fat_header)) / sizeof(fat_arch));
- const uint32_t numArchs = OSSwapBigToHostInt32(nfat_arch);
- if ( numArchs > maxArchs ) {
- diag.error("fat header too large: %u entries", numArchs);
+ if ( OSSwapBigToHostInt32(nfat_arch) > ((4096 - sizeof(fat_header)) / sizeof(fat_arch)) ) {
+ diag.error("fat header too large: %u entries", OSSwapBigToHostInt32(nfat_arch));
return;
}
bool stop = false;
const fat_arch* const archs = (fat_arch*)(((char*)this)+sizeof(fat_header));
- for (uint32_t i=0; i < numArchs; ++i) {
+ for (uint32_t i=0; i < OSSwapBigToHostInt32(nfat_arch); ++i) {
uint32_t cpuType = OSSwapBigToHostInt32(archs[i].cputype);
uint32_t cpuSubType = OSSwapBigToHostInt32(archs[i].cpusubtype);
uint32_t offset = OSSwapBigToHostInt32(archs[i].offset);
uint32_t len = OSSwapBigToHostInt32(archs[i].size);
- if (isValidSlice(diag, fileLen, i, cpuType, cpuSubType, offset, len))
- callback(cpuType, cpuSubType, (uint8_t*)this+offset, len, stop);
+ if ( greaterThanAddOrOverflow(offset, len, fileLen) ) {
+ diag.error("slice %d extends beyond end of file", i);
+ return;
+ }
+ callback(cpuType, cpuSubType, (uint8_t*)this+offset, len, stop);
if ( stop )
break;
- }
-
- // Look for one more slice
- if ( numArchs != maxArchs ) {
- uint32_t cpuType = OSSwapBigToHostInt32(archs[numArchs].cputype);
- uint32_t cpuSubType = OSSwapBigToHostInt32(archs[numArchs].cpusubtype);
- uint32_t offset = OSSwapBigToHostInt32(archs[numArchs].offset);
- uint32_t len = OSSwapBigToHostInt32(archs[numArchs].size);
- if ((cpuType == CPU_TYPE_ARM64) && ((cpuSubType == CPU_SUBTYPE_ARM64_ALL || cpuSubType == CPU_SUBTYPE_ARM64_V8))) {
- if (isValidSlice(diag, fileLen, numArchs, cpuType, cpuSubType, offset, len))
- callback(cpuType, cpuSubType, (uint8_t*)this+offset, len, stop);
- }
}
}
else if ( this->magic == OSSwapBigToHostInt32(FAT_MAGIC_64) ) {
@@ -119,8 +100,11 @@
uint32_t cpuSubType = OSSwapBigToHostInt32(archs[i].cpusubtype);
uint64_t offset = OSSwapBigToHostInt64(archs[i].offset);
uint64_t len = OSSwapBigToHostInt64(archs[i].size);
- if (isValidSlice(diag, fileLen, i, cpuType, cpuSubType, offset, len))
- callback(cpuType, cpuSubType, (uint8_t*)this+offset, len, stop);
+ if ( greaterThanAddOrOverflow(offset, len, fileLen) ) {
+ diag.error("slice %d extends beyond end of file", i);
+ return;
+ }
+ callback(cpuType, cpuSubType, (uint8_t*)this+offset, len, stop);
if ( stop )
break;
}
@@ -130,61 +114,215 @@
}
}
-bool FatFile::isFatFileWithSlice(Diagnostics& diag, uint64_t fileLen, const GradedArchs& archs, uint64_t& sliceOffset, uint64_t& sliceLen, bool& missingSlice) const
+bool FatFile::isFatFileWithSlice(Diagnostics& diag, uint64_t fileLen, const char* archName, uint64_t& sliceOffset, uint64_t& sliceLen, bool& missingSlice) const
{
missingSlice = false;
if ( (this->magic != OSSwapBigToHostInt32(FAT_MAGIC)) && (this->magic != OSSwapBigToHostInt32(FAT_MAGIC_64)) )
return false;
- __block int bestGrade = 0;
+ __block bool found = false;
forEachSlice(diag, fileLen, ^(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, uint64_t sliceSize, bool& stop) {
- if (int sliceGrade = archs.grade(sliceCpuType, sliceCpuSubType)) {
- if ( sliceGrade > bestGrade ) {
- sliceOffset = (char*)sliceStart - (char*)this;
- sliceLen = sliceSize;
- bestGrade = sliceGrade;
- }
+ const char* sliceArchName = MachOFile::archName(sliceCpuType, sliceCpuSubType);
+ if ( strcmp(sliceArchName, archName) == 0 ) {
+ sliceOffset = (char*)sliceStart - (char*)this;
+ sliceLen = sliceSize;
+ found = true;
+ stop = true;
}
});
if ( diag.hasError() )
return false;
- if ( bestGrade == 0 )
+ if ( !found )
missingSlice = true;
- return (bestGrade != 0);
-}
-
-
-//////////////////////////// GradedArchs ////////////////////////////////////////
-
-const GradedArchs GradedArchs::i386 = { {{CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL, 1}} };
-const GradedArchs GradedArchs::x86_64 = { {{CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, 1}} };
-const GradedArchs GradedArchs::x86_64h = { {{CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H, 2}, {CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, 1}}, };
-const GradedArchs GradedArchs::arm64 = { {{CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL, 1}} };
+ // when looking for x86_64h fallback to x86_64
+ if ( !found && (strcmp(archName, "x86_64h") == 0) )
+ return isFatFileWithSlice(diag, fileLen, "x86_64", sliceOffset, sliceLen, missingSlice);
+
+ return found;
+}
+
+
+//////////////////////////// MachOFile ////////////////////////////////////////
+
+
+const MachOFile::ArchInfo MachOFile::_s_archInfos[] = {
+ { "x86_64", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL },
+ { "x86_64h", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H },
+ { "i386", CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL },
+ { "arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL },
#if SUPPORT_ARCH_arm64e
-const GradedArchs GradedArchs::arm64e_compat = { {{CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E, 2}, {CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL, 1}} };
-const GradedArchs GradedArchs::arm64e = { {{CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E, 1}} };
-#endif
-const GradedArchs GradedArchs::armv7k = { {{CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K, 1}} };
-const GradedArchs GradedArchs::armv7 = { {{CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7, 1}} };
-const GradedArchs GradedArchs::armv7s = { {{CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S, 2}, {CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7, 1}} };
+ { "arm64e", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_E },
+#endif
#if SUPPORT_ARCH_arm64_32
-const GradedArchs GradedArchs::arm64_32 = { {{CPU_TYPE_ARM64_32, CPU_SUBTYPE_ARM64_32_V8, 1}} };
-#endif
-
-int GradedArchs::grade(uint32_t cputype, uint32_t cpusubtype) const
-{
- for (const CpuGrade* p = _orderedCpuTypes; p->type != 0; ++p) {
- if ( (p->type == cputype) && (p->subtype == (cpusubtype & ~CPU_SUBTYPE_MASK)) )
- return p->grade;
+ { "arm64_32", CPU_TYPE_ARM64_32, CPU_SUBTYPE_ARM64_32_V8 },
+#endif
+ { "armv7k", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K },
+ { "armv7s", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S },
+ { "armv7", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7 }
+};
+
+const MachOFile::PlatformInfo MachOFile::_s_platformInfos[] = {
+ { "macOS", Platform::macOS, LC_VERSION_MIN_MACOSX },
+ { "iOS", Platform::iOS, LC_VERSION_MIN_IPHONEOS },
+ { "tvOS", Platform::tvOS, LC_VERSION_MIN_TVOS },
+ { "watchOS", Platform::watchOS, LC_VERSION_MIN_WATCHOS },
+ { "bridgeOS", Platform::bridgeOS, LC_BUILD_VERSION },
+ { "iOSMac", Platform::iOSMac, LC_BUILD_VERSION },
+ { "iOS-sim", Platform::iOS_simulator, LC_BUILD_VERSION },
+ { "tvOS-sim", Platform::tvOS_simulator, LC_BUILD_VERSION },
+ { "watchOS-sim", Platform::watchOS_simulator, LC_BUILD_VERSION },
+};
+
+
+bool MachOFile::is64() const
+{
+ return (this->magic == MH_MAGIC_64);
+}
+
+uint32_t MachOFile::pointerSize() const
+{
+ if (this->magic == MH_MAGIC_64)
+ return 8;
+ else
+ return 4;
+}
+
+bool MachOFile::uses16KPages() const
+{
+ switch (this->cputype) {
+ case CPU_TYPE_ARM64:
+ case CPU_TYPE_ARM:
+ case CPU_TYPE_ARM64_32:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MachOFile::isArch(const char* aName) const
+{
+ return (strcmp(aName, archName(this->cputype, this->cpusubtype)) == 0);
+}
+
+const char* MachOFile::archName(uint32_t cputype, uint32_t cpusubtype)
+{
+ for (const ArchInfo& info : _s_archInfos) {
+ if ( (cputype == info.cputype) && ((cpusubtype & ~CPU_SUBTYPE_MASK) == info.cpusubtype) ) {
+ return info.name;
+ }
+ }
+ return "unknown";
+}
+
+uint32_t MachOFile::cpuTypeFromArchName(const char* archName)
+{
+ for (const ArchInfo& info : _s_archInfos) {
+ if ( strcmp(archName, info.name) == 0 ) {
+ return info.cputype;
+ }
}
return 0;
}
-const char* GradedArchs::name() const
-{
- return MachOFile::archName(_orderedCpuTypes[0].type, _orderedCpuTypes[0].subtype);
+uint32_t MachOFile::cpuSubtypeFromArchName(const char* archName)
+{
+ for (const ArchInfo& info : _s_archInfos) {
+ if ( strcmp(archName, info.name) == 0 ) {
+ return info.cpusubtype;
+ }
+ }
+ return 0;
+}
+
+const char* MachOFile::archName() const
+{
+ return archName(this->cputype, this->cpusubtype);
+}
+
+static void appendDigit(char*& s, unsigned& num, unsigned place, bool& startedPrinting)
+{
+ if ( num >= place ) {
+ unsigned dig = (num/place);
+ *s++ = '0' + dig;
+ num -= (dig*place);
+ startedPrinting = true;
+ }
+ else if ( startedPrinting ) {
+ *s++ = '0';
+ }
+}
+
+static void appendNumber(char*& s, unsigned num)
+{
+ assert(num < 99999);
+ bool startedPrinting = false;
+ appendDigit(s, num, 10000, startedPrinting);
+ appendDigit(s, num, 1000, startedPrinting);
+ appendDigit(s, num, 100, startedPrinting);
+ appendDigit(s, num, 10, startedPrinting);
+ appendDigit(s, num, 1, startedPrinting);
+ if ( !startedPrinting )
+ *s++ = '0';
+}
+
+void MachOFile::packedVersionToString(uint32_t packedVersion, char versionString[32])
+{
+ // sprintf(versionString, "%d.%d.%d", (packedVersion >> 16), ((packedVersion >> 8) & 0xFF), (packedVersion & 0xFF));
+ char* s = versionString;
+ appendNumber(s, (packedVersion >> 16));
+ *s++ = '.';
+ appendNumber(s, (packedVersion >> 8) & 0xFF);
+ *s++ = '.';
+ appendNumber(s, (packedVersion & 0xFF));
+ *s++ = '\0';
+}
+
+bool MachOFile::supportsPlatform(Platform reqPlatform) const
+{
+ __block bool foundRequestedPlatform = false;
+ __block bool foundOtherPlatform = false;
+ forEachSupportedPlatform(^(Platform platform, uint32_t minOS, uint32_t sdk) {
+ if ( platform == reqPlatform )
+ foundRequestedPlatform = true;
+ else
+ foundOtherPlatform = true;
+ });
+ if ( foundRequestedPlatform )
+ return true;
+
+ // we did find some platform info, but not requested, so return false
+ if ( foundOtherPlatform )
+ return false;
+
+ // binary has no explict load command to mark platform
+ // could be an old macOS binary, look at arch
+ if ( reqPlatform == Platform::macOS ) {
+ if ( this->cputype == CPU_TYPE_X86_64 )
+ return true;
+ if ( this->cputype == CPU_TYPE_I386 )
+ return true;
+ }
+
+ return false;
+}
+
+Platform MachOFile::currentPlatform()
+{
+#if TARGET_OS_BRIDGE
+ return Platform::bridgeOS;
+#elif TARGET_OS_WATCH
+ return Platform::watchOS;
+#elif TARGET_OS_TV
+ return Platform::tvOS;
+#elif TARGET_OS_IOS
+ return Platform::iOS;
+#elif TARGET_OS_MAC
+ return Platform::macOS;
+#else
+ #error unknown platform
+#endif
}
#if __x86_64__
@@ -205,283 +343,6 @@
return sHaswell;
}
#endif
-
-const GradedArchs& GradedArchs::forCurrentOS(const MachOFile* mainExecutable)
-{
-#if __arm64e__
- if ( mainExecutable->cpusubtype < CPU_SUBTYPE_ARM64E )
- return arm64e_compat;
- else
- return arm64e;
-#elif __ARM64_ARCH_8_32__
- return arm64_32;
-#elif __arm64__
- return arm64;
-#elif __ARM_ARCH_7K__
- return armv7k;
-#elif __ARM_ARCH_7S__
- return armv7s;
-#elif __ARM_ARCH_7A__
- return armv7;
-#elif __x86_64__
- return isHaswell() ? x86_64h : x86_64;
-#elif __i386__
- return i386;
-#else
- #error unknown platform
-#endif
-}
-
-const GradedArchs& GradedArchs::forName(const char* archName, bool forMainExecutable)
-{
- if (strcmp(archName, "x86_64h") == 0 )
- return x86_64h;
- else if (strcmp(archName, "x86_64") == 0 )
- return x86_64;
-#if SUPPORT_ARCH_arm64e
- else if (strcmp(archName, "arm64e") == 0 )
- return forMainExecutable ? arm64e_compat : arm64e;
-#endif
- else if (strcmp(archName, "arm64") == 0 )
- return arm64;
- else if (strcmp(archName, "armv7k") == 0 )
- return armv7k;
- else if (strcmp(archName, "armv7s") == 0 )
- return armv7s;
- else if (strcmp(archName, "armv7") == 0 )
- return armv7;
-#if SUPPORT_ARCH_arm64_32
- else if (strcmp(archName, "arm64_32") == 0 )
- return arm64_32;
-#endif
- else if (strcmp(archName, "i386") == 0 )
- return i386;
- assert(0 && "unknown arch name");
-}
-
-
-//////////////////////////// MachOFile ////////////////////////////////////////
-
-
-const MachOFile::ArchInfo MachOFile::_s_archInfos[] = {
- { "x86_64", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL },
- { "x86_64h", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H },
- { "i386", CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL },
- { "arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL },
-#if SUPPORT_ARCH_arm64e
- { "arm64e", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E },
-#endif
-#if SUPPORT_ARCH_arm64_32
- { "arm64_32", CPU_TYPE_ARM64_32, CPU_SUBTYPE_ARM64_32_V8 },
-#endif
- { "armv7k", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7K },
- { "armv7s", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S },
- { "armv7", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7 }
-};
-
-const MachOFile::PlatformInfo MachOFile::_s_platformInfos[] = {
- { "macOS", Platform::macOS, LC_VERSION_MIN_MACOSX },
- { "iOS", Platform::iOS, LC_VERSION_MIN_IPHONEOS },
- { "tvOS", Platform::tvOS, LC_VERSION_MIN_TVOS },
- { "watchOS", Platform::watchOS, LC_VERSION_MIN_WATCHOS },
- { "bridgeOS", Platform::bridgeOS, LC_BUILD_VERSION },
- { "UIKitForMac", Platform::iOSMac, LC_BUILD_VERSION },
- { "iOS-sim", Platform::iOS_simulator, LC_BUILD_VERSION },
- { "tvOS-sim", Platform::tvOS_simulator, LC_BUILD_VERSION },
- { "watchOS-sim", Platform::watchOS_simulator, LC_BUILD_VERSION },
-};
-
-
-
-bool MachOFile::is64() const
-{
- return (this->magic == MH_MAGIC_64);
-}
-
-size_t MachOFile::machHeaderSize() const
-{
- return is64() ? sizeof(mach_header_64) : sizeof(mach_header);
-}
-
-
-uint32_t MachOFile::pointerSize() const
-{
- if (this->magic == MH_MAGIC_64)
- return 8;
- else
- return 4;
-}
-
-bool MachOFile::uses16KPages() const
-{
- switch (this->cputype) {
- case CPU_TYPE_ARM64:
- case CPU_TYPE_ARM64_32:
- return true;
- case CPU_TYPE_ARM:
- // iOS is 16k aligned for armv7/armv7s and watchOS armv7k is 16k aligned
- return this->cpusubtype == CPU_SUBTYPE_ARM_V7K;
- default:
- return false;
- }
-}
-
-bool MachOFile::isArch(const char* aName) const
-{
- return (strcmp(aName, archName(this->cputype, this->cpusubtype)) == 0);
-}
-
-const char* MachOFile::archName(uint32_t cputype, uint32_t cpusubtype)
-{
- for (const ArchInfo& info : _s_archInfos) {
- if ( (cputype == info.cputype) && ((cpusubtype & ~CPU_SUBTYPE_MASK) == info.cpusubtype) ) {
- return info.name;
- }
- }
- return "unknown";
-}
-
-uint32_t MachOFile::cpuTypeFromArchName(const char* archName)
-{
- for (const ArchInfo& info : _s_archInfos) {
- if ( strcmp(archName, info.name) == 0 ) {
- return info.cputype;
- }
- }
- return 0;
-}
-
-uint32_t MachOFile::cpuSubtypeFromArchName(const char* archName)
-{
- for (const ArchInfo& info : _s_archInfos) {
- if ( strcmp(archName, info.name) == 0 ) {
- return info.cpusubtype;
- }
- }
- return 0;
-}
-
-const char* MachOFile::archName() const
-{
- return archName(this->cputype, this->cpusubtype);
-}
-
-static void appendDigit(char*& s, unsigned& num, unsigned place, bool& startedPrinting)
-{
- if ( num >= place ) {
- unsigned dig = (num/place);
- *s++ = '0' + dig;
- num -= (dig*place);
- startedPrinting = true;
- }
- else if ( startedPrinting ) {
- *s++ = '0';
- }
-}
-
-static void appendNumber(char*& s, unsigned num)
-{
- assert(num < 99999);
- bool startedPrinting = false;
- appendDigit(s, num, 10000, startedPrinting);
- appendDigit(s, num, 1000, startedPrinting);
- appendDigit(s, num, 100, startedPrinting);
- appendDigit(s, num, 10, startedPrinting);
- appendDigit(s, num, 1, startedPrinting);
- if ( !startedPrinting )
- *s++ = '0';
-}
-
-void MachOFile::packedVersionToString(uint32_t packedVersion, char versionString[32])
-{
- // sprintf(versionString, "%d.%d.%d", (packedVersion >> 16), ((packedVersion >> 8) & 0xFF), (packedVersion & 0xFF));
- char* s = versionString;
- appendNumber(s, (packedVersion >> 16));
- *s++ = '.';
- appendNumber(s, (packedVersion >> 8) & 0xFF);
- *s++ = '.';
- appendNumber(s, (packedVersion & 0xFF));
- *s++ = '\0';
-}
-
-bool MachOFile::supportsPlatform(Platform reqPlatform) const
-{
- __block bool foundRequestedPlatform = false;
- __block bool foundOtherPlatform = false;
- forEachSupportedPlatform(^(Platform platform, uint32_t minOS, uint32_t sdk) {
- if ( platform == reqPlatform )
- foundRequestedPlatform = true;
- else
- foundOtherPlatform = true;
- });
- if ( foundRequestedPlatform )
- return true;
-
- // we did find some platform info, but not requested, so return false
- if ( foundOtherPlatform )
- return false;
-
- // binary has no explict load command to mark platform
- // could be an old macOS binary, look at arch
- if ( reqPlatform == Platform::macOS ) {
- if ( this->cputype == CPU_TYPE_X86_64 )
- return true;
- if ( this->cputype == CPU_TYPE_I386 )
- return true;
- }
-
-#if BUILDING_DYLDINFO
- // Allow offline tools to analyze binaries dyld doesn't load, ie, those with platforms
- if ( !foundOtherPlatform && (reqPlatform == Platform::unknown) )
- return true;
-#endif
-
- return false;
-}
-
-bool MachOFile::isZippered() const
-{
- __block bool macOS = false;
- __block bool iOSMac = false;
- forEachSupportedPlatform(^(Platform platform, uint32_t minOS, uint32_t sdk) {
- if ( platform == Platform::macOS )
- macOS = true;
- else if ( platform == Platform::iOSMac )
- iOSMac = true;
- });
- return macOS && iOSMac;
-}
-
-bool MachOFile::inDyldCache() const {
- return (this->flags & 0x80000000);
-}
-
-Platform MachOFile::currentPlatform()
-{
-
-#if TARGET_OS_SIMULATOR
-#if TARGET_OS_WATCH
- return Platform::watchOS_simulator;
-#elif TARGET_OS_TV
- return Platform::tvOS_simulator;
-#else
- return Platform::iOS_simulator;
-#endif
-#elif TARGET_OS_BRIDGE
- return Platform::bridgeOS;
-#elif TARGET_OS_WATCH
- return Platform::watchOS;
-#elif TARGET_OS_TV
- return Platform::tvOS;
-#elif TARGET_OS_IOS
- return Platform::iOS;
-#elif TARGET_OS_MAC
- return Platform::macOS;
-#else
- #error unknown platform
-#endif
-}
-
const char* MachOFile::currentArchName()
{
@@ -508,12 +369,6 @@
#endif
}
-bool MachOFile::isSimulatorPlatform(Platform platform)
-{
- return ( (platform == Platform::iOS_simulator) ||
- (platform == Platform::watchOS_simulator) ||
- (platform == Platform::tvOS_simulator) );
-}
bool MachOFile::isDylib() const
{
@@ -536,26 +391,20 @@
return false;
// static executables do not have dyld load command
- return hasLoadCommand(LC_LOAD_DYLINKER);
-}
-
-bool MachOFile::isStaticExecutable() const
-{
- if ( this->filetype != MH_EXECUTE )
- return false;
-
- // static executables do not have dyld load command
- return !hasLoadCommand(LC_LOAD_DYLINKER);
+ __block bool hasDyldLoad = false;
+ Diagnostics diag;
+ forEachLoadCommand(diag, ^(const load_command* cmd, bool& stop) {
+ if ( cmd->cmd == LC_LOAD_DYLINKER ) {
+ hasDyldLoad = true;
+ stop = true;
+ }
+ });
+ return hasDyldLoad;
}
bool MachOFile::isPIE() const
{
return (this->flags & MH_PIE);
-}
-
-bool MachOFile::isPreload() const
-{
- return (this->filetype == MH_PRELOAD);
}
const char* MachOFile::platformName(Platform reqPlatform)
@@ -607,12 +456,10 @@
bool MachOFile::isMachO(Diagnostics& diag, uint64_t fileSize) const
{
if ( !hasMachOMagic() ) {
- // old PPC slices are not currently valid "mach-o" but should not cause an error
- if ( !hasMachOBigEndianMagic() )
- diag.error("file does not start with MH_MAGIC[_64]");
+ diag.error("file does not start with MH_MAGIC[_64]");
return false;
}
- if ( this->sizeofcmds + machHeaderSize() > fileSize ) {
+ if ( this->sizeofcmds + sizeof(mach_header_64) > fileSize ) {
diag.error("load commands exceed length of first segment");
return false;
}
@@ -624,12 +471,6 @@
{
return ( (this->magic == MH_MAGIC) || (this->magic == MH_MAGIC_64) );
}
-
-bool MachOFile::hasMachOBigEndianMagic() const
-{
- return ( (this->magic == MH_CIGAM) || (this->magic == MH_CIGAM_64) );
-}
-
void MachOFile::forEachLoadCommand(Diagnostics& diag, void (^callback)(const load_command* cmd, bool& stop)) const
{
@@ -639,11 +480,8 @@
startCmds = (load_command*)((char *)this + sizeof(mach_header_64));
else if ( this->magic == MH_MAGIC )
startCmds = (load_command*)((char *)this + sizeof(mach_header));
- else if ( hasMachOBigEndianMagic() )
- return; // can't process big endian mach-o
else {
- const uint32_t* h = (uint32_t*)this;
- diag.error("file does not start with MH_MAGIC[_64]: 0x%08X 0x%08X", h[0], h [1]);
+ diag.error("file does not start with MH_MAGIC[_64]");
return; // not a mach-o file
}
const load_command* const cmdsEnd = (load_command*)((char*)startCmds + this->sizeofcmds);
@@ -651,11 +489,11 @@
for (uint32_t i = 0; i < this->ncmds; ++i) {
const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize);
if ( cmd->cmdsize < 8 ) {
- diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) too small", i, this->ncmds, cmd, this, cmd->cmdsize);
+ diag.error("malformed load command #%d, size too small %d", i, cmd->cmdsize);
return;
}
if ( (nextCmd > cmdsEnd) || (nextCmd < startCmds) ) {
- diag.error("malformed load command #%d of %d at %p with mh=%p, size (0x%X) is too large, load commands end at %p", i, this->ncmds, cmd, this, cmd->cmdsize, cmdsEnd);
+ diag.error("malformed load command #%d, size too large 0x%X", i, cmd->cmdsize);
return;
}
callback(cmd, stop);
@@ -777,7 +615,6 @@
if ( minOS >= 0x00030000 ) // bridgeOS 3.0
result = false;
break;
- case Platform::driverKit:
case Platform::iOSMac:
result = false;
break;
@@ -813,11 +650,8 @@
info.vmSize = segCmd->vmsize;
info.sizeOfSections = sizeOfSections;
info.segName = segCmd->segname;
- info.loadCommandOffset = (uint32_t)((uint8_t*)segCmd - (uint8_t*)this);
info.protections = segCmd->initprot;
info.textRelocs = false;
- info.readOnlyData = ((segCmd->flags & SG_READ_ONLY) != 0);
- info.isProtected = (segCmd->flags & SG_PROTECTED_VERSION_1) ? 1 : 0;
info.p2align = p2align;
info.segIndex = segIndex;
callback(info, stop);
@@ -844,11 +678,8 @@
info.vmSize = segCmd->vmsize;
info.sizeOfSections = sizeOfSections;
info.segName = segCmd->segname;
- info.loadCommandOffset = (uint32_t)((uint8_t*)segCmd - (uint8_t*)this);
info.protections = segCmd->initprot;
info.textRelocs = intel32 && !info.writable() && hasTextRelocs;
- info.readOnlyData = ((segCmd->flags & SG_READ_ONLY) != 0);
- info.isProtected = (segCmd->flags & SG_PROTECTED_VERSION_1) ? 1 : 0;
info.p2align = p2align;
info.segIndex = segIndex;
callback(info, stop);
@@ -861,7 +692,6 @@
void MachOFile::forEachSection(void (^callback)(const SectionInfo& sectInfo, bool malformedSectionRange, bool& stop)) const
{
Diagnostics diag;
- BLOCK_ACCCESSIBLE_ARRAY(char, sectNameCopy, 20); // read as: char sectNameCopy[20];
const bool intel32 = (this->cputype == CPU_TYPE_I386);
__block uint32_t segIndex = 0;
forEachLoadCommand(diag, ^(const load_command* cmd, bool& stop) {
@@ -883,15 +713,13 @@
sectInfo.segInfo.vmSize = segCmd->vmsize;
sectInfo.segInfo.sizeOfSections = sizeOfSections;
sectInfo.segInfo.segName = segCmd->segname;
- sectInfo.segInfo.loadCommandOffset = (uint32_t)((uint8_t*)segCmd - (uint8_t*)this);
sectInfo.segInfo.protections = segCmd->initprot;
sectInfo.segInfo.textRelocs = false;
- sectInfo.segInfo.readOnlyData = ((segCmd->flags & SG_READ_ONLY) != 0);
- sectInfo.segInfo.isProtected = (segCmd->flags & SG_PROTECTED_VERSION_1) ? 1 : 0;
sectInfo.segInfo.p2align = p2align;
sectInfo.segInfo.segIndex = segIndex;
for (const section_64* sect=sectionsStart; !stop && (sect < sectionsEnd); ++sect) {
const char* sectName = sect->sectname;
+ char sectNameCopy[20];
if ( sectName[15] != '\0' ) {
strlcpy(sectNameCopy, sectName, 17);
sectName = sectNameCopy;
@@ -929,15 +757,13 @@
sectInfo.segInfo.vmSize = segCmd->vmsize;
sectInfo.segInfo.sizeOfSections = sizeOfSections;
sectInfo.segInfo.segName = segCmd->segname;
- sectInfo.segInfo.loadCommandOffset = (uint32_t)((uint8_t*)segCmd - (uint8_t*)this);
sectInfo.segInfo.protections = segCmd->initprot;
sectInfo.segInfo.textRelocs = intel32 && !sectInfo.segInfo.writable() && hasTextRelocs;
- sectInfo.segInfo.readOnlyData = ((segCmd->flags & SG_READ_ONLY) != 0);
- sectInfo.segInfo.isProtected = (segCmd->flags & SG_PROTECTED_VERSION_1) ? 1 : 0;
sectInfo.segInfo.p2align = p2align;
sectInfo.segInfo.segIndex = segIndex;
for (const section* sect=sectionsStart; !stop && (sect < sectionsEnd); ++sect) {
const char* sectName = sect->sectname;
+ char sectNameCopy[20];
if ( sectName[15] != '\0' ) {
strlcpy(sectNameCopy, sectName, 17);
sectName = sectNameCopy;
@@ -978,22 +804,8 @@
return (strcmp(&str[strLen-suffixLen], suffix) == 0);
}
-bool MachOFile::isSharedCacheEligiblePath(const char* dylibName) {
- return ( (strncmp(dylibName, "/usr/lib/", 9) == 0)
- || (strncmp(dylibName, "/System/Library/", 16) == 0)
- || (strncmp(dylibName, "/System/iOSSupport/usr/lib/", 27) == 0)
- || (strncmp(dylibName, "/System/iOSSupport/System/Library/", 34) == 0)
- || (strncmp(dylibName, "/Library/Apple/usr/lib/", 23) == 0)
- || (strncmp(dylibName, "/Library/Apple/System/Library/", 30) == 0) );
-}
-
bool MachOFile::canBePlacedInDyldCache(const char* path, void (^failureReason)(const char*)) const
{
- if ( !isSharedCacheEligiblePath(path) ) {
- // Dont spam the user with an error about paths when we know these are never eligible.
- return false;
- }
-
// only dylibs can go in cache
if ( this->filetype != MH_DYLIB ) {
failureReason("Not MH_DYLIB");
@@ -1001,19 +813,16 @@
}
// only dylibs built for /usr/lib or /System/Library can go in cache
-
+ bool retval = true;
const char* dylibName = installName();
if ( dylibName[0] != '/' ) {
+ retval = false;
failureReason("install name not an absolute path");
- // Don't continue as we don't want to spam the log with errors we don't need.
- return false;
- }
- else if ( strcmp(dylibName, path) != 0 ) {
- failureReason("install path does not match install name");
- return false;
- }
-
- bool retval = true;
+ }
+ else if ( (strncmp(dylibName, "/usr/lib/", 9) != 0) && (strncmp(dylibName, "/System/Library/", 16) != 0) ) {
+ retval = false;
+ failureReason("Not in '/usr/lib/' or '/System/Library/'");
+ }
// flat namespace files cannot go in cache
if ( (this->flags & MH_TWOLEVEL) == 0 ) {
@@ -1030,29 +839,26 @@
// dylib must have extra info for moving DATA and TEXT segments apart
__block bool hasExtraInfo = false;
__block bool hasDyldInfo = false;
- __block bool hasExportTrie = false;
Diagnostics diag;
forEachLoadCommand(diag, ^(const load_command* cmd, bool& stop) {
if ( cmd->cmd == LC_SEGMENT_SPLIT_INFO )
hasExtraInfo = true;
if ( cmd->cmd == LC_DYLD_INFO_ONLY )
hasDyldInfo = true;
- if ( cmd->cmd == LC_DYLD_EXPORTS_TRIE )
- hasExportTrie = true;
});
if ( !hasExtraInfo ) {
retval = false;
failureReason("Missing split seg info");
}
- if ( !hasDyldInfo && !hasExportTrie ) {
+ if ( !hasDyldInfo ) {
retval = false;
- failureReason("Old binary, missing dyld info or export trie");
+ failureReason("Old binary, missing dyld info");
}
// dylib can only depend on other dylibs in the shared cache
__block bool allDepPathsAreGood = true;
forEachDependentDylib(^(const char* loadPath, bool isWeak, bool isReExport, bool isUpward, uint32_t compatVersion, uint32_t curVersion, bool& stop) {
- if ( !isSharedCacheEligiblePath(loadPath) ) {
+ if ( (strncmp(loadPath, "/usr/lib/", 9) != 0) && (strncmp(loadPath, "/System/Library/", 16) != 0) ) {
allDepPathsAreGood = false;
stop = true;
}
@@ -1071,14 +877,6 @@
if ( hasInterposing ) {
retval = false;
failureReason("Has interposing tuples");
- }
-
- // Temporarily kick out swift binaries on watchOS simulators as they have missing split seg
- if ( supportsPlatform(Platform::watchOS_simulator) && isArch("i386") ) {
- if ( strncmp(dylibName, "/usr/lib/swift/", 15) == 0 ) {
- retval = false;
- failureReason("i386 swift binary");
- }
}
return retval;
@@ -1122,39 +920,14 @@
}
-bool MachOFile::hasLoadCommand(uint32_t cmdNum) const
-{
- __block bool hasLC = false;
- Diagnostics diag;
- forEachLoadCommand(diag, ^(const load_command* cmd, bool& stop) {
- if ( cmd->cmd == cmdNum ) {
- hasLC = true;
- stop = true;
- }
- });
- return hasLC;
-}
-
-bool MachOFile::allowsAlternatePlatform() const
-{
- __block bool result = false;
- forEachSection(^(const SectionInfo& info, bool malformedSectionRange, bool& stop) {
- if ( (strcmp(info.sectName, "__allow_alt_plat") == 0) && (strncmp(info.segInfo.segName, "__DATA", 6) == 0) ) {
- result = true;
- stop = true;
- }
- });
- return result;
-}
-
bool MachOFile::hasChainedFixups() const
{
#if SUPPORT_ARCH_arm64e
- // arm64e always uses chained fixups
- if ( (this->cputype == CPU_TYPE_ARM64) && (this->cpusubtype == CPU_SUBTYPE_ARM64E) )
- return true;
-#endif
- return hasLoadCommand(LC_DYLD_CHAINED_FIXUPS);
+ // for now only arm64e uses chained fixups
+ return ( strcmp(archName(), "arm64e") == 0 );
+#else
+ return false;
+#endif
}
uint64_t MachOFile::read_uleb128(Diagnostics& diag, const uint8_t*& p, const uint8_t* end)