Loading...
--- dyld/dyld-1340/dyld/DyldAPIs.cpp
+++ dyld/dyld-1165.3/dyld/DyldAPIs.cpp
@@ -47,9 +47,7 @@
#include "dyld_process_info_internal.h"
#include "OptimizerObjC.h"
-#else
- #include <liblibc/plat/dyld/exclaves_dyld.h>
-#endif // !TARGET_OS_EXCLAVEKIT
+#endif
#include "mach-o/dyld.h"
#include "mach-o/dyld_priv.h"
@@ -64,10 +62,7 @@
#include "objc-shared-cache.h"
#include "DyldAPIs.h"
#include "JustInTimeLoader.h"
-#include "Utilities.h"
-
-#include "Header.h"
-#include "Universal.h"
+#include "Utils.h"
#if !TARGET_OS_EXCLAVEKIT
// internal libc.a variable that needs to be reset during fork()
@@ -76,11 +71,6 @@
using dyld3::MachOFile;
using dyld3::MachOLoaded;
-using mach_o::Header;
-using mach_o::Platform;
-using mach_o::PlatformAndVersions;
-using mach_o::Universal;
-using mach_o::Version32;
extern const dyld3::MachOLoaded __dso_handle;
@@ -133,19 +123,16 @@
static const Loader* loaderFromHandle(void* h, bool& firstOnly)
{
- firstOnly = false;
- if ( h == nullptr )
- return nullptr;
-
uintptr_t dyldStart = (uintptr_t)&__dso_handle;
#if __has_feature(ptrauth_calls)
- // Note we don't use ptrauth_auth_data, as we don't want to crash on bad handles
- void* strippedHandle = ptrauth_strip(h, ptrauth_key_process_dependent_data);
- void* validHandle = ptrauth_sign_unauthenticated(strippedHandle, ptrauth_key_process_dependent_data, ptrauth_string_discriminator("dlopen"));
- if ( h != validHandle )
- return nullptr;
- h = strippedHandle;
+ if ( h != nullptr ) {
+ // Note we don't use ptrauth_auth_data, as we don't want to crash on bad handles
+ void* strippedHandle = ptrauth_strip(h, ptrauth_key_process_dependent_data);
+ void* validHandle = ptrauth_sign_unauthenticated(strippedHandle, ptrauth_key_process_dependent_data, ptrauth_string_discriminator("dlopen"));
+ if ( h == validHandle )
+ h = strippedHandle;
+ }
#endif
firstOnly = (((uintptr_t)h) & 1);
@@ -203,16 +190,14 @@
#endif
}
-// called during libSystem_initializer
-void APIs::_libdyld_initialize()
+void APIs::_libdyld_initialize(const dyld4::LibSystemHelpers* helpers)
{
// Since this called from libdyld`_dyld_initializer the allocator will be marked read only
- MemoryManager::withWritableMemory([&]{
- // up to this point locks in dyld did nothing.
- // now that libSystem is initialized, actually start using locks in dyld
- this->locks.setHelpers(libSystemHelpers);
-
- // set up thread-local-variables in initial images and dlerror handling
+ memoryManager.withWritableMemory([&]{
+ // libSystem.dylib is being initialized, set helpers pointer
+ this->setHelpers(helpers);
+
+ // set up thread-local-variable and dlerror handling
this->initialize();
});
}
@@ -233,7 +218,7 @@
#if BUILDING_DYLD && TARGET_OS_OSX && __x86_64__
// some old macOS apps assume index of zero is always the main executable even when dylibs are inserted, so permute order
uint32_t insertCount = config.pathOverrides.insertedDylibCount();
- if ( (insertCount != 0) && (config.process.platform == Platform::macOS) && (config.process.mainExecutableMinOSVersion < 0x0000C0000) ) {
+ if ( (insertCount != 0) && (config.process.platform == dyld3::Platform::macOS) && (config.process.mainExecutableMinOSVersion < 0x0000C0000) ) {
// special case index==0 to map to the main executable
if ( index == 0 )
return insertCount;
@@ -295,7 +280,7 @@
__block const char* result = 0;
locks.withLoadersReadLock(^{
if ( imageIndex < loaded.size() )
- result = loaded[normalizeImageIndex(config, imageIndex)]->path(*this);
+ result = loaded[normalizeImageIndex(config, imageIndex)]->path();
});
if ( config.log.apis )
log("_dyld_get_image_name(%u) => %s\n", imageIndex, result);
@@ -345,12 +330,12 @@
__block int32_t result = -1;
locks.withLoadersReadLock(^{
for ( const dyld4::Loader* image : loaded ) {
- const Header* hdr = (const Header*)image->loadAddress(*this);
+ const MachOLoaded* ml = image->loadAddress(*this);
const char* installName;
- Version32 currentVersion;
- Version32 compatVersion;
- if ( hdr->getDylibInstallName(&installName, &compatVersion, ¤tVersion) && nameMatch(installName, libraryName) ) {
- result = currentVersion.value();
+ uint32_t currentVersion;
+ uint32_t compatVersion;
+ if ( ml->getDylibInstallName(&installName, &compatVersion, ¤tVersion) && nameMatch(installName, libraryName) ) {
+ result = currentVersion;
break;
}
}
@@ -362,13 +347,17 @@
uint32_t APIs::dyld_get_program_sdk_watch_os_version()
{
- uint32_t retval = 0;
- PlatformAndVersions pvs = getImagePlatformAndVersions(config.process.mainExecutableHdr);
-
- if ( pvs.platform.basePlatform() == Platform::watchOS ) {
- retval = pvs.sdk.value();
- }
-
+ __block uint32_t retval = 0;
+ __block bool versionFound = false;
+ forEachImageVersion(config.process.mainExecutable, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
+ if ( versionFound )
+ return;
+
+ if ( MachOFile::basePlatform((dyld3::Platform)platform) == dyld3::Platform::watchOS ) {
+ versionFound = true;
+ retval = sdk_version;
+ }
+ });
if ( config.log.apis )
log("dyld_get_program_sdk_watch_os_version() => 0x%08X\n", retval);
return retval;
@@ -376,47 +365,56 @@
uint32_t APIs::dyld_get_program_min_watch_os_version()
{
- uint32_t retval = 0;
- PlatformAndVersions pvs = getImagePlatformAndVersions(config.process.mainExecutableHdr);
-
- if ( pvs.platform.basePlatform() == Platform::watchOS ) {
- retval = pvs.minOS.value();
- }
-
+ __block uint32_t retval = 0;
+ __block bool versionFound = false;
+ forEachImageVersion(config.process.mainExecutable, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
+ if ( versionFound )
+ return;
+
+ if ( MachOFile::basePlatform((dyld3::Platform)platform) == dyld3::Platform::watchOS ) {
+ versionFound = true;
+ retval = min_version;
+ }
+ });
if ( config.log.apis )
log("dyld_get_program_min_watch_os_version() => 0x%08X\n", retval);
return retval;
}
-void APIs::obsolete_dyld_get_program_sdk_bridge_os_version()
-{
-#if BUILDING_DYLD
- halt("obsolete dyld SPI called");
-#else
- abort();
-#endif
-}
-
-void APIs::obsolete_dyld_get_program_min_bridge_os_version()
-{
-#if BUILDING_DYLD
- halt("obsolete dyld SPI called");
-#else
- abort();
-#endif
-}
-
-// For watchOS and bridgeOS this returns the equivalent iOS SDK version.
-static uint32_t mapLegacyVersion(mach_o::Version32 version, Platform basePlatform)
-{
- if ( basePlatform == Platform::bridgeOS ) {
- return version.value() + 0x00090000;
- }
- else if ( basePlatform == Platform::watchOS ) {
- if ( version.major() < 26 )
- return version.value() + 0x00070000;
- }
- return version.value();
+uint32_t APIs::dyld_get_program_sdk_bridge_os_version()
+{
+ __block uint32_t retval = 0;
+ __block bool versionFound = false;
+ forEachImageVersion(config.process.mainExecutable, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
+ if ( versionFound )
+ return;
+
+ if ( MachOFile::basePlatform((dyld3::Platform)platform) == dyld3::Platform::bridgeOS ) {
+ versionFound = true;
+ retval = sdk_version;
+ }
+ });
+ if ( config.log.apis )
+ log("dyld_get_program_sdk_bridge_os_version() => 0x%08X\n", retval);
+ return retval;
+}
+
+uint32_t APIs::dyld_get_program_min_bridge_os_version()
+{
+ __block uint32_t retval = 0;
+ __block bool versionFound = false;
+ forEachImageVersion(config.process.mainExecutable, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
+ if ( versionFound )
+ return;
+
+ if ( MachOFile::basePlatform((dyld3::Platform)platform) == dyld3::Platform::bridgeOS ) {
+ versionFound = true;
+ retval = min_version;
+ }
+ });
+ if ( config.log.apis )
+ log("dyld_get_program_min_bridge_os_version() => 0x%08X\n", retval);
+ return retval;
}
//
@@ -428,16 +426,34 @@
// Otherwise, looks for the libSystem.B.dylib the binary linked
// against and uses a table to convert that to an sdk version.
//
-// For watchOS and bridgeOS this returns the equivalent iOS SDK version.
-//
uint32_t APIs::getSdkVersion(const mach_header* mh)
{
- uint32_t retval = 0;
- PlatformAndVersions pvs = getImagePlatformAndVersions((const Header*)mh);
-
- if ( pvs.platform == config.process.platform ) {
- retval = mapLegacyVersion(pvs.sdk, pvs.platform.basePlatform());
- }
+ __block bool versionFound = false;
+ __block uint32_t retval = 0;
+ forEachImageVersion(mh, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
+ if ( versionFound )
+ return;
+
+ if ( platform == (dyld_platform_t)config.process.platform ) {
+ versionFound = true;
+ switch ( MachOFile::basePlatform((dyld3::Platform)platform) ) {
+ case dyld3::Platform::bridgeOS:
+ retval = sdk_version + 0x00090000;
+ return;
+ case dyld3::Platform::watchOS:
+ retval = sdk_version + 0x00070000;
+ return;
+ default:
+ retval = sdk_version;
+ return;
+ }
+ }
+ else if ( platform == PLATFORM_IOSSIMULATOR && (dyld_platform_t)config.process.platform == PLATFORM_IOSMAC ) {
+ //FIXME bringup hack
+ versionFound = true;
+ retval = 0x000C0000;
+ }
+ });
return retval;
}
@@ -452,7 +468,7 @@
uint32_t APIs::dyld_get_program_sdk_version()
{
- uint32_t result = getSdkVersion(config.process.mainExecutableMF);
+ uint32_t result = getSdkVersion(config.process.mainExecutable);
if ( config.log.apis )
log("dyld_get_program_sdk_version() => 0x%08X\n", result);
return result;
@@ -460,13 +476,32 @@
uint32_t APIs::dyld_get_min_os_version(const mach_header* mh)
{
- uint32_t retval = 0;
- PlatformAndVersions pvs = getImagePlatformAndVersions((const Header*)mh);
-
- if ( pvs.platform == config.process.platform ) {
- retval = mapLegacyVersion(pvs.minOS, pvs.platform.basePlatform());
- }
-
+ __block bool versionFound = false;
+ __block uint32_t retval = 0;
+ forEachImageVersion(mh, ^(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version) {
+ if ( versionFound )
+ return;
+
+ if ( platform == (dyld_platform_t)config.process.platform ) {
+ versionFound = true;
+ switch ( MachOFile::basePlatform((dyld3::Platform)platform) ) {
+ case dyld3::Platform::bridgeOS:
+ retval = min_version + 0x00090000;
+ return;
+ case dyld3::Platform::watchOS:
+ retval = min_version + 0x00070000;
+ return;
+ default:
+ retval = min_version;
+ return;
+ }
+ }
+ else if ( platform == PLATFORM_IOSSIMULATOR && (dyld_platform_t)config.process.platform == PLATFORM_IOSMAC ) {
+ //FIXME bringup hack
+ versionFound = true;
+ retval = 0x000C0000;
+ }
+ });
if ( config.log.apis )
log("dyld_get_min_os_version(%p) => 0x%08X\n", mh, retval);
return retval;
@@ -474,7 +509,7 @@
dyld_platform_t APIs::dyld_get_active_platform(void)
{
- dyld_platform_t result = config.process.platform.value();
+ dyld_platform_t result = (dyld_platform_t)config.process.platform;
if ( config.log.apis )
log("dyld_get_active_platform() => %d\n", result);
return result;
@@ -482,7 +517,7 @@
dyld_platform_t APIs::dyld_get_base_platform(dyld_platform_t platform)
{
- dyld_platform_t result = Platform(platform).basePlatform().value();
+ dyld_platform_t result = (dyld_platform_t)MachOFile::basePlatform((dyld3::Platform)platform);
if ( config.log.apis )
log("dyld_get_base_platform(%d) => %d\n", platform, result);
return result;
@@ -490,13 +525,13 @@
bool APIs::dyld_is_simulator_platform(dyld_platform_t platform)
{
- bool result = Platform(platform).isSimulator();
+ bool result = MachOFile::isSimulatorPlatform((dyld3::Platform)platform);
if ( config.log.apis )
log("dyld_is_simulator_platform(%d) => %d\n", platform, result);
return result;
}
-dyld_build_version_t APIs::mapFromVersionSet(dyld_build_version_t versionSet, Platform platform)
+dyld_build_version_t APIs::mapFromVersionSet(dyld_build_version_t versionSet)
{
#if TARGET_OS_EXCLAVEKIT
return { 0, 0 }; //FIXME
@@ -513,35 +548,35 @@
if ( foundEntry == nullptr ) {
return { .platform = 0, .version = 0 };
}
- platform = platform.basePlatform();
- if ( platform == Platform::macOS )
- return { .platform = PLATFORM_MACOS, .version = foundEntry->macos };
- if ( platform == Platform::iOS )
- return { .platform = PLATFORM_IOS, .version = foundEntry->ios };
- if ( platform == Platform::watchOS )
- return { .platform = PLATFORM_WATCHOS, .version = foundEntry->watchos };
- if ( platform == Platform::tvOS )
- return { .platform = PLATFORM_TVOS, .version = foundEntry->tvos };
- if ( platform == Platform::bridgeOS )
- return { .platform = PLATFORM_BRIDGEOS, .version = foundEntry->bridgeos };
- if ( platform == Platform::visionOS )
- return { .platform = PLATFORM_VISIONOS, .version = foundEntry->visionos };
-
- return { .platform = (dyld_platform_t)platform.value(), .version = 0 };
+ switch ( MachOFile::basePlatform(config.process.platform) ) {
+ case dyld3::Platform::macOS:
+ return { .platform = PLATFORM_MACOS, .version = foundEntry->macos };
+ case dyld3::Platform::iOS:
+ return { .platform = PLATFORM_IOS, .version = foundEntry->ios };
+ case dyld3::Platform::watchOS:
+ return { .platform = PLATFORM_WATCHOS, .version = foundEntry->watchos };
+ case dyld3::Platform::tvOS:
+ return { .platform = PLATFORM_TVOS, .version = foundEntry->tvos };
+ case dyld3::Platform::bridgeOS:
+ return { .platform = PLATFORM_BRIDGEOS, .version = foundEntry->bridgeos };
+ default:
+ return { .platform = (dyld_platform_t)MachOFile::basePlatform(config.process.platform), .version = 0 };
+ }
#endif
}
bool APIs::dyld_sdk_at_least(const mach_header* mh, dyld_build_version_t atLeast)
{
- dyld_build_version_t concreteAtLeast = mapFromVersionSet(atLeast, config.process.platform);
- bool retval = false;
- PlatformAndVersions pvs = getImagePlatformAndVersions((const Header*)mh);
-
- if ( pvs.platform.basePlatform() == Platform(concreteAtLeast.platform).basePlatform() ) {
- if ( !pvs.platform.basePlatform().empty() && pvs.sdk.value() >= concreteAtLeast.version )
- retval = true;
- }
-
+ dyld_build_version_t concreteAtLeast = mapFromVersionSet(atLeast);
+ __block bool retval = false;
+ forEachImageVersion(mh, ^(dyld_platform_t imagePlatform, uint32_t imageSDK, uint32_t imageOS) {
+ if ( MachOFile::basePlatform((dyld3::Platform)imagePlatform) == MachOFile::basePlatform((dyld3::Platform)concreteAtLeast.platform) ) {
+ if ( MachOFile::basePlatform((dyld3::Platform)imagePlatform) == dyld3::Platform::unknown )
+ return;
+ if ( imageSDK >= concreteAtLeast.version )
+ retval = true;
+ }
+ });
if ( config.log.apis )
log("dyld_sdk_at_least(%p, <%d,0x%08X>) => %d\n", mh, atLeast.platform, atLeast.version, retval);
return retval;
@@ -549,15 +584,16 @@
bool APIs::dyld_minos_at_least(const mach_header* mh, dyld_build_version_t atLeast)
{
- dyld_build_version_t concreteAtLeast = mapFromVersionSet(atLeast, config.process.platform);
- bool retval = false;
- PlatformAndVersions pvs = getImagePlatformAndVersions((const Header*)mh);
-
- if ( pvs.platform.basePlatform() == Platform(concreteAtLeast.platform).basePlatform() ) {
- if ( !pvs.platform.basePlatform().empty() && pvs.minOS.value() >= concreteAtLeast.version )
- retval = true;
- }
-
+ dyld_build_version_t concreteAtLeast = mapFromVersionSet(atLeast);
+ __block bool retval = false;
+ forEachImageVersion(mh, ^(dyld_platform_t imagePlatform, uint32_t imageSDK, uint32_t imageMinOS) {
+ if ( MachOFile::basePlatform((dyld3::Platform)imagePlatform) == MachOFile::basePlatform((dyld3::Platform)concreteAtLeast.platform) ) {
+ if ( MachOFile::basePlatform((dyld3::Platform)imagePlatform) == dyld3::Platform::unknown )
+ return;
+ if ( imageMinOS >= concreteAtLeast.version )
+ retval = true;
+ }
+ });
if ( config.log.apis )
log("dyld_minos_at_least(%p, <%d,0x%08X>) => %d\n", mh, atLeast.platform, atLeast.version, retval);
return retval;
@@ -571,14 +607,14 @@
uint32_t currentVersion = 0;
bool defaultResult = true;
- if ( config.process.basePlatform.empty() ) {
+ if ( config.process.basePlatform == dyld3::Platform::unknown ) {
defaultResult = false;
}
if (version.platform == 0xffffffff) {
currentVersion = config.process.mainExecutableMinOSVersionSet;
- } else if (version.platform == config.process.basePlatform) {
+ } else if (version.platform == (dyld_platform_t)config.process.basePlatform) {
currentVersion = config.process.mainExecutableMinOSVersion;
- } else if (version.platform == config.process.platform) {
+ } else if (version.platform == (dyld_platform_t)config.process.platform) {
currentVersion = config.process.mainExecutableMinOSVersion;
} else {
// Hack
@@ -598,14 +634,14 @@
uint32_t currentVersion = 0;
bool defaultResult = true;
- if ( config.process.basePlatform.empty() ) {
+ if ( config.process.basePlatform == dyld3::Platform::unknown ) {
defaultResult = false;
}
if (version.platform == 0xffffffff) {
currentVersion = config.process.mainExecutableSDKVersionSet;
- } else if (version.platform == config.process.basePlatform) {
+ } else if (version.platform == (dyld_platform_t)config.process.basePlatform) {
currentVersion = config.process.mainExecutableSDKVersion;
- } else if (version.platform == config.process.platform) {
+ } else if (version.platform == (dyld_platform_t)config.process.platform) {
currentVersion = config.process.mainExecutableSDKVersion;
} else {
// Hack
@@ -617,148 +653,139 @@
return ( currentVersion >= version.version ) ? defaultResult : false;
}
-uint64_t APIs::dyld_get_program_sdk_version_token() {
- uint64_t result = 0;
- dyld_build_version_t* token = (dyld_build_version_t*)&result;
- token->platform = config.process.platform.value();
- token->version = config.process.mainExecutableSDKVersion;
- return result;
-}
-
-uint64_t APIs::dyld_get_program_minos_version_token() {
- uint64_t result = 0;
- dyld_build_version_t* token = (dyld_build_version_t*)&result;
- token->platform = config.process.platform.value();
- token->version = config.process.mainExecutableMinOSVersion;
- return result;
-}
-
-dyld_platform_t APIs::dyld_version_token_get_platform(uint64_t token) {
- dyld_build_version_t* versionToken = (dyld_build_version_t*)&token;
- return versionToken->platform;
-}
-
-
-bool APIs::dyld_version_token_at_least(uint64_t token, dyld_build_version_t version) {
- dyld_build_version_t tokenVersion = *(dyld_build_version_t*)&token;
- version = mapFromVersionSet(version, Platform(tokenVersion.platform));
- if (tokenVersion.platform
- && Platform(tokenVersion.platform).basePlatform() == version.platform
- && tokenVersion.version >= version.version) {
- return true;
- }
- return false;
-}
-
-Version32 APIs::linkedDylibVersion(const Header* header, const char* installname)
-{
- __block Version32 retval(0);
- header->forEachLinkedDylib(^(const char *loadPath, mach_o::LinkedDylibAttributes kind, Version32 compatVersion, Version32 currentVersion,
- bool synthesizedLink, bool& stop) {
+uint32_t APIs::linkedDylibVersion(const MachOFile* mf, const char* installname)
+{
+ __block uint32_t retval = 0;
+ mf->forEachDependentDylib(^(const char* loadPath, bool, bool, bool, uint32_t compatVersion, uint32_t currentVersion, bool& stop) {
if ( strcmp(loadPath, installname) == 0 ) {
retval = currentVersion;
stop = true;
}
});
-
return retval;
}
-Version32 APIs::deriveVersionFromDylibs(const Header* header)
+#define PACKED_VERSION(major, minor, tiny) ((((major)&0xffff) << 16) | (((minor)&0xff) << 8) | ((tiny)&0xff))
+
+uint32_t APIs::deriveVersionFromDylibs(const MachOFile* mf)
{
// This is a binary without a version load command, we need to infer things
struct DylibToOSMapping
{
- Version32 dylibVersion;
- Version32 osVersion;
+ uint32_t dylibVersion;
+ uint32_t osVersion;
};
- Version32 linkedVersion(0);
+ uint32_t linkedVersion = 0;
#if TARGET_OS_OSX
- linkedVersion = linkedDylibVersion(header, "/usr/lib/libSystem.B.dylib");
- static constinit const DylibToOSMapping versionMapping[] = {
- { { 88, 1, 3 }, Version32(0x000A0400) },
- { { 111, 0, 0 }, Version32(0x000A0500) },
- { { 123, 0, 0 }, Version32(0x000A0600) },
- { { 159, 0, 0 }, Version32(0x000A0700) },
- { { 169, 3, 0 }, Version32(0x000A0800) },
- { { 1197, 0, 0 }, Version32(0x000A0900) },
- { { 0, 0, 0 }, Version32(0x000A0900) }
+ linkedVersion = linkedDylibVersion(mf, "/usr/lib/libSystem.B.dylib");
+ static const DylibToOSMapping versionMapping[] = {
+ { PACKED_VERSION(88, 1, 3), 0x000A0400 },
+ { PACKED_VERSION(111, 0, 0), 0x000A0500 },
+ { PACKED_VERSION(123, 0, 0), 0x000A0600 },
+ { PACKED_VERSION(159, 0, 0), 0x000A0700 },
+ { PACKED_VERSION(169, 3, 0), 0x000A0800 },
+ { PACKED_VERSION(1197, 0, 0), 0x000A0900 },
+ { PACKED_VERSION(0, 0, 0), 0x000A0900 }
// We don't need to expand this table because all recent
// binaries have LC_VERSION_MIN_ load command.
};
+#elif TARGET_OS_IOS
+ linkedVersion = linkedDylibVersion(mf, "/System/Library/Frameworks/Foundation.framework/Foundation");
+ static const DylibToOSMapping versionMapping[] = {
+ { PACKED_VERSION(678, 24, 0), 0x00020000 },
+ { PACKED_VERSION(678, 26, 0), 0x00020100 },
+ { PACKED_VERSION(678, 29, 0), 0x00020200 },
+ { PACKED_VERSION(678, 47, 0), 0x00030000 },
+ { PACKED_VERSION(678, 51, 0), 0x00030100 },
+ { PACKED_VERSION(678, 60, 0), 0x00030200 },
+ { PACKED_VERSION(751, 32, 0), 0x00040000 },
+ { PACKED_VERSION(751, 37, 0), 0x00040100 },
+ { PACKED_VERSION(751, 49, 0), 0x00040200 },
+ { PACKED_VERSION(751, 58, 0), 0x00040300 },
+ { PACKED_VERSION(881, 0, 0), 0x00050000 },
+ { PACKED_VERSION(890, 1, 0), 0x00050100 },
+ { PACKED_VERSION(992, 0, 0), 0x00060000 },
+ { PACKED_VERSION(993, 0, 0), 0x00060100 },
+ { PACKED_VERSION(1038, 14, 0), 0x00070000 },
+ { PACKED_VERSION(0, 0, 0), 0x00070000 }
+ // We don't need to expand this table because all recent
+ // binaries have LC_VERSION_MIN_ load command.
+ };
#else
static const DylibToOSMapping versionMapping[] = {};
#endif
- if ( linkedVersion.value() != 0 ) {
- Version32 lastOsVersion(0);
- for ( const DylibToOSMapping& map : versionMapping ) {
- if ( map.dylibVersion.value() == 0 ) {
- return map.osVersion;
- }
- if ( linkedVersion < map.dylibVersion ) {
+ if ( linkedVersion != 0 ) {
+ uint32_t lastOsVersion = 0;
+ for ( const DylibToOSMapping* p = versionMapping;; ++p ) {
+ if ( p->dylibVersion == 0 ) {
+ return p->osVersion;
+ }
+ if ( linkedVersion < p->dylibVersion ) {
return lastOsVersion;
}
- lastOsVersion = map.osVersion;
- }
- }
- return Version32(0);
+ lastOsVersion = p->osVersion;
+ }
+ }
+ return 0;
}
// assumes mh has already been validated
-PlatformAndVersions APIs::getPlatformAndVersions(const Header* header)
-{
- PlatformAndVersions pvs = header->platformAndVersions();
- if ( !pvs.platform.empty() ) {
- // The origin LC_VERSION_MIN_MACOSX did not have an "sdk" field. It was reserved and set to zero.
- // If the sdk field is zero, we assume it is an old binary and try to backsolve for its SDK.
- if ( pvs.sdk.value() == 0 ) {
- pvs.sdk = deriveVersionFromDylibs(header);
- }
- return pvs;
- }
+void APIs::forEachPlatform(const MachOFile* mf, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version))
+{
+ __block bool lcFound = false;
+ mf->forEachSupportedPlatform(^(dyld3::Platform platform, uint32_t minOS, uint32_t sdk) {
+ lcFound = true;
+ // If SDK field is empty then derive the value from library linkages
+ if ( sdk == 0 ) {
+ sdk = deriveVersionFromDylibs(mf);
+ }
+ callback((const dyld_platform_t)platform, sdk, minOS);
+ });
// No load command was found, so again, fallback to deriving it from library linkages
- Platform platform = Platform::current();
- Version32 derivedVersion = deriveVersionFromDylibs(header);
- if ( derivedVersion.value() != 0 ) {
- return PlatformAndVersions(platform, derivedVersion, Version32(0));
- }
-
- return PlatformAndVersions(Platform(), Version32(0), Version32(0));
+ if ( !lcFound ) {
+#if TARGET_OS_IOS
+ #if __x86_64__ || __x86__
+ dyld_platform_t platform = PLATFORM_IOSSIMULATOR;
+ #else
+ dyld_platform_t platform = PLATFORM_IOS;
+ #endif
+#elif TARGET_OS_OSX
+ dyld_platform_t platform = PLATFORM_MACOS;
+#else
+ dyld_platform_t platform = 0;
+#endif
+ uint32_t derivedVersion = deriveVersionFromDylibs(mf);
+ if ( platform != 0 && derivedVersion != 0 ) {
+ callback(platform, derivedVersion, 0);
+ }
+ }
}
void APIs::dyld_get_image_versions(const mach_header* mh, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version))
{
if ( config.log.apis )
log("dyld_get_image_versions(%p, %p)\n", mh, callback);
- PlatformAndVersions pvs = getImagePlatformAndVersions((const Header*)mh);
- if ( !pvs.platform.empty() ) {
- pvs.unzip(^(PlatformAndVersions pvs2) {
- callback(pvs2.platform.value(), pvs2.sdk.value(), pvs2.minOS.value());
- });
- }
-}
-
-// getImagePlatformAndVersions will always return one PVS.
-PlatformAndVersions APIs::getImagePlatformAndVersions(const Header* hdr)
+ forEachImageVersion(mh, callback);
+}
+
+void APIs::forEachImageVersion(const mach_header* mh, void (^callback)(dyld_platform_t platform, uint32_t sdk_version, uint32_t min_version))
{
#if !TARGET_OS_EXCLAVEKIT
- if ( hdr == config.process.mainExecutableHdr ) {
+ Diagnostics diag;
+ const MachOFile* mf = (MachOFile*)mh;
+
+ if ( mh == config.process.mainExecutable ) {
// Special case main executable, that info is store in ProcessConfig
- return PlatformAndVersions(config.process.platform, Version32(config.process.mainExecutableMinOSVersion), Version32(config.process.mainExecutableSDKVersion));
- }
- else if ( DyldSharedCache::inDyldCache(config.dyldCache.addr, hdr) ) {
+ callback((dyld_platform_t)config.process.platform, config.process.mainExecutableSDKVersion, config.process.mainExecutableMinOSVersion);
+ }
+ else if ( DyldSharedCache::inDyldCache(config.dyldCache.addr, mf) ) {
// If the image is in the shared cache, then all versions OS and SDK versions are the same
- return PlatformAndVersions(config.dyldCache.platform, Version32(config.dyldCache.osVersion), Version32(config.dyldCache.osVersion));
- }
- else if ( hdr->hasMachOMagic() ) {
- // validiate load commands are well formed
- if ( mach_o::Error err = hdr->validStructureLoadCommands(0x10000) )
- return PlatformAndVersions(Platform(0), Version32(0), Version32(0));
+ callback((dyld_platform_t)config.dyldCache.platform, config.dyldCache.osVersion, config.dyldCache.osVersion);
+ }
+ else if ( mf->isMachO(diag, mh->sizeofcmds + sizeof(mach_header_64)) ) {
// look for LC_BUILD_VERSION or derive from dylib info
- return this->getPlatformAndVersions(hdr);
- } else {
- return PlatformAndVersions(Platform(0), Version32(0), Version32(0));
+ this->forEachPlatform(mf, callback);
}
#else
abort();
@@ -767,15 +794,15 @@
uint32_t APIs::dyld_get_program_min_os_version()
{
- return dyld_get_min_os_version(config.process.mainExecutableMF);
+ return dyld_get_min_os_version(config.process.mainExecutable);
}
bool APIs::_dyld_get_image_uuid(const mach_header* mh, uuid_t uuid)
{
if ( config.log.apis )
log("_dyld_get_image_uuid(%p, %p)\n", mh, uuid);
- const Header* header = (Header*)mh;
- return (header->hasMachOMagic() && header->getUuid(uuid));
+ const MachOFile* mf = (MachOFile*)mh;
+ return (mf->hasMachOMagic() && mf->getUuid(uuid));
}
int APIs::_NSGetExecutablePath(char* buf, uint32_t* bufsize)
@@ -783,7 +810,7 @@
if ( config.log.apis )
log("_NSGetExecutablePath(%p, %p)\n", buf, bufsize);
const char* path = config.process.mainExecutablePath;
- if ( config.process.platform == Platform::macOS )
+ if ( config.process.platform == dyld3::Platform::macOS )
path = config.process.mainUnrealPath; // Note: this is not real-path. It may be a symlink rdar://74451681
size_t pathSize = strlen(path) + 1;
if ( *bufsize >= pathSize ) {
@@ -794,10 +821,10 @@
return -1;
}
-void APIs::_dyld_register_func_for_add_image(NotifyFunc func)
-{
- if ( config.log.apis )
- log("_dyld_register_func_for_add_image(%p)\n", func.raw());
+void APIs::_dyld_register_func_for_add_image(void (*func)(const mach_header* mh, intptr_t slide))
+{
+ if ( config.log.apis )
+ log("_dyld_register_func_for_add_image(%p)\n", func);
#if !TARGET_OS_EXCLAVEKIT
// callback about already loaded images
locks.withLoadersReadLock(^{
@@ -812,14 +839,14 @@
}
for ( unsigned i = 0; i < count; ++i ) {
if ( config.log.notifications )
- log("add notifier %p called with mh=%p\n", func.raw(), mhs[i]);
+ log("add notifier %p called with mh=%p\n", func, mhs[i]);
func(mhs[i], slides[i]);
}
});
// add to list of functions to call about future loads
- const Loader* callbackLoader = this->findImageContaining(func.raw());
- locks.withNotifiersWriteLock(^{
+ const Loader* callbackLoader = this->findImageContaining((void*)func);
+ locks.withNotifiersWriteLock(memoryManager, ^() {
addNotifyAddFunc(callbackLoader, func);
});
#else
@@ -827,14 +854,14 @@
#endif // !TARGET_OS_EXCLAVEKIT
}
-void APIs::_dyld_register_func_for_remove_image(NotifyFunc func)
-{
- if ( config.log.apis )
- log("_dyld_register_func_for_remove_image(%p)\n", func.raw());
+void APIs::_dyld_register_func_for_remove_image(void (*func)(const mach_header* mh, intptr_t slide))
+{
+ if ( config.log.apis )
+ log("_dyld_register_func_for_remove_image(%p)\n", func);
#if !TARGET_OS_EXCLAVEKIT
// add to list of functions to call about future unloads
- const Loader* callbackLoader = this->findImageContaining(func.raw());
- locks.withNotifiersWriteLock(^{
+ const Loader* callbackLoader = this->findImageContaining((void*)func);
+ locks.withNotifiersWriteLock(memoryManager, ^() {
addNotifyRemoveFunc(callbackLoader, func);
});
#else
@@ -843,16 +870,14 @@
}
// FIXME: Remove this once libobjc moves to _dyld_objc_register_callbacks()
-void APIs::_dyld_objc_notify_register(ReadOnlyCallback<_dyld_objc_notify_mapped>,
- ReadOnlyCallback<_dyld_objc_notify_init>,
- ReadOnlyCallback<_dyld_objc_notify_unmapped>)
-{
-#if BUILDING_DYLD
+void APIs::_dyld_objc_notify_register(_dyld_objc_notify_mapped mapped,
+ _dyld_objc_notify_init init,
+ _dyld_objc_notify_unmapped unmapped)
+{
halt("_dyld_objc_notify_register is unsupported");
-#endif
-}
-
-void APIs::_dyld_objc_register_callbacks(const ObjCCallbacks* callbacks)
+}
+
+void APIs::_dyld_objc_register_callbacks(const _dyld_objc_callbacks* callbacks)
{
if ( config.log.apis ) {
void** p = (void**)callbacks;
@@ -860,28 +885,18 @@
}
if ( callbacks->version == 1 ) {
-#if BUILDING_DYLD
halt("_dyld_objc_register_callbacks v1 is no longer supported");
-#endif
}
else if ( callbacks->version == 2 ) {
-#if BUILDING_DYLD
- halt("_dyld_objc_register_callbacks v2 is no longer supported");
-#endif
+ const _dyld_objc_callbacks_v2* v2 = (const _dyld_objc_callbacks_v2*)callbacks;
+ setObjCNotifiers(v2->unmapped, v2->patches, v2->mapped, v2->init, nullptr);
}
else if ( callbacks->version == 3 ) {
-#if BUILDING_DYLD
- halt("_dyld_objc_register_callbacks v3 is no longer supported");
-#endif
- }
- else if ( callbacks->version == 4 ) {
- const ObjCCallbacksV4* v4 = (const ObjCCallbacksV4*)callbacks;
- setObjCNotifiers(v4->unmapped, v4->patches, v4->init, v4->mapped);
+ const _dyld_objc_callbacks_v3* v3 = (const _dyld_objc_callbacks_v3*)callbacks;
+ setObjCNotifiers(v3->unmapped, v3->patches, nullptr, v3->init, v3->mapped);
}
else {
-#if BUILDING_DYLD
halt("_dyld_objc_register_callbacks unknown version");
-#endif
}
#if SUPPORT_PREBUILTLOADERS
@@ -897,6 +912,7 @@
__block bool result = false;
bool inSharedCache = false;
+#if !TARGET_OS_EXCLAVEKIT
// if address is in cache, do fast search of TEXT segments in cache
const DyldSharedCache* dyldCache = config.dyldCache.addr;
if ( (dyldCache != nullptr) && (addr > dyldCache) ) {
@@ -955,7 +971,7 @@
if ( neverUnloads != nullptr )
*neverUnloads = true;
if ( path != nullptr )
- *path = ldr->path(*this);
+ *path = ldr->path();
if ( (segAddr != nullptr) || (segSize != nullptr) ) {
// only needed by _dyld_images_for_addresses()
const void* ldrSegAddr;
@@ -974,6 +990,7 @@
*loader = ldr;
return true;
}
+#endif // !TARGET_OS_EXCLAVEKIT
// slow path - search image list
locks.withLoadersReadLock(^{
@@ -990,7 +1007,7 @@
if ( neverUnloads != nullptr )
*neverUnloads = image->neverUnload;
if ( path != nullptr )
- *path = image->path(*this);
+ *path = image->path();
if ( segAddr != nullptr )
*segAddr = sgAddr;
if ( segSize != nullptr )
@@ -1046,21 +1063,19 @@
// if address is in cache, only TEXT is immutable
__block bool result = false;
+#if !TARGET_OS_EXCLAVEKIT
const DyldSharedCache* dyldCache = config.dyldCache.addr;
if ( (dyldCache != nullptr) && (addr > dyldCache) ) {
if ( addr < (void*)((uint8_t*)dyldCache + dyldCache->mappedSize()) ) {
dyldCache->forEachCache(^(const DyldSharedCache *cache, bool& stopCache) {
cache->forEachRegion(^(const void* content, uint64_t vmAddr, uint64_t size,
- uint32_t initProt, uint32_t maxProt, uint64_t flags,
- uint64_t fileOffset, bool& stopRegion) {
+ uint32_t initProt, uint32_t maxProt, uint64_t flags, bool& stopRegion) {
if ( (addr > content) && (((uint8_t*)addr + length) < ((uint8_t*)content + size)) ) {
// Note: in cache __DATA_CONST has initProt=1 and initProt=3
// we don't want __DATA_CONST to be considered immutable, so we check maxProt
bool writable = (maxProt & VM_PROT_WRITE);
if ( !writable )
result = true;
- stopRegion = true;
- stopCache = true;
}
});
});
@@ -1076,6 +1091,7 @@
result = !writable;
}
}
+#endif // !TARGET_OS_EXCLAVEKIT
if ( config.log.apis )
log("_dyld_is_memory_immutable(%p, %lu) => %d\n", addr, length, result);
return result;
@@ -1141,9 +1157,8 @@
if ( (dyldStart <= targetAddr) && (targetAddr < dyldStart + 0x200000) ) {
uint64_t slide = (uintptr_t)&__dso_handle; // dyld is always zero based
__block bool inDyld = false;
- const Header* mh = (const Header*)&__dso_handle;
- mh->forEachSegment(^(const Header::SegmentInfo& segInfo, bool& stop) {
- if ( ((segInfo.vmaddr + slide) <= targetAddr) && (targetAddr < (segInfo.vmaddr + slide + segInfo.vmsize)) ) {
+ __dso_handle.forEachSegment(^(const MachOAnalyzer::SegmentInfo& segInfo, bool& stop) {
+ if ( ((segInfo.vmAddr + slide) <= targetAddr) && (targetAddr < (segInfo.vmAddr + slide + segInfo.vmSize)) ) {
inDyld = true;
stop = true;
}
@@ -1159,10 +1174,14 @@
info->dli_sname = nullptr;
info->dli_saddr = nullptr;
}
- else if ( info->dli_sname != nullptr ) {
- // strip off leading underscore
- if ( info->dli_sname[0] == '_')
- info->dli_sname = info->dli_sname + 1;
+ // strip off leading underscore
+ else if ( (info->dli_sname != nullptr) && (info->dli_sname[0] == '_') ) {
+ info->dli_sname = info->dli_sname + 1;
+ }
+ if ( strcmp(info->dli_sname, "_ZN5dyld45startEPKNS_10KernelArgsE") == 0 ) {
+ // start (which calls main()) is now in dyld, so be nice and allow dladdr() to return that
+ info->dli_sname = "start";
+ info->dli_saddr = (void*)addr;
}
}
}
@@ -1176,30 +1195,24 @@
struct PerThreadErrorMessage
{
+ size_t sizeAllocated;
bool valid;
char message[1];
};
-
-#if !TARGET_OS_DRIVERKIT
void APIs::clearErrorString()
{
+ if ( (dlerrorPthreadKey() == -1) || !libSystemInitialized() )
+ return;
+ PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)this->libSystemHelpers->pthread_getspecific(dlerrorPthreadKey());
+ if ( errorBuffer != nullptr )
+ errorBuffer->valid = false;
+}
+
+void APIs::setErrorString(const char* format, ...)
+{
// if dlopen/dlsym called before libSystem initialized, dlerrorPthreadKey() won't be set, and malloc won't be available
- if ( (dlerrorPthreadKey() == -1) || !libdyldInitialized() )
- return;
-
- if ( PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)this->libSystemHelpers.pthread_getspecific(dlerrorPthreadKey()) ) {
- if ( this->libSystemHelpers.malloc_size(errorBuffer) == 0 )
- this->libSystemHelpers.pthread_setspecific(dlerrorPthreadKey(), nullptr);
- else
- errorBuffer->valid = false;
- }
-}
-
-void APIs::setErrorString(const char* format, ...)
-{
- // if dlopen/dlsym called before libSystem initialized, dlerrorPthreadKey() won't be set, and malloc won't be available
- if ( (dlerrorPthreadKey() == -1) || !libdyldInitialized() )
+ if ( (dlerrorPthreadKey() == -1) || !libSystemInitialized() )
return;
#if !TARGET_OS_EXCLAVEKIT
@@ -1221,34 +1234,29 @@
size_t strLen = strlen(buf) + 1;
#endif // !TARGET_OS_EXCLAVEKIT
- size_t sizeNeeded = std::max(offsetof(PerThreadErrorMessage, message[strLen]), (size_t)256);
- PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)this->libSystemHelpers.pthread_getspecific(dlerrorPthreadKey());
- bool doAllocate = false;
+ size_t sizeNeeded = sizeof(PerThreadErrorMessage) + strLen;
+ PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)this->libSystemHelpers->pthread_getspecific(dlerrorPthreadKey());
+ if ( errorBuffer != nullptr ) {
+ if ( errorBuffer->sizeAllocated < sizeNeeded ) {
+ this->libSystemHelpers->free(errorBuffer);
+ errorBuffer = nullptr;
+ }
+ }
if ( errorBuffer == nullptr ) {
- doAllocate = true;
- }
- else {
- // check buffer is owned by malloc
- size_t size = this->libSystemHelpers.malloc_size(errorBuffer);
- if ( size == 0 ) {
- doAllocate = true;
- }
- else if ( size < sizeNeeded ) {
- // existing buffer too small, free and allocate new buffer
- this->libSystemHelpers.free(errorBuffer);
- doAllocate = true;
- }
- }
- if ( doAllocate ) {
- errorBuffer = (PerThreadErrorMessage*)this->libSystemHelpers.malloc(sizeNeeded);
- this->libSystemHelpers.pthread_setspecific(dlerrorPthreadKey(), errorBuffer);
+ size_t allocSize = std::max(sizeNeeded, (size_t)256);
+ // dlerrorPthreadKey is set up to call libSystem's free() on thread destruction, so this has to use libSystem's malloc()
+ PerThreadErrorMessage* p = (PerThreadErrorMessage*)this->libSystemHelpers->malloc(allocSize);
+ p->sizeAllocated = allocSize;
+ p->valid = false;
+ this->libSystemHelpers->pthread_setspecific(dlerrorPthreadKey(), p);
+ errorBuffer = p;
}
#if !TARGET_OS_EXCLAVEKIT
- strlcpy(errorBuffer->message, _simple_string(buf), sizeNeeded-1);
+ strcpy(errorBuffer->message, _simple_string(buf));
errorBuffer->valid = true;
_simple_sfree(buf);
#else
- strlcpy(errorBuffer->message, buf, sizeNeeded-1);
+ strlcpy(errorBuffer->message, buf, errorBuffer->sizeAllocated);
errorBuffer->valid = true;
#endif // !TARGET_OS_EXCLAVEKIT
}
@@ -1258,19 +1266,16 @@
if ( config.log.apis )
log("dlerror()");
- if ( (dlerrorPthreadKey() == -1) || !libdyldInitialized() )
+ if ( (dlerrorPthreadKey() == -1) || !libSystemInitialized() )
return nullptr; // if dlopen/dlsym called before libSystem initialized, dlerrorPthreadKey() won't be set
-
- PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)this->libSystemHelpers.pthread_getspecific(dlerrorPthreadKey());
+ PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)this->libSystemHelpers->pthread_getspecific(dlerrorPthreadKey());
if ( errorBuffer != nullptr ) {
- if ( this->libSystemHelpers.malloc_size(errorBuffer) != 0 ) {
- if ( errorBuffer->valid ) {
- // you can only call dlerror() once, then the message is cleared
- errorBuffer->valid = false;
- if ( config.log.apis )
- log(" => '%s'\n", errorBuffer->message);
- return errorBuffer->message;
- }
+ if ( errorBuffer->valid ) {
+ // you can only call dlerror() once, then the message is cleared
+ errorBuffer->valid = false;
+ if ( config.log.apis )
+ log(" => '%s'\n", errorBuffer->message);
+ return errorBuffer->message;
}
}
if ( config.log.apis )
@@ -1278,9 +1283,8 @@
return nullptr;
}
-#endif // !TARGET_OS_DRIVERKIT
-
-const Loader* APIs::findImageContaining(const void* addr)
+
+const Loader* APIs::findImageContaining(void* addr)
{
addr = (void*)stripPointer(addr);
__block const Loader* result = nullptr;
@@ -1298,7 +1302,6 @@
return result;
}
-#if !TARGET_OS_DRIVERKIT
void* APIs::dlopen(const char* path, int mode)
{
void* callerAddress = __builtin_return_address(0);
@@ -1311,14 +1314,13 @@
void* APIs::dlopen_from(const char* path, int mode, void* addressInCaller)
{
#if SUPPPORT_PRE_LC_MAIN
- if (!libdyldInitialized()) {
+ if (!libSystemInitialized()) {
// Usually libSystem will already be initialized, but some legacy binaries can call dlopen() first. If they do then
// we need to force initialization of libSystem at that time. The reason is any library will link to libSystem and
// trigger its initializers anyway, but until libSystem is up unfair locks don't work. If we let that happen we will
// skip taking the api lock on entry, but will try to unlock it on release triggering a lock assertion
const_cast<Loader*>(this->libSystemLoader)->beginInitializers(*this);
this->libSystemLoader->runInitializers(*this);
- this->setLibSystemInitialized();
}
#endif
dyld3::ScopedTimer timer(DBG_DYLD_TIMING_DLOPEN, path, mode, 0);
@@ -1367,341 +1369,242 @@
void* result = nullptr;
const Loader* topLoader = nullptr;
- MemoryManager::withWritableMemory([&] {
- // Put these on the persistent allocator as we can't keep them on the regular stack
- typedef Vector<const Loader*> LoaderVector;
- typedef Vector<Loader::PseudoDylibSymbolToMaterialize> PseudoDylibSymbolsVector;
- UniquePtr<LoaderVector> newlyNotDelayedResult;
- UniquePtr<PseudoDylibSymbolsVector> pseudoDylibSymbolsToMaterializeResult;
-
- locks.withLoadersWriteLockAndProtectedStack([&] {
- // since we have the dyld lock, any appends to state.loaded will be from this dlopen
- // so record the length now, and cut it back to that point if dlopen fails
- const uint64_t startLoaderCount = loaded.size();
- const uint64_t startPatchedObjCClassesCount = this->patchedObjCClasses.size();
- const uint64_t startPatchedSingletonsCount = this->patchedSingletons.size();
- Diagnostics diag;
-
- // try to load specified dylib
- Loader::LoadChain loadChainMain { nullptr, mainExecutableLoader };
- Loader::LoadChain loadChainCaller { &loadChainMain, caller };
- Loader::LoadOptions options;
- options.staticLinkage = false;
- options.launching = false;
- options.canBeMissing = false;
- options.rtldLocal = (mode & RTLD_LOCAL);
- options.rtldNoDelete = (mode & RTLD_NODELETE);
- options.rtldNoLoad = (mode & RTLD_NOLOAD);
- options.insertedDylib = false;
- options.canBeDylib = true;
- options.canBeBundle = true;
- // only allow dlopen() of main executables on macOS (eventually ban there too)
+ STACK_ALLOC_VECTOR(const Loader*, loadersToNotify, 32);
+ STACK_ALLOC_VECTOR(const Loader*, loadersUnDelayed, 32);
+ locks.withLoadersWriteLock(memoryManager, [&] {
+ // since we have the dyld lock, any appends to state.loaded will be from this dlopen
+ // so record the length now, and cut it back to that point if dlopen fails
+ const uint64_t startLoaderCount = loaded.size();
+ const uint64_t startPatchedObjCClassesCount = this->patchedObjCClasses.size();
+ const uint64_t startPatchedSingletonsCount = this->patchedSingletons.size();
+ Diagnostics diag;
+
+ // try to load specified dylib
+ Loader::LoadChain loadChainMain { nullptr, mainExecutableLoader };
+ Loader::LoadChain loadChainCaller { &loadChainMain, caller };
+ Loader::LoadOptions options;
+ options.staticLinkage = false;
+ options.launching = false;
+ options.canBeMissing = false;
+ options.rtldLocal = (mode & RTLD_LOCAL);
+ options.rtldNoDelete = (mode & RTLD_NODELETE);
+ options.rtldNoLoad = (mode & RTLD_NOLOAD);
+ options.insertedDylib = false;
+ options.canBeDylib = true;
+ options.canBeBundle = true;
+ // only allow dlopen() of main executables on macOS (eventually ban there too)
#if TARGET_OS_SIMULATOR
- options.canBeExecutable = (strncmp(config.process.progname, "IBDesignablesAgent", 18) == 0);
-#else
- options.canBeExecutable = (config.process.platform == Platform::macOS);
+ options.canBeExecutable = (strncmp(config.process.progname, "IBDesignablesAgent", 18) == 0);
+#else
+ options.canBeExecutable = (config.process.platform == dyld3::Platform::macOS);
#endif
- options.forceUnloadable = (mode & RTLD_UNLOADABLE);
- options.requestorNeedsFallbacks = caller ? caller->pre2022Binary : false;
- options.rpathStack = (caller ? &loadChainCaller : &loadChainMain);
- options.finder = nullptr;
- topLoader = Loader::getLoader(diag, *this, path, options);
- if ( topLoader == nullptr ) {
- setErrorString("dlopen(%s, 0x%04X): %s", path, mode, diag.errorMessageCStr());
- return;
- }
-
- // if RTLD_LOCAL was *not* used, and image was already loaded hidden, then unhide it
- if ( ((mode & RTLD_LOCAL) == 0) && topLoader->hiddenFromFlat() )
- topLoader->hiddenFromFlat(true);
-
- // RTLD_NOLOAD means don't load if not already loaded
- if ( mode & RTLD_NOLOAD ) {
+ options.forceUnloadable = (mode & RTLD_UNLOADABLE);
+ options.requestorNeedsFallbacks = caller ? caller->pre2022Binary : false;
+ options.rpathStack = (caller ? &loadChainCaller : &loadChainMain);
+ options.finder = nullptr;
+ topLoader = Loader::getLoader(diag, *this, path, options);
+ if ( topLoader == nullptr ) {
+ setErrorString("dlopen(%s, 0x%04X): %s", path, mode, diag.errorMessageCStr());
+ return;
+ }
+
+ // if RTLD_LOCAL was *not* used, and image was already loaded hidden, then unhide it
+ if ( ((mode & RTLD_LOCAL) == 0) && topLoader->hiddenFromFlat() )
+ topLoader->hiddenFromFlat(true);
+
+ // RTLD_NOLOAD means don't load if not already loaded
+ if ( mode & RTLD_NOLOAD ) {
#if SUPPORT_IMAGE_UNLOADING
- incDlRefCount(topLoader);
+ incDlRefCount(topLoader);
#endif // SUPPORT_IMAGE_UNLOADING
- result = handleFromLoader(topLoader, firstOnly);
- return;
- }
-
- // if RTLD_NODELETE is used on any dlopen, it sets the leavedMapped bit
- if ( mode & RTLD_NODELETE ) {
- // dylibs in cache, or dylibs statically link will always remain, so RTLD_NODELETE is already in effect
- if ( !topLoader->dylibInDyldCache && !topLoader->neverUnload && !topLoader->leaveMapped ) {
- // PrebuiltLoaders are never used for things that can be unloaded, so ignore
- if ( !topLoader->isPrebuilt ) {
- JustInTimeLoader* jitLoader = (JustInTimeLoader*)topLoader;
- jitLoader->setLateLeaveMapped();
- }
+ result = handleFromLoader(topLoader, firstOnly);
+ return;
+ }
+
+ // if RTLD_NODELETE is used on any dlopen, it sets the leavedMapped bit
+ if ( mode & RTLD_NODELETE ) {
+ // dylibs in cache, or dylibs statically link will always remain, so RTLD_NODELETE is already in effect
+ if ( !topLoader->dylibInDyldCache && !topLoader->neverUnload && !topLoader->leaveMapped ) {
+ // PrebuiltLoaders are never used for things that can be unloaded, so ignore
+ if ( !topLoader->isPrebuilt ) {
+ JustInTimeLoader* jitLoader = (JustInTimeLoader*)topLoader;
+ jitLoader->setLateLeaveMapped();
}
}
-
- STACK_ALLOC_VECTOR(const Loader*, newlyNotDelayed, 128);
- STACK_ALLOC_VECTOR(Loader::PseudoDylibSymbolToMaterialize, pseudoDylibSymbolsToMaterialize, 8);
-
- // load all dependents
- Loader::LoadChain loadChain { options.rpathStack, topLoader };
- Loader::LoadOptions depOptions;
- depOptions.staticLinkage = true;
- depOptions.rtldLocal = false; // RTLD_LOCAL only effects top level dylib
- depOptions.rtldNoDelete = (mode & RTLD_NODELETE);
- depOptions.canBeDylib = true;
- depOptions.requestorNeedsFallbacks = topLoader->pre2022Binary;
- depOptions.rpathStack = &loadChain;
- ((Loader*)topLoader)->loadDependents(diag, *this, depOptions);
- // only do fixups and notifications if new dylibs are loaded (could be dlopen that just bumps the ref count)
- STACK_ALLOC_VECTOR(const Loader*, newLoaders, loaded.size() - startLoaderCount);
- for (uint64_t i = startLoaderCount; i != loaded.size(); ++i)
- newLoaders.push_back(loaded[i]);
-
- DyldCacheDataConstLazyScopedWriter cacheDataConst(*this);
- if ( diag.noError() && !newLoaders.empty() ) {
- // proactive weakDefMap means we update the weakDefMap with everything just loaded before doing any binding
- if ( config.process.proactivelyUseWeakDefMap ) {
- Loader::addWeakDefsToMap(*this, newLoaders);
+ }
+
+ // load all dependents
+ Loader::LoadChain loadChain { options.rpathStack, topLoader };
+ Loader::LoadOptions depOptions;
+ depOptions.staticLinkage = true;
+ depOptions.rtldLocal = false; // RTLD_LOCAL only effects top level dylib
+ depOptions.rtldNoDelete = (mode & RTLD_NODELETE);
+ depOptions.canBeDylib = true;
+ depOptions.requestorNeedsFallbacks = topLoader->pre2022Binary;
+ depOptions.rpathStack = &loadChain;
+ ((Loader*)topLoader)->loadDependents(diag, *this, depOptions);
+ // only do fixups and notifications if new dylibs are loaded (could be dlopen that just bumps the ref count)
+ STACK_ALLOC_VECTOR(const Loader*, newLoaders, loaded.size() - startLoaderCount);
+ for (uint64_t i = startLoaderCount; i != loaded.size(); ++i)
+ newLoaders.push_back(loaded[i]);
+
+ DyldCacheDataConstLazyScopedWriter cacheDataConst(*this);
+ if ( diag.noError() && !newLoaders.empty() ) {
+ // tell debugger about newly loaded images in case there is a crash during fixups
+ notifyDebuggerLoad(newLoaders);
+
+ // proactive weakDefMap means we update the weakDefMap with everything just loaded before doing any binding
+ if ( config.process.proactivelyUseWeakDefMap ) {
+ Loader::addWeakDefsToMap(*this, newLoaders);
+ }
+
+ // do fixups
+ {
+ dyld3::ScopedTimer fixupsTimer(DBG_DYLD_TIMING_APPLY_FIXUPS, 0, 0, 0);
+
+ for ( const Loader* ldr : newLoaders ) {
+ bool allowLazyBinds = ((mode & RTLD_NOW) == 0);
+ ldr->applyFixups(diag, *this, cacheDataConst, allowLazyBinds);
+ if ( diag.hasError() )
+ break;
+#if BUILDING_DYLD && !TARGET_OS_EXCLAVEKIT
+ // Roots need to patch the uniqued GOTs in the cache
+ //FIXME: Is the right place to conditionalize this?
+ ldr->applyCachePatches(*this, cacheDataConst);
+#endif // BUILDING_DYLD && !TARGET_OS_EXCLAVEKIT
}
-
- // do fixups
- {
- dyld3::ScopedTimer fixupsTimer(DBG_DYLD_TIMING_APPLY_FIXUPS, 0, 0, 0);
-
- for ( const Loader* ldr : newLoaders ) {
- bool allowLazyBinds = ((mode & RTLD_NOW) == 0);
- ldr->applyFixups(diag, *this, cacheDataConst, allowLazyBinds, &pseudoDylibSymbolsToMaterialize);
- if ( diag.hasError() )
- break;
-#if BUILDING_DYLD
- // Roots need to patch the uniqued GOTs in the cache
- //FIXME: Is the right place to conditionalize this?
- ldr->applyCachePatches(*this, cacheDataConst);
-#endif // BUILDING_DYLD &&
- }
+ }
+
+ if ( diag.noError() ) {
+ // add to permanent ranges
+ STACK_ALLOC_ARRAY(const Loader*, nonCacheNeverUnloadLoaders, newLoaders.size());
+ for (const Loader* ldr : newLoaders) {
+ if ( !ldr->dylibInDyldCache && ldr->neverUnload )
+ nonCacheNeverUnloadLoaders.push_back(ldr);
}
-
- if ( diag.noError() ) {
- // add to permanent ranges
- STACK_ALLOC_ARRAY(const Loader*, nonCacheNeverUnloadLoaders, newLoaders.size());
- for (const Loader* ldr : newLoaders) {
- if ( !ldr->dylibInDyldCache && ldr->neverUnload )
- nonCacheNeverUnloadLoaders.push_back(ldr);
-#if TARGET_OS_EXCLAVEKIT
-#ifdef XRT_PLATFORM_PREMAPPED_CACHE_MACHO_FINALIZE_MEMORY_STATE
- // Notify ExclavePlatform that it is safe to setup endpoints in Mach-O sections
- if ( ldr->dylibInDyldCache ) {
- const Header* hdr = ldr->header(*this);
- int64_t slide = hdr->getSlide();
- xrt_platform_premapped_cache_macho_finalize_memory_state((void*)hdr, slide);
- }
-#endif // XRT_PLATFORM_PREMAPPED_CACHE_MACHO_FINALIZE_MEMORY_STATE
+ if ( !nonCacheNeverUnloadLoaders.empty() )
+ this->addPermanentRanges(nonCacheNeverUnloadLoaders);
+
+#if !TARGET_OS_EXCLAVEKIT
+ // notify kernel about new static user probes
+ notifyDtrace(newLoaders);
#endif // !TARGET_OS_EXCLAVEKIT
- }
- if ( !nonCacheNeverUnloadLoaders.empty() )
- this->addPermanentRanges(nonCacheNeverUnloadLoaders);
-
-#if !TARGET_OS_EXCLAVEKIT
- // notify kernel about new static user probes
- notifyDtrace(newLoaders);
-#endif // !TARGET_OS_EXCLAVEKIT
-
- // If any previous images had missing flat lazy symbols, try bind them again now
- rebindMissingFlatLazySymbols(newLoaders);
+
+ // If any previous images had missing flat lazy symbols, try bind them again now
+ rebindMissingFlatLazySymbols(newLoaders);
+
+ // if image has thread locals, set them up
+ for ( const Loader* ldr : newLoaders ) {
+ const MachOAnalyzer* ma = ldr->analyzer(*this);
+ if ( ma->hasThreadLocalVariables() )
+ setUpTLVs(ma);
}
- }
+
+ // Store loaders to be notified later
+ loadersToNotify.reserve(newLoaders.size());
+ for (const Loader* ldr : newLoaders)
+ loadersToNotify.push_back(ldr);
+ }
+ }
#if SUPPORT_IMAGE_UNLOADING
- // increment ref count before notifiers are called and before initializers are run,
- // because either of those could call dlclose() and cause a garbage collection.
- if ( diag.noError() )
- incDlRefCount(topLoader);
+ // increment ref count before notifiers are called and before initializers are run,
+ // because either of those could call dlclose() and cause a garbage collection.
+ if ( diag.noError() )
+ incDlRefCount(topLoader);
#endif // SUPPORT_IMAGE_UNLOADING
- // If there was an error while loading or doing fixups, then unload everything added in this dlopen.
- // This has to be done while we still have the LoadersLock
- if ( diag.hasError() ) {
- setErrorString("dlopen(%s, 0x%04X): %s", path, mode, diag.errorMessageCStr());
-
- // Remove missing lazy symbols for the new loaders. These were recorded eagerly during symbol binding
- removeMissingFlatLazySymbols(newLoaders);
-
- // remove any entries these temp dylibs may have map in the weak-def map
- if ( this->weakDefMap != nullptr ) {
- for ( const Loader* incompleteLoader : newLoaders )
- this->removeDynamicDependencies(incompleteLoader);
- }
+ // If there was an error while loading or doing fixups, then unload everything added in this dlopen.
+ // This has to be done while we still have the LoadersLock
+ if ( diag.hasError() ) {
+ setErrorString("dlopen(%s, 0x%04X): %s", path, mode, diag.errorMessageCStr());
+
+ // Remove missing lazy symbols for the new loaders. These were recorded eagerly during symbol binding
+ removeMissingFlatLazySymbols(newLoaders);
+
+ // remove any entries these temp dylibs may have map in the weak-def map
+ if ( this->weakDefMap != nullptr ) {
+ for ( const Loader* incompleteLoader : newLoaders )
+ this->removeDynamicDependencies(incompleteLoader);
+ }
+
+ // Remove the loaders from the image lists
+ notifyDebuggerUnload(newLoaders);
#if SUPPORT_IMAGE_UNLOADING
- // unmap everthing just loaded (note: unmap() does not unmap stuff in shared cache)
- for ( const Loader* ldr : newLoaders )
- ldr->unmap(*this, true);
+ // unmap everthing just loaded (note: unmap() does not unmap stuff in shared cache)
+ for ( const Loader* ldr : newLoaders )
+ ldr->unmap(*this, true);
#endif
-
- // remove new loaders from runtime list
- while ( loaded.size() > startLoaderCount ) {
- //const Loader* removeeLdr = loaded.back();
- //log("removing %p from state.loaded (%s)\n", removeeLdr, removeeLdr->path(*this));
- loaded.pop_back();
- // FIXME: free malloced JITLoaders
- }
- result = nullptr;
- topLoader = nullptr;
-
- // Clear any potential objc patching entries from the lists. We aren't going to do patching
- // on these binaries as the dlopen failed
- this->objcReplacementClasses.clear();
- while ( this->patchedObjCClasses.size() > startPatchedObjCClassesCount ) {
- this->patchedObjCClasses.pop_back();
- }
- while ( this->patchedSingletons.size() > startPatchedSingletonsCount ) {
- this->patchedSingletons.pop_back();
- }
- }
-
- // on success, run objc notifiers. This has to be done while still in the write lock as
- // the notifier mutates the list of objc classes
- if ( (topLoader != nullptr) && ((mode & RTLD_NOLOAD) == 0) && diag.noError() ) {
- const Loader* rootLoaders[1] = { topLoader };
- std::span<const Loader*> rootLoadersSpan(rootLoaders, 1);
-#if BUILDING_DYLD
- partitionDelayLoads(newLoaders, rootLoadersSpan, &newlyNotDelayed);
- if ( !config.log.linksWith.empty() ) {
- char callerName[256];
- strlcpy(callerName, "dlopen", sizeof(callerName));
- if ( caller != nullptr ) {
- strlcpy(callerName, caller->leafName(*this), sizeof(callerName));
- strlcat(callerName, ": dlopen(", sizeof(callerName));
- strlcat(callerName, topLoader->leafName(*this), sizeof(callerName));
- strlcat(callerName, ")", sizeof(callerName));
- }
- topLoader->logChainToLinksWith(*this, callerName);
- }
-#endif
- // tell debugger about newly loaded images or newly undelayed images
- if ( !newlyNotDelayed.empty() ) {
- std::span<const Loader*> ldrs(&newlyNotDelayed[0], (size_t)newlyNotDelayed.size());
- notifyDebuggerLoad(ldrs);
- }
-
-#if BUILDING_DYLD
- // if image has thread locals, set them up
- for ( const Loader* ldr : newlyNotDelayed ) {
- if ( ldr->hasTLVs ) {
- if ( mach_o::Error err = this->libSystemHelpers.setUpThreadLocals(config.dyldCache.addr, ldr->header(*this)) ) {
- diag.error("failed to set up thread local variables for '%s': %s", ldr->path(*this), err.message());
- }
- }
- }
-#endif
- doSingletonPatching(cacheDataConst);
- notifyObjCPatching();
- }
-
- // Copy the temporary vectors from the protected stack to the persistent allocator for safety
- if ( !newlyNotDelayed.empty() ) {
- newlyNotDelayedResult = persistentAllocator.makeUnique<LoaderVector>(newlyNotDelayed.begin(), newlyNotDelayed.end(),
- persistentAllocator);
- }
- if ( !pseudoDylibSymbolsToMaterialize.empty() ) {
- pseudoDylibSymbolsToMaterializeResult = persistentAllocator.makeUnique<PseudoDylibSymbolsVector>(pseudoDylibSymbolsToMaterialize.begin(),
- pseudoDylibSymbolsToMaterialize.end(),
- persistentAllocator);
- }
- });
-
- // do the initializers on the regular stack. We should never be on the protected stack at this point
- // as it is not supported to re-enter dlopen (from an initializer doing a dlopen) while on the protected stack
- // ie, withProtectedStack() asserts that no-one is using the protected stack, even this thread in an earlier frame
- // Finalize requested symbols.
- if ( pseudoDylibSymbolsToMaterializeResult && !pseudoDylibSymbolsToMaterializeResult->empty() ) {
- const PseudoDylibSymbolsVector& pseudoDylibSymbolsToMaterialize = *pseudoDylibSymbolsToMaterializeResult;
- bool foundError = false;
-
- // n^2, but oh well, maybe there's not too many pseudo dylibs to worry about
- STACK_ALLOC_VECTOR(const Loader*, seenLoaders, 8);
- for ( uint64_t i = 0; i != pseudoDylibSymbolsToMaterialize.size(); ++i ) {
- const Loader::PseudoDylibSymbolToMaterialize& ldrAndSymbol = pseudoDylibSymbolsToMaterialize[i];
- if ( std::find(seenLoaders.begin(), seenLoaders.end(), ldrAndSymbol.first) != seenLoaders.end() )
- continue;
-
- // Get all the symbols for this loader
- STACK_ALLOC_VECTOR(const char *, symbols, 8);
- symbols.push_back(ldrAndSymbol.second);
- for ( uint64_t j = (i + 1); j != pseudoDylibSymbolsToMaterialize.size(); ++j ) {
- const Loader::PseudoDylibSymbolToMaterialize& ldrAndSymbol2 = pseudoDylibSymbolsToMaterialize[j];
- if ( ldrAndSymbol2.first == ldrAndSymbol.first )
- symbols.push_back(ldrAndSymbol2.second);
- }
-
- const PseudoDylib* pd = ldrAndSymbol.first->isJustInTimeLoader()->pseudoDylib();
- if ( char *errMsg = pd->finalizeRequestedSymbols(symbols)) {
- // TODO: roll back image loads above on failure.
- setErrorString("dlopen(%s, 0x%04X): %s", path, mode, errMsg);
- pd->disposeString(errMsg);
- foundError = true;
- break;
- }
-
- seenLoaders.push_back(ldrAndSymbol.first);
- }
-
- if ( foundError ) {
- result = nullptr;
- topLoader = nullptr;
- }
- }
-
- // on success, run initializers
- if ( (topLoader != nullptr) && ((mode & RTLD_NOLOAD) == 0) ) {
- // Note: we have released the withLoadersWriteLock while running the notifiers/initializers
- // This is intentional to avoid deadlocks with other framework locks, that might call dyld
- // inquiry functions now (such as walking loaded images).
- // It is safe, because we still have the API-lock, so no other thread can call dlclose() and remove
- // the images that are having their notifiers/initializers run. A initializer may call dlopen() again and
- // add more images, but that will be on the same thread as this, so the ivar in Loaders about if
- // its initializer has been run does not need to be thread safe.
-
- // notify about any delay-init dylibs that just got moved to being needed
- // as well as images loaded by this dlopen that are not delayed
- if ( newlyNotDelayedResult && !newlyNotDelayedResult->empty() ) {
- LoaderVector& vec = *newlyNotDelayedResult;
- std::span<const Loader*> ldrs(&vec[0], (size_t)vec.size());
- notifyLoad(ldrs);
- }
-
- // run initializers (don't run them if dlopen() call was within libSystem's initializer)
- bool runInitializer = this->libSystemInitialized(); // lib system initialized
- #if SUPPPORT_PRE_LC_MAIN
- // if this is a pre-10.8 macOS main executable, do run initializer (rdar://130506337)
- if ( !runInitializer && (this->config.process.mainExecutableHdr->unixThreadLoadCommand() != nullptr) )
- runInitializer = true;
- #endif
- if ( runInitializer )
- topLoader->runInitializersBottomUpPlusUpwardLinks(*this);
- else if ( this->config.log.initializers )
- log("dlopen() within libSystem's initializer, so skipping initialization of %s\n", topLoader->path(*this));
-
- // make handle
- result = handleFromLoader(topLoader, firstOnly);
- }
-
- // Clear the data on the persistent allocator. We do this with a lock for the allocator
- if ( newlyNotDelayedResult || pseudoDylibSymbolsToMaterializeResult ) {
- locks.withLoadersWriteLockAndProtectedStack([&] {
- if ( newlyNotDelayedResult )
- newlyNotDelayedResult.release();
- if ( pseudoDylibSymbolsToMaterializeResult )
- pseudoDylibSymbolsToMaterializeResult.release();
- });
- }
-
- if ( config.log.apis ) {
- PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)this->libSystemHelpers.pthread_getspecific(dlerrorPthreadKey());
- if ( (errorBuffer != nullptr) && errorBuffer->valid )
- log(" dlopen(%s) => NULL, '%s'\n", Loader::leafName(path), errorBuffer->message);
- else
- log(" dlopen(%s) => %p\n", Loader::leafName(path), result);
+
+ // remove new loaders from runtime list
+ while ( loaded.size() > startLoaderCount ) {
+ //const Loader* removeeLdr = loaded.back();
+ //log("removing %p from state.loaded (%s)\n", removeeLdr, removeeLdr->path());
+ loaded.pop_back();
+ // FIXME: free malloced JITLoaders
+ }
+ result = nullptr;
+ topLoader = nullptr;
+
+ // Clear any potential objc patching entries from the lists. We aren't going to do patching
+ // on these binaries as the dlopen failed
+ this->objcReplacementClasses.clear();
+ while ( this->patchedObjCClasses.size() > startPatchedObjCClassesCount ) {
+ this->patchedObjCClasses.pop_back();
+ }
+ while ( this->patchedSingletons.size() > startPatchedSingletonsCount ) {
+ this->patchedSingletons.pop_back();
+ }
+ }
+
+ // on success, run objc notifiers. This has to be done while still in the write lock as
+ // the notifier mutates the list of objc classes
+ if ( (topLoader != nullptr) && ((mode & RTLD_NOLOAD) == 0) && diag.noError() ) {
+ const Loader* rootLoaders[1] = { topLoader };
+ std::span<const Loader*> rootLoadersSpan(rootLoaders, 1);
+ partitionDelayLoads(newLoaders, rootLoadersSpan, loadersUnDelayed);
+ doSingletonPatching(cacheDataConst);
+ notifyObjCPatching();
}
});
+ // on success, run initializers
+ if ( (topLoader != nullptr) && ((mode & RTLD_NOLOAD) == 0) ) {
+ // Note: we have released the withLoadersWriteLock while running the notifiers/initializers
+ // This is intentional to avoid deadlocks with other framework locks, that might call dyld
+ // inquiry functions now (such as walking loaded images).
+ // It is safe, because we still have the API-lock, so no other thread can call dlclose() and remove
+ // the images that are having their notifiers/initializers run. A initializer may call dlopen() again and
+ // add more images, but that will be on the same thread as this, so the ivar in Loaders about if
+ // its initializer has been run does not need to be thread safe.
+
+ // first notify about any delay-init dylibs that just got moved to being needed
+ if ( !loadersUnDelayed.empty() ) {
+ std::span<const Loader*> ldrs(&loadersUnDelayed[0], (size_t)loadersUnDelayed.size());
+ notifyLoad(ldrs);
+ }
+
+ // notify everyone else about all loaded images (do this late, so we don't have to undo incase of error).
+ if ( !loadersToNotify.empty() ) {
+ std::span<const Loader*> ldrs(&loadersToNotify[0], (size_t)loadersToNotify.size());
+ notifyLoad(ldrs);
+ }
+
+ // run initializers
+ topLoader->runInitializersBottomUpPlusUpwardLinks(*this);
+
+ // make handle
+ result = handleFromLoader(topLoader, firstOnly);
+ }
+
+ if ( config.log.apis ) {
+ PerThreadErrorMessage* errorBuffer = (PerThreadErrorMessage*)this->libSystemHelpers->pthread_getspecific(dlerrorPthreadKey());
+ if ( (errorBuffer != nullptr) && errorBuffer->valid )
+ log(" dlopen(%s) => NULL, '%s'\n", Loader::leafName(path), errorBuffer->message);
+ else
+ log(" dlopen(%s) => %p\n", Loader::leafName(path), result);
+ }
timer.setData4(result);
return result;
}
@@ -1768,10 +1671,8 @@
__block Diagnostics diag;
config.pathOverrides.forEachPathVariant(path, config.process.platform, false, true, topStop, ^(const char* possiblePath, ProcessConfig::PathOverrides::Type type, bool& stop) {
__block Diagnostics possiblePathDiag;
- config.syscall.withReadOnlyMappedFile(possiblePathDiag, possiblePath, true, ^(const void* mapping, size_t mappedSize, bool isOSBinary, const FileID&, const char*, const int) {
- uint64_t sliceOffset = 0;
- uint64_t sliceSize = 0;
- if ( MachOFile::compatibleSlice(possiblePathDiag, sliceOffset, sliceSize, mapping, mappedSize, path, config.process.platform, isOSBinary, *config.process.archs, config.security.internalInstall) != nullptr ) {
+ config.syscall.withReadOnlyMappedFile(possiblePathDiag, possiblePath, true, ^(const void* mapping, size_t mappedSize, bool isOSBinary, const FileID&, const char*) {
+ if ( MachOFile::compatibleSlice(possiblePathDiag, mapping, mappedSize, path, config.process.platform, isOSBinary, *config.process.archs, config.security.internalInstall) != nullptr ) {
result = true;
stop = true;
}
@@ -1796,10 +1697,12 @@
#endif // !TARGET_OS_EXCLAVEKIT
}
+#if !__i386__
void* APIs::dlopen_audited(const char* path, int mode)
{
return dlopen(path, mode);
}
+#endif
void* APIs::dlsym(void* handle, const char* symbolName)
{
@@ -1813,8 +1716,16 @@
#if !TARGET_OS_EXCLAVEKIT
// allow apps to disable dlsym()
- if ( addressLookupsDisabled(symbolName) ) {
- // dlsym() blocked is enabled and this symbol is not in the allow list
+ if ( config.security.dlsymBlocked ) {
+ // either abort
+ if ( config.security.dlsymAbort ) {
+#if BUILDING_DYLD
+ halt("dlsym() called");
+#elif BUILDING_UNIT_TESTS
+ abort();
+#endif
+ }
+ // or silently return NULL
if ( config.log.apis )
log(" dlsym(\"%s\") => NULL (blocked)\n", symbolName);
return nullptr;
@@ -1834,8 +1745,7 @@
__block bool found = false;
locks.withLoadersReadLock(^{
for ( const dyld4::Loader* image : loaded ) {
- if ( image->header(*this)->noDynamicAccess() )
- continue;
+
if ( !image->hiddenFromFlat() && image->hasExportedSymbol(diag, *this, underscoredName, Loader::shallow, Loader::runResolver, &result) ) {
found = true;
break;
@@ -1898,6 +1808,15 @@
// handle value was something returned by dlopen()
bool firstOnly;
const Loader* image = loaderFromHandle(handle, firstOnly);
+#if TARGET_OS_OSX
+ // FIXME: temp work around for syspolicyd <rdar://73731400>
+ if ( (MachOAnalyzer*)handle == config.process.mainExecutable ) {
+ setErrorString("dlsym(%p, %s): invalid handle", handle, symbolName);
+ if ( config.log.apis )
+ log(" dlsym(\"%s\") => NULL\n", symbolName);
+ return nullptr;
+ }
+#endif
// verify is a valid loader
if ( !validLoader(image) ) {
setErrorString("dlsym(%p, %s): invalid handle", handle, symbolName);
@@ -1917,25 +1836,12 @@
}
if ( result.targetLoader != nullptr ) {
- if ( result.targetLoader->header(*this)->noDynamicAccess() ) {
- if ( config.log.apis )
- log(" dlsym(\"%s\") => NULL (no dynamic access)\n", symbolName);
- return nullptr;
- }
- void* ptr = (void*)result.targetAddressForDlsym;
-
- // Finalize the symbol if this is a pseudodylib loader.
- if ( result.isMaterializing ) {
- auto *pd = result.targetLoader->isJustInTimeLoader()->pseudoDylib();
- if ( char *errMsg = pd->finalizeRequestedSymbols({&result.targetSymbolName, 1})) {
- if ( config.log.apis )
- log(" dlsym(\"%s\") => NULL, error finalizing pseudo-dylib symbols: %s", symbolName, errMsg);
- setErrorString("dlsym(%s): error finalizing pseudo-dylib symbols: %s", symbolName, errMsg);
- pd->disposeString(errMsg);
- return nullptr;
- }
- }
-
+ void* ptr = (void*)Loader::resolvedAddress(*this, result);
+ ptr = (void*)Loader::interpose(*this, (uintptr_t)ptr);
+#if __has_feature(ptrauth_calls)
+ if ( result.isCode )
+ ptr = __builtin_ptrauth_sign_unauthenticated(ptr, ptrauth_key_asia, 0);
+#endif
if ( config.log.apis )
log(" dlsym(\"%s\") => %p\n", symbolName, ptr);
timer.setData4((uint64_t)(stripPointer(ptr)));
@@ -1946,7 +1852,6 @@
return nullptr;
}
-#endif // !TARGET_OS_DRIVERKIT
bool APIs::dyld_shared_cache_some_image_overridden()
{
@@ -1960,12 +1865,16 @@
{
if ( config.log.apis )
log("_dyld_get_shared_cache_uuid(%p)\n", uuid);
+#if !TARGET_OS_EXCLAVEKIT
const DyldSharedCache* sharedCache = config.dyldCache.addr;
if ( sharedCache != nullptr ) {
sharedCache->getUUID(uuid);
return true;
}
return false;
+#else
+ return false;
+#endif // !TARGET_OS_EXCLAVEKIT
}
const void* APIs::_dyld_get_shared_cache_range(size_t* mappedSize)
@@ -1974,10 +1883,12 @@
log("_dyld_get_shared_cache_range(%p)", mappedSize);
const void* result = nullptr;
*mappedSize = 0;
+#if !TARGET_OS_EXCLAVEKIT
if ( const DyldSharedCache* sharedCache = config.dyldCache.addr ) {
*mappedSize = (size_t)sharedCache->mappedSize();
result = sharedCache;
}
+#endif // !TARGET_OS_EXCLAVEKIT
if ( config.log.apis )
log(" => %p,0x%lX\n", result, *mappedSize);
return result;
@@ -2020,7 +1931,7 @@
if ( ml != nullptr ) {
infos[i].image = ml;
infos[i].offsetInImage = (uintptr_t)addr - (uintptr_t)ml;
- ((Header*)ml)->getUuid(infos[i].uuid);
+ ml->getUuid(infos[i].uuid);
}
}
}
@@ -2028,21 +1939,21 @@
void APIs::_dyld_register_for_image_loads(LoadNotifyFunc func)
{
if ( config.log.apis )
- log("_dyld_register_for_image_loads(%p)\n", func.raw());
+ log("_dyld_register_for_image_loads(%p)\n", func);
#if !TARGET_OS_EXCLAVEKIT
// callback about already loaded images
locks.withLoadersReadLock(^{
for ( const dyld4::Loader* image : loaded ) {
const MachOLoaded* ml = image->loadAddress(*this);
if ( config.log.notifications )
- log("add notifier %p called with mh=%p\n", func.raw(), ml);
- func(ml, image->path(*this), !image->neverUnload);
+ log("add notifier %p called with mh=%p\n", func, ml);
+ func(ml, image->path(), !image->neverUnload);
}
});
// add to list of functions to call about future loads
- const Loader* callbackLoader = this->findImageContaining(func.raw());
- locks.withNotifiersWriteLock(^{
+ const Loader* callbackLoader = this->findImageContaining((void*)func);
+ locks.withNotifiersWriteLock(memoryManager, ^() {
addNotifyLoadImage(callbackLoader, func);
});
#else
@@ -2050,10 +1961,10 @@
#endif // !TARGET_OS_EXCLAVEKIT
}
-void APIs::_dyld_register_for_bulk_image_loads(BulkLoadNotifier func)
-{
- if ( config.log.apis )
- log("_dyld_register_for_bulk_image_loads(%p)\n", func.raw());
+void APIs::_dyld_register_for_bulk_image_loads(void (*func)(unsigned imageCount, const mach_header* mhs[], const char* paths[]))
+{
+ if ( config.log.apis )
+ log("_dyld_register_for_bulk_image_loads(%p)\n", func);
#if !TARGET_OS_EXCLAVEKIT
// callback about already loaded images
@@ -2063,17 +1974,17 @@
const char* paths[count];
for ( unsigned i = 0; i < count; ++i ) {
mhs[i] = loaded[i]->loadAddress(*this);
- paths[i] = loaded[i]->path(*this);
+ paths[i] = loaded[i]->path();
}
//dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE, (uint64_t)mhs[0], (uint64_t)func, 0);
if ( config.log.notifications )
- log("add bulk notifier %p called with %d images\n", func.raw(), count);
- func(count, (const mach_header**)mhs, (const char**)paths);
+ log("add bulk notifier %p called with %d images\n", func, count);
+ func(count, mhs, paths);
});
// add to list of functions to call about future loads
- const Loader* callbackLoader = this->findImageContaining(func.raw());
- locks.withNotifiersWriteLock(^{
+ const Loader* callbackLoader = this->findImageContaining((void*)func);
+ locks.withNotifiersWriteLock(memoryManager, ^() {
addNotifyBulkLoadImage(callbackLoader, func);
});
#else
@@ -2212,7 +2123,7 @@
}
#endif // !TARGET_OS_EXCLAVEKIT
-int APIs::dyld_shared_cache_find_iterate_text(const uuid_t cacheUuid, const char* extraSearchDirs[], IterateCacheTextFunc callback)
+int APIs::dyld_shared_cache_find_iterate_text(const uuid_t cacheUuid, const char* extraSearchDirs[], void (^callback)(const dyld_shared_cache_dylib_text_info* info))
{
if ( config.log.apis )
log("dyld_shared_cache_find_iterate_text()\n");
@@ -2297,8 +2208,7 @@
// get base address of cache
__block uint64_t cacheUnslidBaseAddress = 0;
- sharedCache->forEachRegion(^(const void* content, uint64_t vmAddr, uint64_t size, uint32_t initProt,
- uint32_t maxProt, uint64_t flags, uint64_t fileOffset, bool& stopRegion) {
+ sharedCache->forEachRegion(^(const void* content, uint64_t vmAddr, uint64_t size, uint32_t initProt, uint32_t maxProt, uint64_t flags, bool& stopRegion) {
if ( cacheUnslidBaseAddress == 0 )
cacheUnslidBaseAddress = vmAddr;
});
@@ -2324,7 +2234,7 @@
#endif // !TARGET_OS_EXCLAVEKIT
}
-int APIs::dyld_shared_cache_iterate_text(const uuid_t cacheUuid, IterateCacheTextFunc callback)
+int APIs::dyld_shared_cache_iterate_text(const uuid_t cacheUuid, void (^callback)(const dyld_shared_cache_dylib_text_info* info))
{
if ( config.log.apis )
log("dyld_shared_cache_iterate_text()\n");
@@ -2340,7 +2250,7 @@
mach_task_self_ = task_self_trap();
#if HAS_EXTERNAL_STATE
- this->externallyViewable->fork_child();
+ this->externallyViewable.fork_child();
#endif // !HAS_EXTERNAL_STATE
locks.resetLockInForkChild();
#else
@@ -2407,10 +2317,12 @@
#if SUPPORT_PREBUILTLOADERS
// If main program has PrebuiltLoader, check selector table in that
if ( const PrebuiltLoaderSet* mainSet = this->processPrebuiltLoaderSet() ) {
- const char* uniqueName = prebuilt_objc::findSelector(this, this->objcSelectorMap, selName);
- if ( config.log.apis )
- log("_dyld_get_objc_selector(%s) => %s\n", selName, uniqueName);
- return uniqueName;
+ if ( const ObjCSelectorOpt* selectorHashTable = mainSet->objcSelectorOpt() ) {
+ const char* uniqueName = selectorHashTable->getString(selName, *this);
+ if ( config.log.apis )
+ log("_dyld_get_objc_selector(%s) => %s\n", selName, uniqueName);
+ return uniqueName;
+ }
}
#endif // SUPPORT_PREBUILTLOADERS
if ( config.log.apis )
@@ -2422,7 +2334,7 @@
}
void APIs::_dyld_for_each_objc_class(const char* className,
- ObjCClassFunc callback)
+ void (^callback)(void* classPtr, bool isLoaded, bool* stop))
{
if ( config.log.apis )
log("_dyld_get_objc_class(%s)\n", className);
@@ -2430,18 +2342,12 @@
#if SUPPORT_PREBUILTLOADERS
// If main program has PrebuiltLoader, check classes table in that
if ( const PrebuiltLoaderSet* mainSet = this->processPrebuiltLoaderSet() ) {
- __block bool stop = false;
- prebuilt_objc::forEachClass(this, this->objcClassMap, className,
- ^(const dyld3::Array<const PrebuiltLoader::BindTargetRef*>& values) {
- for ( const PrebuiltLoader::BindTargetRef* value : values ) {
- callback((void*)value->value(*this), true, &stop);
- if ( stop )
- break;
- }
- });
- if ( stop ) {
- // If we found the class here, then stop. Otherwise fall through to looking in the shared cache
- return;
+ if ( const ObjCDataStructOpt* classesHashTable = mainSet->objcClassOpt() ) {
+ bool stop = classesHashTable->forEachDataStruct(className, *this, callback);
+ if ( stop ) {
+ // If we found the class here, then stop. Otherwise fall through to looking in the shared cache
+ return;
+ }
}
}
#endif
@@ -2469,7 +2375,7 @@
}
void APIs::_dyld_for_each_objc_protocol(const char* protocolName,
- ObjCProtocolFunc callback)
+ void (^callback)(void* protocolPtr, bool isLoaded, bool* stop))
{
if ( config.log.apis )
log("_dyld_get_objc_protocol(%s)\n", protocolName);
@@ -2477,18 +2383,12 @@
#if SUPPORT_PREBUILTLOADERS
// If main program has PrebuiltLoader, check protocols table in that
if ( const PrebuiltLoaderSet* mainSet = this->processPrebuiltLoaderSet() ) {
- __block bool stop = false;
- prebuilt_objc::forEachProtocol(this, this->objcProtocolMap, protocolName,
- ^(const dyld3::Array<const PrebuiltLoader::BindTargetRef*>& values) {
- for ( const PrebuiltLoader::BindTargetRef* value : values ) {
- callback((void*)value->value(*this), true, &stop);
- if ( stop )
- break;
- }
- });
- if ( stop ) {
- // If we found the protocol here, then stop. Otherwise fall through to looking in the shared cache
- return;
+ if ( const ObjCDataStructOpt* protocolsHashTable = mainSet->objcProtocolOpt() ) {
+ bool stop = protocolsHashTable->forEachDataStruct(protocolName, *this, callback);
+ if ( stop ) {
+ // If we found the class here, then stop. Otherwise fall through to looking in the shared cache
+ return;
+ }
}
}
#endif
@@ -2515,7 +2415,7 @@
#endif // !TARGET_OS_EXCLAVEKIT
}
-void APIs::_dyld_visit_objc_classes(ObjCVisitClassesFunc callback)
+void APIs::_dyld_visit_objc_classes(void (^callback)(const void* classPtr))
{
if ( config.log.apis )
log("_dyld_visit_objc_classes()\n");
@@ -2678,7 +2578,7 @@
const SwiftOptimizationHeader* swiftOptHeader = config.dyldCache.swiftCacheInfo;
// We need objc, swift, and of the correct versions. If anything isn't right, just bail out
- if ( !objcHeaderInfoRW || !swiftOptHeader )
+ if ( !objcHeaderInfoRW || !swiftOptHeader || (swiftOptHeader->version != 1))
return { _dyld_protocol_conformance_result_kind_not_found, nullptr };
if ( (typeDescriptor != nullptr) && (swiftOptHeader->typeConformanceHashTableCacheOffset != 0) ) {
@@ -2761,7 +2661,7 @@
const SwiftOptimizationHeader* swiftOptHeader = config.dyldCache.swiftCacheInfo;
// We need objc, swift, and of the correct versions. If anything isn't right, just bail out
- if ( !objcHeaderInfoRW || !swiftOptHeader )
+ if ( !objcHeaderInfoRW || !swiftOptHeader || (swiftOptHeader->version != 1))
return { _dyld_protocol_conformance_result_kind_not_found, nullptr };
if ( swiftOptHeader->foreignTypeConformanceHashTableCacheOffset != 0 ) {
@@ -2959,7 +2859,7 @@
return { _dyld_protocol_conformance_result_kind_not_found, nullptr };
}
-static _dyld_section_info_result lookupObjCInfo(_dyld_section_location_kind kind, const Header* hdr,
+static _dyld_section_info_result lookupObjCInfo(_dyld_section_location_kind kind, const dyld3::MachOFile* mf,
const SectionLocations* metadata)
{
const uint64_t* sectionOffsets = metadata->offsets;
@@ -2968,7 +2868,7 @@
uint64_t sectionOffset = sectionOffsets[kind];
uint64_t sectionSize = sectionSizes[kind];
if ( sectionOffset != 0 )
- return { (uint8_t*)hdr + sectionOffset, (size_t)sectionSize };
+ return { (uint8_t*)mf + sectionOffset, (size_t)sectionSize };
return { nullptr, 0 };
}
@@ -2982,11 +2882,11 @@
if ( kind >= _dyld_section_location_count )
return { nullptr, (size_t)-1 };
- const Header* hdr = (const Header*)mh;
+ const dyld3::MachOFile* mf = (const dyld3::MachOFile*)mh;
if ( sectionLocations == nullptr ) {
SectionLocations metadata;
- JustInTimeLoader::parseSectionLocations(hdr, metadata);
- return lookupObjCInfo(kind, hdr, &metadata);
+ JustInTimeLoader::parseSectionLocations(mf, metadata);
+ return lookupObjCInfo(kind, mf, &metadata);
}
#if !TARGET_OS_EXCLAVEKIT
@@ -3004,22 +2904,20 @@
// We have metadata, but it might be the wrong version, ie, dyld root running with shared cache
// metadata
const Loader* ldr = (const Loader*)sectionLocations;
- if ( !ldr->validMagic() || ldr->getSectionLocations()->version != 1 )
+ if ( ldr->getSectionLocations()->version != 1 )
return this->_dyld_lookup_section_info(mh, nullptr, kind);
- return lookupObjCInfo(kind, hdr, ldr->getSectionLocations());
-}
-
-#if !TARGET_OS_EXCLAVEKIT
+ return lookupObjCInfo(kind, mf, ldr->getSectionLocations());
+}
+
static PseudoDylibCallbacks *createPseudoDylibCallbacks(Allocator &allocator,
- ReadOnlyCallback<_dyld_pseudodylib_dispose_string> dispose_string,
- ReadOnlyCallback<_dyld_pseudodylib_initialize> initialize,
- ReadOnlyCallback<_dyld_pseudodylib_deinitialize> deinitialize,
- ReadOnlyCallback<_dyld_pseudodylib_lookup_symbols> lookup_symbols,
- ReadOnlyCallback<_dyld_pseudodylib_lookup_address> lookup_address,
- ReadOnlyCallback<_dyld_pseudodylib_find_unwind_sections> find_unwind_sections,
- ReadOnlyCallback<_dyld_pseudodylib_loadable_at_path> loadable_at_path,
- ReadOnlyCallback<_dyld_pseudodylib_finalize_requested_symbols> finalize_requested_symbols) {
+ _dyld_pseudodylib_dispose_string dispose_string,
+ _dyld_pseudodylib_initialize initialize,
+ _dyld_pseudodylib_deinitialize deinitialize,
+ _dyld_pseudodylib_lookup_symbols lookup_symbols,
+ _dyld_pseudodylib_lookup_address lookup_address,
+ _dyld_pseudodylib_find_unwind_sections find_unwind_sections,
+ _dyld_pseudodylib_loadable_at_path loadable_at_path) {
PseudoDylibCallbacks* pd_cb =
(PseudoDylibCallbacks*)allocator.aligned_alloc(alignof(PseudoDylibCallbacks),
sizeof(PseudoDylibCallbacks));
@@ -3030,42 +2928,25 @@
pd_cb->lookupAddress = lookup_address;
pd_cb->findUnwindSections = find_unwind_sections;
pd_cb->loadableAtPath = loadable_at_path;
- pd_cb->finalizeRequestedSymbols = finalize_requested_symbols;
return pd_cb;
}
-#endif // !TARGET_OS_EXCLAVEKIT
-
-_dyld_pseudodylib_callbacks_handle APIs::_dyld_pseudodylib_register_callbacks(const struct PseudoDylibRegisterCallbacks* callbacks) {
-#if !TARGET_OS_EXCLAVEKIT
- if ( !this->config.security.allowDevelopmentVars ) {
- if ( this->config.log.apis )
- log("_dyld_pseudodylib_register_callbacks() => nullptr: blocked by security policy");
- return nullptr;
- }
-
+
+_dyld_pseudodylib_callbacks_handle APIs::_dyld_pseudodylib_register_callbacks(const struct _dyld_pseudodylib_callbacks* callbacks) {
PseudoDylibCallbacks* pd_cb = nullptr;
- locks.withLoadersWriteLock([&] {
+ locks.withLoadersWriteLock(memoryManager, [&] {
if (callbacks->version == 1) {
- const auto* callbacks_v1 = (const PseudoDylibRegisterCallbacksV1*)callbacks;
+ const auto* callbacks_v1 = (const _dyld_pseudodylib_callbacks_v1*)callbacks;
pd_cb = createPseudoDylibCallbacks(persistentAllocator, callbacks_v1->dispose_error_message,
callbacks_v1->initialize, callbacks_v1->deinitialize,
callbacks_v1->lookup_symbols, callbacks_v1->lookup_address,
- callbacks_v1->find_unwind_sections, nullptr, nullptr);
+ callbacks_v1->find_unwind_sections, nullptr);
} else if (callbacks->version == 2) {
- const auto* callbacks_v2 = (const PseudoDylibRegisterCallbacksV2*)callbacks;
+ const auto* callbacks_v2 = (const _dyld_pseudodylib_callbacks_v2*)callbacks;
pd_cb = createPseudoDylibCallbacks(persistentAllocator, callbacks_v2->dispose_string,
callbacks_v2->initialize, callbacks_v2->deinitialize,
callbacks_v2->lookup_symbols, callbacks_v2->lookup_address,
callbacks_v2->find_unwind_sections,
- callbacks_v2->loadable_at_path, nullptr);
- } else if (callbacks->version == 3) {
- const auto* callbacks_v3 = (const PseudoDylibRegisterCallbacksV3*)callbacks;
- pd_cb = createPseudoDylibCallbacks(persistentAllocator, callbacks_v3->dispose_string,
- callbacks_v3->initialize, callbacks_v3->deinitialize,
- callbacks_v3->lookup_symbols, callbacks_v3->lookup_address,
- callbacks_v3->find_unwind_sections,
- callbacks_v3->loadable_at_path,
- callbacks_v3->finalize_requested_symbols);
+ callbacks_v2->loadable_at_path);
}
});
@@ -3075,40 +2956,20 @@
}
return (_dyld_pseudodylib_callbacks_handle)pd_cb;
-#else
- unavailable_on_exclavekit();
-#endif // !TARGET_OS_EXCLAVEKIT
}
void APIs::_dyld_pseudodylib_deregister_callbacks(_dyld_pseudodylib_callbacks_handle callbacks_handle) {
-#if !TARGET_OS_EXCLAVEKIT
- if ( !this->config.security.allowDevelopmentVars ) {
- if ( this->config.log.apis )
- log("_dyld_pseudodylib_deregister_callbacks(): blocked by security policy");
- return;
- }
-
if (!callbacks_handle)
return;
- locks.withLoadersWriteLock([&] {
+ locks.withLoadersWriteLock(memoryManager, [&] {
persistentAllocator.free((PseudoDylibCallbacks*)callbacks_handle);
});
-#else
- unavailable_on_exclavekit();
-#endif // !TARGET_OS_EXCLAVEKIT
}
_dyld_pseudodylib_handle APIs::_dyld_pseudodylib_register(
void* addr, size_t size, _dyld_pseudodylib_callbacks_handle callbacks_handle, void* context) {
-#if !TARGET_OS_EXCLAVEKIT
- if ( !this->config.security.allowDevelopmentVars ) {
- if ( this->config.log.apis )
- log("_dyld_pseudodylib_register() => nullptr: blocked by security policy");
- return nullptr;
- }
-
- const Header* pseudoDylibHdr = (const Header*)addr;
- const char* path = pseudoDylibHdr->installName();
+ const MachOFile* pseudoDylibMF = (const MachOFile*)addr;
+ const char* path = pseudoDylibMF->installName();
if (!path) {
if ( config.log.apis ) {
@@ -3124,7 +2985,7 @@
_dyld_pseudodylib_handle result = nullptr;
PseudoDylib* existingPD = nullptr;
- locks.withLoadersWriteLock([&] {
+ locks.withLoadersWriteLock(memoryManager, [&] {
for (auto &pd : pseudoDylibs)
if (strcmp(pd->getIdentifier(), path) == 0) {
existingPD = pd;
@@ -3146,24 +3007,21 @@
}
return result;
-#else
- unavailable_on_exclavekit();
-#endif // !TARGET_OS_EXCLAVEKIT
}
void APIs::_dyld_pseudodylib_deregister(_dyld_pseudodylib_handle pd_handle) {
- const PseudoDylib* pd = (PseudoDylib*)pd_handle;
+ PseudoDylib* pd = (PseudoDylib*)pd_handle;
if ( config.log.apis )
log("_dyld_deregister_pseudodylib(<handle for \"%s\">)\n", pd->getIdentifier());
bool found = false;
- locks.withLoadersWriteLock([&] {
+ locks.withLoadersWriteLock(memoryManager, [&] {
for (auto it = pseudoDylibs.begin(); it != pseudoDylibs.end(); ++it)
if (*it == pd) {
found = true;
pseudoDylibs.erase(it);
- persistentAllocator.free((void*)pd);
+ persistentAllocator.free(pd);
break;
}
});
@@ -3176,7 +3034,7 @@
const mach_header* APIs::_dyld_get_prog_image_header()
{
- const mach_header* result = config.process.mainExecutableMF;
+ const mach_header* result = config.process.mainExecutable;
if ( config.log.apis )
log("_dyld_get_prog_image_header() => %p\n", result);
return result;
@@ -3192,10 +3050,8 @@
bool APIs::_dyld_is_objc_constant(DyldObjCConstantKind kind, const void* addr)
{
-#if !TARGET_OS_EXCLAVEKIT
if ( config.log.apis )
log("_dyld_is_objc_constant(%d, %p)\n", kind, addr);
-#endif // !TARGET_OS_EXCLAVEKIT
// FIXME
return false;
}
@@ -3236,7 +3092,7 @@
if ( config.log.apis )
log("_dyld_register_driverkit_main(%p)\n", mainFunc);
- if ( config.process.platform == Platform::driverKit ) {
+ if ( config.process.platform == dyld3::Platform::driverKit ) {
#if BUILDING_DYLD
if ( this->mainFunc() != nullptr )
halt("_dyld_register_driverkit_main() may only be called once");
@@ -3283,11 +3139,46 @@
return false;
}
-bool APIs::_dyld_dlsym_blocked()
-{
- return config.security.dlsymBlocked;
-}
-
+void APIs::_dyld_missing_symbol_abort()
+{
+#if BUILDING_DYLD
+ halt("missing symbol called");
+#endif
+}
+
+void APIs::_tlv_atexit(void (*termFunc)(void* objAddr), void* objAddr)
+{
+#if !TARGET_OS_EXCLAVEKIT
+ #if __has_feature(tls)
+ addTLVTerminationFunc(termFunc, objAddr);
+ #endif
+#else
+ unavailable_on_exclavekit();
+#endif // !TARGET_OS_EXCLAVEKIT
+}
+
+// called by exit() before it calls cxa_finalize() so that thread_local
+// objects are destroyed before global objects.
+void APIs::_tlv_exit()
+{
+#if !TARGET_OS_EXCLAVEKIT
+ #if __has_feature(tls)
+ exitTLV();
+ #endif
+#else
+ unavailable_on_exclavekit();
+#endif // !TARGET_OS_EXCLAVEKIT
+}
+
+#if __has_feature(tls)
+// linked images with TLV have references to this symbol, but it is never used at runtime
+void APIs::_tlv_bootstrap()
+{
+#if BUILDING_DYLD
+ halt("_tlv_bootstrap called");
+#endif
+}
+#endif
void APIs::obsolete()
{
@@ -3317,9 +3208,9 @@
return NSObjectFileImageFailure;
// create ofi that just contains path. NSLinkModule does all the work (can't use operator new in dyld)
- void* storage = this->libSystemHelpers.malloc(sizeof(__NSObjectFileImage));
+ void* storage = this->libSystemHelpers->malloc(sizeof(__NSObjectFileImage));
__NSObjectFileImage* result = new (storage) __NSObjectFileImage();
- result->path = (char*)this->libSystemHelpers.malloc(strlen(path)+1);
+ result->path = (char*)this->libSystemHelpers->malloc(strlen(path)+1);
strcpy((char*)(result->path), path);
*ofi = result;
@@ -3335,35 +3226,41 @@
if ( config.log.apis )
log("NSCreateObjectFileImageFromMemory(%p, 0x%08lX)\n", memImage, memImageSize);
// sanity check the buffer is a mach-o file
- std::span<const uint8_t> content = { (const uint8_t*)memImage, memImageSize };
- const Header* hdr = nullptr;
-
+ __block Diagnostics diag;
+
// check if it is current arch mach-o or fat with slice for current arch
- if ( const Universal* uni = Universal::isUniversal(content) ) {
- Universal::Slice slice;
- if ( uni->bestSlice(*config.process.archs, false, slice) )
- hdr = Header::isMachO(slice.buffer);
-
- } else {
- hdr = Header::isMachO(content);
- }
-
- if ( hdr == nullptr )
+ bool usable = false;
+ const MachOFile* mf = (MachOFile*)memImage;
+ if ( mf->hasMachOMagic() && mf->isMachO(diag, memImageSize) ) {
+ usable = (config.process.archs->grade(mf->cputype, mf->cpusubtype, false) != 0);
+ }
+ else if ( const dyld3::FatFile* ff = dyld3::FatFile::isFatFile(memImage) ) {
+ uint64_t sliceOffset;
+ uint64_t sliceLen;
+ bool missingSlice;
+ if ( ff->isFatFileWithSlice(diag, memImageSize, *config.process.archs, false, sliceOffset, sliceLen, missingSlice) ) {
+ mf = (MachOFile*)((long)memImage + sliceOffset);
+ if ( mf->isMachO(diag, sliceLen) ) {
+ usable = true;
+ }
+ }
+ }
+ if ( usable ) {
+ if ( !mf->loadableIntoProcess(config.process.platform, "OFI", config.security.isInternalOS) )
+ usable = false;
+ }
+ if ( !usable ) {
return NSObjectFileImageFailure;
-
- if ( ! config.process.archs->isCompatible(hdr->arch()) )
- return NSObjectFileImageFailure;
-
- if ( !hdr->loadableIntoProcess(config.process.platform, "OFI", config.security.isInternalOS) )
- return NSObjectFileImageFailure;
-
+ }
+
// this API can only be used with bundles
- if ( !hdr->isBundle() )
+ if ( !mf->isBundle() ) {
return NSObjectFileImageInappropriateFile;
+ }
// some apps deallocate the buffer right after calling NSCreateObjectFileImageFromMemory(), so we need to copy the buffer
vm_address_t newAddr = 0;
- kern_return_t r = this->libSystemHelpers.vm_allocate(mach_task_self(), &newAddr, memImageSize, VM_FLAGS_ANYWHERE);
+ kern_return_t r = this->libSystemHelpers->vm_allocate(mach_task_self(), &newAddr, memImageSize, VM_FLAGS_ANYWHERE);
if ( r == KERN_SUCCESS ) {
::memcpy((void*)newAddr, memImage, memImageSize);
if ( config.log.apis )
@@ -3372,7 +3269,7 @@
}
// allocate ofi that just lists the memory range
- void* storage = this->libSystemHelpers.malloc(sizeof(__NSObjectFileImage));
+ void* storage = this->libSystemHelpers->malloc(sizeof(__NSObjectFileImage));
__NSObjectFileImage* result = new (storage) __NSObjectFileImage();
result->memSource = memImage;
result->memLength = memImageSize;
@@ -3395,8 +3292,7 @@
// make temp file with content of memory buffer
ofi->path = nullptr;
char tempFileName[PATH_MAX];
- // <rdar://115105325> prevent setuid programs from being exploited by a rogue $TMPDIR, they always use /tmp
- const char* tmpDir = (config.security.allowClassicFallbackPaths ? this->libSystemHelpers.getenv("TMPDIR") : "/tmp/");
+ const char* tmpDir = this->libSystemHelpers->getenv("TMPDIR");
if ( (tmpDir != nullptr) && (strlen(tmpDir) > 2) ) {
strlcpy(tempFileName, tmpDir, PATH_MAX);
if ( tmpDir[strlen(tmpDir) - 1] != '/' )
@@ -3405,11 +3301,11 @@
else
strlcpy(tempFileName, "/tmp/", PATH_MAX);
strlcat(tempFileName, "NSCreateObjectFileImageFromMemory-XXXXXXXX", PATH_MAX);
- int fd = this->libSystemHelpers.mkstemp(tempFileName);
+ int fd = this->libSystemHelpers->mkstemp(tempFileName);
if ( fd != -1 ) {
ssize_t writtenSize = ::pwrite(fd, ofi->memSource, ofi->memLength, 0);
if ( writtenSize == ofi->memLength ) {
- ofi->path = (char*)this->libSystemHelpers.malloc(strlen(tempFileName)+1);
+ ofi->path = (char*)this->libSystemHelpers->malloc(strlen(tempFileName)+1);
::strcpy((char*)(ofi->path), tempFileName);
}
else {
@@ -3475,18 +3371,18 @@
// if object was created from a memory, release that memory
// NOTE: this is the way dyld has always done this. NSCreateObjectFileImageFromMemory() hands ownership of the memory to dyld
// we don't know if memory came from malloc or vm_allocate, so ask malloc
- if ( this->libSystemHelpers.malloc_size(ofi->memSource) != 0 )
- this->libSystemHelpers.free((void*)(ofi->memSource));
+ if ( this->libSystemHelpers->malloc_size(ofi->memSource) != 0 )
+ this->libSystemHelpers->free((void*)(ofi->memSource));
else
- this->libSystemHelpers.vm_deallocate(mach_task_self(), (vm_address_t)ofi->memSource, ofi->memLength);
+ this->libSystemHelpers->vm_deallocate(mach_task_self(), (vm_address_t)ofi->memSource, ofi->memLength);
}
// ofi always owns the path
if ( ofi->path != nullptr )
- this->libSystemHelpers.free((void*)(ofi->path));
+ this->libSystemHelpers->free((void*)(ofi->path));
// free object
- this->libSystemHelpers.free((void*)ofi);
+ this->libSystemHelpers->free((void*)ofi);
return true;
#else
@@ -3550,7 +3446,7 @@
log("NSNameOfModule(%p)\n", m);
bool firstOnly;
if ( const Loader* ldr = loaderFromHandle(m, firstOnly) )
- return ldr->path(*this);
+ return ldr->path();
return nullptr;
#else
obsolete();
@@ -3564,7 +3460,7 @@
log("NSLibraryNameForModule(%p)\n", m);
bool firstOnly;
if ( const Loader* ldr = loaderFromHandle(m, firstOnly) )
- return ldr->path(*this);
+ return ldr->path();
return nullptr;
#else
obsolete();
@@ -3626,9 +3522,6 @@
NSSymbol APIs::NSLookupAndBindSymbol(const char* symbolName)
{
#if TARGET_OS_OSX && !TARGET_OS_EXCLAVEKIT
- // allow apps to disable dlsym()
- if ( addressLookupsDisabled() )
- return nullptr;
const mach_header* foundInImageAtLoadAddress;
void* symbolAddress;
if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
@@ -3643,9 +3536,6 @@
NSSymbol APIs::NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint)
{
#if TARGET_OS_OSX && !TARGET_OS_EXCLAVEKIT
- // allow apps to disable dlsym()
- if ( addressLookupsDisabled() )
- return nullptr;
const mach_header* foundInImageAtLoadAddress;
void* symbolAddress;
if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
@@ -3662,9 +3552,6 @@
#if TARGET_OS_OSX && !TARGET_OS_EXCLAVEKIT
if ( config.log.apis )
log("NSLookupSymbolInModule(%p, %s)\n", module, symbolName);
- // allow apps to disable dlsym()
- if ( addressLookupsDisabled() )
- return nullptr;
bool firstOnly;
if ( const Loader* ldr = loaderFromHandle(module, firstOnly) ) {
if ( validLoader(ldr) ) {
@@ -3705,9 +3592,6 @@
NSSymbol APIs::NSLookupSymbolInImage(const mach_header* mh, const char* symbolName, uint32_t options)
{
#if TARGET_OS_OSX && !TARGET_OS_EXCLAVEKIT
- // allow apps to disable dlsym()
- if ( addressLookupsDisabled() )
- return nullptr;
void* addr;
bool resultPointsToInstructions = false;
if ( ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions) ) {
@@ -3723,63 +3607,9 @@
#endif // TARGET_OS_OSX
}
-// symbolName=nullptr blocks all uses
-bool APIs::addressLookupsDisabled(const char* symbolName) const
-{
- // check if there is an allow-list and symbol is in it
- // note: performance is not important. dlsym is already slow
- if ( (config.security.dlsymAllowList != nullptr) && (symbolName != nullptr) ) {
- // coarse check that symbolName appears anywhere in list
- if ( const char* inList = ::strstr(config.security.dlsymAllowList, symbolName) ) {
- // symbolName string is in list, verify it has delimiters on both sides
- char pre = inList[-1];
- char post = inList[strlen(symbolName)];
- if ( (post == '\0') || (post == ':') ) {
- if ( pre == ':' ) {
- // allow this symbol to be looked up
- return false;
- }
- }
- }
- // have an allow-list, and symbolName not in it
- if ( DlsymNotify notify = this->dlsymNotifier() ) {
- notify(symbolName);
- }
- }
- else if ( !config.security.dlsymBlocked ) {
- // program is not using dlsym-blocking or allow-list, so it will be notified about all dlsym usages
- if ( DlsymNotify notify = this->dlsymNotifier() )
- notify(symbolName);
- }
-
- // allow apps to disable dlsym()
- if ( config.security.dlsymBlocked ) {
- // either abort
- if ( config.security.dlsymAbort ) {
-#if BUILDING_DYLD
- StructuredError errInfo;
- errInfo.kind = DYLD_EXIT_REASON_DLSYM_BLOCKED;
- errInfo.clientOfDylibPath = nullptr;
- errInfo.targetDylibPath = nullptr;
- errInfo.symbolName = symbolName;
- halt("symbol address lookup (dlsym) disabled in process", &errInfo);
-#elif BUILDING_UNIT_TESTS
- abort();
-#endif
- }
- return true;
- }
- return false;
-}
-
-
void* APIs::NSAddressOfSymbol(NSSymbol symbol)
{
#if TARGET_OS_OSX && !TARGET_OS_EXCLAVEKIT
- // allow apps to disable dlsym()
- if ( addressLookupsDisabled() )
- return nullptr;
-
// special case NULL
if ( symbol == nullptr )
return nullptr;
@@ -3790,14 +3620,13 @@
#if __has_feature(ptrauth_calls)
const MachOLoaded* ml;
if ( findImageMappedAt(result, &ml) ) {
- const Header* hdr = (const Header*)ml;
- int64_t slide = hdr->getSlide();
+ int64_t slide = ml->getSlide();
__block bool resultPointsToInstructions = false;
- hdr->forEachSection(^(const Header::SectionInfo& sectInfo, bool& stop) {
- uint64_t sectStartAddr = sectInfo.address + slide;
- uint64_t sectEndAddr = sectStartAddr + sectInfo.size;
+ ml->forEachSection(^(const MachOAnalyzer::SectionInfo& sectInfo, bool malformedSectionRange, bool& stop) {
+ uint64_t sectStartAddr = sectInfo.sectAddr + slide;
+ uint64_t sectEndAddr = sectStartAddr + sectInfo.sectSize;
if ( ((uint64_t)result >= sectStartAddr) && ((uint64_t)result < sectEndAddr) ) {
- resultPointsToInstructions = (sectInfo.flags & S_ATTR_PURE_INSTRUCTIONS) || (sectInfo.flags & S_ATTR_SOME_INSTRUCTIONS);
+ resultPointsToInstructions = (sectInfo.sectFlags & S_ATTR_PURE_INSTRUCTIONS) || (sectInfo.sectFlags & S_ATTR_SOME_INSTRUCTIONS);
stop = true;
}
});
@@ -3999,11 +3828,14 @@
if (!libSystemInitialized()) {
const_cast<Loader*>(this->libSystemLoader)->beginInitializers(*this);
this->libSystemLoader->runInitializers(*this);
- this->setLibSystemInitialized();
}
#if HAS_EXTERNAL_STATE
- this->externallyViewable->setLibSystemInitialized();
+#if TARGET_OS_EXCLAVEKIT
+ this->externallyViewable.setLibSystemInitializedOld();
+#else
+ this->externallyViewable.setLibSystemInitialized();
+#endif // TARGET_OS_EXCLAVEKIT
#endif /* HAS_EXTERNAL_STATE */
// after running libSystem's initializer, tell objc to run any +load methods on libSystem sub-dylibs
@@ -4012,7 +3844,7 @@
// Iterate using indices so that the array doesn't grow underneath us if a +load dloopen's
for ( uint32_t i = 0; i != this->loaded.size(); ++i ) {
const Loader* ldr = this->loaded[i];
- if ( ldr->belowLibSystem ) {
+ if ( (ldr->dylibInDyldCache || ldr->analyzer(*this)->isDylib()) && (strncmp(ldr->analyzer(*this)->installName(), "/usr/lib/system/lib", 19) == 0) ) {
// check install name instead of path, to handle DYLD_LIBRARY_PATH overrides of libsystem sub-dylibs
const_cast<Loader*>(ldr)->beginInitializers(*this);
this->notifyObjCInit(ldr);
@@ -4022,8 +3854,8 @@
#if TARGET_OS_OSX && !TARGET_OS_EXCLAVEKIT
// If we're PID 1, scan for roots
- if ( (this->config.process.pid == 1) && (this->libSystemHelpers.version() >= 5) ) {
- this->libSystemHelpers.run_async(&ProcessConfig::scanForRoots, (void*)&this->config);
+ if ( (this->config.process.pid == 1) && (this->libSystemHelpers->version() >= 5) ) {
+ this->libSystemHelpers->run_async(&ProcessConfig::scanForRoots, (void*)&this->config);
}
#endif // TARGET_OS_OSX
@@ -4040,203 +3872,4 @@
}
-void APIs::_dyld_register_dlsym_notifier(DlsymNotify callback)
-{
-#if !TARGET_OS_EXCLAVEKIT
- locks.withNotifiersWriteLock(^{
- // only support one notifier being registered
- this->setDlsymNotifier(callback);
- });
-#endif
-}
-
-const void* APIs::_dyld_get_swift_prespecialized_data()
-{
-#if TARGET_OS_EXCLAVEKIT
- return nullptr;
-#else
- if ( config.process.commPage.disableSwiftPrespecData )
- return nullptr;
-
- if ( config.log.apis )
- log("_dyld_get_swift_prespecialized_data()\n");
-
- if ( !config.dyldCache.addr )
- return nullptr;
-
- const SwiftOptimizationHeader* swiftOpt = config.dyldCache.addr->swiftOpt();
- if ( !swiftOpt || (swiftOpt->version < 2) )
- return nullptr;
-
- if ( swiftOpt->prespecializationDataCacheOffset == 0 )
- return nullptr;
-
- void* result = (char*)config.dyldCache.addr + swiftOpt->prespecializationDataCacheOffset;
- if ( config.log.apis )
- log("_dyld_get_swift_prespecialized_data() => %p\n", result);
- return result;
-#endif
-}
-
-bool APIs::_dyld_is_pseudodylib(void* handle)
-{
-#if TARGET_OS_EXCLAVEKIT
- return false;
-#else
- if ( config.log.apis )
- log("_dyld_is_pseudodylib(%p)\n", handle);
-
- bool firstOnly;
- const Loader* ldr = loaderFromHandle(handle, firstOnly);
- if ( !validLoader(ldr) ) {
- // if an invalid 'handle` passed in, return false
- return false;
- }
-
- bool result = false;
- if ( const JustInTimeLoader* jitLoader = ldr->isJustInTimeLoader() )
- result = (jitLoader->pseudoDylib() != nullptr);
-
- return result;
-#endif // TARGET_OS_EXCLAVEKIT
-}
-
-const void* APIs::_dyld_find_pointer_hash_table_entry(const void *table, const void *key1,
- size_t restKeysCount, const void **restKeys)
-{
-#if TARGET_OS_EXCLAVEKIT
- return nullptr;
-#else
-
- if ( config.log.apis )
- log("_dyld_find_pointer_hash_table_entry(%p, %p, %lu, %p)\n", table, key1, restKeysCount, restKeys);
-
- if ( !config.dyldCache.addr )
- return nullptr;
-
- const SwiftOptimizationHeader* swiftOpt = config.dyldCache.addr->swiftOpt();
- if ( !swiftOpt || (swiftOpt->version < 3) )
- return nullptr;
-
- const SwiftHashTable* ptrTable = nullptr;
- for ( uint64_t ptrTableOffset : swiftOpt->prespecializedMetadataHashTableCacheOffsets ) {
- // end of tables
- if ( ptrTableOffset == 0 )
- break;
-
- const SwiftHashTable* thisTable = (const SwiftHashTable*)((uint8_t*)config.dyldCache.addr + ptrTableOffset);
- if ( (void*)thisTable == table ) {
- ptrTable = thisTable;
- break;
- }
- }
-
- if ( ptrTable == nullptr ) {
- if ( config.log.apis )
- log("_dyld_find_pointer_hash_table_entry() invalid table pointer %p\n", table);
- return nullptr;
-
- }
- if ( swiftOpt->prespecializationDataCacheOffset == 0 )
- return nullptr;
-
- // fixed limit for the number key pointers
- uint32_t nextKeyIndex = 0;
- uint64_t tableKeys[PointerHashTableKeyMaxPointers];
-
- // rest keys + key1
- if ( restKeysCount >= PointerHashTableKeyMaxPointers ) {
- if ( config.log.apis )
- log("_dyld_find_pointer_hash_table_entry() exceeded key pointers limit: %lu\n", restKeysCount + 1);
- return nullptr;
- }
-
- const DyldSharedCache* dyldCache = config.dyldCache.addr;
- const uint8_t* dyldCacheStart = (uint8_t*)dyldCache;
- const uint8_t* dyldCacheEnd = (uint8_t*)dyldCacheStart + dyldCache->mappedSize();
-
- if ( key1 >= dyldCacheStart && key1 < dyldCacheEnd ) {
- tableKeys[nextKeyIndex++] = (uint8_t*)key1-(uint8_t*)config.dyldCache.addr;
- } else {
- if ( config.log.apis )
- log("_dyld_find_pointer_hash_table_entry() key %p not in shared cache\n", key1);
- return nullptr;
- }
-
- for ( size_t i = 0; i < restKeysCount; ++i ) {
- uint8_t* nextKey = (uint8_t*)restKeys[i];
- if ( nextKey >= dyldCacheStart && nextKey < dyldCacheEnd ) {
- tableKeys[nextKeyIndex++] = (uint8_t*)nextKey-(uint8_t*)config.dyldCache.addr;
- } else {
- if ( config.log.apis )
- log("_dyld_find_pointer_hash_table_entry() key %p not in shared cache\n", nextKey);
- return nullptr;
- }
- }
-
- const void* result = nullptr;
-
- PointerHashTableBuilderKey key;
- key.cacheOffsets = tableKeys;
- key.numOffsets = nextKeyIndex;
- const PointerHashTableValue* val = ptrTable->getValue<PointerHashTableBuilderKey, PointerHashTableValue>(key, nullptr);
- if ( val )
- result = dyldCacheStart + val->cacheOffset;
-
- if ( config.log.apis )
- log("_dyld_find_pointer_hash_table_entry() => %p\n", result);
- return result;
-#endif
-}
-
-dyld_all_image_infos* APIs::_dyld_all_image_infos_TEMP()
-{
-#if HAS_EXTERNAL_STATE
- return this->externallyViewable->getProcessInfo();
-#else
- return nullptr;
-#endif
-}
-
-#if !TARGET_OS_EXCLAVEKIT
-DyldCommPage APIs::_dyld_commpage()
-{
- return this->config.process.commPage;
-}
-#endif
-
-#if SUPPPORT_PRE_LC_MAIN
-MainFunc APIs::_dyld_get_main_func() {
- return this->mainFunc();
-}
-#endif
-
-
-void APIs::_dyld_stack_range(const void** stackBottom, const void** stackTop)
-{
- this->protectedStack().getRange(*stackBottom, *stackTop);
-}
-
-void APIs::_dyld_for_each_prewarming_range(PrewarmingDataFunc callback)
-{
-#if !TARGET_OS_EXCLAVEKIT
- const DyldSharedCache* dyldCache = config.dyldCache.addr;
- if ( dyldCache == nullptr )
- return;
-
- dyldCache->forEachPrewarmingEntry(^(const void *content, uint64_t unslidVMAddr, uint64_t vmSize) {
- callback(content, (size_t)vmSize);
- });
-#endif
-}
-
-void APIs::_dyld_call_with_writable_tpro_memory(void (*func)(void*), void* ctx) {
- if (libSystemInitialized()) {
- halt("Illegal TPRO memory access");
- }
- MemoryManager::withWritableMemory([&] {
- func(ctx);
- });
-}
-
} // namespace