X-Git-Url: https://git.saurik.com/apple/dyld.git/blobdiff_plain/2fd3f4e8fd2c2f2c7d149fbea471d8b3fb56f15a..5f39f99244da210e6860ddd9fdd67baa46f62504:/src/dyldAPIsInLibSystem.cpp diff --git a/src/dyldAPIsInLibSystem.cpp b/src/dyldAPIsInLibSystem.cpp index 314c658..d1e48f5 100644 --- a/src/dyldAPIsInLibSystem.cpp +++ b/src/dyldAPIsInLibSystem.cpp @@ -34,11 +34,13 @@ #include "mach-o/dyld.h" #include "mach-o/dyld_priv.h" +#include "ImageLoader.h" #include "dyldLock.h" #include "start_glue.h" extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso); extern "C" void __cxa_finalize(const void *dso); +extern "C" void __cxa_finalize_ranges(const struct __cxa_range_t ranges[], int count); #ifndef LC_VERSION_MIN_MACOSX @@ -56,12 +58,19 @@ extern "C" void __cxa_finalize(const void *dso); #define LC_VERSION_MIN_IPHONEOS 0x25 #endif +#ifndef LC_VERSION_MIN_TVOS + #define LC_VERSION_MIN_TVOS 0x2F +#endif + +#ifndef LC_VERSION_MIN_WATCHOS + #define LC_VERSION_MIN_WATCHOS 0x30 +#endif + #ifndef LC_LOAD_UPWARD_DYLIB #define LC_LOAD_UPWARD_DYLIB (0x23|LC_REQ_DYLD) /* load of dylib whose initializers run later */ #endif -#define DYLD_SHARED_CACHE_SUPPORT (__i386__ || __x86_64__ || __arm__) // deprecated APIs are still availble on Mac OS X, but not on iPhone OS #if __IPHONE_OS_VERSION_MIN_REQUIRED @@ -79,10 +88,10 @@ extern "C" void __cxa_finalize(const void *dso); static bool names_match( -char *install_name, +const char *install_name, const char* libraryName) { - char *basename; + const char *basename; unsigned long n; /* @@ -103,7 +112,7 @@ const char* libraryName) * of the -framework cases. */ if(strcmp(basename, libraryName) == 0) - return(TRUE); + return true; /* * Now check the base name for "lib" if so proceed to check for the @@ -113,14 +122,14 @@ const char* libraryName) n = strlen(libraryName); if(strncmp(basename+3, libraryName, n) == 0){ if(strncmp(basename+3+n, ".dylib", 6) == 0) - return(TRUE); + return true; if(basename[3+n] == '.' && basename[3+n+1] != '\0' && strncmp(basename+3+n+2, ".dylib", 6) == 0) - return(TRUE); + return true; } } - return(FALSE); + return false; } #if DEPRECATED_APIS_SUPPORTED @@ -346,42 +355,35 @@ uint32_t options) * and not a list of current versions that dependent libraries and bundles the * program is using were built with. */ -int32_t -NSVersionOfLinkTimeLibrary( -const char* libraryName) +int32_t NSVersionOfLinkTimeLibrary(const char* libraryName) { - unsigned long i; - struct load_command *load_commands, *lc; - struct dylib_command *dl; - char *install_name; + // Lazily call _NSGetMachExecuteHeader() and cache result #if __LP64__ - static struct mach_header_64 *mh = NULL; + static mach_header_64* mh = NULL; #else - static struct mach_header *mh = NULL; + static mach_header* mh = NULL; #endif - if(mh == NULL) + if ( mh == NULL ) mh = _NSGetMachExecuteHeader(); - load_commands = (struct load_command *) #if __LP64__ - ((char *)mh + sizeof(struct mach_header_64)); + const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header_64)); #else - ((char *)mh + sizeof(struct mach_header)); + const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header)); #endif - lc = load_commands; - for(i = 0; i < mh->ncmds; i++){ + for(uint32_t i = 0; i < mh->ncmds; i++){ switch ( lc->cmd ) { case LC_LOAD_DYLIB: case LC_LOAD_WEAK_DYLIB: case LC_LOAD_UPWARD_DYLIB: - dl = (struct dylib_command *)lc; - install_name = (char *)dl + dl->dylib.name.offset; - if(names_match(install_name, libraryName) == TRUE) - return(dl->dylib.current_version); + const dylib_command* dl = (dylib_command *)lc; + const char* install_name = (char*)dl + dl->dylib.name.offset; + if ( names_match(install_name, libraryName) ) + return dl->dylib.current_version; break; } - lc = (struct load_command *)((char *)lc + lc->cmdsize); + lc = (load_command*)((char*)lc + lc->cmdsize); } - return(-1); + return (-1); } /* @@ -391,103 +393,116 @@ const char* libraryName) * it would be "x" and with -framework Foo it would be "Foo"). If the program * is not using the specified library it returns -1. */ -int32_t -NSVersionOfRunTimeLibrary( -const char* libraryName) -{ - unsigned long i, j, n; - char *install_name; - struct load_command *load_commands, *lc; - struct dylib_command *dl; - const struct mach_header *mh; - - n = _dyld_image_count(); - for(i = 0; i < n; i++){ - mh = _dyld_get_image_header(i); - if(mh->filetype != MH_DYLIB) - continue; - load_commands = (struct load_command *) +int32_t NSVersionOfRunTimeLibrary(const char* libraryName) +{ + uint32_t n = _dyld_image_count(); + for(uint32_t i = 0; i < n; i++){ + const mach_header* mh = _dyld_get_image_header(i); + if ( mh == NULL ) + continue; + if ( mh->filetype != MH_DYLIB ) + continue; #if __LP64__ - ((char *)mh + sizeof(struct mach_header_64)); + const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header_64)); #else - ((char *)mh + sizeof(struct mach_header)); + const load_command* lc = (load_command*)((char*)mh + sizeof(mach_header)); #endif - lc = load_commands; - for(j = 0; j < mh->ncmds; j++){ - if(lc->cmd == LC_ID_DYLIB){ - dl = (struct dylib_command *)lc; - install_name = (char *)dl + dl->dylib.name.offset; - if(names_match(install_name, libraryName) == TRUE) - return(dl->dylib.current_version); - } - lc = (struct load_command *)((char *)lc + lc->cmdsize); + for(uint32_t j = 0; j < mh->ncmds; j++){ + if ( lc->cmd == LC_ID_DYLIB ) { + const dylib_command* dl = (dylib_command*)lc; + const char* install_name = (char *)dl + dl->dylib.name.offset; + if ( names_match(install_name, libraryName) ) + return dl->dylib.current_version; + } + lc = (load_command*)((char*)lc + lc->cmdsize); } } - return(-1); + return (-1); } + #define PACKED_VERSION(major, minor, tiny) ((((major) & 0xffff) << 16) | (((minor) & 0xff) << 8) | ((tiny) & 0xff)) -/* - * Returns the sdk version (encode as nibble XXXX.YY.ZZ) the - * specified binary was built against. - * - * First looks for LC_VERSION_MIN_MACOSX/LC_VERSION_MIN_IPHONEOS - * in binary and if sdk field is not zero, return that value. - * Otherwise, looks for the libSystem.B.dylib the binary linked - * against and uses a table to convert that to an sdk version. - */ -uint32_t dyld_get_sdk_version(const mach_header* mh) +static bool getVersionLoadCommandInfo(const mach_header* mh, uint32_t* loadCommand, uint32_t* minOS, uint32_t* sdk) +{ + const load_command* startCmds = NULL; + if ( mh->magic == MH_MAGIC_64 ) + startCmds = (load_command*)((char *)mh + sizeof(mach_header_64)); + else if ( mh->magic == MH_MAGIC ) + startCmds = (load_command*)((char *)mh + sizeof(mach_header)); + else + return false; // not a mach-o file, or wrong endianness + + const load_command* const cmdsEnd = (load_command*)((char*)startCmds + mh->sizeofcmds); + const load_command* cmd = startCmds; + for(uint32_t i = 0; i < mh->ncmds; ++i) { + const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize); + if ( (cmd->cmdsize < 8) || (nextCmd > cmdsEnd) || (nextCmd < startCmds)) { + return 0; + } + const version_min_command* versCmd; + switch ( cmd->cmd ) { + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_MACOSX: + case LC_VERSION_MIN_TVOS: + case LC_VERSION_MIN_WATCHOS: + versCmd = (version_min_command*)cmd; + *loadCommand = versCmd->cmd; + *minOS = versCmd->version; + *sdk = versCmd->sdk; + return true; + } + cmd = nextCmd; + } + return false; +} + +#if !__WATCH_OS_VERSION_MIN_REQUIRED && !__TV_OS_VERSION_MIN_REQUIRED +static uint32_t deriveSDKVersFromDylibs(const mach_header* mh) { - const load_command* cmds = NULL; + const load_command* startCmds = NULL; if ( mh->magic == MH_MAGIC_64 ) - cmds = (load_command*)((char *)mh + sizeof(mach_header_64)); + startCmds = (load_command*)((char *)mh + sizeof(mach_header_64)); else if ( mh->magic == MH_MAGIC ) - cmds = (load_command*)((char *)mh + sizeof(mach_header)); + startCmds = (load_command*)((char *)mh + sizeof(mach_header)); else return 0; // not a mach-o file, or wrong endianness - const version_min_command* versCmd; + const load_command* const cmdsEnd = (load_command*)((char*)startCmds + mh->sizeofcmds); const dylib_command* dylibCmd; - const load_command* cmd = cmds; + const load_command* cmd = startCmds; const char* dylibName; -#if __IPHONE_OS_VERSION_MIN_REQUIRED + #if __IPHONE_OS_VERSION_MIN_REQUIRED uint32_t foundationVers = 0; -#else + #else uint32_t libSystemVers = 0; -#endif + #endif for(uint32_t i = 0; i < mh->ncmds; ++i) { - switch ( cmd->cmd ) { -#if __IPHONE_OS_VERSION_MIN_REQUIRED - case LC_VERSION_MIN_IPHONEOS: -#else - case LC_VERSION_MIN_MACOSX: -#endif - versCmd = (version_min_command*)cmd; -#ifdef DICE_KIND_DATA - if ( versCmd->sdk != 0 ) - return versCmd->sdk; // found explicit SDK version -#else - if ( versCmd->reserved != 0 ) - return versCmd->reserved; // found explicit SDK version -#endif - break; + const load_command* nextCmd = (load_command*)((char *)cmd + cmd->cmdsize); + // sanity check size of command + if ( (cmd->cmdsize < 8) || (nextCmd > cmdsEnd) || (nextCmd < startCmds)) { + return 0; + } + switch ( cmd->cmd ) { case LC_LOAD_DYLIB: case LC_LOAD_WEAK_DYLIB: case LC_LOAD_UPWARD_DYLIB: dylibCmd = (dylib_command*)cmd; + // sanity check dylib command layout + if ( dylibCmd->dylib.name.offset > cmd->cmdsize ) + return 0; dylibName = (char*)dylibCmd + dylibCmd->dylib.name.offset; -#if __IPHONE_OS_VERSION_MIN_REQUIRED + #if __IPHONE_OS_VERSION_MIN_REQUIRED if ( strcmp(dylibName, "/System/Library/Frameworks/Foundation.framework/Foundation") == 0 ) foundationVers = dylibCmd->dylib.current_version; -#else + #else if ( strcmp(dylibName, "/usr/lib/libSystem.B.dylib") == 0 ) libSystemVers = dylibCmd->dylib.current_version; -#endif + #endif break; } - cmd = (load_command*)((char *)cmd + cmd->cmdsize); + cmd = nextCmd; } struct DylibToOSMapping { @@ -495,7 +510,7 @@ uint32_t dyld_get_sdk_version(const mach_header* mh) uint32_t osVersion; }; -#if __IPHONE_OS_VERSION_MIN_REQUIRED + #if __IPHONE_OS_VERSION_MIN_REQUIRED static const DylibToOSMapping foundationMapping[] = { { PACKED_VERSION(678,24,0), DYLD_IOS_VERSION_2_0 }, { PACKED_VERSION(678,26,0), DYLD_IOS_VERSION_2_1 }, @@ -511,8 +526,10 @@ uint32_t dyld_get_sdk_version(const mach_header* mh) { PACKED_VERSION(890,1,0), DYLD_IOS_VERSION_5_1 }, { PACKED_VERSION(992,0,0), DYLD_IOS_VERSION_6_0 }, { PACKED_VERSION(993,0,0), DYLD_IOS_VERSION_6_1 }, - { PACKED_VERSION(1038,14,0),DYLD_IOS_VERSION_7_0 }, // check final - { PACKED_VERSION(0,0,0), DYLD_IOS_VERSION_7_0 } + { PACKED_VERSION(1038,14,0),DYLD_IOS_VERSION_7_0 }, + { PACKED_VERSION(0,0,0), DYLD_IOS_VERSION_7_0 } + // We don't need to expand this table because all recent + // binaries have LC_VERSION_MIN_ load command. }; if ( foundationVers != 0 ) { @@ -526,7 +543,7 @@ uint32_t dyld_get_sdk_version(const mach_header* mh) } } -#else + #else // Note: versions are for the GM release. The last entry should // always be zero. At the start of the next major version, // a new last entry needs to be added and the previous zero @@ -539,6 +556,8 @@ uint32_t dyld_get_sdk_version(const mach_header* mh) { PACKED_VERSION(169,3,0), DYLD_MACOSX_VERSION_10_8 }, { PACKED_VERSION(1197,0,0), DYLD_MACOSX_VERSION_10_9 }, { PACKED_VERSION(0,0,0), DYLD_MACOSX_VERSION_10_9 } + // We don't need to expand this table because all recent + // binaries have LC_VERSION_MIN_ load command. }; if ( libSystemVers != 0 ) { @@ -551,9 +570,82 @@ uint32_t dyld_get_sdk_version(const mach_header* mh) lastOsVersion = p->osVersion; } } + #endif + return 0; +} +#endif + + +#if __WATCH_OS_VERSION_MIN_REQUIRED +static uint32_t watchVersToIOSVers(uint32_t vers) +{ + return vers + 0x00070000; +} + +uint32_t dyld_get_program_sdk_watch_os_version() +{ + const mach_header* mh = (mach_header*)_NSGetMachExecuteHeader(); + uint32_t loadCommand; + uint32_t minOS; + uint32_t sdk; + + if ( getVersionLoadCommandInfo(mh, &loadCommand, &minOS, &sdk) ) { + if ( loadCommand == LC_VERSION_MIN_WATCHOS ) + return sdk; + } + return 0; +} #endif - + +/* + * Returns the sdk version (encode as nibble XXXX.YY.ZZ) the + * specified binary was built against. + * + * First looks for LC_VERSION_MIN_* in binary and if sdk field is + * not zero, return that value. + * Otherwise, looks for the libSystem.B.dylib the binary linked + * against and uses a table to convert that to an sdk version. + */ +uint32_t dyld_get_sdk_version(const mach_header* mh) +{ + uint32_t loadCommand; + uint32_t minOS; + uint32_t sdk; + + if ( getVersionLoadCommandInfo(mh, &loadCommand, &minOS, &sdk) ) { + switch (loadCommand) { +#if __WATCH_OS_VERSION_MIN_REQUIRED + case LC_VERSION_MIN_WATCHOS: + // new binary. sdk version looks like "2.0" but API wants "9.0" + return watchVersToIOSVers(sdk); + case LC_VERSION_MIN_IPHONEOS: + // old binary. sdk matches API semantics so can return directly. + return sdk; +#elif __TV_OS_VERSION_MIN_REQUIRED + case LC_VERSION_MIN_TVOS: + case LC_VERSION_MIN_IPHONEOS: + return sdk; +#elif __IPHONE_OS_VERSION_MIN_REQUIRED + case LC_VERSION_MIN_IPHONEOS: + if ( sdk != 0 ) // old binaries might not have SDK set + return sdk; + break; +#else + case LC_VERSION_MIN_MACOSX: + if ( sdk != 0 ) // old binaries might not have SDK set + return sdk; + break; +#endif + } + } + +#if __WATCH_OS_VERSION_MIN_REQUIRED ||__TV_OS_VERSION_MIN_REQUIRED + // All WatchOS and tv OS binaries should have version load command. return 0; +#else + // MacOSX and iOS have old binaries without version load commmand. + return deriveSDKVersFromDylibs(mh); +#endif } uint32_t dyld_get_program_sdk_version() @@ -561,31 +653,33 @@ uint32_t dyld_get_program_sdk_version() return dyld_get_sdk_version((mach_header*)_NSGetMachExecuteHeader()); } - uint32_t dyld_get_min_os_version(const struct mach_header* mh) { - const load_command* cmds = NULL; - if ( mh->magic == MH_MAGIC_64 ) - cmds = (load_command*)((char *)mh + sizeof(mach_header_64)); - else if ( mh->magic == MH_MAGIC ) - cmds = (load_command*)((char *)mh + sizeof(mach_header)); - else - return 0; // not a mach-o file, or wrong endianness - - const version_min_command* versCmd; - const load_command* cmd = cmds; - for(uint32_t i = 0; i < mh->ncmds; ++i) { - switch ( cmd->cmd ) { -#if __IPHONE_OS_VERSION_MIN_REQUIRED + uint32_t loadCommand; + uint32_t minOS; + uint32_t sdk; + + if ( getVersionLoadCommandInfo(mh, &loadCommand, &minOS, &sdk) ) { + switch (loadCommand) { +#if __WATCH_OS_VERSION_MIN_REQUIRED + case LC_VERSION_MIN_WATCHOS: + // new binary. OS version looks like "2.0" but API wants "9.0" + return watchVersToIOSVers(minOS); + case LC_VERSION_MIN_IPHONEOS: + // old binary. OS matches API semantics so can return directly. + return minOS; +#elif __TV_OS_VERSION_MIN_REQUIRED + case LC_VERSION_MIN_TVOS: + case LC_VERSION_MIN_IPHONEOS: + return minOS; +#elif __IPHONE_OS_VERSION_MIN_REQUIRED case LC_VERSION_MIN_IPHONEOS: + return minOS; #else case LC_VERSION_MIN_MACOSX: + return minOS; #endif - versCmd = (version_min_command*)cmd; - return versCmd->version; // found explicit min OS version - break; } - cmd = (load_command*)((char *)cmd + cmd->cmdsize); } return 0; } @@ -1093,7 +1187,7 @@ uint32_t _dyld_image_count(void) { DYLD_NO_LOCK_THIS_BLOCK; - static unsigned long (*p)(void) = NULL; + static uint32_t (*p)(void) = NULL; if(p == NULL) _dyld_func_lookup("__dyld_image_count", (void**)&p); @@ -1168,17 +1262,6 @@ const void* address) return p(address); } -void _dyld_moninit( -void (*monaddition)(char *lowpc, char *highpc)) -{ - DYLD_LOCK_THIS_BLOCK; - typedef void (*monproc)(char *lowpc, char *highpc); - static void (*p)(monproc monaddition) = NULL; - - if(p == NULL) - _dyld_func_lookup("__dyld_moninit", (void**)&p); - p(monaddition); -} #if DEPRECATED_APIS_SUPPORTED bool _dyld_launched_prebound(void) @@ -1219,12 +1302,12 @@ static bool dlerrorPerThreadKeyInitialized = false; // data kept per-thread struct dlerrorPerThreadData { - uint32_t sizeAllocated; + size_t sizeAllocated; char message[1]; }; // function called by dyld to get buffer to store dlerror message -static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired) +static char* getPerThreadBufferFor_dlerror(size_t sizeRequired) { // ok to create key lazily because this function is called within dyld lock, so there is no race condition if (!dlerrorPerThreadKeyInitialized ) { @@ -1233,11 +1316,11 @@ static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired) dlerrorPerThreadKeyInitialized = true; } - const int size = (sizeRequired < 256) ? 256 : sizeRequired; + const size_t size = (sizeRequired < 256) ? 256 : sizeRequired; dlerrorPerThreadData* data = (dlerrorPerThreadData*)pthread_getspecific(dlerrorPerThreadKey); if ( data == NULL ) { //int mallocSize = offsetof(dlerrorPerThreadData, message[size]); - const int mallocSize = sizeof(dlerrorPerThreadData)+size; + const size_t mallocSize = sizeof(dlerrorPerThreadData)+size; data = (dlerrorPerThreadData*)malloc(mallocSize); data->sizeAllocated = size; pthread_setspecific(dlerrorPerThreadKey, data); @@ -1245,7 +1328,7 @@ static char* getPerThreadBufferFor_dlerror(uint32_t sizeRequired) else if ( data->sizeAllocated < sizeRequired ) { free(data); //int mallocSize = offsetof(dlerrorPerThreadData, message[size]); - const int mallocSize = sizeof(dlerrorPerThreadData)+size; + const size_t mallocSize = sizeof(dlerrorPerThreadData)+size; data = (dlerrorPerThreadData*)malloc(mallocSize); data->sizeAllocated = size; pthread_setspecific(dlerrorPerThreadKey, data); @@ -1294,7 +1377,7 @@ static void shared_cache_out_of_date() // the table passed to dyld containing thread helpers -static dyld::LibSystemHelpers sHelpers = { 12, &dyldGlobalLockAcquire, &dyldGlobalLockRelease, +static dyld::LibSystemHelpers sHelpers = { 13, &dyldGlobalLockAcquire, &dyldGlobalLockRelease, &getPerThreadBufferFor_dlerror, &malloc, &free, &__cxa_atexit, #if DYLD_SHARED_CACHE_SUPPORT &shared_cache_missing, &shared_cache_out_of_date, @@ -1310,7 +1393,8 @@ static dyld::LibSystemHelpers sHelpers = { 12, &dyldGlobalLockAcquire, &dyldGlob &hasPerThreadBufferFor_dlerror, &isLaunchdOwned, &vm_allocate, - &mmap}; + &mmap, + &__cxa_finalize_ranges}; // @@ -1421,7 +1505,7 @@ const struct dyld_all_image_infos* _dyld_get_all_image_infos() return p(); } -#if !__arm__ +#if SUPPORT_ZERO_COST_EXCEPTIONS bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info) { DYLD_NO_LOCK_THIS_BLOCK; @@ -1434,7 +1518,7 @@ bool _dyld_find_unwind_sections(void* addr, dyld_unwind_sections* info) #endif -#if __i386__ || __x86_64__ || __arm__ +#if __i386__ || __x86_64__ || __arm__ || __arm64__ __attribute__((visibility("hidden"))) void* _dyld_fast_stub_entry(void* loadercache, long lazyinfo) { @@ -1458,7 +1542,17 @@ const char* dyld_image_path_containing_address(const void* addr) return p(addr); } -#if __IPHONE_OS_VERSION_MIN_REQUIRED +const struct mach_header* dyld_image_header_containing_address(const void* addr) +{ + DYLD_NO_LOCK_THIS_BLOCK; + static const mach_header* (*p)(const void*) = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_get_image_header_containing_address", (void**)&p); + return p(addr); +} + + bool dyld_shared_cache_some_image_overridden() { DYLD_NO_LOCK_THIS_BLOCK; @@ -1468,7 +1562,6 @@ bool dyld_shared_cache_some_image_overridden() _dyld_func_lookup("__dyld_shared_cache_some_image_overridden", (void**)&p); return p(); } -#endif bool dyld_process_is_restricted() @@ -1481,7 +1574,27 @@ bool dyld_process_is_restricted() return p(); } +#if DYLD_SHARED_CACHE_SUPPORT +const char* dyld_shared_cache_file_path() +{ + DYLD_NO_LOCK_THIS_BLOCK; + static const char* (*p)() = NULL; + + if(p == NULL) + _dyld_func_lookup("__dyld_shared_cache_file_path", (void**)&p); + return p(); +} +#endif +void dyld_dynamic_interpose(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count) +{ + DYLD_LOCK_THIS_BLOCK; + static void (*p)(const struct mach_header* mh, const struct dyld_interpose_tuple array[], size_t count) = NULL; + + if (p == NULL) + _dyld_func_lookup("__dyld_dynamic_interpose", (void**)&p); + p(mh, array, count); +} // SPI called __fork