1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2013 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
34 #include <sys/param.h>
35 #include <mach/mach_time.h> // mach_absolute_time()
36 #include <mach/mach_init.h>
37 #include <mach/mach_traps.h>
38 #include <sys/types.h>
40 #include <sys/syscall.h>
41 #include <sys/socket.h>
43 #include <sys/syslog.h>
45 #include <sys/xattr.h>
46 #include <mach/mach.h>
47 #include <mach-o/fat.h>
48 #include <mach-o/loader.h>
49 #include <mach-o/ldsyms.h>
50 #include <libkern/OSByteOrder.h>
51 #include <libkern/OSAtomic.h>
52 #include <sys/sysctl.h>
54 #include <sys/dtrace.h>
55 #include <libkern/OSAtomic.h>
56 #include <Availability.h>
57 #include <System/sys/codesign.h>
58 #include <System/sys/csr.h>
60 #include <os/lock_private.h>
61 #include <System/machine/cpu_capabilities.h>
62 #include <System/sys/reason.h>
63 #include <kern/kcdata.h>
65 #include <sys/fsgetpath.h>
66 #include <System/sys/content_protection.h>
68 #define SUPPORT_LOGGING_TO_CONSOLE !TARGET_OS_SIMULATOR
69 #if SUPPORT_LOGGING_TO_CONSOLE
70 #include <paths.h> // for logging to console
73 #if !TARGET_OS_SIMULATOR
75 // The comm page is being renamed, so set our define to the new value if the old
77 #ifndef _COMM_PAGE_DYLD_SYSTEM_FLAGS
79 #ifndef _COMM_PAGE_DYLD_FLAGS
80 #error Must define _COMM_PAGE_DYLD_FLAGS or _COMM_PAGE_DYLD_SYSTEM_FLAGS
83 #define _COMM_PAGE_DYLD_SYSTEM_FLAGS _COMM_PAGE_DYLD_FLAGS
89 #if TARGET_OS_SIMULATOR
91 AMFI_DYLD_INPUT_PROC_IN_SIMULATOR
= (1 << 0),
93 enum amfi_dyld_policy_output_flag_set
{
94 AMFI_DYLD_OUTPUT_ALLOW_AT_PATH
= (1 << 0),
95 AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS
= (1 << 1),
96 AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE
= (1 << 2),
97 AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS
= (1 << 3),
98 AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS
= (1 << 4),
99 AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION
= (1 << 5),
100 AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING
= (1 << 6),
102 extern "C" int amfi_check_dyld_policy_self(uint64_t input_flags
, uint64_t* output_flags
);
108 #include <sandbox/private.h>
109 #if __has_feature(ptrauth_calls)
113 extern "C" int __fork();
121 #include "ImageLoader.h"
122 #include "ImageLoaderMachO.h"
123 #include "dyldLibSystemInterface.h"
124 #include "dyld_cache_format.h"
125 #include "dyld_process_info_internal.h"
127 #if SUPPORT_ACCELERATE_TABLES
128 #include "ImageLoaderMegaDylib.h"
131 #if TARGET_OS_SIMULATOR
132 extern "C" void* gSyscallHelpers
;
134 #include "dyldSyscallInterface.h"
138 #include "libdyldEntryVector.h"
139 #include "MachOLoaded.h"
141 #include "DyldSharedCache.h"
142 #include "SharedCacheRuntime.h"
143 #include "StringUtils.h"
145 #include "ClosureBuilder.h"
146 #include "ClosureFileSystemPhysical.h"
147 #include "FileUtils.h"
148 #include "BootArgs.h"
150 #include "RootsChecker.h"
153 #define MH_HAS_OBJC 0x40000000
156 // not libc header for send() syscall interface
157 extern "C" ssize_t
__sendto(int, const void *, size_t, int, const struct sockaddr
*, socklen_t
);
160 // ARM and x86_64 are the only architecture that use cpu-sub-types
161 #define CPU_SUBTYPES_SUPPORTED ((__arm__ || __arm64__ || __x86_64__) && !TARGET_OS_SIMULATOR)
164 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
165 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
166 #define LC_ENCRYPT_COMMAND LC_ENCRYPTION_INFO
167 #define macho_segment_command segment_command_64
168 #define macho_section section_64
170 #define LC_SEGMENT_COMMAND LC_SEGMENT
171 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
172 #define LC_ENCRYPT_COMMAND LC_ENCRYPTION_INFO_64
173 #define macho_segment_command segment_command
174 #define macho_section section
177 #define DYLD_CLOSURE_XATTR_NAME "com.apple.dyld"
179 #define CPU_TYPE_MASK 0x00FFFFFF /* complement of CPU_ARCH_MASK */
182 /* implemented in dyld_gdb.cpp */
183 extern void resetAllImages();
184 extern void addImagesToAllImages(uint32_t infoCount
, const dyld_image_info info
[]);
185 extern void addAotImagesToAllAotImages(uint32_t aotInfoCount
, const dyld_aot_image_info aotInfo
[]);
186 extern void removeImageFromAllImages(const mach_header
* mh
);
187 extern void addNonSharedCacheImageUUID(const dyld_uuid_info
& info
);
188 extern const char* notifyGDB(enum dyld_image_states state
, uint32_t infoCount
, const dyld_image_info info
[]);
189 extern size_t allImagesCount();
191 // magic so CrashReporter logs message
193 char error_string
[1024];
196 // magic linker symbol for start of dyld binary
197 extern "C" const macho_header __dso_handle
;
199 extern bool gEnableSharedCacheDataConst
;
203 // The file contains the core of dyld used to get a process to main().
204 // The API's that dyld supports are implemented in dyldAPIs.cpp.
211 struct RegisteredDOF
{ const mach_header
* mh
; int registrationID
; };
212 struct DylibOverride
{ const char* installName
; const char* override
; };
216 VECTOR_NEVER_DESTRUCTED(ImageLoader
*);
217 VECTOR_NEVER_DESTRUCTED(dyld::RegisteredDOF
);
218 VECTOR_NEVER_DESTRUCTED(dyld::ImageCallback
);
219 VECTOR_NEVER_DESTRUCTED(dyld::DylibOverride
);
220 VECTOR_NEVER_DESTRUCTED(ImageLoader::DynamicReference
);
222 VECTOR_NEVER_DESTRUCTED(dyld_image_state_change_handler
);
228 // state of all environment variables dyld uses
230 struct EnvironmentVariables
{
231 const char* const * DYLD_FRAMEWORK_PATH
;
232 const char* const * DYLD_FALLBACK_FRAMEWORK_PATH
;
233 const char* const * DYLD_LIBRARY_PATH
;
234 const char* const * DYLD_FALLBACK_LIBRARY_PATH
;
235 const char* const * DYLD_INSERT_LIBRARIES
;
236 const char* const * LD_LIBRARY_PATH
; // for unix conformance
237 const char* const * DYLD_VERSIONED_LIBRARY_PATH
;
238 const char* const * DYLD_VERSIONED_FRAMEWORK_PATH
;
239 bool DYLD_PRINT_LIBRARIES_POST_LAUNCH
;
240 bool DYLD_BIND_AT_LAUNCH
;
241 bool DYLD_PRINT_STATISTICS
;
242 bool DYLD_PRINT_STATISTICS_DETAILS
;
243 bool DYLD_PRINT_OPTS
;
245 bool DYLD_DISABLE_DOFS
;
247 // DYLD_SHARED_CACHE_DIR ==> sSharedCacheOverrideDir
248 // DYLD_ROOT_PATH ==> gLinkContext.rootPaths
249 // DYLD_IMAGE_SUFFIX ==> gLinkContext.imageSuffix
250 // DYLD_PRINT_OPTS ==> gLinkContext.verboseOpts
251 // DYLD_PRINT_ENV ==> gLinkContext.verboseEnv
252 // DYLD_FORCE_FLAT_NAMESPACE ==> gLinkContext.bindFlat
253 // DYLD_PRINT_INITIALIZERS ==> gLinkContext.verboseInit
254 // DYLD_PRINT_SEGMENTS ==> gLinkContext.verboseMapping
255 // DYLD_PRINT_BINDINGS ==> gLinkContext.verboseBind
256 // DYLD_PRINT_WEAK_BINDINGS ==> gLinkContext.verboseWeakBind
257 // DYLD_PRINT_REBASINGS ==> gLinkContext.verboseRebase
258 // DYLD_PRINT_DOFS ==> gLinkContext.verboseDOF
259 // DYLD_PRINT_APIS ==> gLogAPIs
260 // DYLD_IGNORE_PREBINDING ==> gLinkContext.prebindUsage
261 // DYLD_PREBIND_DEBUG ==> gLinkContext.verbosePrebinding
262 // DYLD_NEW_LOCAL_SHARED_REGIONS ==> gLinkContext.sharedRegionMode
263 // DYLD_SHARED_REGION ==> gLinkContext.sharedRegionMode
264 // DYLD_PRINT_WARNINGS ==> gLinkContext.verboseWarnings
265 // DYLD_PRINT_RPATHS ==> gLinkContext.verboseRPaths
266 // DYLD_PRINT_INTERPOSING ==> gLinkContext.verboseInterposing
267 // DYLD_PRINT_LIBRARIES ==> gLinkContext.verboseLoading
272 typedef std::vector
<dyld_image_state_change_handler
> StateHandlers
;
275 enum EnvVarMode
{ envNone
, envPrintOnly
, envAll
};
278 static const char* sExecPath
= NULL
;
279 static const char* sExecShortName
= NULL
;
280 static const macho_header
* sMainExecutableMachHeader
= NULL
;
281 static uintptr_t sMainExecutableSlide
= 0;
282 #if CPU_SUBTYPES_SUPPORTED
283 static cpu_type_t sHostCPU
;
284 static cpu_subtype_t sHostCPUsubtype
;
286 typedef ImageLoaderMachO
* __ptrauth_dyld_address_auth MainExecutablePointerType
;
287 static MainExecutablePointerType sMainExecutable
= NULL
;
288 static size_t sInsertedDylibCount
= 0;
289 static std::vector
<ImageLoader
*> sAllImages
;
290 static std::vector
<ImageLoader
*> sImageRoots
;
291 static std::vector
<ImageLoader
*> sImageFilesNeedingTermination
;
292 static std::vector
<RegisteredDOF
> sImageFilesNeedingDOFUnregistration
;
293 static std::vector
<ImageCallback
> sAddImageCallbacks
;
294 static std::vector
<ImageCallback
> sRemoveImageCallbacks
;
295 static std::vector
<LoadImageCallback
> sAddLoadImageCallbacks
;
296 static std::vector
<LoadImageBulkCallback
> sAddBulkLoadImageCallbacks
;
297 static bool sRemoveImageCallbacksInUse
= false;
298 static void* sSingleHandlers
[7][3];
299 static void* sBatchHandlers
[7][3];
300 static ImageLoader
* sLastImageByAddressCache
;
301 static EnvironmentVariables sEnv
;
303 static const char* sFrameworkFallbackPaths
[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL
};
304 static const char* sLibraryFallbackPaths
[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL
};
305 static const char* sRestrictedFrameworkFallbackPaths
[] = { "/System/Library/Frameworks", NULL
};
306 static const char* sRestrictedLibraryFallbackPaths
[] = { "/usr/lib", NULL
};
308 static const char* sFrameworkFallbackPaths
[] = { "/System/Library/Frameworks", NULL
};
309 static const char* sLibraryFallbackPaths
[] = { "/usr/local/lib", "/usr/lib", NULL
};
311 static UndefinedHandler sUndefinedHandler
= NULL
;
312 static ImageLoader
* sBundleBeingLoaded
= NULL
; // hack until OFI is reworked
313 static dyld3::SharedCacheLoadInfo sSharedCacheLoadInfo
;
314 static const char* sSharedCacheOverrideDir
;
315 bool gSharedCacheOverridden
= false;
316 ImageLoader::LinkContext gLinkContext
;
317 bool gLogAPIs
= false;
318 #if SUPPORT_ACCELERATE_TABLES
319 bool gLogAppAPIs
= false;
321 const struct LibSystemHelpers
* gLibSystemHelpers
= NULL
;
322 #if SUPPORT_OLD_CRT_INITIALIZATION
323 bool gRunInitializersOldWay
= false;
325 static std::vector
<DylibOverride
> sDylibOverrides
;
326 #if !TARGET_OS_SIMULATOR
327 static int sLogSocket
= -1;
329 static bool sFrameworksFoundAsDylibs
= false;
330 #if __x86_64__ && !TARGET_OS_SIMULATOR
331 static bool sHaswell
= false;
333 static std::vector
<ImageLoader::DynamicReference
> sDynamicReferences
;
334 #pragma clang diagnostic push
335 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
336 static OSSpinLock sDynamicReferencesLock
= 0;
337 #pragma clang diagnostic pop
338 #if !TARGET_OS_SIMULATOR
339 static bool sLogToFile
= false;
341 static char sLoadingCrashMessage
[1024] = "dyld: launch, loading dependent libraries";
342 static _dyld_objc_notify_mapped sNotifyObjCMapped
;
343 static _dyld_objc_notify_init sNotifyObjCInit
;
344 static _dyld_objc_notify_unmapped sNotifyObjCUnmapped
;
346 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
347 static bool sForceStderr
= false;
351 #if SUPPORT_ACCELERATE_TABLES
352 static ImageLoaderMegaDylib
* sAllCacheImagesProxy
= NULL
;
353 // Note these are now off by default as everything should use dyld3.
354 static bool sDisableAcceleratorTables
= true;
357 bool gUseDyld3
= false;
358 static uint32_t sLaunchModeUsed
= 0;
359 static bool sSkipMain
= false;
360 static void (*sEntryOverride
)() = nullptr;
361 static bool sJustBuildClosure
= false;
362 #if !TARGET_OS_SIMULATOR
363 static bool sLogClosureFailure
= false;
365 static bool sKeysDisabled
= false;
366 static bool sOnlyPlatformArm64e
= false; // arm64e binaries can only be loaded if they are part of the OS
368 static dyld3::RootsChecker sRootsChecker
;
370 enum class ClosureMode
{
371 // Unset means we haven't provided an env variable or boot-arg to explicitly choose a mode
373 // On means we set DYLD_USE_CLOSURES=1, or we didn't have DYLD_USE_CLOSURES=0 but did have
374 // -force_dyld3=1 env variable or a customer cache on iOS
376 // Off means we set DYLD_USE_CLOSURES=0, or we didn't have DYLD_USE_CLOSURES=1 but did have
377 // -force_dyld2=1 env variable or an internal cache on iOS
379 // PreBuiltOnly means only use a shared cache closure and don't try build a new one
383 enum class ClosureKind
{
389 static ClosureMode sClosureMode
= ClosureMode::Unset
;
390 static ClosureKind sClosureKind
= ClosureKind::unset
;
391 static bool sForceInvalidSharedCacheClosureFormat
= false;
392 static uint64_t launchTraceID
= 0;
394 // These flags are the values in the 64-bit _COMM_PAGE_DYLD_SYSTEM_FLAGS entry
395 // Note we own this and can write it from PID 1
396 enum CommPageFlags
: uint64_t {
399 // The boot args can set the low 32-bits of the comm page. We'll reserve the high 32-bits
400 // for runtime (launchd) set values.
401 CommPageBootArgMask
= 0xFFFFFFFF,
403 // Are the simulator support dylibs definitely roots when launchd scanned them
404 libsystemKernelIsRoot
= 1ULL << 32,
405 libsystemPlatformIsRoot
= 1ULL << 33,
406 libsystemPThreadIsRoot
= 1ULL << 34,
408 // Is the file system writable, ie, could the simulator support dylibs be written
409 // later, after PID 1
410 fileSystemCanBeModified
= 1ULL << 35
414 // The MappedRanges structure is used for fast address->image lookups.
415 // The table is only updated when the dyld lock is held, so we don't
416 // need to worry about multiple writers. But readers may look at this
417 // data without holding the lock. Therefore, all updates must be done
418 // in an order that will never cause readers to see inconsistent data.
419 // The general rule is that if the image field is non-NULL then
420 // the other fields are valid.
433 static MappedRanges
* sMappedRangesStart
;
435 #pragma clang diagnostic push
436 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
437 void addMappedRange(ImageLoader
* image
, uintptr_t start
, uintptr_t end
)
439 //dyld::log("addMappedRange(0x%lX->0x%lX) for %s\n", start, end, image->getShortName());
440 for (MappedRanges
* p
= sMappedRangesStart
; p
!= NULL
; p
= p
->next
) {
441 for (unsigned long i
=0; i
< p
->count
; ++i
) {
442 if ( p
->array
[i
].image
== NULL
) {
443 p
->array
[i
].start
= start
;
444 p
->array
[i
].end
= end
;
445 // add image field last with a barrier so that any reader will see consistent records
447 p
->array
[i
].image
= image
;
452 // table must be full, chain another
453 #if SUPPORT_ACCELERATE_TABLES
454 unsigned count
= (sAllCacheImagesProxy
!= NULL
) ? 16 : 400;
456 unsigned count
= 400;
458 size_t allocationSize
= sizeof(MappedRanges
) + (count
-1)*3*sizeof(void*);
459 MappedRanges
* newRanges
= (MappedRanges
*)malloc(allocationSize
);
460 bzero(newRanges
, allocationSize
);
461 newRanges
->count
= count
;
462 newRanges
->array
[0].start
= start
;
463 newRanges
->array
[0].end
= end
;
464 newRanges
->array
[0].image
= image
;
466 if ( sMappedRangesStart
== NULL
) {
467 sMappedRangesStart
= newRanges
;
470 for (MappedRanges
* p
= sMappedRangesStart
; p
!= NULL
; p
= p
->next
) {
471 if ( p
->next
== NULL
) {
480 void removedMappedRanges(ImageLoader
* image
)
482 for (MappedRanges
* p
= sMappedRangesStart
; p
!= NULL
; p
= p
->next
) {
483 for (unsigned long i
=0; i
< p
->count
; ++i
) {
484 if ( p
->array
[i
].image
== image
) {
485 // clear with a barrier so that any reader will see consistent records
487 p
->array
[i
].image
= NULL
;
492 #pragma clang diagnostic pop
494 ImageLoader
* findMappedRange(uintptr_t target
)
496 for (MappedRanges
* p
= sMappedRangesStart
; p
!= NULL
; p
= p
->next
) {
497 for (unsigned long i
=0; i
< p
->count
; ++i
) {
498 if ( p
->array
[i
].image
!= NULL
) {
499 if ( (p
->array
[i
].start
<= target
) && (target
< p
->array
[i
].end
) )
500 return p
->array
[i
].image
;
509 const char* mkstringf(const char* format
, ...)
511 _SIMPLE_STRING buf
= _simple_salloc();
514 va_start(list
, format
);
515 _simple_vsprintf(buf
, format
, list
);
517 const char* t
= strdup(_simple_string(buf
));
522 return "mkstringf, out of memory error";
526 void throwf(const char* format
, ...)
528 _SIMPLE_STRING buf
= _simple_salloc();
531 va_start(list
, format
);
532 _simple_vsprintf(buf
, format
, list
);
534 const char* t
= strdup(_simple_string(buf
));
539 throw "throwf, out of memory error";
543 #if !TARGET_OS_SIMULATOR
544 static int sLogfile
= STDERR_FILENO
;
547 #if !TARGET_OS_SIMULATOR
548 // based on CFUtilities.c: also_do_stderr()
549 static bool useSyslog()
551 // Use syslog() for processes managed by launchd
552 static bool launchdChecked
= false;
553 static bool launchdOwned
= false;
554 if ( !launchdChecked
&& gProcessInfo
->libSystemInitialized
) {
555 if ( (gLibSystemHelpers
!= NULL
) && (gLibSystemHelpers
->version
>= 11) ) {
556 // <rdar://problem/23520449> only call isLaunchdOwned() after libSystem is initialized
557 launchdOwned
= (*gLibSystemHelpers
->isLaunchdOwned
)();
558 launchdChecked
= true;
561 if ( launchdChecked
&& launchdOwned
)
564 // If stderr is not available, use syslog()
566 int result
= fstat(STDERR_FILENO
, &sb
);
568 return true; // file descriptor 2 is closed
574 static void socket_syslogv(int priority
, const char* format
, va_list list
)
576 // lazily create socket and connection to syslogd
577 if ( sLogSocket
== -1 ) {
578 sLogSocket
= ::socket(AF_UNIX
, SOCK_DGRAM
, 0);
579 if (sLogSocket
== -1)
580 return; // cannot log
581 ::fcntl(sLogSocket
, F_SETFD
, 1);
583 struct sockaddr_un addr
;
584 addr
.sun_family
= AF_UNIX
;
585 strncpy(addr
.sun_path
, _PATH_LOG
, sizeof(addr
.sun_path
));
586 if ( ::connect(sLogSocket
, (struct sockaddr
*)&addr
, sizeof(addr
)) == -1 ) {
593 // format message to syslogd like: "<priority>Process[pid]: message"
594 _SIMPLE_STRING buf
= _simple_salloc();
597 if ( _simple_sprintf(buf
, "<%d>%s[%d]: ", LOG_USER
|LOG_NOTICE
, sExecShortName
, getpid()) == 0 ) {
598 if ( _simple_vsprintf(buf
, format
, list
) == 0 ) {
599 const char* p
= _simple_string(buf
);
600 ::__sendto(sLogSocket
, p
, strlen(p
), 0, NULL
, 0);
608 void vlog(const char* format
, va_list list
)
610 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
611 // <rdar://problem/25965832> log to console when running iOS app from Xcode
612 if ( !sLogToFile
&& !sForceStderr
&& useSyslog() )
614 if ( !sLogToFile
&& useSyslog() )
616 socket_syslogv(LOG_ERR
, format
, list
);
618 _simple_vdprintf(sLogfile
, format
, list
);
622 void log(const char* format
, ...)
625 va_start(list
, format
);
631 void vwarn(const char* format
, va_list list
)
633 _simple_dprintf(sLogfile
, "dyld: warning, ");
634 _simple_vdprintf(sLogfile
, format
, list
);
637 void warn(const char* format
, ...)
640 va_start(list
, format
);
645 void logToConsole(const char* format
, ...) {
646 #if SUPPORT_LOGGING_TO_CONSOLE
647 int cfd
= open(_PATH_CONSOLE
, O_WRONLY
|O_NOCTTY
);
652 va_start(list
, format
);
653 _simple_vdprintf(cfd
, format
, list
);
661 extern void vlog(const char* format
, va_list list
);
662 #endif // !TARGET_OS_SIMULATOR
665 #pragma clang diagnostic push
666 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
667 // <rdar://problem/8867781> control access to sAllImages through a lock
668 // because global dyld lock is not held during initialization phase of dlopen()
669 // <rdar://problem/16145518> Use OSSpinLockLock to allow yielding
670 static OSSpinLock sAllImagesLock
= 0;
672 static void allImagesLock()
674 OSSpinLockLock(&sAllImagesLock
);
677 static void allImagesUnlock()
679 OSSpinLockUnlock(&sAllImagesLock
);
681 #pragma clang diagnostic pop
684 // utility class to assure files are closed when an exception is thrown
687 FileOpener(const char* path
);
689 int getFileDescriptor() { return fd
; }
694 FileOpener::FileOpener(const char* path
)
697 fd
= dyld3::open(path
, O_RDONLY
, 0);
700 FileOpener::~FileOpener()
707 static void registerDOFs(const std::vector
<ImageLoader::DOFInfo
>& dofs
)
709 const size_t dofSectionCount
= dofs
.size();
710 if ( !sEnv
.DYLD_DISABLE_DOFS
&& (dofSectionCount
!= 0) ) {
711 int fd
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
);
713 //dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n");
716 // allocate a buffer on the stack for the variable length dof_ioctl_data_t type
717 uint8_t buffer
[sizeof(dof_ioctl_data_t
) + dofSectionCount
*sizeof(dof_helper_t
)];
718 dof_ioctl_data_t
* ioctlData
= (dof_ioctl_data_t
*)buffer
;
720 // fill in buffer with one dof_helper_t per DOF section
721 ioctlData
->dofiod_count
= dofSectionCount
;
722 for (unsigned int i
=0; i
< dofSectionCount
; ++i
) {
723 strlcpy(ioctlData
->dofiod_helpers
[i
].dofhp_mod
, dofs
[i
].imageShortName
, DTRACE_MODNAMELEN
);
724 ioctlData
->dofiod_helpers
[i
].dofhp_dof
= (uintptr_t)(dofs
[i
].dof
);
725 ioctlData
->dofiod_helpers
[i
].dofhp_addr
= (uintptr_t)(dofs
[i
].dof
);
728 // tell kernel about all DOF sections en mas
729 // pass pointer to ioctlData because ioctl() only copies a fixed size amount of data into kernel
730 user_addr_t val
= (user_addr_t
)(unsigned long)ioctlData
;
731 if ( ioctl(fd
, DTRACEHIOC_ADDDOF
, &val
) != -1 ) {
732 // kernel returns a unique identifier for each section in the dofiod_helpers[].dofhp_dof field.
733 for (unsigned int i
=0; i
< dofSectionCount
; ++i
) {
735 info
.mh
= dofs
[i
].imageHeader
;
736 info
.registrationID
= (int)(ioctlData
->dofiod_helpers
[i
].dofhp_dof
);
737 sImageFilesNeedingDOFUnregistration
.push_back(info
);
738 if ( gLinkContext
.verboseDOF
) {
739 dyld::log("dyld: registering DOF section %p in %s with dtrace, ID=0x%08X\n",
740 dofs
[i
].dof
, dofs
[i
].imageShortName
, info
.registrationID
);
745 //dyld::log( "dyld: ioctl to register dtrace DOF section failed\n");
752 static void unregisterDOF(int registrationID
)
754 int fd
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
, 0);
756 dyld::warn("can't open /dev/" DTRACEMNR_HELPER
" to unregister dtrace DOF section\n");
759 ioctl(fd
, DTRACEHIOC_REMOVE
, registrationID
);
761 if ( gLinkContext
.verboseInit
)
762 dyld::warn("unregistering DOF section ID=0x%08X with dtrace\n", registrationID
);
768 // _dyld_register_func_for_add_image() is implemented as part of the general image state change notification
769 // Returns true if we did call add image callbacks on this image
771 static bool notifyAddImageCallbacks(ImageLoader
* image
)
773 // use guard so that we cannot notify about the same image twice
774 if ( ! image
->addFuncNotified() ) {
775 for (std::vector
<ImageCallback
>::iterator it
=sAddImageCallbacks
.begin(); it
!= sAddImageCallbacks
.end(); it
++) {
776 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*it
), 0);
777 (*it
)(image
->machHeader(), image
->getSlide());
779 for (LoadImageCallback func
: sAddLoadImageCallbacks
) {
780 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*func
), 0);
781 (*func
)(image
->machHeader(), image
->getPath(), !image
->neverUnload());
783 image
->setAddFuncNotified();
791 // notify gdb about these new images
792 static const char* updateAllImages(enum dyld_image_states state
, uint32_t infoCount
, const struct dyld_image_info info
[])
794 // <rdar://problem/8812589> don't add images without paths to all-image-info-list
795 if ( info
[0].imageFilePath
!= NULL
)
796 addImagesToAllImages(infoCount
, info
);
801 static StateHandlers
* stateToHandlers(dyld_image_states state
, void* handlersArray
[7][3])
804 case dyld_image_state_mapped
:
805 return reinterpret_cast<StateHandlers
*>(&handlersArray
[0]);
807 case dyld_image_state_dependents_mapped
:
808 return reinterpret_cast<StateHandlers
*>(&handlersArray
[1]);
810 case dyld_image_state_rebased
:
811 return reinterpret_cast<StateHandlers
*>(&handlersArray
[2]);
813 case dyld_image_state_bound
:
814 return reinterpret_cast<StateHandlers
*>(&handlersArray
[3]);
816 case dyld_image_state_dependents_initialized
:
817 return reinterpret_cast<StateHandlers
*>(&handlersArray
[4]);
819 case dyld_image_state_initialized
:
820 return reinterpret_cast<StateHandlers
*>(&handlersArray
[5]);
822 case dyld_image_state_terminated
:
823 return reinterpret_cast<StateHandlers
*>(&handlersArray
[6]);
828 #if SUPPORT_ACCELERATE_TABLES
829 static dyld_image_state_change_handler
getPreInitNotifyHandler(unsigned index
)
831 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(dyld_image_state_dependents_initialized
, sSingleHandlers
);
832 if ( index
>= handlers
->size() )
834 return (*handlers
)[index
];
837 static dyld_image_state_change_handler
getBoundBatchHandler(unsigned index
)
839 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(dyld_image_state_bound
, sBatchHandlers
);
840 if ( index
>= handlers
->size() )
842 return (*handlers
)[index
];
845 static void notifySingleFromCache(dyld_image_states state
, const mach_header
* mh
, const char* path
)
847 //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath());
848 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(state
, sSingleHandlers
);
849 if ( handlers
!= NULL
) {
850 dyld_image_info info
;
851 info
.imageLoadAddress
= mh
;
852 info
.imageFilePath
= path
;
853 info
.imageFileModDate
= 0;
854 for (dyld_image_state_change_handler handler
: *handlers
) {
855 const char* result
= (*handler
)(state
, 1, &info
);
856 if ( (result
!= NULL
) && (state
== dyld_image_state_mapped
) ) {
857 //fprintf(stderr, " image rejected by handler=%p\n", *it);
858 // make copy of thrown string so that later catch clauses can free it
859 const char* str
= strdup(result
);
864 if ( (state
== dyld_image_state_dependents_initialized
) && (sNotifyObjCInit
!= NULL
) && (mh
->flags
& MH_HAS_OBJC
) ) {
865 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_OBJC_INIT
, (uint64_t)mh
, 0, 0);
866 (*sNotifyObjCInit
)(path
, mh
);
871 #if !TARGET_OS_SIMULATOR
872 #define DYLD_PROCESS_INFO_NOTIFY_MAGIC 0x49414E46
874 struct RemoteNotificationResponder
{
875 RemoteNotificationResponder(const RemoteNotificationResponder
&) = delete;
876 RemoteNotificationResponder(RemoteNotificationResponder
&&) = delete;
877 RemoteNotificationResponder() {
878 if (dyld::gProcessInfo
->notifyPorts
[0] != DYLD_PROCESS_INFO_NOTIFY_MAGIC
) {
879 // No notifier found, early out
883 kern_return_t kr
= task_dyld_process_info_notify_get(_names
, &_namesCnt
);
884 while (kr
== KERN_NO_SPACE
) {
885 // In the future the SPI may return the size we need, but for now we just double the count. Since we don't want to depend on the
886 // return value in _nameCnt we set it to have a minimm of 16, double the inline storage value
887 _namesCnt
= std::max
<uint32_t>(16, 2*_namesCnt
);
888 _namesSize
= _namesCnt
*sizeof(mach_port_t
);
889 kr
= vm_allocate(mach_task_self(), (vm_address_t
*)&_names
, _namesSize
, VM_FLAGS_ANYWHERE
);
890 if (kr
!= KERN_SUCCESS
) {
891 // We could not allocate memory, time to error out
894 kr
= task_dyld_process_info_notify_get(_names
, &_namesCnt
);
895 if (kr
!= KERN_SUCCESS
) {
896 // We failed, so deallocate the memory. If the failures was KERN_NO_SPACE we will loop back and try again
897 (void)vm_deallocate(mach_task_self(), (vm_address_t
)_names
, _namesSize
);
901 if (kr
!= KERN_SUCCESS
) {
902 // We failed, set _namesCnt to 0 so nothing else will happen
906 ~RemoteNotificationResponder() {
908 for (auto i
= 0; i
< _namesCnt
; ++i
) {
909 (void)mach_port_deallocate(mach_task_self(), _names
[i
]);
911 if (_namesSize
!= 0) {
912 // We are not using inline memory, we need to free it
913 (void)vm_deallocate(mach_task_self(), (vm_address_t
)_names
, _namesSize
);
917 void sendMessage(mach_msg_id_t msgId
, mach_msg_size_t sendSize
, mach_msg_header_t
* buffer
) {
918 if (_namesCnt
== 0) { return; }
919 // Allocate a port to listen on in this monitoring task
920 mach_port_t replyPort
= MACH_PORT_NULL
;
921 mach_port_options_t options
= { .flags
= MPO_CONTEXT_AS_GUARD
| MPO_STRICT
, .mpl
= { 1 }};
922 kern_return_t kr
= mach_port_construct(mach_task_self(), &options
, (mach_port_context_t
)&replyPort
, &replyPort
);
923 if (kr
!= KERN_SUCCESS
) {
926 for (auto i
= 0; i
< _namesCnt
; ++i
) {
927 if (_names
[i
] == MACH_PORT_NULL
) { continue; }
928 // Assemble a message
929 uint8_t replyBuffer
[sizeof(mach_msg_header_t
) + MAX_TRAILER_SIZE
];
930 mach_msg_header_t
* msg
= buffer
;
931 msg
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND_ONCE
);
932 msg
->msgh_id
= msgId
;
933 msg
->msgh_local_port
= replyPort
;
934 msg
->msgh_remote_port
= _names
[i
];
935 msg
->msgh_reserved
= 0;
936 msg
->msgh_size
= sendSize
;
937 kr
= mach_msg_overwrite(msg
, MACH_SEND_MSG
| MACH_RCV_MSG
, msg
->msgh_size
, sizeof(replyBuffer
), replyPort
, 0, MACH_PORT_NULL
,
938 (mach_msg_header_t
*)&replyBuffer
[0], 0);
939 if (kr
!= KERN_SUCCESS
) {
940 // Send failed, we may have been psuedo recieved. destroy the message
941 (void)mach_msg_destroy(msg
);
942 // Mark the port as null. It does not matter why we failed... if it is s single message we will not retry, if it
943 // is a fragmented message then subsequent messages will not decode correctly
944 _names
[i
] = MACH_PORT_NULL
;
947 (void)mach_port_destruct(mach_task_self(), replyPort
, 0, (mach_port_context_t
)&replyPort
);
950 bool const active() const {
951 for (auto i
= 0; i
< _namesCnt
; ++i
) {
952 if (_names
[i
] != MACH_PORT_NULL
) {
959 mach_port_t _namesArray
[8] = {0};
960 mach_port_name_array_t _names
= (mach_port_name_array_t
)&_namesArray
[0];
961 mach_msg_type_number_t _namesCnt
= 8;
962 vm_size_t _namesSize
= 0;
965 //FIXME: Remove this once we drop support for iOS 11 simulators
966 // This is an enormous hack to keep remote introspection of older simulators working
967 // It works by interposing mach_msg, and redirecting message sent to a special port name. Messages to that portname will trigger a full set
968 // of sends to all kernel registered notifiers. In this mode mach_msg_sim_interposed() must return KERN_SUCCESS or the older dyld_sim may
969 // try to cleanup the notifer array.
970 kern_return_t
mach_msg_sim_interposed( mach_msg_header_t
* msg
, mach_msg_option_t option
, mach_msg_size_t send_size
, mach_msg_size_t rcv_size
,
971 mach_port_name_t rcv_name
, mach_msg_timeout_t timeout
, mach_port_name_t notify
) {
972 if (msg
->msgh_remote_port
!= DYLD_PROCESS_INFO_NOTIFY_MAGIC
) {
973 // Not the magic port, so just pass through to the real mach_msg()
974 return mach_msg(msg
, option
, send_size
, rcv_size
, rcv_name
, timeout
, notify
);
977 // The magic port. We know dyld_sim is trying to message observers, so lets call into our messaging code directly.
978 // This is kind of weird since we effectively built a buffer in dyld_sim, then pass it to mach_msg, which we interpose, unpack, and then
979 // pass to send_message which then sends the buffer back out vis mach_message_overwrite(), but it should work at least as well as the old
981 RemoteNotificationResponder responder
;
982 responder
.sendMessage(msg
->msgh_id
, send_size
, msg
);
984 // We always return KERN_SUCCESS, otherwise old dyld_sims might clear the port
988 static void notifyMonitoringDyld(RemoteNotificationResponder
& responder
, bool unloading
, unsigned imageCount
,
989 const struct mach_header
* loadAddresses
[], const char* imagePaths
[])
991 // Make sure there is at least enough room to hold a the largest single file entry that can exist.
992 static_assert((MAXPATHLEN
+ sizeof(dyld_process_info_image_entry
) + 1 + MAX_TRAILER_SIZE
) <= DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE
);
994 unsigned entriesSize
= imageCount
*sizeof(dyld_process_info_image_entry
);
995 unsigned pathsSize
= 0;
996 for (unsigned j
=0; j
< imageCount
; ++j
) {
997 pathsSize
+= (strlen(imagePaths
[j
]) + 1);
1000 unsigned totalSize
= (sizeof(struct dyld_process_info_notify_header
) + entriesSize
+ pathsSize
+ 127) & -128; // align
1001 // The reciever has a fixed buffer of DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE, whcih needs to hold both the message and a trailer.
1002 // If the total size exceeds that we need to fragment the message.
1003 if ( (totalSize
+ MAX_TRAILER_SIZE
) > DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE
) {
1004 // Putting all image paths into one message would make buffer too big.
1005 // Instead split into two messages. Recurse as needed until paths fit in buffer.
1006 unsigned imageHalfCount
= imageCount
/2;
1007 notifyMonitoringDyld(responder
, unloading
, imageHalfCount
, loadAddresses
, imagePaths
);
1008 notifyMonitoringDyld(responder
, unloading
, imageCount
- imageHalfCount
, &loadAddresses
[imageHalfCount
], &imagePaths
[imageHalfCount
]);
1011 uint8_t buffer
[totalSize
+ MAX_TRAILER_SIZE
];
1012 dyld_process_info_notify_header
* header
= (dyld_process_info_notify_header
*)buffer
;
1013 header
->version
= 1;
1014 header
->imageCount
= imageCount
;
1015 header
->imagesOffset
= sizeof(dyld_process_info_notify_header
);
1016 header
->stringsOffset
= sizeof(dyld_process_info_notify_header
) + entriesSize
;
1017 header
->timestamp
= dyld::gProcessInfo
->infoArrayChangeTimestamp
;
1018 dyld_process_info_image_entry
* entries
= (dyld_process_info_image_entry
*)&buffer
[header
->imagesOffset
];
1019 char* const pathPoolStart
= (char*)&buffer
[header
->stringsOffset
];
1020 char* pathPool
= pathPoolStart
;
1021 for (unsigned j
=0; j
< imageCount
; ++j
) {
1022 strcpy(pathPool
, imagePaths
[j
]);
1023 uint32_t len
= (uint32_t)strlen(pathPool
);
1024 bzero(entries
->uuid
, 16);
1025 dyld3::MachOFile
* mf
= (dyld3::MachOFile
*)loadAddresses
[j
];
1026 mf
->getUuid(entries
->uuid
);
1027 entries
->loadAddress
= (uint64_t)loadAddresses
[j
];
1028 entries
->pathStringOffset
= (uint32_t)(pathPool
- pathPoolStart
);
1029 entries
->pathLength
= len
;
1030 pathPool
+= (len
+1);
1034 responder
.sendMessage(DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
, totalSize
, (mach_msg_header_t
*)buffer
);
1036 responder
.sendMessage(DYLD_PROCESS_INFO_NOTIFY_LOAD_ID
, totalSize
, (mach_msg_header_t
*)buffer
);
1040 static void notifyMonitoringDyld(bool unloading
, unsigned imageCount
, const struct mach_header
* loadAddresses
[],
1041 const char* imagePaths
[])
1043 dyld3::ScopedTimer(DBG_DYLD_REMOTE_IMAGE_NOTIFIER
, 0, 0, 0);
1044 RemoteNotificationResponder responder
;
1045 if (!responder
.active()) { return; }
1046 notifyMonitoringDyld(responder
, unloading
, imageCount
, loadAddresses
, imagePaths
);
1049 static void notifyMonitoringDyldMain() {
1050 dyld3::ScopedTimer(DBG_DYLD_REMOTE_IMAGE_NOTIFIER
, 0, 0, 0);
1051 RemoteNotificationResponder responder
;
1052 uint8_t buffer
[sizeof(mach_msg_header_t
) + MAX_TRAILER_SIZE
];
1053 responder
.sendMessage(DYLD_PROCESS_INFO_NOTIFY_MAIN_ID
, sizeof(mach_msg_header_t
), (mach_msg_header_t
*)buffer
);
1056 extern void notifyMonitoringDyldMain() VIS_HIDDEN
;
1057 extern void notifyMonitoringDyld(bool unloading
, unsigned imageCount
, const struct mach_header
* loadAddresses
[],
1058 const char* imagePaths
[]) VIS_HIDDEN
;
1061 void notifyKernel(const ImageLoader
& image
, bool loading
) {
1062 uint32_t baseCode
= loading
? DBG_DYLD_UUID_MAP_A
: DBG_DYLD_UUID_UNMAP_A
;
1064 image
.getUUID(uuid
);
1065 if ( image
.inSharedCache() ) {
1066 dyld3::kdebug_trace_dyld_image(baseCode
, image
.getInstallPath(), (const uuid_t
*)&uuid
, {0}, {{ 0, 0 }}, image
.machHeader());
1068 fsid_t fsid
= {{0, 0}};
1069 fsobj_id_t fsobj
= {0};
1070 ino_t inode
= image
.getInode();
1071 fsobj
.fid_objno
= (uint32_t)inode
;
1072 fsobj
.fid_generation
= (uint32_t)(inode
>>32);
1073 fsid
.val
[0] = image
.getDevice();
1074 dyld3::kdebug_trace_dyld_image(baseCode
, image
.getPath(), (const uuid_t
*)&uuid
, fsobj
, fsid
, image
.machHeader());
1078 static void notifySingle(dyld_image_states state
, const ImageLoader
* image
, ImageLoader::InitializerTimingList
* timingInfo
)
1080 //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath());
1081 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(state
, sSingleHandlers
);
1082 if ( handlers
!= NULL
) {
1083 dyld_image_info info
;
1084 info
.imageLoadAddress
= image
->machHeader();
1085 info
.imageFilePath
= image
->getRealPath();
1086 info
.imageFileModDate
= image
->lastModified();
1087 for (std::vector
<dyld_image_state_change_handler
>::iterator it
= handlers
->begin(); it
!= handlers
->end(); ++it
) {
1088 const char* result
= (*it
)(state
, 1, &info
);
1089 if ( (result
!= NULL
) && (state
== dyld_image_state_mapped
) ) {
1090 //fprintf(stderr, " image rejected by handler=%p\n", *it);
1091 // make copy of thrown string so that later catch clauses can free it
1092 const char* str
= strdup(result
);
1097 if ( state
== dyld_image_state_mapped
) {
1098 // <rdar://problem/7008875> Save load addr + UUID for images from outside the shared cache
1099 // <rdar://problem/50432671> Include UUIDs for shared cache dylibs in all image info when using private mapped shared caches
1100 if (!image
->inSharedCache()
1101 || (gLinkContext
.sharedRegionMode
== ImageLoader::kUsePrivateSharedRegion
)) {
1102 dyld_uuid_info info
;
1103 if ( image
->getUUID(info
.imageUUID
) ) {
1104 info
.imageLoadAddress
= image
->machHeader();
1105 addNonSharedCacheImageUUID(info
);
1109 if ( (state
== dyld_image_state_dependents_initialized
) && (sNotifyObjCInit
!= NULL
) && image
->notifyObjC() ) {
1110 uint64_t t0
= mach_absolute_time();
1111 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_OBJC_INIT
, (uint64_t)image
->machHeader(), 0, 0);
1112 (*sNotifyObjCInit
)(image
->getRealPath(), image
->machHeader());
1113 uint64_t t1
= mach_absolute_time();
1114 uint64_t t2
= mach_absolute_time();
1115 uint64_t timeInObjC
= t1
-t0
;
1116 uint64_t emptyTime
= (t2
-t1
)*100;
1117 if ( (timeInObjC
> emptyTime
) && (timingInfo
!= NULL
) ) {
1118 timingInfo
->addTime(image
->getShortName(), timeInObjC
);
1121 // mach message csdlc about dynamically unloaded images
1122 if ( image
->addFuncNotified() && (state
== dyld_image_state_terminated
) ) {
1123 notifyKernel(*image
, false);
1124 const struct mach_header
* loadAddress
[] = { image
->machHeader() };
1125 const char* loadPath
[] = { image
->getPath() };
1126 notifyMonitoringDyld(true, 1, loadAddress
, loadPath
);
1132 // Normally, dyld_all_image_infos is only updated in batches after an entire
1133 // graph is loaded. But if there is an error loading the initial set of
1134 // dylibs needed by the main executable, dyld_all_image_infos is not yet set
1135 // up, leading to usually brief crash logs.
1137 // This function manually adds the images loaded so far to dyld::gProcessInfo.
1138 // It should only be called before terminating.
1140 void syncAllImages()
1142 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); ++it
) {
1143 dyld_image_info info
;
1144 ImageLoader
* image
= *it
;
1145 info
.imageLoadAddress
= image
->machHeader();
1146 info
.imageFilePath
= image
->getRealPath();
1147 info
.imageFileModDate
= image
->lastModified();
1148 // add to all_image_infos if not already there
1150 int existingCount
= dyld::gProcessInfo
->infoArrayCount
;
1151 const dyld_image_info
* existing
= dyld::gProcessInfo
->infoArray
;
1152 if ( existing
!= NULL
) {
1153 for (int i
=0; i
< existingCount
; ++i
) {
1154 if ( existing
[i
].imageLoadAddress
== info
.imageLoadAddress
) {
1155 //dyld::log("not adding %s\n", info.imageFilePath);
1162 //dyld::log("adding %s\n", info.imageFilePath);
1163 addImagesToAllImages(1, &info
);
1169 static int imageSorter(const void* l
, const void* r
)
1171 const ImageLoader
* left
= *((ImageLoader
**)l
);
1172 const ImageLoader
* right
= *((ImageLoader
**)r
);
1173 return left
->compare(right
);
1176 static void notifyBatchPartial(dyld_image_states state
, bool orLater
, dyld_image_state_change_handler onlyHandler
, bool preflightOnly
, bool onlyObjCMappedNotification
)
1178 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(state
, sBatchHandlers
);
1179 if ( (handlers
!= NULL
) || ((state
== dyld_image_state_bound
) && (sNotifyObjCMapped
!= NULL
)) ) {
1180 // don't use a vector because it will use malloc/free and we want notifcation to be low cost
1182 dyld_image_info infos
[allImagesCount()+1];
1183 ImageLoader
* images
[allImagesCount()+1];
1184 ImageLoader
** end
= images
;
1185 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
1186 dyld_image_states imageState
= (*it
)->getState();
1187 if ( (imageState
== state
) || (orLater
&& (imageState
> state
)) )
1190 if ( sBundleBeingLoaded
!= NULL
) {
1191 dyld_image_states imageState
= sBundleBeingLoaded
->getState();
1192 if ( (imageState
== state
) || (orLater
&& (imageState
> state
)) )
1193 *end
++ = sBundleBeingLoaded
;
1195 const char* dontLoadReason
= NULL
;
1196 uint32_t imageCount
= (uint32_t)(end
-images
);
1197 if ( imageCount
!= 0 ) {
1199 qsort(images
, imageCount
, sizeof(ImageLoader
*), &imageSorter
);
1201 const mach_header
* mhs
[imageCount
];
1202 const char* paths
[imageCount
];
1203 uint32_t bulkNotifyImageCount
= 0;
1206 for (unsigned int i
=0; i
< imageCount
; ++i
) {
1207 dyld_image_info
* p
= &infos
[i
];
1208 ImageLoader
* image
= images
[i
];
1209 //dyld::log(" state=%d, name=%s\n", state, image->getPath());
1210 p
->imageLoadAddress
= image
->machHeader();
1211 p
->imageFilePath
= image
->getRealPath();
1212 p
->imageFileModDate
= image
->lastModified();
1213 // get these registered with the kernel as early as possible
1214 if ( state
== dyld_image_state_dependents_mapped
)
1215 notifyKernel(*image
, true);
1216 // special case for add_image hook
1217 if ( state
== dyld_image_state_bound
) {
1218 if ( notifyAddImageCallbacks(image
) ) {
1219 // Add this to the list of images to bulk notify
1220 mhs
[bulkNotifyImageCount
] = infos
[i
].imageLoadAddress
;
1221 paths
[bulkNotifyImageCount
] = infos
[i
].imageFilePath
;
1222 ++bulkNotifyImageCount
;
1227 if ( (state
== dyld_image_state_bound
) && !sAddBulkLoadImageCallbacks
.empty() && (bulkNotifyImageCount
!= 0) ) {
1228 for (LoadImageBulkCallback func
: sAddBulkLoadImageCallbacks
) {
1229 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)mhs
[0], (uint64_t)func
, 0);
1230 (*func
)(bulkNotifyImageCount
, mhs
, paths
);
1234 #if SUPPORT_ACCELERATE_TABLES
1235 if ( sAllCacheImagesProxy
!= NULL
) {
1236 unsigned cacheCount
= sAllCacheImagesProxy
->appendImagesToNotify(state
, orLater
, &infos
[imageCount
]);
1237 // support _dyld_register_func_for_add_image()
1238 if ( state
== dyld_image_state_bound
) {
1239 for (ImageCallback callback
: sAddImageCallbacks
) {
1240 for (unsigned i
=0; i
< cacheCount
; ++i
) {
1241 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)infos
[imageCount
+i
].imageLoadAddress
, (uint64_t)(*callback
), 0);
1242 (*callback
)(infos
[imageCount
+i
].imageLoadAddress
, sSharedCacheLoadInfo
.slide
);
1245 for (LoadImageCallback func
: sAddLoadImageCallbacks
) {
1246 for (unsigned i
=0; i
< cacheCount
; ++i
) {
1247 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)infos
[imageCount
+i
].imageLoadAddress
, (uint64_t)(*func
), 0);
1248 (*func
)(infos
[imageCount
+i
].imageLoadAddress
, infos
[imageCount
+i
].imageFilePath
, false);
1251 if ( !sAddBulkLoadImageCallbacks
.empty() ) {
1252 const mach_header
* bulk_mhs
[cacheCount
];
1253 const char* bulk_paths
[cacheCount
];
1254 for (int i
=0; i
< cacheCount
; ++i
) {
1255 bulk_mhs
[i
] = infos
[imageCount
+i
].imageLoadAddress
;
1256 bulk_paths
[i
] = infos
[imageCount
+i
].imageFilePath
;
1258 for (LoadImageBulkCallback func
: sAddBulkLoadImageCallbacks
) {
1259 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)bulk_mhs
[0], (uint64_t)func
, 0);
1260 (*func
)(cacheCount
, bulk_mhs
, bulk_paths
);
1264 imageCount
+= cacheCount
;
1267 if ( imageCount
!= 0 ) {
1268 if ( !onlyObjCMappedNotification
) {
1269 if ( onlyHandler
!= NULL
) {
1270 const char* result
= NULL
;
1271 if ( result
== NULL
) {
1272 result
= (*onlyHandler
)(state
, imageCount
, infos
);
1274 if ( (result
!= NULL
) && (state
== dyld_image_state_dependents_mapped
) ) {
1275 //fprintf(stderr, " images rejected by handler=%p\n", onlyHandler);
1276 // make copy of thrown string so that later catch clauses can free it
1277 dontLoadReason
= strdup(result
);
1281 // call each handler with whole array
1282 if ( handlers
!= NULL
) {
1283 for (std::vector
<dyld_image_state_change_handler
>::iterator it
= handlers
->begin(); it
!= handlers
->end(); ++it
) {
1284 const char* result
= (*it
)(state
, imageCount
, infos
);
1285 if ( (result
!= NULL
) && (state
== dyld_image_state_dependents_mapped
) ) {
1286 //fprintf(stderr, " images rejected by handler=%p\n", *it);
1287 // make copy of thrown string so that later catch clauses can free it
1288 dontLoadReason
= strdup(result
);
1295 // tell objc about new images
1296 if ( (onlyHandler
== NULL
) && ((state
== dyld_image_state_bound
) || (orLater
&& (dyld_image_state_bound
> state
))) && (sNotifyObjCMapped
!= NULL
) ) {
1297 const char* paths
[imageCount
];
1298 const mach_header
* mhs
[imageCount
];
1299 unsigned objcImageCount
= 0;
1300 for (int i
=0; i
< imageCount
; ++i
) {
1301 ImageLoader
* image
= findImageByMachHeader(infos
[i
].imageLoadAddress
);
1302 bool hasObjC
= false;
1303 if ( image
!= NULL
) {
1304 if ( image
->objCMappedNotified() )
1306 hasObjC
= image
->notifyObjC();
1308 #if SUPPORT_ACCELERATE_TABLES
1309 else if ( sAllCacheImagesProxy
!= NULL
) {
1310 const mach_header
* mh
;
1313 if ( sAllCacheImagesProxy
->addressInCache(infos
[i
].imageLoadAddress
, &mh
, &path
, &index
) ) {
1314 hasObjC
= (mh
->flags
& MH_HAS_OBJC
);
1319 paths
[objcImageCount
] = infos
[i
].imageFilePath
;
1320 mhs
[objcImageCount
] = infos
[i
].imageLoadAddress
;
1322 if ( image
!= NULL
)
1323 image
->setObjCMappedNotified();
1326 if ( objcImageCount
!= 0 ) {
1327 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_OBJC_MAP
, 0, 0, 0);
1328 uint64_t t0
= mach_absolute_time();
1329 (*sNotifyObjCMapped
)(objcImageCount
, paths
, mhs
);
1330 uint64_t t1
= mach_absolute_time();
1331 ImageLoader::fgTotalObjCSetupTime
+= (t1
-t0
);
1336 if ( dontLoadReason
!= NULL
)
1337 throw dontLoadReason
;
1338 if ( !preflightOnly
&& (state
== dyld_image_state_dependents_mapped
) ) {
1339 const struct mach_header
* loadAddresses
[imageCount
];
1340 const char* loadPaths
[imageCount
];
1341 for(uint32_t i
= 0; i
<imageCount
; ++i
) {
1342 loadAddresses
[i
] = infos
[i
].imageLoadAddress
;
1343 loadPaths
[i
] = infos
[i
].imageFilePath
;
1345 notifyMonitoringDyld(false, imageCount
, loadAddresses
, loadPaths
);
1350 static void notifyBatch(dyld_image_states state
, bool preflightOnly
)
1352 notifyBatchPartial(state
, false, NULL
, preflightOnly
, false);
1357 void coresymbolication_load_notifier(void* connection
, uint64_t timestamp
, const char* path
, const struct mach_header
* mh
)
1359 const struct mach_header
* loadAddress
[] = { mh
};
1360 const char* loadPath
[] = { path
};
1361 notifyMonitoringDyld(false, 1, loadAddress
, loadPath
);
1365 void coresymbolication_unload_notifier(void* connection
, uint64_t timestamp
, const char* path
, const struct mach_header
* mh
)
1367 const struct mach_header
* loadAddress
= { mh
};
1368 const char* loadPath
= { path
};
1369 notifyMonitoringDyld(true, 1, &loadAddress
, &loadPath
);
1373 kern_return_t
legacy_task_register_dyld_image_infos(task_t task
, dyld_kernel_image_info_array_t dyld_images
,
1374 mach_msg_type_number_t dyld_imagesCnt
)
1376 return KERN_SUCCESS
;
1380 kern_return_t
legacy_task_unregister_dyld_image_infos(task_t task
, dyld_kernel_image_info_array_t dyld_images
,
1381 mach_msg_type_number_t dyld_imagesCnt
)
1383 return KERN_SUCCESS
;
1387 kern_return_t
legacy_task_get_dyld_image_infos(task_inspect_t task
, dyld_kernel_image_info_array_t
*dyld_images
,
1388 mach_msg_type_number_t
*dyld_imagesCnt
)
1390 return KERN_SUCCESS
;
1394 kern_return_t
legacy_task_register_dyld_shared_cache_image_info(task_t task
, dyld_kernel_image_info_t dyld_cache_image
,
1395 boolean_t no_cache
, boolean_t private_cache
)
1397 return KERN_SUCCESS
;
1401 kern_return_t
legacy_task_register_dyld_set_dyld_state(task_t task
, uint8_t dyld_state
)
1403 return KERN_SUCCESS
;
1407 kern_return_t
legacy_task_register_dyld_get_process_state(task_t task
, dyld_kernel_process_info_t
*dyld_process_state
)
1409 return KERN_SUCCESS
;
1413 // In order for register_func_for_add_image() callbacks to to be called bottom up,
1414 // we need to maintain a list of root images. The main executable is usally the
1415 // first root. Any images dynamically added are also roots (unless already loaded).
1416 // If DYLD_INSERT_LIBRARIES is used, those libraries are first.
1417 static void addRootImage(ImageLoader
* image
)
1419 //dyld::log("addRootImage(%p, %s)\n", image, image->getPath());
1420 // add to list of roots
1421 sImageRoots
.push_back(image
);
1425 static void clearAllDepths()
1427 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++)
1428 (*it
)->clearDepth();
1431 static void printAllDepths()
1433 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++)
1434 dyld::log("%03d %s\n", (*it
)->getDepth(), (*it
)->getShortName());
1438 static unsigned int imageCount()
1441 unsigned int result
= (unsigned int)sAllImages
.size();
1447 static void setNewProgramVars(const ProgramVars
& newVars
)
1449 // make a copy of the pointers to program variables
1450 gLinkContext
.programVars
= newVars
;
1452 // now set each program global to their initial value
1453 *gLinkContext
.programVars
.NXArgcPtr
= gLinkContext
.argc
;
1454 *gLinkContext
.programVars
.NXArgvPtr
= gLinkContext
.argv
;
1455 *gLinkContext
.programVars
.environPtr
= gLinkContext
.envp
;
1456 *gLinkContext
.programVars
.__prognamePtr
= gLinkContext
.progname
;
1459 #if SUPPORT_OLD_CRT_INITIALIZATION
1460 static void setRunInitialzersOldWay()
1462 gRunInitializersOldWay
= true;
1466 static bool sandboxBlocked(const char* path
, const char* kind
)
1468 #if TARGET_OS_SIMULATOR
1469 // sandbox calls not yet supported in simulator runtime
1472 sandbox_filter_type filter
= (sandbox_filter_type
)(SANDBOX_FILTER_PATH
| SANDBOX_CHECK_NO_REPORT
);
1473 return ( sandbox_check(getpid(), kind
, filter
, path
) > 0 );
1477 bool sandboxBlockedMmap(const char* path
)
1479 return sandboxBlocked(path
, "file-map-executable");
1482 bool sandboxBlockedOpen(const char* path
)
1484 return sandboxBlocked(path
, "file-read-data");
1487 bool sandboxBlockedStat(const char* path
)
1489 return sandboxBlocked(path
, "file-read-metadata");
1493 static void addDynamicReference(ImageLoader
* from
, ImageLoader
* to
) {
1494 // don't add dynamic reference if target is in the shared cache (since it can't be unloaded)
1495 if ( to
->inSharedCache() )
1498 // don't add dynamic reference if there already is a static one
1499 if ( from
->dependsOn(to
) )
1502 #pragma clang diagnostic push
1503 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1504 // don't add if this combination already exists
1505 OSSpinLockLock(&sDynamicReferencesLock
);
1506 for (std::vector
<ImageLoader::DynamicReference
>::iterator it
=sDynamicReferences
.begin(); it
!= sDynamicReferences
.end(); ++it
) {
1507 if ( (it
->from
== from
) && (it
->to
== to
) ) {
1508 OSSpinLockUnlock(&sDynamicReferencesLock
);
1513 //dyld::log("addDynamicReference(%s, %s\n", from->getShortName(), to->getShortName());
1514 ImageLoader::DynamicReference t
;
1517 sDynamicReferences
.push_back(t
);
1518 OSSpinLockUnlock(&sDynamicReferencesLock
);
1519 #pragma clang diagnostic pop
1522 static void addImage(ImageLoader
* image
)
1524 // add to master list
1526 sAllImages
.push_back(image
);
1529 // update mapped ranges
1530 uintptr_t lastSegStart
= 0;
1531 uintptr_t lastSegEnd
= 0;
1532 for(unsigned int i
=0, e
=image
->segmentCount(); i
< e
; ++i
) {
1533 if ( image
->segUnaccessible(i
) )
1535 uintptr_t start
= image
->segActualLoadAddress(i
);
1536 uintptr_t end
= image
->segActualEndAddress(i
);
1537 if ( start
== lastSegEnd
) {
1538 // two segments are contiguous, just record combined segments
1542 // non-contiguous segments, record last (if any)
1543 if ( lastSegEnd
!= 0 )
1544 addMappedRange(image
, lastSegStart
, lastSegEnd
);
1545 lastSegStart
= start
;
1549 if ( lastSegEnd
!= 0 )
1550 addMappedRange(image
, lastSegStart
, lastSegEnd
);
1553 if ( gLinkContext
.verboseLoading
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) {
1554 const char *imagePath
= image
->getPath();
1556 if ( image
->getUUID(imageUUID
) ) {
1557 uuid_string_t imageUUIDStr
;
1558 uuid_unparse_upper(imageUUID
, imageUUIDStr
);
1559 dyld::log("dyld: loaded: <%s> %s\n", imageUUIDStr
, imagePath
);
1562 dyld::log("dyld: loaded: %s\n", imagePath
);
1569 // Helper for std::remove_if
1571 class RefUsesImage
{
1573 RefUsesImage(ImageLoader
* image
) : _image(image
) {}
1574 bool operator()(const ImageLoader::DynamicReference
& ref
) const {
1575 return ( (ref
.from
== _image
) || (ref
.to
== _image
) );
1578 ImageLoader
* _image
;
1583 void removeImage(ImageLoader
* image
)
1585 // if has dtrace DOF section, tell dtrace it is going away, then remove from sImageFilesNeedingDOFUnregistration
1586 for (std::vector
<RegisteredDOF
>::iterator it
=sImageFilesNeedingDOFUnregistration
.begin(); it
!= sImageFilesNeedingDOFUnregistration
.end(); ) {
1587 if ( it
->mh
== image
->machHeader() ) {
1588 unregisterDOF(it
->registrationID
);
1589 sImageFilesNeedingDOFUnregistration
.erase(it
);
1590 // don't increment iterator, the erase caused next element to be copied to where this iterator points
1597 // tell all registered remove image handlers about this
1598 // do this before removing image from internal data structures so that the callback can query dyld about the image
1599 if ( image
->getState() >= dyld_image_state_bound
) {
1600 sRemoveImageCallbacksInUse
= true; // This only runs inside dyld's global lock, so ok to use a global for the in-use flag.
1601 for (std::vector
<ImageCallback
>::iterator it
=sRemoveImageCallbacks
.begin(); it
!= sRemoveImageCallbacks
.end(); it
++) {
1602 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_REMOVE_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*it
), 0);
1603 (*it
)(image
->machHeader(), image
->getSlide());
1605 sRemoveImageCallbacksInUse
= false;
1607 if ( sNotifyObjCUnmapped
!= NULL
&& image
->notifyObjC() )
1608 (*sNotifyObjCUnmapped
)(image
->getRealPath(), image
->machHeader());
1612 notifySingle(dyld_image_state_terminated
, image
, NULL
);
1614 // remove from mapped images table
1615 removedMappedRanges(image
);
1617 // remove from master list
1619 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
1620 if ( *it
== image
) {
1621 sAllImages
.erase(it
);
1627 #pragma clang diagnostic push
1628 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1629 // remove from sDynamicReferences
1630 OSSpinLockLock(&sDynamicReferencesLock
);
1631 sDynamicReferences
.erase(std::remove_if(sDynamicReferences
.begin(), sDynamicReferences
.end(), RefUsesImage(image
)), sDynamicReferences
.end());
1632 OSSpinLockUnlock(&sDynamicReferencesLock
);
1633 #pragma clang diagnostic pop
1635 // flush find-by-address cache (do this after removed from master list, so there is no chance it can come back)
1636 if ( sLastImageByAddressCache
== image
)
1637 sLastImageByAddressCache
= NULL
;
1639 // if in root list, pull it out
1640 for (std::vector
<ImageLoader
*>::iterator it
=sImageRoots
.begin(); it
!= sImageRoots
.end(); it
++) {
1641 if ( *it
== image
) {
1642 sImageRoots
.erase(it
);
1647 // If this image is the potential canonical definition of any weak defs, then set them to a tombstone value
1648 if ( gLinkContext
.weakDefMapInitialized
&& image
->hasCoalescedExports() && (image
->getState() >= dyld_image_state_bound
) ) {
1650 const dyld3::MachOAnalyzer
* ma
= (const dyld3::MachOAnalyzer
*)image
->machHeader();
1651 ma
->forEachWeakDef(diag
, ^(const char *symbolName
, uint64_t imageOffset
, bool isFromExportTrie
) {
1652 auto it
= gLinkContext
.weakDefMap
.find(symbolName
);
1653 assert(it
!= gLinkContext
.weakDefMap
.end());
1654 it
->second
= { nullptr, 0 };
1655 if ( !isFromExportTrie
) {
1656 // The string was already duplicated if we are an export trie
1657 // so only strdup as we are the nlist
1658 size_t hash1
= ImageLoader::HashCString::hash(it
->first
);
1659 it
->first
= strdup(it
->first
);
1660 size_t hash2
= ImageLoader::HashCString::hash(it
->first
);
1661 assert(hash1
== hash2
);
1667 if ( gLinkContext
.verboseLoading
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) {
1668 const char *imagePath
= image
->getPath();
1670 if ( image
->getUUID(imageUUID
) ) {
1671 uuid_string_t imageUUIDStr
;
1672 uuid_unparse_upper(imageUUID
, imageUUIDStr
);
1673 dyld::log("dyld: unloaded: <%s> %s\n", imageUUIDStr
, imagePath
);
1676 dyld::log("dyld: unloaded: %s\n", imagePath
);
1680 // tell gdb, new way
1681 removeImageFromAllImages(image
->machHeader());
1685 void runImageStaticTerminators(ImageLoader
* image
)
1687 // if in termination list, pull it out and run terminator
1690 mightBeMore
= false;
1691 for (std::vector
<ImageLoader
*>::iterator it
=sImageFilesNeedingTermination
.begin(); it
!= sImageFilesNeedingTermination
.end(); it
++) {
1692 if ( *it
== image
) {
1693 sImageFilesNeedingTermination
.erase(it
);
1694 if (gLogAPIs
) dyld::log("dlclose(), running static terminators for %p %s\n", image
, image
->getShortName());
1695 image
->doTermination(gLinkContext
);
1700 } while ( mightBeMore
);
1703 static void terminationRecorder(ImageLoader
* image
)
1707 // <rdar://problem/71820555> Don't run static terminator for arm64e
1708 const mach_header
* mh
= image
->machHeader();
1709 if ( (mh
->cputype
== CPU_TYPE_ARM64
) && ((mh
->cpusubtype
& ~CPU_SUBTYPE_MASK
) == CPU_SUBTYPE_ARM64E
) )
1713 sImageFilesNeedingTermination
.push_back(image
);
1716 const char* getExecutablePath()
1721 static void runAllStaticTerminators(void* extra
)
1724 const size_t imageCount
= sImageFilesNeedingTermination
.size();
1725 for(size_t i
=imageCount
; i
> 0; --i
){
1726 ImageLoader
* image
= sImageFilesNeedingTermination
[i
-1];
1727 image
->doTermination(gLinkContext
);
1729 sImageFilesNeedingTermination
.clear();
1730 notifyBatch(dyld_image_state_terminated
, false);
1732 catch (const char* msg
) {
1737 void initializeMainExecutable()
1739 // record that we've reached this step
1740 gLinkContext
.startedInitializingMainExecutable
= true;
1742 // run initialzers for any inserted dylibs
1743 ImageLoader::InitializerTimingList initializerTimes
[allImagesCount()];
1744 initializerTimes
[0].count
= 0;
1745 const size_t rootCount
= sImageRoots
.size();
1746 if ( rootCount
> 1 ) {
1747 for(size_t i
=1; i
< rootCount
; ++i
) {
1748 sImageRoots
[i
]->runInitializers(gLinkContext
, initializerTimes
[0]);
1752 // run initializers for main executable and everything it brings up
1753 sMainExecutable
->runInitializers(gLinkContext
, initializerTimes
[0]);
1755 // register cxa_atexit() handler to run static terminators in all loaded images when this process exits
1756 if ( gLibSystemHelpers
!= NULL
)
1757 (*gLibSystemHelpers
->cxa_atexit
)(&runAllStaticTerminators
, NULL
, NULL
);
1759 // dump info if requested
1760 if ( sEnv
.DYLD_PRINT_STATISTICS
)
1761 ImageLoader::printStatistics((unsigned int)allImagesCount(), initializerTimes
[0]);
1762 if ( sEnv
.DYLD_PRINT_STATISTICS_DETAILS
)
1763 ImageLoaderMachO::printStatisticsDetails((unsigned int)allImagesCount(), initializerTimes
[0]);
1766 bool mainExecutablePrebound()
1768 return sMainExecutable
->usablePrebinding(gLinkContext
);
1771 ImageLoader
* mainExecutable()
1773 return sMainExecutable
;
1779 #if SUPPORT_VERSIONED_PATHS
1781 // forward reference
1782 static bool getDylibVersionAndInstallname(const char* dylibPath
, uint32_t* version
, char* installName
);
1786 // Examines a dylib file and if its current_version is newer than the installed
1787 // dylib at its install_name, then add the dylib file to sDylibOverrides.
1789 static void checkDylibOverride(const char* dylibFile
)
1791 //dyld::log("checkDylibOverride('%s')\n", dylibFile);
1792 uint32_t altVersion
;
1793 char sysInstallName
[PATH_MAX
];
1794 if ( getDylibVersionAndInstallname(dylibFile
, &altVersion
, sysInstallName
) && (sysInstallName
[0] =='/') ) {
1795 //dyld::log("%s has version 0x%08X and install name %s\n", dylibFile, altVersion, sysInstallName);
1796 uint32_t sysVersion
;
1797 if ( getDylibVersionAndInstallname(sysInstallName
, &sysVersion
, NULL
) ) {
1798 //dyld::log("%s has version 0x%08X\n", sysInstallName, sysVersion);
1799 if ( altVersion
> sysVersion
) {
1800 //dyld::log("override found: %s -> %s\n", sysInstallName, dylibFile);
1801 // see if there already is an override for this dylib
1802 bool entryExists
= false;
1803 for (std::vector
<DylibOverride
>::iterator it
= sDylibOverrides
.begin(); it
!= sDylibOverrides
.end(); ++it
) {
1804 if ( strcmp(it
->installName
, sysInstallName
) == 0 ) {
1806 uint32_t prevVersion
;
1807 if ( getDylibVersionAndInstallname(it
->override
, &prevVersion
, NULL
) ) {
1808 if ( altVersion
> prevVersion
) {
1809 // found an even newer override
1810 free((void*)(it
->override
));
1811 char resolvedPath
[PATH_MAX
];
1812 if ( realpath(dylibFile
, resolvedPath
) != NULL
)
1813 it
->override
= strdup(resolvedPath
);
1815 it
->override
= strdup(dylibFile
);
1821 if ( ! entryExists
) {
1822 DylibOverride entry
;
1823 entry
.installName
= strdup(sysInstallName
);
1824 char resolvedPath
[PATH_MAX
];
1825 if ( realpath(dylibFile
, resolvedPath
) != NULL
)
1826 entry
.override
= strdup(resolvedPath
);
1828 entry
.override
= strdup(dylibFile
);
1829 sDylibOverrides
.push_back(entry
);
1830 //dyld::log("added override: %s -> %s\n", entry.installName, entry.override);
1838 static void checkDylibOverridesInDir(const char* dirPath
)
1840 //dyld::log("checkDylibOverridesInDir('%s')\n", dirPath);
1841 char dylibPath
[PATH_MAX
];
1842 long dirPathLen
= strlcpy(dylibPath
, dirPath
, PATH_MAX
-1);
1843 if ( dirPathLen
>= PATH_MAX
)
1845 DIR* dirp
= opendir(dirPath
);
1846 if ( dirp
!= NULL
) {
1848 dirent
* entp
= NULL
;
1849 while ( readdir_r(dirp
, &entry
, &entp
) == 0 ) {
1852 if ( entp
->d_type
!= DT_REG
)
1854 dylibPath
[dirPathLen
] = '/';
1855 dylibPath
[dirPathLen
+1] = '\0';
1856 if ( strlcat(dylibPath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX
)
1858 checkDylibOverride(dylibPath
);
1865 static void checkFrameworkOverridesInDir(const char* dirPath
)
1867 //dyld::log("checkFrameworkOverridesInDir('%s')\n", dirPath);
1868 char frameworkPath
[PATH_MAX
];
1869 long dirPathLen
= strlcpy(frameworkPath
, dirPath
, PATH_MAX
-1);
1870 if ( dirPathLen
>= PATH_MAX
)
1872 DIR* dirp
= opendir(dirPath
);
1873 if ( dirp
!= NULL
) {
1875 dirent
* entp
= NULL
;
1876 while ( readdir_r(dirp
, &entry
, &entp
) == 0 ) {
1879 if ( entp
->d_type
!= DT_DIR
)
1881 frameworkPath
[dirPathLen
] = '/';
1882 frameworkPath
[dirPathLen
+1] = '\0';
1883 int dirNameLen
= (int)strlen(entp
->d_name
);
1884 if ( dirNameLen
< 11 )
1886 if ( strcmp(&entp
->d_name
[dirNameLen
-10], ".framework") != 0 )
1888 if ( strlcat(frameworkPath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX
)
1890 if ( strlcat(frameworkPath
, "/", PATH_MAX
) >= PATH_MAX
)
1892 if ( strlcat(frameworkPath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX
)
1894 frameworkPath
[strlen(frameworkPath
)-10] = '\0';
1895 checkDylibOverride(frameworkPath
);
1900 #endif // SUPPORT_VERSIONED_PATHS
1904 // Turns a colon separated list of strings into a NULL terminated array
1905 // of string pointers. If mainExecutableDir param is not NULL,
1906 // substitutes @loader_path with main executable's dir.
1908 static const char** parseColonList(const char* list
, const char* mainExecutableDir
)
1910 static const char* sEmptyList
[] = { NULL
};
1912 if ( list
[0] == '\0' )
1916 for(const char* s
=list
; *s
!= '\0'; ++s
) {
1922 const char* start
= list
;
1923 char** result
= new char*[colonCount
+2];
1924 for(const char* s
=list
; *s
!= '\0'; ++s
) {
1926 size_t len
= s
-start
;
1927 if ( (mainExecutableDir
!= NULL
) && (strncmp(start
, "@loader_path/", 13) == 0) ) {
1928 if ( !gLinkContext
.allowAtPaths
) {
1929 dyld::log("dyld: warning: @loader_path/ ignored because of amfi policy (Codesign main executable with Library Validation to allow @ paths)\n");
1932 size_t mainExecDirLen
= strlen(mainExecutableDir
);
1933 char* str
= new char[mainExecDirLen
+len
+1];
1934 strcpy(str
, mainExecutableDir
);
1935 strlcat(str
, &start
[13], mainExecDirLen
+len
+1);
1936 str
[mainExecDirLen
+len
-13] = '\0';
1938 result
[index
++] = str
;
1940 else if ( (mainExecutableDir
!= NULL
) && (strncmp(start
, "@executable_path/", 17) == 0) ) {
1941 if ( !gLinkContext
.allowAtPaths
) {
1942 dyld::log("dyld: warning: @executable_path/ ignored because of amfi policy (Codesign main executable with Library Validation to allow @ paths)\n");
1945 size_t mainExecDirLen
= strlen(mainExecutableDir
);
1946 char* str
= new char[mainExecDirLen
+len
+1];
1947 strcpy(str
, mainExecutableDir
);
1948 strlcat(str
, &start
[17], mainExecDirLen
+len
+1);
1949 str
[mainExecDirLen
+len
-17] = '\0';
1951 result
[index
++] = str
;
1954 char* str
= new char[len
+1];
1955 strncpy(str
, start
, len
);
1958 result
[index
++] = str
;
1962 size_t len
= strlen(start
);
1963 if ( (mainExecutableDir
!= NULL
) && (strncmp(start
, "@loader_path/", 13) == 0) ) {
1964 if ( !gLinkContext
.allowAtPaths
) {
1965 dyld::log("dyld: warning: @loader_path/ ignored because of amfi policy (Codesign main executable with Library Validation to allow @ paths)\n");
1969 size_t mainExecDirLen
= strlen(mainExecutableDir
);
1970 char* str
= new char[mainExecDirLen
+len
+1];
1971 strcpy(str
, mainExecutableDir
);
1972 strlcat(str
, &start
[13], mainExecDirLen
+len
+1);
1973 str
[mainExecDirLen
+len
-13] = '\0';
1974 result
[index
++] = str
;
1977 else if ( (mainExecutableDir
!= NULL
) && (strncmp(start
, "@executable_path/", 17) == 0) ) {
1978 if ( !gLinkContext
.allowAtPaths
) {
1979 dyld::log("dyld: warning: @executable_path/ ignored because of amfi policy (Codesign main executable with Library Validation to allow @ paths)\n");
1983 size_t mainExecDirLen
= strlen(mainExecutableDir
);
1984 char* str
= new char[mainExecDirLen
+len
+1];
1985 strcpy(str
, mainExecutableDir
);
1986 strlcat(str
, &start
[17], mainExecDirLen
+len
+1);
1987 str
[mainExecDirLen
+len
-17] = '\0';
1988 result
[index
++] = str
;
1992 char* str
= new char[len
+1];
1994 result
[index
++] = str
;
1996 result
[index
] = NULL
;
1998 //dyld::log("parseColonList(%s)\n", list);
1999 //for(int i=0; result[i] != NULL; ++i)
2000 // dyld::log(" %s\n", result[i]);
2001 return (const char**)result
;
2004 static void appendParsedColonList(const char* list
, const char* mainExecutableDir
, const char* const ** storage
)
2006 const char** newlist
= parseColonList(list
, mainExecutableDir
);
2007 if ( *storage
== NULL
) {
2008 // first time, just set
2012 // need to append to existing list
2013 const char* const* existing
= *storage
;
2015 for(int i
=0; existing
[i
] != NULL
; ++i
)
2017 for(int i
=0; newlist
[i
] != NULL
; ++i
)
2019 const char** combinedList
= new const char*[count
+2];
2021 for(int i
=0; existing
[i
] != NULL
; ++i
)
2022 combinedList
[index
++] = existing
[i
];
2023 for(int i
=0; newlist
[i
] != NULL
; ++i
)
2024 combinedList
[index
++] = newlist
[i
];
2025 combinedList
[index
] = NULL
;
2026 delete[] newlist
; // free array, note: strings in newList may be leaked
2027 *storage
= combinedList
;
2032 static void paths_expand_roots(const char **paths
, const char *key
, const char *val
)
2034 // assert(val != NULL);
2035 // assert(paths != NULL);
2037 size_t keyLen
= strlen(key
);
2038 for(int i
=0; paths
[i
] != NULL
; ++i
) {
2039 if ( strncmp(paths
[i
], key
, keyLen
) == 0 ) {
2040 char* newPath
= new char[strlen(val
) + (strlen(paths
[i
]) - keyLen
) + 1];
2041 strcpy(newPath
, val
);
2042 strcat(newPath
, &paths
[i
][keyLen
]);
2050 static void removePathWithPrefix(const char* paths
[], const char* prefix
)
2052 size_t prefixLen
= strlen(prefix
);
2055 for(i
= 0; paths
[i
] != NULL
; ++i
) {
2056 if ( strncmp(paths
[i
], prefix
, prefixLen
) == 0 )
2059 paths
[i
-skip
] = paths
[i
];
2061 paths
[i
-skip
] = NULL
;
2067 static void paths_dump(const char **paths
)
2069 // assert(paths != NULL);
2070 const char **strs
= paths
;
2071 while(*strs
!= NULL
)
2073 dyld::log("\"%s\"\n", *strs
);
2082 static void printOptions(const char* argv
[])
2085 while ( NULL
!= argv
[i
] ) {
2086 dyld::log("opt[%i] = \"%s\"\n", i
, argv
[i
]);
2091 static void printEnvironmentVariables(const char* envp
[])
2093 while ( NULL
!= *envp
) {
2094 dyld::log("%s\n", *envp
);
2099 void processDyldEnvironmentVariable(const char* key
, const char* value
, const char* mainExecutableDir
)
2101 if ( strcmp(key
, "DYLD_FRAMEWORK_PATH") == 0 ) {
2102 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FRAMEWORK_PATH
);
2103 sEnv
.hasOverride
= true;
2105 else if ( strcmp(key
, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) {
2106 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
);
2107 sEnv
.hasOverride
= true;
2109 else if ( strcmp(key
, "DYLD_LIBRARY_PATH") == 0 ) {
2110 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_LIBRARY_PATH
);
2111 sEnv
.hasOverride
= true;
2113 else if ( strcmp(key
, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) {
2114 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FALLBACK_LIBRARY_PATH
);
2115 sEnv
.hasOverride
= true;
2117 #if SUPPORT_ROOT_PATH
2118 else if ( (strcmp(key
, "DYLD_ROOT_PATH") == 0) || (strcmp(key
, "DYLD_PATHS_ROOT") == 0) ) {
2119 if ( strcmp(value
, "/") != 0 ) {
2120 gLinkContext
.rootPaths
= parseColonList(value
, mainExecutableDir
);
2121 for (int i
=0; gLinkContext
.rootPaths
[i
] != NULL
; ++i
) {
2122 if ( gLinkContext
.rootPaths
[i
][0] != '/' ) {
2123 dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n");
2124 gLinkContext
.rootPaths
= NULL
;
2129 sEnv
.hasOverride
= true;
2132 else if ( strcmp(key
, "DYLD_IMAGE_SUFFIX") == 0 ) {
2133 gLinkContext
.imageSuffix
= parseColonList(value
, NULL
);
2134 sEnv
.hasOverride
= true;
2136 else if ( strcmp(key
, "DYLD_INSERT_LIBRARIES") == 0 ) {
2137 sEnv
.DYLD_INSERT_LIBRARIES
= parseColonList(value
, NULL
);
2138 #if SUPPORT_ACCELERATE_TABLES
2139 sDisableAcceleratorTables
= true;
2141 sEnv
.hasOverride
= true;
2143 else if ( strcmp(key
, "DYLD_PRINT_OPTS") == 0 ) {
2144 sEnv
.DYLD_PRINT_OPTS
= true;
2146 else if ( strcmp(key
, "DYLD_PRINT_ENV") == 0 ) {
2147 sEnv
.DYLD_PRINT_ENV
= true;
2149 else if ( strcmp(key
, "DYLD_DISABLE_DOFS") == 0 ) {
2150 sEnv
.DYLD_DISABLE_DOFS
= true;
2152 else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES") == 0 ) {
2153 gLinkContext
.verboseLoading
= true;
2155 else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) {
2156 sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH
= true;
2158 else if ( strcmp(key
, "DYLD_BIND_AT_LAUNCH") == 0 ) {
2159 sEnv
.DYLD_BIND_AT_LAUNCH
= true;
2161 else if ( strcmp(key
, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) {
2162 gLinkContext
.bindFlat
= true;
2164 else if ( strcmp(key
, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) {
2165 // ignore, no longer relevant but some scripts still set it
2167 else if ( strcmp(key
, "DYLD_NO_FIX_PREBINDING") == 0 ) {
2169 else if ( strcmp(key
, "DYLD_PREBIND_DEBUG") == 0 ) {
2170 gLinkContext
.verbosePrebinding
= true;
2172 else if ( strcmp(key
, "DYLD_PRINT_INITIALIZERS") == 0 ) {
2173 gLinkContext
.verboseInit
= true;
2175 else if ( strcmp(key
, "DYLD_PRINT_DOFS") == 0 ) {
2176 gLinkContext
.verboseDOF
= true;
2178 else if ( strcmp(key
, "DYLD_PRINT_STATISTICS") == 0 ) {
2179 sEnv
.DYLD_PRINT_STATISTICS
= true;
2180 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
2181 // <rdar://problem/26614838> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps
2182 sForceStderr
= true;
2185 else if ( strcmp(key
, "DYLD_PRINT_TO_STDERR") == 0 ) {
2186 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
2187 // <rdar://problem/26633440> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps
2188 sForceStderr
= true;
2191 else if ( strcmp(key
, "DYLD_PRINT_STATISTICS_DETAILS") == 0 ) {
2192 sEnv
.DYLD_PRINT_STATISTICS_DETAILS
= true;
2194 else if ( strcmp(key
, "DYLD_PRINT_SEGMENTS") == 0 ) {
2195 gLinkContext
.verboseMapping
= true;
2197 else if ( strcmp(key
, "DYLD_PRINT_BINDINGS") == 0 ) {
2198 gLinkContext
.verboseBind
= true;
2200 else if ( strcmp(key
, "DYLD_PRINT_WEAK_BINDINGS") == 0 ) {
2201 gLinkContext
.verboseWeakBind
= true;
2203 else if ( strcmp(key
, "DYLD_PRINT_REBASINGS") == 0 ) {
2204 gLinkContext
.verboseRebase
= true;
2206 else if ( strcmp(key
, "DYLD_PRINT_APIS") == 0 ) {
2209 #if SUPPORT_ACCELERATE_TABLES
2210 else if ( strcmp(key
, "DYLD_PRINT_APIS_APP") == 0 ) {
2214 else if ( strcmp(key
, "DYLD_PRINT_WARNINGS") == 0 ) {
2215 gLinkContext
.verboseWarnings
= true;
2217 else if ( strcmp(key
, "DYLD_PRINT_RPATHS") == 0 ) {
2218 gLinkContext
.verboseRPaths
= true;
2220 else if ( strcmp(key
, "DYLD_PRINT_INTERPOSING") == 0 ) {
2221 gLinkContext
.verboseInterposing
= true;
2223 else if ( strcmp(key
, "DYLD_PRINT_CODE_SIGNATURES") == 0 ) {
2224 gLinkContext
.verboseCodeSignatures
= true;
2226 else if ( (strcmp(key
, "DYLD_SHARED_REGION") == 0) && gLinkContext
.allowEnvVarsSharedCache
) {
2227 if ( strcmp(value
, "private") == 0 ) {
2228 gLinkContext
.sharedRegionMode
= ImageLoader::kUsePrivateSharedRegion
;
2230 else if ( strcmp(value
, "avoid") == 0 ) {
2231 gLinkContext
.sharedRegionMode
= ImageLoader::kDontUseSharedRegion
;
2233 else if ( strcmp(value
, "use") == 0 ) {
2234 gLinkContext
.sharedRegionMode
= ImageLoader::kUseSharedRegion
;
2236 else if ( value
[0] == '\0' ) {
2237 gLinkContext
.sharedRegionMode
= ImageLoader::kUseSharedRegion
;
2240 dyld::warn("unknown option to DYLD_SHARED_REGION. Valid options are: use, private, avoid\n");
2243 else if ( (strcmp(key
, "DYLD_SHARED_CACHE_DIR") == 0) && gLinkContext
.allowEnvVarsSharedCache
) {
2244 sSharedCacheOverrideDir
= value
;
2246 else if ( strcmp(key
, "DYLD_USE_CLOSURES") == 0 ) {
2247 // Handled elsewhere
2249 else if ( strcmp(key
, "DYLD_SHARED_REGION_DATA_CONST") == 0 ) {
2250 // Handled elsewhere
2252 else if ( strcmp(key
, "DYLD_FORCE_INVALID_CACHE_CLOSURES") == 0 ) {
2253 if ( dyld3::internalInstall() ) {
2254 sForceInvalidSharedCacheClosureFormat
= true;
2257 else if ( strcmp(key
, "DYLD_IGNORE_PREBINDING") == 0 ) {
2258 if ( strcmp(value
, "all") == 0 ) {
2259 gLinkContext
.prebindUsage
= ImageLoader::kUseNoPrebinding
;
2261 else if ( strcmp(value
, "app") == 0 ) {
2262 gLinkContext
.prebindUsage
= ImageLoader::kUseAllButAppPredbinding
;
2264 else if ( strcmp(value
, "nonsplit") == 0 ) {
2265 gLinkContext
.prebindUsage
= ImageLoader::kUseSplitSegPrebinding
;
2267 else if ( value
[0] == '\0' ) {
2268 gLinkContext
.prebindUsage
= ImageLoader::kUseSplitSegPrebinding
;
2271 dyld::warn("unknown option to DYLD_IGNORE_PREBINDING. Valid options are: all, app, nonsplit\n");
2274 #if SUPPORT_VERSIONED_PATHS
2275 else if ( strcmp(key
, "DYLD_VERSIONED_LIBRARY_PATH") == 0 ) {
2276 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_VERSIONED_LIBRARY_PATH
);
2277 #if SUPPORT_ACCELERATE_TABLES
2278 sDisableAcceleratorTables
= true;
2280 sEnv
.hasOverride
= true;
2282 else if ( strcmp(key
, "DYLD_VERSIONED_FRAMEWORK_PATH") == 0 ) {
2283 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
);
2284 #if SUPPORT_ACCELERATE_TABLES
2285 sDisableAcceleratorTables
= true;
2287 sEnv
.hasOverride
= true;
2290 #if !TARGET_OS_SIMULATOR
2291 else if ( (strcmp(key
, "DYLD_PRINT_TO_FILE") == 0) && (mainExecutableDir
== NULL
) && gLinkContext
.allowEnvVarsSharedCache
) {
2292 int fd
= dyld3::open(value
, O_WRONLY
| O_CREAT
| O_APPEND
, 0644);
2298 dyld::log("dyld: could not open DYLD_PRINT_TO_FILE='%s', errno=%d\n", value
, errno
);
2301 else if ( (strcmp(key
, "DYLD_SKIP_MAIN") == 0)) {
2302 if ( dyld3::internalInstall() )
2305 else if ( (strcmp(key
, "DYLD_JUST_BUILD_CLOSURE") == 0) ) {
2306 // handled elsewhere
2309 else if (strcmp(key
, "DYLD_FORCE_PLATFORM") == 0) {
2310 // handled elsewhere
2312 else if (strcmp(key
, "DYLD_AMFI_FAKE") == 0) {
2313 // handled elsewhere
2316 dyld::warn("unknown environment variable: %s\n", key
);
2321 #if SUPPORT_LC_DYLD_ENVIRONMENT
2322 static void checkLoadCommandEnvironmentVariables()
2324 // <rdar://problem/8440934> Support augmenting dyld environment variables in load commands
2325 const uint32_t cmd_count
= sMainExecutableMachHeader
->ncmds
;
2326 const struct load_command
* const cmds
= (struct load_command
*)(((char*)sMainExecutableMachHeader
)+sizeof(macho_header
));
2327 const struct load_command
* cmd
= cmds
;
2328 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2330 case LC_DYLD_ENVIRONMENT
:
2332 const struct dylinker_command
* envcmd
= (struct dylinker_command
*)cmd
;
2333 const char* keyEqualsValue
= (char*)envcmd
+ envcmd
->name
.offset
;
2334 char mainExecutableDir
[strlen(sExecPath
)+2];
2335 strcpy(mainExecutableDir
, sExecPath
);
2336 char* lastSlash
= strrchr(mainExecutableDir
, '/');
2337 if ( lastSlash
!= NULL
)
2338 lastSlash
[1] = '\0';
2339 // only process variables that start with DYLD_ and end in _PATH
2340 if ( (strncmp(keyEqualsValue
, "DYLD_", 5) == 0) ) {
2341 const char* equals
= strchr(keyEqualsValue
, '=');
2342 if ( equals
!= NULL
) {
2343 if ( strncmp(&equals
[-5], "_PATH", 5) == 0 ) {
2344 const char* value
= &equals
[1];
2345 const size_t keyLen
= equals
-keyEqualsValue
;
2346 // <rdar://problem/22799635> don't let malformed load command overflow stack
2347 if ( keyLen
< 40 ) {
2349 strncpy(key
, keyEqualsValue
, keyLen
);
2351 //dyld::log("processing: %s\n", keyEqualsValue);
2352 //dyld::log("mainExecutableDir: %s\n", mainExecutableDir);
2353 #if SUPPORT_ROOT_PATH
2354 if ( (strcmp(key
, "DYLD_ROOT_PATH") == 0) || (strcmp(key
, "DYLD_PATHS_ROOT") == 0) )
2357 processDyldEnvironmentVariable(key
, value
, mainExecutableDir
);
2365 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2368 #endif // SUPPORT_LC_DYLD_ENVIRONMENT
2371 static bool hasCodeSignatureLoadCommand(const macho_header
* mh
)
2373 const uint32_t cmd_count
= mh
->ncmds
;
2374 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
2375 const struct load_command
* cmd
= cmds
;
2376 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2377 if (cmd
->cmd
== LC_CODE_SIGNATURE
)
2379 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2385 #if SUPPORT_VERSIONED_PATHS
2386 static void checkVersionedPaths()
2388 // search DYLD_VERSIONED_LIBRARY_PATH directories for dylibs and check if they are newer
2389 if ( sEnv
.DYLD_VERSIONED_LIBRARY_PATH
!= NULL
) {
2390 for(const char* const* lp
= sEnv
.DYLD_VERSIONED_LIBRARY_PATH
; *lp
!= NULL
; ++lp
) {
2391 checkDylibOverridesInDir(*lp
);
2395 // search DYLD_VERSIONED_FRAMEWORK_PATH directories for dylibs and check if they are newer
2396 if ( sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
!= NULL
) {
2397 for(const char* const* fp
= sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
; *fp
!= NULL
; ++fp
) {
2398 checkFrameworkOverridesInDir(*fp
);
2407 // For security, setuid programs ignore DYLD_* environment variables.
2408 // Additionally, the DYLD_* enviroment variables are removed
2409 // from the environment, so that any child processes don't see them.
2411 static void pruneEnvironmentVariables(const char* envp
[], const char*** applep
)
2413 #if SUPPORT_LC_DYLD_ENVIRONMENT
2414 checkLoadCommandEnvironmentVariables();
2417 // Are we testing dyld on an internal config?
2418 if ( _simple_getenv(envp
, "DYLD_SKIP_MAIN") != NULL
) {
2419 if ( dyld3::internalInstall() )
2423 // delete all DYLD_* and LD_LIBRARY_PATH environment variables
2424 int removedCount
= 0;
2425 const char** d
= envp
;
2426 for(const char** s
= envp
; *s
!= NULL
; s
++) {
2428 if ( (strncmp(*s
, "DYLD_", 5) != 0) && (strncmp(*s
, "LD_LIBRARY_PATH=", 16) != 0) ) {
2436 // slide apple parameters
2437 if ( removedCount
> 0 ) {
2440 *d
= d
[removedCount
];
2441 } while ( *d
++ != NULL
);
2442 for(int i
=0; i
< removedCount
; ++i
)
2446 // disable framework and library fallback paths for setuid binaries rdar://problem/4589305
2447 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
= NULL
;
2448 sEnv
.DYLD_FALLBACK_LIBRARY_PATH
= NULL
;
2450 if ( removedCount
> 0 )
2451 strlcat(sLoadingCrashMessage
, ", ignoring DYLD_* env vars", sizeof(sLoadingCrashMessage
));
2455 static void defaultUninitializedFallbackPaths(const char* envp
[])
2458 if ( !gLinkContext
.allowClassicFallbackPaths
) {
2459 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
= sRestrictedFrameworkFallbackPaths
;
2460 sEnv
.DYLD_FALLBACK_LIBRARY_PATH
= sRestrictedLibraryFallbackPaths
;
2464 // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
2465 const char* home
= _simple_getenv(envp
, "HOME");;
2466 if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
== NULL
) {
2467 const char** fpaths
= sFrameworkFallbackPaths
;
2469 removePathWithPrefix(fpaths
, "$HOME");
2471 paths_expand_roots(fpaths
, "$HOME", home
);
2472 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
= fpaths
;
2475 // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment
2476 if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH
== NULL
) {
2477 const char** lpaths
= sLibraryFallbackPaths
;
2479 removePathWithPrefix(lpaths
, "$HOME");
2481 paths_expand_roots(lpaths
, "$HOME", home
);
2482 sEnv
.DYLD_FALLBACK_LIBRARY_PATH
= lpaths
;
2485 if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
== NULL
)
2486 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
= sFrameworkFallbackPaths
;
2488 if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH
== NULL
)
2489 sEnv
.DYLD_FALLBACK_LIBRARY_PATH
= sLibraryFallbackPaths
;
2494 static void checkEnvironmentVariables(const char* envp
[])
2496 if ( !gLinkContext
.allowEnvVarsPath
&& !gLinkContext
.allowEnvVarsPrint
)
2499 for(p
= envp
; *p
!= NULL
; p
++) {
2500 const char* keyEqualsValue
= *p
;
2501 if ( strncmp(keyEqualsValue
, "DYLD_", 5) == 0 ) {
2502 const char* equals
= strchr(keyEqualsValue
, '=');
2503 if ( equals
!= NULL
) {
2504 strlcat(sLoadingCrashMessage
, "\n", sizeof(sLoadingCrashMessage
));
2505 strlcat(sLoadingCrashMessage
, keyEqualsValue
, sizeof(sLoadingCrashMessage
));
2506 const char* value
= &equals
[1];
2507 const size_t keyLen
= equals
-keyEqualsValue
;
2509 strncpy(key
, keyEqualsValue
, keyLen
);
2511 if ( (strncmp(key
, "DYLD_PRINT_", 11) == 0) && !gLinkContext
.allowEnvVarsPrint
)
2513 processDyldEnvironmentVariable(key
, value
, NULL
);
2516 else if ( strncmp(keyEqualsValue
, "LD_LIBRARY_PATH=", 16) == 0 ) {
2517 const char* path
= &keyEqualsValue
[16];
2518 sEnv
.LD_LIBRARY_PATH
= parseColonList(path
, NULL
);
2522 #if SUPPORT_LC_DYLD_ENVIRONMENT
2523 checkLoadCommandEnvironmentVariables();
2524 #endif // SUPPORT_LC_DYLD_ENVIRONMENT
2526 #if SUPPORT_ROOT_PATH
2527 // <rdar://problem/11281064> DYLD_IMAGE_SUFFIX and DYLD_ROOT_PATH cannot be used together
2528 if ( (gLinkContext
.imageSuffix
!= NULL
&& *gLinkContext
.imageSuffix
!= NULL
) && (gLinkContext
.rootPaths
!= NULL
) ) {
2529 dyld::warn("Ignoring DYLD_IMAGE_SUFFIX because DYLD_ROOT_PATH is used.\n");
2530 gLinkContext
.imageSuffix
= NULL
; // this leaks allocations from parseColonList
2535 #if __x86_64__ && !TARGET_OS_SIMULATOR
2536 static bool isGCProgram(const macho_header
* mh
, uintptr_t slide
)
2538 const uint32_t cmd_count
= mh
->ncmds
;
2539 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
2540 const struct load_command
* cmd
= cmds
;
2541 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
2543 case LC_SEGMENT_COMMAND
:
2545 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
2546 if (strcmp(seg
->segname
, "__DATA") == 0) {
2547 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
2548 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
2549 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
2550 if (strncmp(sect
->sectname
, "__objc_imageinfo", 16) == 0) {
2551 const uint32_t* objcInfo
= (uint32_t*)(sect
->addr
+ slide
);
2552 return (objcInfo
[1] & 6); // 6 = (OBJC_IMAGE_SUPPORTS_GC | OBJC_IMAGE_REQUIRES_GC)
2559 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
2565 static void getHostInfo(const macho_header
* mainExecutableMH
, uintptr_t mainExecutableSlide
)
2567 #if CPU_SUBTYPES_SUPPORTED
2569 sHostCPU
= CPU_TYPE_ARM
;
2570 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V7K
;
2571 #elif __ARM_ARCH_7A__
2572 sHostCPU
= CPU_TYPE_ARM
;
2573 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V7
;
2574 #elif __ARM_ARCH_6K__
2575 sHostCPU
= CPU_TYPE_ARM
;
2576 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V6
;
2577 #elif __ARM_ARCH_7F__
2578 sHostCPU
= CPU_TYPE_ARM
;
2579 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V7F
;
2580 #elif __ARM_ARCH_7S__
2581 sHostCPU
= CPU_TYPE_ARM
;
2582 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V7S
;
2583 #elif __ARM64_ARCH_8_32__
2584 sHostCPU
= CPU_TYPE_ARM64_32
;
2585 sHostCPUsubtype
= CPU_SUBTYPE_ARM64_32_V8
;
2587 sHostCPU
= CPU_TYPE_ARM64
;
2588 sHostCPUsubtype
= CPU_SUBTYPE_ARM64E
;
2590 sHostCPU
= CPU_TYPE_ARM64
;
2591 sHostCPUsubtype
= CPU_SUBTYPE_ARM64_V8
;
2593 struct host_basic_info info
;
2594 mach_msg_type_number_t count
= HOST_BASIC_INFO_COUNT
;
2595 mach_port_t hostPort
= mach_host_self();
2596 kern_return_t result
= host_info(hostPort
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
);
2597 if ( result
!= KERN_SUCCESS
)
2598 throw "host_info() failed";
2599 sHostCPU
= info
.cpu_type
;
2600 sHostCPUsubtype
= info
.cpu_subtype
;
2601 mach_port_deallocate(mach_task_self(), hostPort
);
2603 // host_info returns CPU_TYPE_I386 even for x86_64. Override that here so that
2604 // we don't need to mask the cpu type later.
2605 sHostCPU
= CPU_TYPE_X86_64
;
2606 #if !TARGET_OS_SIMULATOR
2607 sHaswell
= (sHostCPUsubtype
== CPU_SUBTYPE_X86_64_H
);
2608 // <rdar://problem/18528074> x86_64h: Fall back to the x86_64 slice if an app requires GC.
2610 if ( isGCProgram(mainExecutableMH
, mainExecutableSlide
) ) {
2611 // When running a GC program on a haswell machine, don't use and 'h slices
2612 sHostCPUsubtype
= CPU_SUBTYPE_X86_64_ALL
;
2614 gLinkContext
.sharedRegionMode
= ImageLoader::kDontUseSharedRegion
;
2623 static void checkSharedRegionDisable(const dyld3::MachOLoaded
* mainExecutableMH
, uintptr_t mainExecutableSlide
)
2626 // if main executable has segments that overlap the shared region,
2627 // then disable using the shared region
2628 if ( mainExecutableMH
->intersectsRange(SHARED_REGION_BASE
, SHARED_REGION_SIZE
) ) {
2629 gLinkContext
.sharedRegionMode
= ImageLoader::kDontUseSharedRegion
;
2630 if ( gLinkContext
.verboseMapping
)
2631 dyld::warn("disabling shared region because main executable overlaps\n");
2634 if ( !gLinkContext
.allowEnvVarsPath
) {
2635 // <rdar://problem/15280847> use private or no shared region for suid processes
2636 gLinkContext
.sharedRegionMode
= ImageLoader::kUsePrivateSharedRegion
;
2640 #if TARGET_OS_SIMULATOR
2641 gLinkContext
.sharedRegionMode
= ImageLoader::kUsePrivateSharedRegion
;
2643 // iOS cannot run without shared region
2646 bool validImage(const ImageLoader
* possibleImage
)
2648 const size_t imageCount
= sAllImages
.size();
2649 for(size_t i
=0; i
< imageCount
; ++i
) {
2650 if ( possibleImage
== sAllImages
[i
] ) {
2657 uint32_t getImageCount()
2659 return (uint32_t)sAllImages
.size();
2662 ImageLoader
* getIndexedImage(unsigned int index
)
2664 if ( index
< sAllImages
.size() )
2665 return sAllImages
[index
];
2669 ImageLoader
* findImageByMachHeader(const struct mach_header
* target
)
2671 return findMappedRange((uintptr_t)target
);
2675 ImageLoader
* findImageContainingAddress(const void* addr
)
2677 #if SUPPORT_ACCELERATE_TABLES
2678 if ( sAllCacheImagesProxy
!= NULL
) {
2679 const mach_header
* mh
;
2682 if ( sAllCacheImagesProxy
->addressInCache(addr
, &mh
, &path
, &index
) )
2683 return sAllCacheImagesProxy
;
2686 return findMappedRange((uintptr_t)addr
);
2690 ImageLoader
* findImageContainingSymbol(const void* symbol
)
2692 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
2693 ImageLoader
* anImage
= *it
;
2694 if ( anImage
->containsSymbol(symbol
) )
2702 void forEachImageDo( void (*callback
)(ImageLoader
*, void* userData
), void* userData
)
2704 const size_t imageCount
= sAllImages
.size();
2705 for(size_t i
=0; i
< imageCount
; ++i
) {
2706 ImageLoader
* anImage
= sAllImages
[i
];
2707 (*callback
)(anImage
, userData
);
2711 ImageLoader
* findLoadedImage(const struct stat
& stat_buf
)
2713 const size_t imageCount
= sAllImages
.size();
2714 for(size_t i
=0; i
< imageCount
; ++i
){
2715 ImageLoader
* anImage
= sAllImages
[i
];
2716 if ( anImage
->statMatch(stat_buf
) )
2722 // based on ANSI-C strstr()
2723 static const char* strrstr(const char* str
, const char* sub
)
2725 const size_t sublen
= strlen(sub
);
2726 for(const char* p
= &str
[strlen(str
)]; p
!= str
; --p
) {
2727 if ( strncmp(p
, sub
, sublen
) == 0 )
2735 // Find framework path
2737 // /path/foo.framework/foo => foo.framework/foo
2738 // /path/foo.framework/Versions/A/foo => foo.framework/Versions/A/foo
2739 // /path/foo.framework/Frameworks/bar.framework/bar => bar.framework/bar
2740 // /path/foo.framework/Libraries/bar.dylb => NULL
2741 // /path/foo.framework/bar => NULL
2743 // Returns NULL if not a framework path
2745 static const char* getFrameworkPartialPath(const char* path
)
2747 const char* dirDot
= strrstr(path
, ".framework/");
2748 if ( dirDot
!= NULL
) {
2749 const char* dirStart
= dirDot
;
2750 for ( ; dirStart
>= path
; --dirStart
) {
2751 if ( (*dirStart
== '/') || (dirStart
== path
) ) {
2752 const char* frameworkStart
= &dirStart
[1];
2753 if ( dirStart
== path
)
2755 size_t len
= dirDot
- frameworkStart
;
2756 char framework
[len
+1];
2757 strncpy(framework
, frameworkStart
, len
);
2758 framework
[len
] = '\0';
2759 const char* leaf
= strrchr(path
, '/');
2760 if ( leaf
!= NULL
) {
2761 if ( strcmp(framework
, &leaf
[1]) == 0 ) {
2762 return frameworkStart
;
2764 if ( gLinkContext
.imageSuffix
!= NULL
) {
2765 // some debug frameworks have install names that end in _debug
2766 if ( strncmp(framework
, &leaf
[1], len
) == 0 ) {
2767 for (const char* const* suffix
=gLinkContext
.imageSuffix
; *suffix
!= NULL
; ++suffix
) {
2768 if ( strcmp(*suffix
, &leaf
[len
+1]) == 0 )
2769 return frameworkStart
;
2781 static const char* getLibraryLeafName(const char* path
)
2783 const char* start
= strrchr(path
, '/');
2784 if ( start
!= NULL
)
2791 // only for architectures that use cpu-sub-types
2792 #if CPU_SUBTYPES_SUPPORTED
2794 const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST
= -1;
2798 // A fat file may contain multiple sub-images for the same CPU type.
2799 // In that case, dyld picks which sub-image to use by scanning a table
2800 // of preferred cpu-sub-types for the running cpu.
2802 // There is one row in the table for each cpu-sub-type on which dyld might run.
2803 // The first entry in a row is that cpu-sub-type. It is followed by all
2804 // cpu-sub-types that can run on that cpu, if preferred order. Each row ends with
2805 // a "SUBTYPE_ALL" (to denote that images written to run on any cpu-sub-type are usable),
2806 // followed by one or more CPU_SUBTYPE_END_OF_LIST to pad out this row.
2812 // ARM sub-type lists
2814 const int kARM_RowCount
= 8;
2815 static const cpu_subtype_t kARM
[kARM_RowCount
][9] = {
2817 // armv7f can run: v7f, v7, v6, v5, and v4
2818 { CPU_SUBTYPE_ARM_V7F
, CPU_SUBTYPE_ARM_V7
, CPU_SUBTYPE_ARM_V6
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
},
2820 // armv7k can run: v7k
2821 { CPU_SUBTYPE_ARM_V7K
, CPU_SUBTYPE_END_OF_LIST
},
2823 // armv7s can run: v7s, v7, v7f, v7k, v6, v5, and v4
2824 { CPU_SUBTYPE_ARM_V7S
, CPU_SUBTYPE_ARM_V7
, CPU_SUBTYPE_ARM_V7F
, CPU_SUBTYPE_ARM_V6
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
},
2826 // armv7 can run: v7, v6, v5, and v4
2827 { CPU_SUBTYPE_ARM_V7
, CPU_SUBTYPE_ARM_V6
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
},
2829 // armv6 can run: v6, v5, and v4
2830 { CPU_SUBTYPE_ARM_V6
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
},
2832 // xscale can run: xscale, v5, and v4
2833 { CPU_SUBTYPE_ARM_XSCALE
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
},
2835 // armv5 can run: v5 and v4
2836 { CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
},
2838 // armv4 can run: v4
2839 { CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
, CPU_SUBTYPE_END_OF_LIST
},
2843 #if __ARM64_ARCH_8_32__
2845 // arm64_32 sub-type lists
2847 static const cpu_subtype_t kARM64_32
[] = { CPU_SUBTYPE_ARM64_32_V8
, CPU_SUBTYPE_END_OF_LIST
};
2850 #if __arm64__ && __LP64__
2852 // arm64[e] sub-type handing
2855 // arm64e with keys on
2856 static const cpu_subtype_t kARM64e
[] = { CPU_SUBTYPE_ARM64E
, CPU_SUBTYPE_END_OF_LIST
};
2857 // arm64 or arm64e with keys off
2858 static const cpu_subtype_t kARM64eKeysOff
[] = { CPU_SUBTYPE_ARM64E
, CPU_SUBTYPE_ARM64_V8
, CPU_SUBTYPE_ARM64_ALL
, CPU_SUBTYPE_END_OF_LIST
};
2860 // arm64 main binary
2861 static const cpu_subtype_t kARM64
[] = { CPU_SUBTYPE_ARM64_V8
, CPU_SUBTYPE_ARM64_ALL
, CPU_SUBTYPE_END_OF_LIST
};
2862 #endif // __arm64e__
2868 // x86_64 sub-type lists
2870 const int kX86_64_RowCount
= 2;
2871 static const cpu_subtype_t kX86_64
[kX86_64_RowCount
][5] = {
2873 // x86_64h can run: x86_64h, x86_64h(lib), x86_64(lib), and x86_64
2874 { CPU_SUBTYPE_X86_64_H
, (cpu_subtype_t
)(CPU_SUBTYPE_LIB64
|CPU_SUBTYPE_X86_64_H
), (cpu_subtype_t
)(CPU_SUBTYPE_LIB64
|CPU_SUBTYPE_X86_64_ALL
), CPU_SUBTYPE_X86_64_ALL
, CPU_SUBTYPE_END_OF_LIST
},
2876 // x86_64 can run: x86_64(lib) and x86_64
2877 { CPU_SUBTYPE_X86_64_ALL
, (cpu_subtype_t
)(CPU_SUBTYPE_LIB64
|CPU_SUBTYPE_X86_64_ALL
), CPU_SUBTYPE_END_OF_LIST
},
2883 // scan the tables above to find the cpu-sub-type-list for this machine
2884 static const cpu_subtype_t
* findCPUSubtypeList(cpu_type_t cpu
, cpu_subtype_t subtype
)
2889 for (int i
=0; i
< kARM_RowCount
; ++i
) {
2890 if ( kARM
[i
][0] == subtype
)
2897 case CPU_TYPE_ARM64
:
2899 return ( sKeysDisabled
? kARM64eKeysOff
: kARM64e
);
2907 case CPU_TYPE_ARM64_32
:
2913 case CPU_TYPE_X86_64
:
2914 for (int i
=0; i
< kX86_64_RowCount
; ++i
) {
2915 if ( kX86_64
[i
][0] == subtype
)
2925 // scan fat table-of-contents for best most preferred subtype
2926 static bool fatFindBestFromOrderedList(cpu_type_t cpu
, const cpu_subtype_t list
[], const fat_header
* fh
, int fd
, uint64_t* offset
, uint64_t* len
)
2928 const fat_arch
* const archs
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
));
2929 for (uint32_t subTypeIndex
=0; list
[subTypeIndex
] != CPU_SUBTYPE_END_OF_LIST
; ++subTypeIndex
) {
2930 for(uint32_t fatIndex
=0; fatIndex
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++fatIndex
) {
2931 cpu_type_t sliceCpuType
= OSSwapBigToHostInt32(archs
[fatIndex
].cputype
);
2932 cpu_subtype_t sliceCpuSubType
= OSSwapBigToHostInt32(archs
[fatIndex
].cpusubtype
) & ~CPU_SUBTYPE_MASK
;
2933 uint64_t sliceOffset
= OSSwapBigToHostInt32(archs
[fatIndex
].offset
);
2934 uint64_t sliceLen
= OSSwapBigToHostInt32(archs
[fatIndex
].size
);
2935 if ( (sliceCpuType
== cpu
) && ((list
[subTypeIndex
] & ~CPU_SUBTYPE_MASK
) == sliceCpuSubType
) ) {
2936 #if TARGET_OS_OSX && __has_feature(ptrauth_calls)
2937 if ( sOnlyPlatformArm64e
&& (sliceCpuType
== CPU_TYPE_ARM64
) && (sliceCpuSubType
== CPU_SUBTYPE_ARM64E
) ) {
2938 // if we can only load arm64e slices that are platform binaries, skip over slices that are not
2939 if ( !dyld3::MachOAnalyzer::sliceIsOSBinary(fd
, sliceOffset
, sliceLen
) )
2943 *offset
= sliceOffset
;
2952 #if !TARGET_OS_OSX || !__has_feature(ptrauth_calls)
2953 // scan fat table-of-contents for exact match of cpu and cpu-sub-type
2954 static bool fatFindExactMatch(cpu_type_t cpu
, cpu_subtype_t subtype
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
)
2956 const fat_arch
* archs
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
));
2957 for(uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2958 if ( ((cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
)
2959 && ((cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == subtype
) ) {
2960 *offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2961 *len
= OSSwapBigToHostInt32(archs
[i
].size
);
2969 // scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types
2970 static bool fatFindRunsOnAllCPUs(cpu_type_t cpu
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
)
2972 const fat_arch
* archs
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
));
2973 for(uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
2974 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
) {
2978 if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_ARM_ALL
) {
2979 *offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2980 *len
= OSSwapBigToHostInt32(archs
[i
].size
);
2986 case CPU_TYPE_ARM64
:
2987 if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_ARM64_ALL
) {
2988 *offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2989 *len
= OSSwapBigToHostInt32(archs
[i
].size
);
2995 case CPU_TYPE_X86_64
:
2996 if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_X86_64_ALL
) {
2997 *offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
2998 *len
= OSSwapBigToHostInt32(archs
[i
].size
);
3009 #endif // CPU_SUBTYPES_SUPPORTED
3013 // Validate the fat_header and fat_arch array:
3015 // 1) arch count would not cause array to extend past 4096 byte read buffer
3016 // 2) no slice overlaps the fat_header and arch array
3017 // 3) arch list does not contain duplicate cputype/cpusubtype tuples
3018 // 4) arch list does not have two overlapping slices.
3020 static bool fatValidate(const fat_header
* fh
)
3022 if ( fh
->magic
!= OSSwapBigToHostInt32(FAT_MAGIC
) )
3025 // since only first 4096 bytes of file read, we can only handle up to 204 slices.
3026 const uint32_t sliceCount
= OSSwapBigToHostInt32(fh
->nfat_arch
);
3027 if ( sliceCount
> 204 )
3030 // compare all slices looking for conflicts
3031 const fat_arch
* archs
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
));
3032 for (uint32_t i
=0; i
< sliceCount
; ++i
) {
3033 uint32_t i_offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
3034 uint32_t i_size
= OSSwapBigToHostInt32(archs
[i
].size
);
3035 uint32_t i_cputype
= OSSwapBigToHostInt32(archs
[i
].cputype
);
3036 uint32_t i_cpusubtype
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
);
3037 uint32_t i_end
= i_offset
+ i_size
;
3038 // slice cannot overlap with header
3039 if ( i_offset
< 4096 )
3041 // slice size cannot overflow
3042 if ( i_end
< i_offset
)
3044 for (uint32_t j
=i
+1; j
< sliceCount
; ++j
) {
3045 uint32_t j_offset
= OSSwapBigToHostInt32(archs
[j
].offset
);
3046 uint32_t j_size
= OSSwapBigToHostInt32(archs
[j
].size
);
3047 uint32_t j_cputype
= OSSwapBigToHostInt32(archs
[j
].cputype
);
3048 uint32_t j_cpusubtype
= OSSwapBigToHostInt32(archs
[j
].cpusubtype
);
3049 uint32_t j_end
= j_offset
+ j_size
;
3050 // duplicate slices types not allowed
3051 if ( (i_cputype
== j_cputype
) && (i_cpusubtype
== j_cpusubtype
) )
3053 // slice size cannot overflow
3054 if ( j_end
< j_offset
)
3056 // check for overlap of slices
3057 if ( i_offset
<= j_offset
) {
3058 if ( j_offset
< i_end
)
3059 return false; // j overlaps end of i
3062 // j overlaps end of i
3063 if ( i_offset
< j_end
)
3064 return false; // i overlaps end of j
3072 // A fat file may contain multiple sub-images for the same cpu-type,
3073 // each optimized for a different cpu-sub-type (e.g G3 or G5).
3074 // This routine picks the optimal sub-image.
3076 static bool fatFindBest(const fat_header
* fh
, uint64_t* offset
, uint64_t* len
, int fd
=-1)
3078 if ( !fatValidate(fh
) )
3081 #if CPU_SUBTYPES_SUPPORTED
3082 // assume all dylibs loaded must have same cpu type as main executable
3083 const cpu_type_t cpu
= sMainExecutableMachHeader
->cputype
;
3085 // We only know the subtype to use if the main executable cpu type matches the host
3086 if ( cpu
== sHostCPU
) {
3087 // get preference ordered list of subtypes
3088 const cpu_subtype_t
* subTypePreferenceList
= findCPUSubtypeList(cpu
, sHostCPUsubtype
);
3090 // use ordered list to find best sub-image in fat file
3091 if ( subTypePreferenceList
!= NULL
) {
3092 if ( fatFindBestFromOrderedList(cpu
, subTypePreferenceList
, fh
, fd
, offset
, len
) )
3095 #if TARGET_OS_OSX && __has_feature(ptrauth_calls)
3096 // don't use fallbacks for macOS arm64e to ensure only compatible binaries are loaded
3099 // if running cpu is not in list, try for an exact match
3100 if ( fatFindExactMatch(cpu
, sHostCPUsubtype
, fh
, offset
, len
) )
3105 // running on an uknown cpu, can only load generic code
3106 return fatFindRunsOnAllCPUs(cpu
, fh
, offset
, len
);
3108 // just find first slice with matching architecture
3109 const fat_arch
* archs
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
));
3110 for(uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
3111 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == sMainExecutableMachHeader
->cputype
) {
3112 *offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
3113 *len
= OSSwapBigToHostInt32(archs
[i
].size
);
3121 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
3122 #ifndef kIsTranslated
3123 #define kIsTranslated 0x4000000000000000ULL
3127 return ((*(uint64_t*)_COMM_PAGE_CPU_CAPABILITIES64
) & kIsTranslated
);
3133 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used
3134 // on the current processor. //
3135 bool isCompatibleMachO(const uint8_t* firstPage
, const char* path
, int fd
=-1, uint64_t sliceOffset
=0, uint64_t sliceLen
=-1)
3137 #if CPU_SUBTYPES_SUPPORTED
3138 // It is deemed compatible if any of the following are true:
3139 // 1) mach_header subtype is in list of compatible subtypes for running processor
3140 // 2) mach_header subtype is same as running processor subtype
3141 // 3) mach_header subtype runs on all processor variants
3142 const mach_header
* mh
= (mach_header
*)firstPage
;
3143 if ( mh
->magic
== sMainExecutableMachHeader
->magic
) {
3144 if ( mh
->cputype
== sMainExecutableMachHeader
->cputype
) {
3145 if ( mh
->cputype
== sHostCPU
) {
3146 const cpu_subtype_t mhCPUSubtype
= mh
->cpusubtype
& ~CPU_SUBTYPE_MASK
;
3147 // get preference ordered list of subtypes that this machine can use
3148 const cpu_subtype_t
* subTypePreferenceList
= findCPUSubtypeList(mh
->cputype
, sHostCPUsubtype
);
3149 if ( subTypePreferenceList
!= NULL
) {
3150 // if image's subtype is in the list, it is compatible
3151 for (const cpu_subtype_t
* p
= subTypePreferenceList
; *p
!= CPU_SUBTYPE_END_OF_LIST
; ++p
) {
3152 if ( *p
== mhCPUSubtype
) {
3153 #if TARGET_OS_OSX && __has_feature(ptrauth_calls)
3154 if ( mhCPUSubtype
== CPU_SUBTYPE_ARM64E
) {
3155 if ( !sOnlyPlatformArm64e
|| dyld3::MachOAnalyzer::sliceIsOSBinary(fd
, sliceOffset
, sliceLen
) )
3163 // have list and not in list, so not compatible
3164 throwf("incompatible cpu-subtype: 0x%08X in %s", mhCPUSubtype
, path
);
3166 // unknown cpu sub-type, but if exact match for current subtype then ok to use
3167 if ( mhCPUSubtype
== sHostCPUsubtype
)
3171 // cpu type has no ordered list of subtypes
3172 switch (mh
->cputype
) {
3174 case CPU_TYPE_X86_64
:
3175 // subtypes are not used or these architectures
3181 // For architectures that don't support cpu-sub-types
3182 // this just check the cpu type.
3183 const mach_header
* mh
= (mach_header
*)firstPage
;
3184 if ( mh
->magic
== sMainExecutableMachHeader
->magic
) {
3185 if ( mh
->cputype
== sMainExecutableMachHeader
->cputype
) {
3196 // The kernel maps in main executable before dyld gets control. We need to
3197 // make an ImageLoader* for the already mapped in main executable.
3198 static ImageLoaderMachO
* instantiateFromLoadedImage(const macho_header
* mh
, uintptr_t slide
, const char* path
)
3200 // try mach-o loader
3201 // if ( isCompatibleMachO((const uint8_t*)mh, path) ) {
3202 ImageLoader
* image
= ImageLoaderMachO::instantiateMainExecutable(mh
, slide
, path
, gLinkContext
);
3204 return (ImageLoaderMachO
*)image
;
3207 // throw "main executable not a known format";
3210 #if SUPPORT_ACCELERATE_TABLES
3211 static bool dylibsCanOverrideCache()
3213 if ( !dyld3::internalInstall() )
3215 return ( (sSharedCacheLoadInfo
.loadAddress
!= nullptr) && (sSharedCacheLoadInfo
.loadAddress
->header
.cacheType
== kDyldSharedCacheTypeDevelopment
) );
3219 const void* imMemorySharedCacheHeader()
3221 return sSharedCacheLoadInfo
.loadAddress
;
3225 const char* getStandardSharedCacheFilePath()
3227 if ( sSharedCacheLoadInfo
.loadAddress
!= nullptr )
3228 return sSharedCacheLoadInfo
.path
;
3233 bool hasInsertedOrInterposingLibraries() {
3234 return (sInsertedDylibCount
> 0) || ImageLoader::haveInterposingTuples();
3238 #if SUPPORT_VERSIONED_PATHS
3239 static bool findInSharedCacheImage(const char* path
, bool searchByPath
, const struct stat
* stat_buf
, const macho_header
** mh
, const char** pathInCache
, long* slide
)
3241 dyld3::SharedCacheFindDylibResults results
;
3242 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &results
) ) {
3243 *mh
= (macho_header
*)results
.mhInCache
;
3244 *pathInCache
= results
.pathInCache
;
3245 *slide
= results
.slideInCache
;
3252 bool inSharedCache(const char* path
)
3254 return dyld3::pathIsInSharedCacheImage(sSharedCacheLoadInfo
, path
);
3258 static ImageLoader
* checkandAddImage(ImageLoader
* image
, const LoadContext
& context
)
3260 // now sanity check that this loaded image does not have the same install path as any existing image
3261 const char* loadedImageInstallPath
= image
->getInstallPath();
3262 if ( image
->isDylib() && (loadedImageInstallPath
!= NULL
) && (loadedImageInstallPath
[0] == '/') ) {
3263 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
3264 ImageLoader
* anImage
= *it
;
3265 const char* installPath
= anImage
->getInstallPath();
3266 if ( installPath
!= NULL
) {
3267 if ( strcmp(loadedImageInstallPath
, installPath
) == 0 ) {
3268 //dyld::log("duplicate(%s) => %p\n", installPath, anImage);
3270 ImageLoader::deleteImage(image
);
3277 // some API's restrict what they can load
3278 if ( context
.mustBeBundle
&& !image
->isBundle() )
3279 throw "not a bundle";
3280 if ( context
.mustBeDylib
&& !image
->isDylib() )
3281 throw "not a dylib";
3283 // regular main executables cannot be loaded
3284 if ( image
->isExecutable() ) {
3285 if ( !context
.canBePIE
|| !image
->isPositionIndependentExecutable() )
3286 throw "can't load a main executable";
3289 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
3290 if ( ! image
->isBundle() )
3296 #if TARGET_OS_SIMULATOR
3297 static bool isSimulatorBinary(const uint8_t* firstPages
, const char* path
)
3299 const macho_header
* mh
= (macho_header
*)firstPages
;
3300 const uint32_t cmd_count
= mh
->ncmds
;
3301 const load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
3302 const load_command
* const cmdsEnd
= (load_command
*)((char*)cmds
+ mh
->sizeofcmds
);
3303 const struct load_command
* cmd
= cmds
;
3304 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
3307 case LC_VERSION_MIN_WATCHOS
:
3310 case LC_VERSION_MIN_TVOS
:
3313 case LC_VERSION_MIN_IPHONEOS
:
3316 case LC_VERSION_MIN_MACOSX
:
3317 // grandfather in a few libSystem dylibs
3318 if ((strcmp(path
, "/usr/lib/system/libsystem_kernel.dylib") == 0) ||
3319 (strcmp(path
, "/usr/lib/system/libsystem_platform.dylib") == 0) ||
3320 (strcmp(path
, "/usr/lib/system/libsystem_pthread.dylib") == 0) ||
3321 (strcmp(path
, "/usr/lib/system/libsystem_platform_debug.dylib") == 0) ||
3322 (strcmp(path
, "/usr/lib/system/libsystem_pthread_debug.dylib") == 0) ||
3323 (strcmp(path
, "/sbin/launchd_sim_trampoline") == 0) ||
3324 (strcmp(path
, "/usr/sbin/iokitsimd") == 0) ||
3325 (strcmp(path
, "/usr/lib/system/host/liblaunch_sim.dylib") == 0))
3328 case LC_BUILD_VERSION
:
3330 // Same logic as above, but for LC_BUILD_VERSION instead of legacy load commands
3331 const struct build_version_command
* buildVersionCmd
= (build_version_command
*)cmd
;
3332 switch(buildVersionCmd
->platform
) {
3333 case PLATFORM_IOSSIMULATOR
:
3334 case PLATFORM_TVOSSIMULATOR
:
3335 case PLATFORM_WATCHOSSIMULATOR
:
3336 case PLATFORM_WATCHOS
:
3338 case PLATFORM_MACOS
:
3339 if ((strcmp(path
, "/usr/lib/system/libsystem_kernel.dylib") == 0) ||
3340 (strcmp(path
, "/usr/lib/system/libsystem_platform.dylib") == 0) ||
3341 (strcmp(path
, "/usr/lib/system/libsystem_pthread.dylib") == 0) ||
3342 (strcmp(path
, "/usr/lib/system/libsystem_platform_debug.dylib") == 0) ||
3343 (strcmp(path
, "/usr/lib/system/libsystem_pthread_debug.dylib") == 0) ||
3344 (strcmp(path
, "/sbin/launchd_sim_trampoline") == 0) ||
3345 (strcmp(path
, "/usr/sbin/iokitsimd") == 0) ||
3346 (strcmp(path
, "/usr/lib/system/host/liblaunch_sim.dylib") == 0))
3351 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
3352 if ( cmd
> cmdsEnd
)
3360 // map in file and instantiate an ImageLoader
3361 static ImageLoader
* loadPhase6(int fd
, const struct stat
& stat_buf
, const char* path
, const LoadContext
& context
)
3363 //dyld::log("%s(%s)\n", __func__ , path);
3364 uint64_t fileOffset
= 0;
3365 uint64_t fileLength
= stat_buf
.st_size
;
3367 // validate it is a file (not directory)
3368 if ( (stat_buf
.st_mode
& S_IFMT
) != S_IFREG
)
3371 uint8_t firstPages
[MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE
];
3372 bool shortPage
= false;
3374 // min mach-o file is 4K
3375 if ( fileLength
< 4096 ) {
3376 if ( pread(fd
, firstPages
, (size_t)fileLength
, 0) != (ssize_t
)fileLength
)
3377 throwf("pread of short file failed: %d", errno
);
3381 // optimistically read only first 4KB
3382 if ( pread(fd
, firstPages
, 4096, 0) != 4096 )
3383 throwf("pread of first 4K failed: %d", errno
);
3386 // if fat wrapper, find usable sub-file
3387 const fat_header
* fileStartAsFat
= (fat_header
*)firstPages
;
3388 if ( fileStartAsFat
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
3389 if ( OSSwapBigToHostInt32(fileStartAsFat
->nfat_arch
) > ((4096 - sizeof(fat_header
)) / sizeof(fat_arch
)) )
3390 throwf("fat header too large: %u entries", OSSwapBigToHostInt32(fileStartAsFat
->nfat_arch
));
3391 if ( fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
, fd
) ) {
3392 if ( (fileOffset
+fileLength
) > (uint64_t)(stat_buf
.st_size
) )
3393 throwf("truncated fat file. file length=%llu, but needed slice goes to %llu", stat_buf
.st_size
, fileOffset
+fileLength
);
3394 if (pread(fd
, firstPages
, 4096, fileOffset
) != 4096)
3395 throwf("pread of fat file failed: %d", errno
);
3398 throw "no matching architecture in universal wrapper";
3402 // try mach-o loader
3404 throw "file too short";
3406 if ( isCompatibleMachO(firstPages
, path
, fd
, fileOffset
, fileLength
) ) {
3408 // only MH_BUNDLE, MH_DYLIB, and some MH_EXECUTE can be dynamically loaded
3409 const mach_header
* mh
= (mach_header
*)firstPages
;
3410 switch ( mh
->filetype
) {
3416 throw "mach-o, but wrong filetype";
3419 uint32_t headerAndLoadCommandsSize
= sizeof(macho_header
) + mh
->sizeofcmds
;
3420 if ( headerAndLoadCommandsSize
> fileLength
)
3421 dyld::throwf("malformed mach-o: load commands size (%u) > mach-o file size (%llu)", headerAndLoadCommandsSize
, fileLength
);
3423 vm_address_t vmAllocatedFirstPages
= 0;
3424 if ( headerAndLoadCommandsSize
> MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE
) {
3425 if ( ::vm_allocate(mach_task_self(), &vmAllocatedFirstPages
, headerAndLoadCommandsSize
, VM_FLAGS_ANYWHERE
) == 0 ) {
3426 if ( ::pread(fd
, (void*)vmAllocatedFirstPages
, headerAndLoadCommandsSize
, fileOffset
) != headerAndLoadCommandsSize
)
3427 throwf("pread of all load commands failed: %d", errno
);
3428 mh
= (mach_header
*)vmAllocatedFirstPages
;
3431 throwf("malformed mach-o: load commands size (%u) > %u", headerAndLoadCommandsSize
, MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE
);
3434 else if ( headerAndLoadCommandsSize
> 4096 ) {
3436 unsigned readAmount
= headerAndLoadCommandsSize
- 4096;
3437 if ( pread(fd
, &firstPages
[4096], readAmount
, fileOffset
+4096) != readAmount
)
3438 throwf("pread of extra load commands past 4KB failed: %d", errno
);
3441 if ( !((dyld3::MachOFile
*)mh
)->loadableIntoProcess((dyld3::Platform
)gProcessInfo
->platform
, path
) ) {
3442 throwf("mach-o, but not built for platform %s", dyld3::MachOFile::platformName((dyld3::Platform
)gProcessInfo
->platform
));
3445 #if __has_feature(ptrauth_calls)
3446 if ( !sKeysDisabled
&& ((sMainExecutableMachHeader
->cpusubtype
& ~CPU_SUBTYPE_MASK
) == CPU_SUBTYPE_ARM64E
) && ((mh
->cpusubtype
& ~CPU_SUBTYPE_MASK
) != CPU_SUBTYPE_ARM64E
) )
3447 throw "arm64 dylibs cannot be loaded into arm64e processes";
3449 ImageLoader
* image
= nullptr;
3451 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_MAP_IMAGE
, path
, 0, 0);
3452 image
= ImageLoaderMachO::instantiateFromFile(path
, fd
, (uint8_t*)mh
, headerAndLoadCommandsSize
, fileOffset
, fileLength
, stat_buf
, gLinkContext
);
3453 timer
.setData4((uint64_t)image
->machHeader());
3456 if ( vmAllocatedFirstPages
!= 0 )
3457 ::vm_deallocate(mach_task_self(), (vm_address_t
)vmAllocatedFirstPages
, headerAndLoadCommandsSize
);
3460 return checkandAddImage(image
, context
);
3463 // try other file formats here...
3466 // throw error about what was found
3467 switch (*(uint32_t*)firstPages
) {
3472 throw "mach-o, but wrong architecture";
3474 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
3475 firstPages
[0], firstPages
[1], firstPages
[2], firstPages
[3], firstPages
[4], firstPages
[5], firstPages
[6],firstPages
[7]);
3480 static ImageLoader
* loadPhase5open(const char* path
, const LoadContext
& context
, const struct stat
& stat_buf
, std::vector
<const char*>* exceptions
)
3482 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3484 // open file (automagically closed when this function exits)
3485 FileOpener
file(path
);
3487 // just return NULL if file not found, but record any other errors
3488 if ( file
.getFileDescriptor() == -1 ) {
3490 if ( err
!= ENOENT
) {
3492 if ( (err
== EPERM
) && sandboxBlockedOpen(path
) )
3493 newMsg
= dyld::mkstringf("file system sandbox blocked open() of '%s'", path
);
3495 newMsg
= dyld::mkstringf("%s: open() failed with errno=%d", path
, err
);
3496 exceptions
->push_back(newMsg
);
3502 return loadPhase6(file
.getFileDescriptor(), stat_buf
, path
, context
);
3504 catch (const char* msg
) {
3505 const char* newMsg
= dyld::mkstringf("%s: %s", path
, msg
);
3506 exceptions
->push_back(newMsg
);
3512 static bool isFileRelativePath(const char* path
)
3514 if ( path
[0] == '/' )
3516 if ( path
[0] != '.' )
3518 if ( path
[1] == '/' )
3520 if ( (path
[1] == '.') && (path
[2] == '/') )
3525 static ImageLoader
* loadPhase5check(const char* path
, const char* orgPath
, const LoadContext
& context
);
3529 static ImageLoader
* loadPhase5load(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
)
3531 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3533 // <rdar://problem/47682983> don't allow file system relative paths in hardened programs
3534 if ( (exceptions
!= NULL
) && !gLinkContext
.allowEnvVarsPath
&& isFileRelativePath(path
) ) {
3535 exceptions
->push_back("file system relative paths not allowed in hardened programs");
3539 #if SUPPORT_ACCELERATE_TABLES
3540 if ( sAllCacheImagesProxy
!= NULL
) {
3541 if ( sAllCacheImagesProxy
->hasDylib(path
, &cacheIndex
) )
3542 return sAllCacheImagesProxy
;
3546 struct stat statBuf
;
3547 bool didStat
= false;
3549 __block
dyld3::SharedCacheFindDylibResults shareCacheResults
;
3550 shareCacheResults
.image
= nullptr;
3552 #if TARGET_OS_SIMULATOR
3554 auto findSharedCacheImage
= ^() {
3555 // in simulators, 'path' has DYLD_ROOT_PATH prepended, but cache index does not have the prefix, so use orgPath
3556 return dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, orgPath
, &shareCacheResults
);
3561 auto findSharedCacheImage
= ^() {
3562 return dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &shareCacheResults
);
3567 if ( findSharedCacheImage() ) {
3568 // see if this image in the cache was already loaded via a different path
3569 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); ++it
) {
3570 ImageLoader
* anImage
= *it
;
3571 if ( (const mach_header
*)anImage
->machHeader() == shareCacheResults
.mhInCache
)
3574 // if RTLD_NOLOAD, do nothing if not already loaded
3575 if ( context
.dontLoad
) {
3576 // <rdar://33412890> possible that there is an override of cache
3577 if ( dyld3::stat(path
, &statBuf
) == 0 ) {
3578 ImageLoader
* imageLoader
= findLoadedImage(statBuf
);
3579 if ( imageLoader
!= NULL
)
3584 bool useCache
= false;
3585 if ( shareCacheResults
.image
== nullptr ) {
3586 // HACK to support old caches
3587 existsOnDisk
= ( dyld3::stat(path
, &statBuf
) == 0 );
3590 useCache
= !existsOnDisk
;
3593 // <rdar://problem/7014995> zero out stat buffer so mtime, etc are zero for items from the shared cache
3594 bzero(&statBuf
, sizeof(statBuf
));
3595 if ( shareCacheResults
.image
->overridableDylib() ) {
3596 existsOnDisk
= ( dyld3::stat(path
, &statBuf
) == 0 );
3598 if ( sSharedCacheLoadInfo
.loadAddress
->header
.dylibsExpectedOnDisk
) {
3599 // old style macOS with dylibs on disk
3600 uint64_t expectedINode
;
3601 uint64_t expectedMtime
;
3602 if ( shareCacheResults
.image
->hasFileModTimeAndInode(expectedINode
, expectedMtime
) ) {
3603 // if dylib found has same inode/mtime as one in cache, use one in cache
3604 if ( (expectedMtime
== statBuf
.st_mtime
) && (expectedINode
== statBuf
.st_ino
) )
3609 // MRM style where dylibs are not on disk
3610 if ( !existsOnDisk
) {
3611 // looking at path where dylib should be, and we expect it to not be there but rather in the cache
3612 // Its possible we are looking at a deleted symlink path. For example, we are trying to open .../AppKit but
3613 // there's already a loaded root of .../Versions/C/AppKit. That used to work when the symlink was on-disk as
3614 // we'd realpath to find the shared cache path. Now we record the aliases in the cache and delete the symlinks.
3615 const char* pathInSharedCache
= shareCacheResults
.image
->path();
3616 if ( strcmp(path
, pathInSharedCache
) != 0 ) {
3617 ImageLoader
* imageLoader
= loadPhase5check(pathInSharedCache
, orgPath
, context
);
3618 if ( imageLoader
!= NULL
)
3623 else if ( !sRootsChecker
.onDiskFileIsRoot(path
, sSharedCacheLoadInfo
.loadAddress
,
3624 shareCacheResults
.image
, nullptr, statBuf
.st_ino
, statBuf
.st_mtime
) ) {
3625 // we found a file on disk, at the same path as the dyld cache has a dylib and it is one of the magic three
3631 // we are trying to override a dylib in the cache that does not allow overrides, ignore override and use cache
3636 const dyld3::MachOFile
* cacheDylibMH
= (dyld3::MachOFile
*)shareCacheResults
.mhInCache
;
3637 if ( !cacheDylibMH
->loadableIntoProcess((dyld3::Platform
)gProcessInfo
->platform
, path
) )
3638 throwf("mach-o, but not built for platform %s", dyld3::MachOFile::platformName((dyld3::Platform
)gProcessInfo
->platform
));
3640 ImageLoader
* imageLoader
= ImageLoaderMachO::instantiateFromCache((macho_header
*)cacheDylibMH
, shareCacheResults
.pathInCache
, shareCacheResults
.slideInCache
, statBuf
, gLinkContext
);
3641 return checkandAddImage(imageLoader
, context
);
3645 // not in cache or cache not usable
3647 existsOnDisk
= ( dyld3::stat(path
, &statBuf
) == 0 );
3650 if ( existsOnDisk
) {
3651 // in case image was renamed or found via symlinks, check for inode match
3652 ImageLoader
* imageLoader
= findLoadedImage(statBuf
);
3653 if ( imageLoader
!= NULL
)
3655 // do nothing if not already loaded and if RTLD_NOLOAD
3656 if ( context
.dontLoad
)
3659 imageLoader
= loadPhase5open(path
, context
, statBuf
, exceptions
);
3660 if ( imageLoader
!= NULL
) {
3661 if ( shareCacheResults
.image
!= nullptr ) {
3662 // if image was found in cache, but is overridden by a newer file on disk, record what the image overrides
3663 imageLoader
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum());
3669 // just return NULL if file not found, but record any other errors
3670 if ( (statErrNo
!= ENOENT
) && (statErrNo
!= 0) ) {
3671 if ( (statErrNo
== EPERM
) && sandboxBlockedStat(path
) )
3672 exceptions
->push_back(dyld::mkstringf("%s: file system sandbox blocked stat()", path
));
3674 exceptions
->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path
, statErrNo
));
3679 // look for path match with existing loaded images
3680 static ImageLoader
* loadPhase5check(const char* path
, const char* orgPath
, const LoadContext
& context
)
3682 //dyld::log("%s(%s, %s)\n", __func__ , path, orgPath);
3683 // search path against load-path and install-path of all already loaded images
3684 uint32_t hash
= ImageLoader::hash(path
);
3685 //dyld::log("check() hash=%d, path=%s\n", hash, path);
3686 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
3687 ImageLoader
* anImage
= *it
;
3688 // check hash first to cut down on strcmp calls
3689 //dyld::log(" check() hash=%d, path=%s\n", anImage->getPathHash(), anImage->getPath());
3690 if ( anImage
->getPathHash() == hash
) {
3691 if ( strcmp(path
, anImage
->getPath()) == 0 ) {
3692 // if we are looking for a dylib don't return something else
3693 if ( !context
.mustBeDylib
|| anImage
->isDylib() )
3697 if ( context
.matchByInstallName
|| anImage
->matchInstallPath() ) {
3698 const char* installPath
= anImage
->getInstallPath();
3699 if ( installPath
!= NULL
) {
3700 if ( strcmp(path
, installPath
) == 0 ) {
3701 // if we are looking for a dylib don't return something else
3702 if ( !context
.mustBeDylib
|| anImage
->isDylib() )
3707 // an install name starting with @rpath should match by install name, not just real path
3708 if ( (orgPath
[0] == '@') && (strncmp(orgPath
, "@rpath/", 7) == 0) ) {
3709 const char* installPath
= anImage
->getInstallPath();
3710 if ( installPath
!= NULL
) {
3711 if ( !context
.mustBeDylib
|| anImage
->isDylib() ) {
3712 if ( strcmp(orgPath
, installPath
) == 0 )
3719 //dyld::log("%s(%s) => NULL\n", __func__, path);
3724 // open or check existing
3725 static ImageLoader
* loadPhase5(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
)
3727 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3729 // check for specific dylib overrides
3730 for (std::vector
<DylibOverride
>::iterator it
= sDylibOverrides
.begin(); it
!= sDylibOverrides
.end(); ++it
) {
3731 if ( strcmp(it
->installName
, path
) == 0 ) {
3732 path
= it
->override
;
3737 if ( exceptions
!= NULL
)
3738 return loadPhase5load(path
, orgPath
, context
, cacheIndex
, exceptions
);
3740 return loadPhase5check(path
, orgPath
, context
);
3743 // try with and without image suffix
3744 static ImageLoader
* loadPhase4(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
)
3746 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3747 ImageLoader
* image
= NULL
;
3748 if ( gLinkContext
.imageSuffix
!= NULL
) {
3749 for (const char* const* suffix
=gLinkContext
.imageSuffix
; *suffix
!= NULL
; ++suffix
) {
3750 char pathWithSuffix
[strlen(path
)+strlen(*suffix
)+2];
3751 ImageLoader::addSuffix(path
, *suffix
, pathWithSuffix
);
3752 image
= loadPhase5(pathWithSuffix
, orgPath
, context
, cacheIndex
, exceptions
);
3753 if ( image
!= NULL
)
3756 if ( image
!= NULL
) {
3757 // if original path is in the dyld cache, then mark this one found as an override
3758 dyld3::SharedCacheFindDylibResults shareCacheResults
;
3759 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &shareCacheResults
) && (shareCacheResults
.image
!= nullptr) )
3760 image
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum());
3763 if ( image
== NULL
)
3764 image
= loadPhase5(path
, orgPath
, context
, cacheIndex
, exceptions
);
3768 static ImageLoader
* loadPhase2(const char* path
, const char* orgPath
, const LoadContext
& context
,
3769 const char* const frameworkPaths
[], const char* const libraryPaths
[],
3770 unsigned& cacheIndex
, std::vector
<const char*>* exceptions
); // forward reference
3773 // expand @ variables
3774 static ImageLoader
* loadPhase3(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
)
3776 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3777 ImageLoader
* image
= NULL
;
3778 if ( strncmp(path
, "@executable_path/", 17) == 0 ) {
3779 // executable_path cannot be in used in any binary in a setuid process rdar://problem/4589305
3780 if ( !gLinkContext
.allowAtPaths
)
3781 throwf("unsafe use of @executable_path in %s with restricted binary (Codesign main executable with Library Validation to allow @ paths)", context
.origin
);
3782 // handle @executable_path path prefix
3783 const char* executablePath
= sExecPath
;
3784 char newPath
[strlen(executablePath
) + strlen(path
)];
3785 strcpy(newPath
, executablePath
);
3786 char* addPoint
= strrchr(newPath
,'/');
3787 if ( addPoint
!= NULL
)
3788 strcpy(&addPoint
[1], &path
[17]);
3790 strcpy(newPath
, &path
[17]);
3791 image
= loadPhase4(newPath
, orgPath
, context
, cacheIndex
, exceptions
);
3792 if ( image
!= NULL
)
3795 // perhaps main executable path is a sym link, find realpath and retry
3796 char resolvedPath
[PATH_MAX
];
3797 if ( realpath(sExecPath
, resolvedPath
) != NULL
) {
3798 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
3799 strcpy(newRealPath
, resolvedPath
);
3800 addPoint
= strrchr(newRealPath
,'/');
3801 if ( addPoint
!= NULL
)
3802 strcpy(&addPoint
[1], &path
[17]);
3804 strcpy(newRealPath
, &path
[17]);
3805 image
= loadPhase4(newRealPath
, orgPath
, context
, cacheIndex
, exceptions
);
3806 if ( image
!= NULL
)
3810 else if ( (strncmp(path
, "@loader_path/", 13) == 0) && (context
.origin
!= NULL
) ) {
3811 // @loader_path cannot be used from the main executable of a setuid process rdar://problem/4589305
3812 if ( !gLinkContext
.allowAtPaths
&& (strcmp(context
.origin
, sExecPath
) == 0) )
3813 throwf("unsafe use of @loader_path in %s with restricted binary (Codesign main executable with Library Validation to allow @ paths)", context
.origin
);
3814 // handle @loader_path path prefix
3815 char newPath
[strlen(context
.origin
) + strlen(path
)];
3816 strcpy(newPath
, context
.origin
);
3817 char* addPoint
= strrchr(newPath
,'/');
3818 if ( addPoint
!= NULL
)
3819 strcpy(&addPoint
[1], &path
[13]);
3821 strcpy(newPath
, &path
[13]);
3822 image
= loadPhase4(newPath
, orgPath
, context
, cacheIndex
, exceptions
);
3823 if ( image
!= NULL
)
3826 // perhaps loader path is a sym link, find realpath and retry
3827 char resolvedPath
[PATH_MAX
];
3828 if ( realpath(context
.origin
, resolvedPath
) != NULL
) {
3829 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
3830 strcpy(newRealPath
, resolvedPath
);
3831 addPoint
= strrchr(newRealPath
,'/');
3832 if ( addPoint
!= NULL
)
3833 strcpy(&addPoint
[1], &path
[13]);
3835 strcpy(newRealPath
, &path
[13]);
3836 image
= loadPhase4(newRealPath
, orgPath
, context
, cacheIndex
, exceptions
);
3837 if ( image
!= NULL
)
3841 else if ( context
.implicitRPath
|| (strncmp(path
, "@rpath/", 7) == 0) ) {
3842 const char* trailingPath
= (strncmp(path
, "@rpath/", 7) == 0) ? &path
[7] : path
;
3843 // substitute @rpath with all -rpath paths up the load chain
3844 for(const ImageLoader::RPathChain
* rp
=context
.rpath
; rp
!= NULL
; rp
=rp
->next
) {
3845 if (rp
->paths
!= NULL
) {
3846 for(std::vector
<const char*>::iterator it
=rp
->paths
->begin(); it
!= rp
->paths
->end(); ++it
) {
3847 const char* anRPath
= *it
;
3848 char newPath
[strlen(anRPath
) + strlen(trailingPath
)+2];
3849 strcpy(newPath
, anRPath
);
3850 if ( newPath
[strlen(newPath
)-1] != '/' )
3851 strcat(newPath
, "/");
3852 strcat(newPath
, trailingPath
);
3853 image
= loadPhase4(newPath
, orgPath
, context
, cacheIndex
, exceptions
);
3854 if ( gLinkContext
.verboseRPaths
&& (exceptions
!= NULL
) ) {
3855 if ( image
!= NULL
)
3856 dyld::log("RPATH successful expansion of %s to: %s\n", orgPath
, newPath
);
3858 dyld::log("RPATH failed expanding %s to: %s\n", orgPath
, newPath
);
3860 if ( image
!= NULL
)
3866 // substitute @rpath with LD_LIBRARY_PATH
3867 if ( sEnv
.LD_LIBRARY_PATH
!= NULL
) {
3868 image
= loadPhase2(trailingPath
, orgPath
, context
, NULL
, sEnv
.LD_LIBRARY_PATH
, cacheIndex
, exceptions
);
3869 if ( image
!= NULL
)
3873 // if this is the "open" pass, don't try to open @rpath/... as a relative path
3874 if ( (exceptions
!= NULL
) && (trailingPath
!= path
) )
3877 else if ( !gLinkContext
.allowEnvVarsPath
&& (path
[0] != '/' ) ) {
3878 throwf("unsafe use of relative rpath %s in %s with restricted binary", path
, context
.origin
);
3881 return loadPhase4(path
, orgPath
, context
, cacheIndex
, exceptions
);
3884 static ImageLoader
* loadPhase2cache(const char* path
, const char *orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) {
3885 ImageLoader
* image
= NULL
;
3886 #if !TARGET_OS_SIMULATOR
3887 if ( (exceptions
!= NULL
) && (gLinkContext
.allowEnvVarsPath
|| !isFileRelativePath(path
)) && (path
[0] != '@') ) {
3888 char resolvedPath
[PATH_MAX
];
3889 realpath(path
, resolvedPath
);
3891 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
3892 if ( (myerr
== ENOENT
) || (myerr
== 0) )
3894 image
= loadPhase4(resolvedPath
, orgPath
, context
, cacheIndex
, exceptions
);
3903 static ImageLoader
* loadPhase2(const char* path
, const char* orgPath
, const LoadContext
& context
,
3904 const char* const frameworkPaths
[], const char* const libraryPaths
[],
3905 unsigned& cacheIndex
, std::vector
<const char*>* exceptions
)
3907 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3908 ImageLoader
* image
= NULL
;
3909 const char* frameworkPartialPath
= getFrameworkPartialPath(path
);
3910 if ( frameworkPaths
!= NULL
) {
3911 if ( frameworkPartialPath
!= NULL
) {
3912 const size_t frameworkPartialPathLen
= strlen(frameworkPartialPath
);
3913 for(const char* const* fp
= frameworkPaths
; *fp
!= NULL
; ++fp
) {
3914 char npath
[strlen(*fp
)+frameworkPartialPathLen
+8];
3917 strcat(npath
, frameworkPartialPath
);
3918 //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
3919 image
= loadPhase4(npath
, orgPath
, context
, cacheIndex
, exceptions
);
3920 // Look in the cache if appropriate
3922 image
= loadPhase2cache(npath
, orgPath
, context
, cacheIndex
, exceptions
);
3923 if ( image
!= NULL
) {
3924 // if original path is in the dyld cache, then mark this one found as an override
3925 dyld3::SharedCacheFindDylibResults shareCacheResults
;
3926 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &shareCacheResults
) && (shareCacheResults
.image
!= nullptr) ) {
3927 image
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum());
3929 #if SUPPORT_ROOT_PATH
3930 else if ( (gLinkContext
.rootPaths
!= nullptr)
3931 && dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, orgPath
, &shareCacheResults
)
3932 && (shareCacheResults
.image
!= nullptr) ) {
3933 // DYLD_ROOT_PATH, ie, iOSMac, also needs to check if the original path is overridden
3934 // as the root prefix has been applied to 'path', but the framework path searches without a root path prefix
3935 image
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum());
3943 // <rdar://problem/12649639> An executable with the same name as a framework & DYLD_LIBRARY_PATH pointing to it gets loaded twice
3944 // <rdar://problem/14160846> Some apps depend on frameworks being found via library paths
3945 if ( (libraryPaths
!= NULL
) && ((frameworkPartialPath
== NULL
) || sFrameworksFoundAsDylibs
) ) {
3946 const char* libraryLeafName
= getLibraryLeafName(path
);
3947 const size_t libraryLeafNameLen
= strlen(libraryLeafName
);
3948 for(const char* const* lp
= libraryPaths
; *lp
!= NULL
; ++lp
) {
3949 char libpath
[strlen(*lp
)+libraryLeafNameLen
+8];
3950 strcpy(libpath
, *lp
);
3951 strcat(libpath
, "/");
3952 strcat(libpath
, libraryLeafName
);
3953 //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
3954 image
= loadPhase4(libpath
, orgPath
, context
, cacheIndex
, exceptions
);
3955 // Look in the cache if appropriate
3957 image
= loadPhase2cache(libpath
, orgPath
, context
, cacheIndex
, exceptions
);
3958 if ( image
!= NULL
) {
3959 // if original path is in the dyld cache, then mark this one found as an override
3960 dyld3::SharedCacheFindDylibResults shareCacheResults
;
3961 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &shareCacheResults
) && (shareCacheResults
.image
!= nullptr) ) {
3962 image
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum());
3964 #if SUPPORT_ROOT_PATH
3965 else if ( (gLinkContext
.rootPaths
!= nullptr)
3966 && dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, orgPath
, &shareCacheResults
)
3967 && (shareCacheResults
.image
!= nullptr) ) {
3968 // DYLD_ROOT_PATH, ie, iOSMac, also needs to check if the original path is overridden
3969 // as the root prefix has been applied to 'path', but the library path searches without a root path prefix
3970 image
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum());
3980 // try search overrides and fallbacks
3981 static ImageLoader
* loadPhase1(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
)
3983 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3984 ImageLoader
* image
= NULL
;
3986 bool pathIsInDyldCacheWhichCannotBeOverridden
= false;
3987 if ( sSharedCacheLoadInfo
.loadAddress
!= nullptr ) {
3988 pathIsInDyldCacheWhichCannotBeOverridden
= sSharedCacheLoadInfo
.loadAddress
->hasNonOverridablePath(path
);
3991 // <rdar://problem/48490116> dyld customer cache cannot be overridden
3992 if ( !pathIsInDyldCacheWhichCannotBeOverridden
) {
3993 // handle LD_LIBRARY_PATH environment variables that force searching
3994 if ( context
.useLdLibraryPath
&& (sEnv
.LD_LIBRARY_PATH
!= NULL
) ) {
3995 image
= loadPhase2(path
, orgPath
, context
, NULL
, sEnv
.LD_LIBRARY_PATH
, cacheIndex
,exceptions
);
3996 if ( image
!= NULL
)
4000 // handle DYLD_ environment variables that force searching
4001 if ( context
.useSearchPaths
&& ((sEnv
.DYLD_FRAMEWORK_PATH
!= NULL
) || (sEnv
.DYLD_LIBRARY_PATH
!= NULL
)) ) {
4002 image
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_FRAMEWORK_PATH
, sEnv
.DYLD_LIBRARY_PATH
, cacheIndex
, exceptions
);
4003 if ( image
!= NULL
)
4009 image
= loadPhase3(path
, orgPath
, context
, cacheIndex
, exceptions
);
4010 if ( image
!= NULL
)
4013 // try fallback paths during second time (will open file)
4014 const char* const* fallbackLibraryPaths
= sEnv
.DYLD_FALLBACK_LIBRARY_PATH
;
4015 if ( (fallbackLibraryPaths
!= NULL
) && !context
.useFallbackPaths
)
4016 fallbackLibraryPaths
= NULL
;
4017 if ( !context
.dontLoad
&& (exceptions
!= NULL
) && ((sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
!= NULL
) || (fallbackLibraryPaths
!= NULL
)) ) {
4018 image
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
, fallbackLibraryPaths
, cacheIndex
, exceptions
);
4019 if ( image
!= NULL
)
4023 // <rdar://problem/47682983> if hardened app calls dlopen() with a leaf path, dyld should only look in /usr/lib
4024 if ( context
.useLdLibraryPath
&& (fallbackLibraryPaths
== NULL
) ) {
4025 const char* stdPaths
[2] = { "/usr/lib", NULL
};
4026 image
= loadPhase2(path
, orgPath
, context
, NULL
, stdPaths
, cacheIndex
, exceptions
);
4027 if ( image
!= NULL
)
4031 #if SUPPORT_VERSIONED_PATHS
4032 // <rdar://problem/53215116> DYLD_VERSIONED_FRAMEWORK_PATH fails to load a framework if it does not also exist at the system install path
4033 // Scan to see if the dylib appears in a versioned path. Don't worry if we find the newest, that will handled later
4034 if ( !context
.dontLoad
&& (exceptions
!= NULL
) && ((sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
!= NULL
) || (sEnv
.DYLD_VERSIONED_LIBRARY_PATH
!= NULL
)) ) {
4035 image
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
, sEnv
.DYLD_VERSIONED_LIBRARY_PATH
, cacheIndex
, exceptions
);
4036 if ( image
!= NULL
)
4044 // try root substitutions
4045 static ImageLoader
* loadPhase0(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
)
4047 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
4050 // handle macOS dylibs dlopen()ing versioned path which needs to map to flat path in mazipan simulator
4051 if ( gLinkContext
.iOSonMac
&& strstr(path
, ".framework/Versions/")) {
4052 uintptr_t sourceOffset
= 0;
4053 uintptr_t destOffset
= 0;
4054 size_t sourceLangth
= strlen(path
);
4055 char flatPath
[sourceLangth
];
4057 const char* frameworkBase
= NULL
;
4058 while ((frameworkBase
= strstr(&path
[sourceOffset
], ".framework/Versions/"))) {
4059 uintptr_t foundLength
= (frameworkBase
- &path
[sourceOffset
]) + strlen(".framework/") ;
4060 strlcat(&flatPath
[destOffset
], &path
[sourceOffset
], foundLength
);
4061 sourceOffset
+= foundLength
+ strlen("Versions/") + 1;
4062 destOffset
+= foundLength
- 1;
4064 strlcat(&flatPath
[destOffset
], &path
[sourceOffset
], sourceLangth
);
4065 ImageLoader
* image
= loadPhase0(flatPath
, orgPath
, context
, cacheIndex
, exceptions
);
4066 if ( image
!= NULL
)
4071 #if SUPPORT_ROOT_PATH
4072 // handle DYLD_ROOT_PATH which forces absolute paths to use a new root
4073 if ( (gLinkContext
.rootPaths
!= NULL
) && (path
[0] == '/') ) {
4074 for(const char* const* rootPath
= gLinkContext
.rootPaths
; *rootPath
!= NULL
; ++rootPath
) {
4075 size_t rootLen
= strlen(*rootPath
);
4076 if ( strncmp(path
, *rootPath
, rootLen
) != 0 ) {
4077 char newPath
[rootLen
+ strlen(path
)+2];
4078 strcpy(newPath
, *rootPath
);
4079 strcat(newPath
, path
);
4080 ImageLoader
* image
= loadPhase1(newPath
, orgPath
, context
, cacheIndex
, exceptions
);
4081 if ( image
!= NULL
)
4089 return loadPhase1(path
, orgPath
, context
, cacheIndex
, exceptions
);
4093 // Given all the DYLD_ environment variables, the general case for loading libraries
4094 // is that any given path expands into a list of possible locations to load. We
4095 // also must take care to ensure two copies of the "same" library are never loaded.
4097 // The algorithm used here is that there is a separate function for each "phase" of the
4098 // path expansion. Each phase function calls the next phase with each possible expansion
4099 // of that phase. The result is the last phase is called with all possible paths.
4101 // To catch duplicates the algorithm is run twice. The first time, the last phase checks
4102 // the path against all loaded images. The second time, the last phase calls open() on
4103 // the path. Either time, if an image is found, the phases all unwind without checking
4106 ImageLoader
* load(const char* path
, const LoadContext
& context
, unsigned& cacheIndex
)
4108 CRSetCrashLogMessage2(path
);
4109 const char* orgPath
= path
;
4110 cacheIndex
= UINT32_MAX
;
4112 //dyld::log("%s(%s)\n", __func__ , path);
4113 char realPath
[PATH_MAX
];
4114 // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match
4115 if ( context
.useSearchPaths
&& ( gLinkContext
.imageSuffix
!= NULL
&& *gLinkContext
.imageSuffix
!= NULL
) ) {
4116 if ( realpath(path
, realPath
) != NULL
)
4120 // try all path permutations and check against existing loaded images
4122 ImageLoader
* image
= loadPhase0(path
, orgPath
, context
, cacheIndex
, NULL
);
4123 if ( image
!= NULL
) {
4124 CRSetCrashLogMessage2(NULL
);
4128 // try all path permutations and try open() until first success
4129 std::vector
<const char*> exceptions
;
4130 image
= loadPhase0(path
, orgPath
, context
, cacheIndex
, &exceptions
);
4131 #if !TARGET_OS_SIMULATOR
4132 // <rdar://problem/16704628> support symlinks on disk to a path in dyld shared cache
4134 image
= loadPhase2cache(path
, orgPath
, context
, cacheIndex
, &exceptions
);
4136 CRSetCrashLogMessage2(NULL
);
4137 if ( image
!= NULL
) {
4138 // <rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables
4139 for (std::vector
<const char*>::iterator it
= exceptions
.begin(); it
!= exceptions
.end(); ++it
) {
4142 // if loaded image is not from cache, but original path is in cache
4143 // set gSharedCacheOverridden flag to disable some ObjC optimizations
4144 if ( !gSharedCacheOverridden
&& !image
->inSharedCache() && image
->isDylib() && dyld3::MachOFile::isSharedCacheEligiblePath(path
) && inSharedCache(path
) ) {
4145 gSharedCacheOverridden
= true;
4147 // <rdar://problem/59327556> if file loaded via symlink to a root of something in dyld cache, mark it as an override
4148 dyld3::SharedCacheFindDylibResults shareCacheResults
;
4149 if ( !image
->inSharedCache() && dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, image
->getRealPath(), &shareCacheResults
) && (shareCacheResults
.image
!= nullptr) )
4150 image
->setOverridesCachedDylib(shareCacheResults
.image
->imageNum());
4154 else if ( exceptions
.size() == 0 ) {
4155 if ( context
.dontLoad
) {
4159 throw "image not found";
4162 const char* msgStart
= "no suitable image found. Did find:";
4163 const char* delim
= "\n\t";
4164 size_t allsizes
= strlen(msgStart
)+8;
4165 for (size_t i
=0; i
< exceptions
.size(); ++i
)
4166 allsizes
+= (strlen(exceptions
[i
]) + strlen(delim
));
4167 char* fullMsg
= new char[allsizes
];
4168 strcpy(fullMsg
, msgStart
);
4169 for (size_t i
=0; i
< exceptions
.size(); ++i
) {
4170 strcat(fullMsg
, delim
);
4171 strcat(fullMsg
, exceptions
[i
]);
4172 free((void*)exceptions
[i
]);
4174 throw (const char*)fullMsg
;
4182 static void mapSharedCache(uintptr_t mainExecutableSlide
)
4184 dyld3::SharedCacheOptions opts
;
4185 opts
.cacheDirOverride
= sSharedCacheOverrideDir
;
4186 opts
.forcePrivate
= (gLinkContext
.sharedRegionMode
== ImageLoader::kUsePrivateSharedRegion
);
4187 #if __x86_64__ && !TARGET_OS_SIMULATOR
4188 opts
.useHaswell
= sHaswell
;
4190 opts
.useHaswell
= false;
4192 opts
.verbose
= gLinkContext
.verboseMapping
;
4193 // <rdar://problem/32031197> respect -disable_aslr boot-arg
4194 // <rdar://problem/56299169> kern.bootargs is now blocked
4195 opts
.disableASLR
= (mainExecutableSlide
== 0) && dyld3::internalInstall(); // infer ASLR is off if main executable is not slid
4196 loadDyldCache(opts
, &sSharedCacheLoadInfo
);
4198 // update global state
4199 if ( sSharedCacheLoadInfo
.loadAddress
!= nullptr ) {
4200 gLinkContext
.dyldCache
= sSharedCacheLoadInfo
.loadAddress
;
4201 dyld::gProcessInfo
->processDetachedFromSharedRegion
= opts
.forcePrivate
;
4202 dyld::gProcessInfo
->sharedCacheSlide
= sSharedCacheLoadInfo
.slide
;
4203 dyld::gProcessInfo
->sharedCacheBaseAddress
= (unsigned long)sSharedCacheLoadInfo
.loadAddress
;
4204 sSharedCacheLoadInfo
.loadAddress
->getUUID(dyld::gProcessInfo
->sharedCacheUUID
);
4205 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_SHARED_CACHE_A
, sSharedCacheLoadInfo
.path
, (const uuid_t
*)&dyld::gProcessInfo
->sharedCacheUUID
[0], {0,0}, {{ 0, 0 }}, (const mach_header
*)sSharedCacheLoadInfo
.loadAddress
);
4208 //#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
4209 // RAM disk booting does not have shared cache yet
4210 // Don't make lack of a shared cache fatal in that case
4211 // if ( sSharedCacheLoadInfo.loadAddress == nullptr ) {
4212 // if ( sSharedCacheLoadInfo.errorMessage != nullptr )
4213 // halt(sSharedCacheLoadInfo.errorMessage);
4215 // halt("error loading dyld shared cache");
4222 // create when NSLinkModule is called for a second time on a bundle
4223 ImageLoader
* cloneImage(ImageLoader
* image
)
4225 // open file (automagically closed when this function exits)
4226 FileOpener
file(image
->getPath());
4228 struct stat stat_buf
;
4229 if ( fstat(file
.getFileDescriptor(), &stat_buf
) == -1)
4232 dyld::LoadContext context
;
4233 context
.useSearchPaths
= false;
4234 context
.useFallbackPaths
= false;
4235 context
.useLdLibraryPath
= false;
4236 context
.implicitRPath
= false;
4237 context
.matchByInstallName
= false;
4238 context
.dontLoad
= false;
4239 context
.mustBeBundle
= true;
4240 context
.mustBeDylib
= false;
4241 context
.canBePIE
= false;
4242 context
.origin
= NULL
;
4243 context
.rpath
= NULL
;
4244 return loadPhase6(file
.getFileDescriptor(), stat_buf
, image
->getPath(), context
);
4248 ImageLoader
* loadFromMemory(const uint8_t* mem
, uint64_t len
, const char* moduleName
)
4250 // if fat wrapper, find usable sub-file
4251 const fat_header
* memStartAsFat
= (fat_header
*)mem
;
4252 uint64_t fileOffset
= 0;
4253 uint64_t fileLength
= len
;
4254 if ( memStartAsFat
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
4255 if ( fatFindBest(memStartAsFat
, &fileOffset
, &fileLength
) ) {
4256 mem
= &mem
[fileOffset
];
4260 throw "no matching architecture in universal wrapper";
4265 if ( isCompatibleMachO(mem
, moduleName
) ) {
4266 ImageLoader
* image
= ImageLoaderMachO::instantiateFromMemory(moduleName
, (macho_header
*)mem
, len
, gLinkContext
);
4267 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
4268 if ( ! image
->isBundle() )
4273 // try other file formats here...
4275 // throw error about what was found
4276 switch (*(uint32_t*)mem
) {
4281 throw "mach-o, but wrong architecture";
4283 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
4284 mem
[0], mem
[1], mem
[2], mem
[3], mem
[4], mem
[5], mem
[6],mem
[7]);
4289 void registerAddCallback(ImageCallback func
)
4291 // now add to list to get notified when any more images are added
4292 sAddImageCallbacks
.push_back(func
);
4294 // call callback with all existing images
4295 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
4296 ImageLoader
* image
= *it
;
4297 if ( image
->getState() >= dyld_image_state_bound
&& image
->getState() < dyld_image_state_terminated
) {
4298 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*func
), 0);
4299 (*func
)(image
->machHeader(), image
->getSlide());
4302 #if SUPPORT_ACCELERATE_TABLES
4303 if ( sAllCacheImagesProxy
!= NULL
) {
4304 dyld_image_info infos
[allImagesCount()+1];
4305 unsigned cacheCount
= sAllCacheImagesProxy
->appendImagesToNotify(dyld_image_state_bound
, true, infos
);
4306 for (unsigned i
=0; i
< cacheCount
; ++i
) {
4307 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)infos
[i
].imageLoadAddress
, (uint64_t)(*func
), 0);
4308 (*func
)(infos
[i
].imageLoadAddress
, sSharedCacheLoadInfo
.slide
);
4314 void registerLoadCallback(LoadImageCallback func
)
4316 // now add to list to get notified when any more images are added
4317 sAddLoadImageCallbacks
.push_back(func
);
4319 // call callback with all existing images
4320 for (ImageLoader
* image
: sAllImages
) {
4321 if ( image
->getState() >= dyld_image_state_bound
&& image
->getState() < dyld_image_state_terminated
) {
4322 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)image
->machHeader(), (uint64_t)(*func
), 0);
4323 (*func
)(image
->machHeader(), image
->getPath(), !image
->neverUnload());
4326 #if SUPPORT_ACCELERATE_TABLES
4327 if ( sAllCacheImagesProxy
!= NULL
) {
4328 dyld_image_info infos
[allImagesCount()+1];
4329 unsigned cacheCount
= sAllCacheImagesProxy
->appendImagesToNotify(dyld_image_state_bound
, true, infos
);
4330 for (unsigned i
=0; i
< cacheCount
; ++i
) {
4331 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)infos
[i
].imageLoadAddress
, (uint64_t)(*func
), 0);
4332 (*func
)(infos
[i
].imageLoadAddress
, infos
[i
].imageFilePath
, false);
4338 void registerBulkLoadCallback(LoadImageBulkCallback func
)
4340 // call callback with all existing images
4341 unsigned count
= dyld::gProcessInfo
->infoArrayCount
;
4342 const dyld_image_info
* infoArray
= dyld::gProcessInfo
->infoArray
;
4343 if ( infoArray
!= NULL
) {
4344 const mach_header
* mhs
[count
];
4345 const char* paths
[count
];
4346 for (unsigned i
=0; i
< count
; ++i
) {
4347 mhs
[i
] = infoArray
[i
].imageLoadAddress
;
4348 paths
[i
] = infoArray
[i
].imageFilePath
;
4350 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE
, (uint64_t)mhs
[0], (uint64_t)func
, 0);
4351 func(count
, mhs
, paths
);
4354 // now add to list to get notified when any more images are added
4355 sAddBulkLoadImageCallbacks
.push_back(func
);
4358 void registerRemoveCallback(ImageCallback func
)
4360 // <rdar://problem/15025198> ignore calls to register a notification during a notification
4361 if ( sRemoveImageCallbacksInUse
)
4363 sRemoveImageCallbacks
.push_back(func
);
4366 void clearErrorMessage()
4368 error_string
[0] = '\0';
4371 void setErrorMessage(const char* message
)
4373 // save off error message in global buffer for CrashReporter to find
4374 strlcpy(error_string
, message
, sizeof(error_string
));
4377 const char* getErrorMessage()
4379 return error_string
;
4382 void halt(const char* message
)
4384 if ( sSharedCacheLoadInfo
.errorMessage
!= nullptr ) {
4385 // <rdar://problem/45957449> if dyld fails with a missing dylib and there is no shared cache, display the shared cache load error message
4386 dyld::log("dyld: dyld cache load error: %s\n", sSharedCacheLoadInfo
.errorMessage
);
4387 dyld::log("dyld: %s\n", message
);
4388 strlcpy(error_string
, "dyld cache load error: ", sizeof(error_string
));
4389 strlcat(error_string
, sSharedCacheLoadInfo
.errorMessage
, sizeof(error_string
));
4390 strlcat(error_string
, "\n", sizeof(error_string
));
4391 strlcat(error_string
, message
, sizeof(error_string
));
4392 } else if ( dyld::gProcessInfo
->errorKind
== DYLD_EXIT_REASON_DYLIB_MISSING
) {
4393 // If a dylib is missing, but we have the cache, print the cache UUID to make it easier
4394 // to see what might have gone wrong
4395 if ( sSharedCacheLoadInfo
.loadAddress
== nullptr ) {
4396 strlcpy(error_string
, "dyld: No shared cache present\n", sizeof(error_string
));
4399 sSharedCacheLoadInfo
.loadAddress
->getUUID(cacheUUID
);
4400 uuid_string_t uuidStr
;
4401 uuid_unparse_upper(cacheUUID
, uuidStr
);
4403 strlcpy(error_string
, "dyld: Using shared cache: ", sizeof(error_string
));
4404 strlcat(error_string
, uuidStr
, sizeof(error_string
));
4405 strlcat(error_string
, "\n", sizeof(error_string
));
4408 dyld::log("dyld: %s\n", message
);
4409 strlcat(error_string
, message
, sizeof(error_string
));
4412 dyld::log("dyld: %s\n", message
);
4413 strlcpy(error_string
, message
, sizeof(error_string
));
4416 dyld::gProcessInfo
->errorMessage
= error_string
;
4417 if ( !gLinkContext
.startedInitializingMainExecutable
)
4418 dyld::gProcessInfo
->terminationFlags
= 1;
4420 dyld::gProcessInfo
->terminationFlags
= 0;
4422 char payloadBuffer
[EXIT_REASON_PAYLOAD_MAX_LEN
];
4423 dyld_abort_payload
* payload
= (dyld_abort_payload
*)payloadBuffer
;
4424 payload
->version
= 1;
4425 payload
->flags
= gLinkContext
.startedInitializingMainExecutable
? 0 : 1;
4426 payload
->targetDylibPathOffset
= 0;
4427 payload
->clientPathOffset
= 0;
4428 payload
->symbolOffset
= 0;
4429 int payloadSize
= sizeof(dyld_abort_payload
);
4431 if ( dyld::gProcessInfo
->errorTargetDylibPath
!= NULL
) {
4432 payload
->targetDylibPathOffset
= payloadSize
;
4433 payloadSize
+= strlcpy(&payloadBuffer
[payloadSize
], dyld::gProcessInfo
->errorTargetDylibPath
, sizeof(payloadBuffer
)-payloadSize
) + 1;
4435 if ( dyld::gProcessInfo
->errorClientOfDylibPath
!= NULL
) {
4436 payload
->clientPathOffset
= payloadSize
;
4437 payloadSize
+= strlcpy(&payloadBuffer
[payloadSize
], dyld::gProcessInfo
->errorClientOfDylibPath
, sizeof(payloadBuffer
)-payloadSize
) + 1;
4439 if ( dyld::gProcessInfo
->errorSymbol
!= NULL
) {
4440 payload
->symbolOffset
= payloadSize
;
4441 payloadSize
+= strlcpy(&payloadBuffer
[payloadSize
], dyld::gProcessInfo
->errorSymbol
, sizeof(payloadBuffer
)-payloadSize
) + 1;
4443 char truncMessage
[EXIT_REASON_USER_DESC_MAX_LEN
];
4444 strlcpy(truncMessage
, error_string
, EXIT_REASON_USER_DESC_MAX_LEN
);
4445 abort_with_payload(OS_REASON_DYLD
, dyld::gProcessInfo
->errorKind
? dyld::gProcessInfo
->errorKind
: DYLD_EXIT_REASON_OTHER
, payloadBuffer
, payloadSize
, truncMessage
, 0);
4448 static void setErrorStrings(unsigned errorCode
, const char* errorClientOfDylibPath
,
4449 const char* errorTargetDylibPath
, const char* errorSymbol
)
4451 dyld::gProcessInfo
->errorKind
= errorCode
;
4452 dyld::gProcessInfo
->errorClientOfDylibPath
= errorClientOfDylibPath
;
4453 dyld::gProcessInfo
->errorTargetDylibPath
= errorTargetDylibPath
;
4454 dyld::gProcessInfo
->errorSymbol
= errorSymbol
;
4458 uintptr_t bindLazySymbol(const mach_header
* mh
, uintptr_t* lazyPointer
)
4460 uintptr_t result
= 0;
4461 // acquire read-lock on dyld's data structures
4462 #if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved
4463 if ( gLibSystemHelpers
!= NULL
)
4464 (*gLibSystemHelpers
->lockForReading
)();
4466 // lookup and bind lazy pointer and get target address
4468 ImageLoader
* target
;
4470 // fast stubs pass NULL for mh and image is instead found via the location of stub (aka lazyPointer)
4472 target
= dyld::findImageContainingAddress(lazyPointer
);
4474 target
= dyld::findImageByMachHeader(mh
);
4476 // note, target should always be mach-o, because only mach-o lazy handler wired up to this
4477 target
= dyld::findImageByMachHeader(mh
);
4479 if ( target
== NULL
)
4480 throwf("image not found for lazy pointer at %p", lazyPointer
);
4481 DyldSharedCache::DataConstLazyScopedWriter
patcher(gLinkContext
.dyldCache
, mach_task_self(), gLinkContext
.verboseMapping
? &dyld::log
: nullptr);
4482 result
= target
->doBindLazySymbol(lazyPointer
, gLinkContext
, patcher
);
4484 catch (const char* message
) {
4485 dyld::log("dyld: lazy symbol binding failed: %s\n", message
);
4488 // release read-lock on dyld's data structures
4490 if ( gLibSystemHelpers
!= NULL
)
4491 (*gLibSystemHelpers
->unlockForReading
)();
4493 // return target address to glue which jumps to it with real parameters restored
4498 uintptr_t fastBindLazySymbol(ImageLoader
** imageLoaderCache
, uintptr_t lazyBindingInfoOffset
)
4500 uintptr_t result
= 0;
4502 if ( *imageLoaderCache
== NULL
) {
4504 *imageLoaderCache
= dyld::findMappedRange((uintptr_t)imageLoaderCache
);
4505 if ( *imageLoaderCache
== NULL
) {
4506 #if SUPPORT_ACCELERATE_TABLES
4507 if ( sAllCacheImagesProxy
!= NULL
) {
4508 const mach_header
* mh
;
4511 if ( sAllCacheImagesProxy
->addressInCache(imageLoaderCache
, &mh
, &path
, &index
) ) {
4512 result
= sAllCacheImagesProxy
->bindLazy(lazyBindingInfoOffset
, gLinkContext
, mh
, index
);
4513 if ( result
== 0 ) {
4514 halt("dyld: lazy symbol binding failed for image in dyld shared\n");
4520 const char* message
= "fast lazy binding from unknown image";
4521 dyld::log("dyld: %s\n", message
);
4526 // bind lazy pointer and return it
4528 result
= (*imageLoaderCache
)->doBindFastLazySymbol((uint32_t)lazyBindingInfoOffset
, gLinkContext
,
4529 (dyld::gLibSystemHelpers
!= NULL
) ? dyld::gLibSystemHelpers
->acquireGlobalDyldLock
: NULL
,
4530 (dyld::gLibSystemHelpers
!= NULL
) ? dyld::gLibSystemHelpers
->releaseGlobalDyldLock
: NULL
);
4532 catch (const char* message
) {
4533 dyld::log("dyld: lazy symbol binding failed: %s\n", message
);
4537 // return target address to glue which jumps to it with real parameters restored
4543 void registerUndefinedHandler(UndefinedHandler handler
)
4545 sUndefinedHandler
= handler
;
4548 static void undefinedHandler(const char* symboName
)
4550 if ( sUndefinedHandler
!= NULL
) {
4551 (*sUndefinedHandler
)(symboName
);
4555 static bool findExportedSymbol(const char* name
, bool onlyInCoalesced
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
, ImageLoader::CoalesceNotifier notifier
=NULL
)
4557 // search all images in order
4558 const ImageLoader
* firstWeakImage
= NULL
;
4559 const ImageLoader::Symbol
* firstWeakSym
= NULL
;
4560 const ImageLoader
* firstNonWeakImage
= NULL
;
4561 const ImageLoader::Symbol
* firstNonWeakSym
= NULL
;
4562 const size_t imageCount
= sAllImages
.size();
4563 for(size_t i
=0; i
< imageCount
; ++i
) {
4564 ImageLoader
* anImage
= sAllImages
[i
];
4565 // the use of inserted libraries alters search order
4566 // so that inserted libraries are found before the main executable
4567 if ( sInsertedDylibCount
> 0 ) {
4568 if ( i
< sInsertedDylibCount
)
4569 anImage
= sAllImages
[i
+1];
4570 else if ( i
== sInsertedDylibCount
)
4571 anImage
= sAllImages
[0];
4573 //dyld::log("findExportedSymbol(%s) looking at %s\n", name, anImage->getPath());
4574 if ( ! anImage
->hasHiddenExports() && (!onlyInCoalesced
|| anImage
->hasCoalescedExports()) ) {
4575 const ImageLoader
* foundInImage
;
4576 *sym
= anImage
->findExportedSymbol(name
, false, &foundInImage
);
4577 //dyld::log("findExportedSymbol(%s) found: sym=%p, anImage=%p, foundInImage=%p\n", name, *sym, anImage, foundInImage /*, (foundInImage ? foundInImage->getPath() : "")*/);
4578 if ( *sym
!= NULL
) {
4579 if ( notifier
&& (foundInImage
== anImage
) )
4580 notifier(*sym
, foundInImage
, foundInImage
->machHeader());
4581 // if weak definition found, record first one found
4582 if ( (foundInImage
->getExportedSymbolInfo(*sym
) & ImageLoader::kWeakDefinition
) != 0 ) {
4583 if ( firstWeakImage
== NULL
) {
4584 firstWeakImage
= foundInImage
;
4585 firstWeakSym
= *sym
;
4590 if ( !onlyInCoalesced
) {
4591 // for flat lookups, return first found
4592 *image
= foundInImage
;
4595 if ( firstNonWeakImage
== NULL
) {
4596 firstNonWeakImage
= foundInImage
;
4597 firstNonWeakSym
= *sym
;
4603 if ( firstNonWeakImage
!= NULL
) {
4604 // found a weak definition, but no non-weak, so return first weak found
4605 *sym
= firstNonWeakSym
;
4606 *image
= firstNonWeakImage
;
4609 if ( firstWeakSym
!= NULL
) {
4610 // found a weak definition, but no non-weak, so return first weak found
4611 *sym
= firstWeakSym
;
4612 *image
= firstWeakImage
;
4615 #if SUPPORT_ACCELERATE_TABLES
4616 if ( sAllCacheImagesProxy
!= NULL
) {
4617 if ( sAllCacheImagesProxy
->flatFindSymbol(name
, onlyInCoalesced
, sym
, image
, notifier
) )
4625 bool flatFindExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
)
4627 return findExportedSymbol(name
, false, sym
, image
);
4630 bool findCoalescedExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
, ImageLoader::CoalesceNotifier notifier
)
4632 return findExportedSymbol(name
, true, sym
, image
, notifier
);
4636 bool flatFindExportedSymbolWithHint(const char* name
, const char* librarySubstring
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
)
4638 // search all images in order
4639 const size_t imageCount
= sAllImages
.size();
4640 for(size_t i
=0; i
< imageCount
; ++i
){
4641 ImageLoader
* anImage
= sAllImages
[i
];
4642 // only look at images whose paths contain the hint string (NULL hint string is wildcard)
4643 if ( ! anImage
->isBundle() && ((librarySubstring
==NULL
) || (strstr(anImage
->getPath(), librarySubstring
) != NULL
)) ) {
4644 *sym
= anImage
->findExportedSymbol(name
, false, image
);
4645 if ( *sym
!= NULL
) {
4654 unsigned int getCoalescedImages(ImageLoader
* images
[], unsigned imageIndex
[])
4656 unsigned int count
= 0;
4657 const size_t imageCount
= sAllImages
.size();
4658 for(size_t i
=0; i
< imageCount
; ++i
) {
4659 ImageLoader
* anImage
= sAllImages
[i
];
4660 // the use of inserted libraries alters search order
4661 // so that inserted libraries are found before the main executable
4662 if ( sInsertedDylibCount
> 0 ) {
4663 if ( i
< sInsertedDylibCount
)
4664 anImage
= sAllImages
[i
+1];
4665 else if ( i
== sInsertedDylibCount
)
4666 anImage
= sAllImages
[0];
4668 if ( anImage
->participatesInCoalescing() ) {
4669 images
[count
] = anImage
;
4670 imageIndex
[count
] = 0;
4674 #if SUPPORT_ACCELERATE_TABLES
4675 if ( sAllCacheImagesProxy
!= NULL
) {
4676 sAllCacheImagesProxy
->appendImagesNeedingCoalescing(images
, imageIndex
, count
);
4683 static ImageLoader::MappedRegion
* getMappedRegions(ImageLoader::MappedRegion
* regions
)
4685 ImageLoader::MappedRegion
* end
= regions
;
4686 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
4687 (*it
)->getMappedRegions(end
);
4692 void registerImageStateSingleChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
)
4694 // mark the image that the handler is in as never-unload because dyld has a reference into it
4695 ImageLoader
* handlerImage
= findImageContainingAddress((void*)handler
);
4696 if ( handlerImage
!= NULL
)
4697 handlerImage
->setNeverUnload();
4699 // add to list of handlers
4700 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(state
, sSingleHandlers
);
4701 if ( handlers
!= NULL
) {
4702 // <rdar://problem/10332417> need updateAllImages() to be last in dyld_image_state_mapped list
4703 // so that if ObjC adds a handler that prevents a load, it happens before the gdb list is updated
4704 if ( state
== dyld_image_state_mapped
)
4705 handlers
->insert(handlers
->begin(), handler
);
4707 handlers
->push_back(handler
);
4709 // call callback with all existing images
4710 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
4711 ImageLoader
* image
= *it
;
4712 dyld_image_info info
;
4713 info
.imageLoadAddress
= image
->machHeader();
4714 info
.imageFilePath
= image
->getRealPath();
4715 info
.imageFileModDate
= image
->lastModified();
4716 // should only call handler if state == image->state
4717 if ( image
->getState() == state
)
4718 (*handler
)(state
, 1, &info
);
4719 // ignore returned string, too late to do anything
4724 void registerImageStateBatchChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
)
4726 // mark the image that the handler is in as never-unload because dyld has a reference into it
4727 ImageLoader
* handlerImage
= findImageContainingAddress((void*)handler
);
4728 if ( handlerImage
!= NULL
)
4729 handlerImage
->setNeverUnload();
4731 // add to list of handlers
4732 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(state
, sBatchHandlers
);
4733 if ( handlers
!= NULL
) {
4734 // insert at front, so that gdb handler is always last
4735 handlers
->insert(handlers
->begin(), handler
);
4737 // call callback with all existing images
4739 notifyBatchPartial(state
, true, handler
, false, false);
4741 catch (const char* msg
) {
4742 // ignore request to abort during registration
4748 void registerObjCNotifiers(_dyld_objc_notify_mapped mapped
, _dyld_objc_notify_init init
, _dyld_objc_notify_unmapped unmapped
)
4750 // record functions to call
4751 sNotifyObjCMapped
= mapped
;
4752 sNotifyObjCInit
= init
;
4753 sNotifyObjCUnmapped
= unmapped
;
4755 // call 'mapped' function with all images mapped so far
4757 notifyBatchPartial(dyld_image_state_bound
, true, NULL
, false, true);
4759 catch (const char* msg
) {
4760 // ignore request to abort during registration
4763 // <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem)
4764 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
4765 ImageLoader
* image
= *it
;
4766 if ( (image
->getState() == dyld_image_state_initialized
) && image
->notifyObjC() ) {
4767 dyld3::ScopedTimer
timer(DBG_DYLD_TIMING_OBJC_INIT
, (uint64_t)image
->machHeader(), 0, 0);
4768 (*sNotifyObjCInit
)(image
->getRealPath(), image
->machHeader());
4773 bool sharedCacheUUID(uuid_t uuid
)
4775 if ( sSharedCacheLoadInfo
.loadAddress
== nullptr )
4778 sSharedCacheLoadInfo
.loadAddress
->getUUID(uuid
);
4782 #if SUPPORT_ACCELERATE_TABLES
4784 bool dlopenFromCache(const char* path
, int mode
, void** handle
)
4786 if ( sAllCacheImagesProxy
== NULL
)
4788 char fallbackPath
[PATH_MAX
];
4789 bool result
= sAllCacheImagesProxy
->dlopenFromCache(gLinkContext
, path
, mode
, handle
);
4790 if ( !result
&& (strchr(path
, '/') == NULL
) ) {
4791 // POSIX says you can call dlopen() with a leaf name (e.g. dlopen("libz.dylb"))
4792 strcpy(fallbackPath
, "/usr/lib/");
4793 strlcat(fallbackPath
, path
, PATH_MAX
);
4794 result
= sAllCacheImagesProxy
->dlopenFromCache(gLinkContext
, fallbackPath
, mode
, handle
);
4796 path
= fallbackPath
;
4799 // leaf name could be a symlink
4800 char resolvedPath
[PATH_MAX
];
4801 realpath(path
, resolvedPath
);
4802 int realpathErrno
= errno
;
4803 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
4804 if ( (realpathErrno
== ENOENT
) || (realpathErrno
== 0) ) {
4805 result
= sAllCacheImagesProxy
->dlopenFromCache(gLinkContext
, resolvedPath
, mode
, handle
);
4812 bool makeCacheHandle(ImageLoader
* image
, unsigned cacheIndex
, int mode
, void** result
)
4814 if ( sAllCacheImagesProxy
== NULL
)
4816 return sAllCacheImagesProxy
->makeCacheHandle(gLinkContext
, cacheIndex
, mode
, result
);
4819 bool isCacheHandle(void* handle
)
4821 if ( sAllCacheImagesProxy
== NULL
)
4823 return sAllCacheImagesProxy
->isCacheHandle(handle
, NULL
, NULL
);
4826 bool isPathInCache(const char* path
)
4828 if ( sAllCacheImagesProxy
== NULL
)
4831 return sAllCacheImagesProxy
->hasDylib(path
, &index
);
4834 const char* getPathFromIndex(unsigned cacheIndex
)
4836 if ( sAllCacheImagesProxy
== NULL
)
4838 return sAllCacheImagesProxy
->getIndexedPath(cacheIndex
);
4841 void* dlsymFromCache(void* handle
, const char* symName
, unsigned index
)
4843 if ( sAllCacheImagesProxy
== NULL
)
4845 return sAllCacheImagesProxy
->dlsymFromCache(gLinkContext
, handle
, symName
, index
);
4848 bool addressInCache(const void* address
, const mach_header
** mh
, const char** path
, unsigned* index
)
4850 if ( sAllCacheImagesProxy
== NULL
)
4853 return sAllCacheImagesProxy
->addressInCache(address
, mh
, path
, index
? index
: &ignore
);
4856 bool findUnwindSections(const void* addr
, dyld_unwind_sections
* info
)
4858 if ( sAllCacheImagesProxy
== NULL
)
4860 return sAllCacheImagesProxy
->findUnwindSections(addr
, info
);
4863 bool dladdrFromCache(const void* address
, Dl_info
* info
)
4865 if ( sAllCacheImagesProxy
== NULL
)
4867 return sAllCacheImagesProxy
->dladdrFromCache(address
, info
);
4871 static ImageLoader
* libraryLocator(const char* libraryName
, bool search
, const char* origin
, const ImageLoader::RPathChain
* rpaths
, unsigned& cacheIndex
)
4873 dyld::LoadContext context
;
4874 context
.useSearchPaths
= search
;
4875 context
.useFallbackPaths
= search
;
4876 context
.useLdLibraryPath
= false;
4877 context
.implicitRPath
= false;
4878 context
.matchByInstallName
= false;
4879 context
.dontLoad
= false;
4880 context
.mustBeBundle
= false;
4881 context
.mustBeDylib
= true;
4882 context
.canBePIE
= false;
4883 context
.origin
= origin
;
4884 context
.rpath
= rpaths
;
4885 return load(libraryName
, context
, cacheIndex
);
4888 static const char* basename(const char* path
)
4890 const char* last
= path
;
4891 for (const char* s
= path
; *s
!= '\0'; s
++) {
4898 static void setContext(const macho_header
* mainExecutableMH
, int argc
, const char* argv
[], const char* envp
[], const char* apple
[])
4900 gLinkContext
.loadLibrary
= &libraryLocator
;
4901 gLinkContext
.terminationRecorder
= &terminationRecorder
;
4902 gLinkContext
.flatExportFinder
= &flatFindExportedSymbol
;
4903 gLinkContext
.coalescedExportFinder
= &findCoalescedExportedSymbol
;
4904 gLinkContext
.getCoalescedImages
= &getCoalescedImages
;
4905 gLinkContext
.undefinedHandler
= &undefinedHandler
;
4906 gLinkContext
.getAllMappedRegions
= &getMappedRegions
;
4907 gLinkContext
.bindingHandler
= NULL
;
4908 gLinkContext
.notifySingle
= ¬ifySingle
;
4909 gLinkContext
.notifyBatch
= ¬ifyBatch
;
4910 gLinkContext
.removeImage
= &removeImage
;
4911 gLinkContext
.registerDOFs
= dyld3::Loader::dtraceUserProbesEnabled() ? ®isterDOFs
: NULL
;
4912 gLinkContext
.clearAllDepths
= &clearAllDepths
;
4913 gLinkContext
.printAllDepths
= &printAllDepths
;
4914 gLinkContext
.imageCount
= &imageCount
;
4915 gLinkContext
.setNewProgramVars
= &setNewProgramVars
;
4916 gLinkContext
.inSharedCache
= &inSharedCache
;
4917 gLinkContext
.setErrorStrings
= &setErrorStrings
;
4918 #if SUPPORT_OLD_CRT_INITIALIZATION
4919 gLinkContext
.setRunInitialzersOldWay
= &setRunInitialzersOldWay
;
4921 gLinkContext
.findImageContainingAddress
= &findImageContainingAddress
;
4922 gLinkContext
.addDynamicReference
= &addDynamicReference
;
4923 #if SUPPORT_ACCELERATE_TABLES
4924 gLinkContext
.notifySingleFromCache
= ¬ifySingleFromCache
;
4925 gLinkContext
.getPreInitNotifyHandler
= &getPreInitNotifyHandler
;
4926 gLinkContext
.getBoundBatchHandler
= &getBoundBatchHandler
;
4928 gLinkContext
.bindingOptions
= ImageLoader::kBindingNone
;
4929 gLinkContext
.argc
= argc
;
4930 gLinkContext
.argv
= argv
;
4931 gLinkContext
.envp
= envp
;
4932 gLinkContext
.apple
= apple
;
4933 gLinkContext
.progname
= (argv
[0] != NULL
) ? basename(argv
[0]) : "";
4934 gLinkContext
.programVars
.mh
= mainExecutableMH
;
4935 gLinkContext
.programVars
.NXArgcPtr
= &gLinkContext
.argc
;
4936 gLinkContext
.programVars
.NXArgvPtr
= &gLinkContext
.argv
;
4937 gLinkContext
.programVars
.environPtr
= &gLinkContext
.envp
;
4938 gLinkContext
.programVars
.__prognamePtr
=&gLinkContext
.progname
;
4939 gLinkContext
.mainExecutable
= NULL
;
4940 gLinkContext
.imageSuffix
= NULL
;
4941 gLinkContext
.dynamicInterposeArray
= NULL
;
4942 gLinkContext
.dynamicInterposeCount
= 0;
4943 gLinkContext
.prebindUsage
= ImageLoader::kUseAllPrebinding
;
4944 gLinkContext
.sharedRegionMode
= ImageLoader::kUseSharedRegion
;
4950 // Look for a special segment in the mach header.
4951 // Its presences means that the binary wants to have DYLD ignore
4952 // DYLD_ environment variables.
4955 static bool hasRestrictedSegment(const macho_header
* mh
)
4957 const uint32_t cmd_count
= mh
->ncmds
;
4958 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
4959 const struct load_command
* cmd
= cmds
;
4960 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
4962 case LC_SEGMENT_COMMAND
:
4964 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
4966 //dyld::log("seg name: %s\n", seg->segname);
4967 if (strcmp(seg
->segname
, "__RESTRICT") == 0) {
4968 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
4969 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
4970 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
4971 if (strcmp(sect
->sectname
, "__restrict") == 0)
4978 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
4985 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
4986 static bool isFairPlayEncrypted(const macho_header
* mh
)
4988 const uint32_t cmd_count
= mh
->ncmds
;
4989 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
4990 const struct load_command
* cmd
= cmds
;
4991 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
4992 if ( cmd
->cmd
== LC_ENCRYPT_COMMAND
) {
4993 const encryption_info_command
* enc
= (encryption_info_command
*)cmd
;
4994 return (enc
->cryptid
!= 0);
4996 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
5003 #if SUPPORT_VERSIONED_PATHS
5005 #define FIRST_PAGE_BUFFER_SIZE 16384
5007 static bool readFirstPage(const char* dylibPath
, uint8_t firstPage
[FIRST_PAGE_BUFFER_SIZE
])
5010 // open file (automagically closed when this function exits)
5011 FileOpener
file(dylibPath
);
5013 if ( file
.getFileDescriptor() == -1 )
5016 if ( pread(file
.getFileDescriptor(), firstPage
, FIRST_PAGE_BUFFER_SIZE
, 0) != FIRST_PAGE_BUFFER_SIZE
)
5019 // if fat wrapper, find usable sub-file
5020 const fat_header
* fileStartAsFat
= (fat_header
*)firstPage
;
5021 if ( fileStartAsFat
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
5022 uint64_t fileOffset
;
5023 uint64_t fileLength
;
5024 if ( fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) ) {
5025 if ( pread(file
.getFileDescriptor(), firstPage
, FIRST_PAGE_BUFFER_SIZE
, fileOffset
) != FIRST_PAGE_BUFFER_SIZE
)
5037 // Peeks at a dylib file and returns its current_version and install_name.
5038 // Returns false on error.
5040 static bool getDylibVersionAndInstallname(const char* dylibPath
, uint32_t* version
, char* installName
)
5042 uint8_t firstPage
[FIRST_PAGE_BUFFER_SIZE
];
5043 const macho_header
* mh
= (macho_header
*)firstPage
;
5044 if ( !readFirstPage(dylibPath
, firstPage
) ) {
5045 // If file cannot be read, check to see if path is in shared cache
5046 const macho_header
* mhInCache
;
5047 const char* pathInCache
;
5049 if ( !findInSharedCacheImage(dylibPath
, true, NULL
, &mhInCache
, &pathInCache
, &slideInCache
) )
5054 // check mach-o header
5055 if ( mh
->magic
!= sMainExecutableMachHeader
->magic
)
5057 if ( mh
->cputype
!= sMainExecutableMachHeader
->cputype
)
5060 // scan load commands for LC_ID_DYLIB
5061 const uint32_t cmd_count
= mh
->ncmds
;
5062 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
5063 const struct load_command
* const cmdsReadEnd
= (struct load_command
*)(((char*)mh
)+FIRST_PAGE_BUFFER_SIZE
);
5064 const struct load_command
* cmd
= cmds
;
5065 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
5069 const struct dylib_command
* id
= (struct dylib_command
*)cmd
;
5070 *version
= id
->dylib
.current_version
;
5071 if ( installName
!= NULL
)
5072 strlcpy(installName
, (char *)id
+ id
->dylib
.name
.offset
, PATH_MAX
);
5077 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
5078 if ( cmd
> cmdsReadEnd
)
5084 #endif // SUPPORT_VERSIONED_PATHS
5088 static void printAllImages()
5090 dyld::log("printAllImages()\n");
5091 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
5092 ImageLoader
* image
= *it
;
5093 dyld_image_states imageState
= image
->getState();
5094 dyld::log(" state=%d, dlopen-count=%d, never-unload=%d, in-use=%d, name=%s\n",
5095 imageState
, image
->dlopenCount(), image
->neverUnload(), image
->isMarkedInUse(), image
->getShortName());
5100 void link(ImageLoader
* image
, bool forceLazysBound
, bool neverUnload
, const ImageLoader::RPathChain
& loaderRPaths
, unsigned cacheIndex
)
5102 // add to list of known images. This did not happen at creation time for bundles
5103 if ( image
->isBundle() && !image
->isLinked() )
5106 // we detect root images as those not linked in yet
5107 if ( !image
->isLinked() )
5108 addRootImage(image
);
5112 const char* path
= image
->getPath();
5113 #if SUPPORT_ACCELERATE_TABLES
5114 if ( image
== sAllCacheImagesProxy
)
5115 path
= sAllCacheImagesProxy
->getIndexedPath(cacheIndex
);
5117 image
->link(gLinkContext
, forceLazysBound
, false, neverUnload
, loaderRPaths
, path
);
5119 catch (const char* msg
) {
5120 garbageCollectImages();
5126 void runInitializers(ImageLoader
* image
)
5128 // do bottom up initialization
5129 ImageLoader::InitializerTimingList initializerTimes
[allImagesCount()];
5130 initializerTimes
[0].count
= 0;
5131 image
->runInitializers(gLinkContext
, initializerTimes
[0]);
5134 // This function is called at the end of dlclose() when the reference count goes to zero.
5135 // The dylib being unloaded may have brought in other dependent dylibs when it was loaded.
5136 // Those dependent dylibs need to be unloaded, but only if they are not referenced by
5137 // something else. We use a standard mark and sweep garbage collection.
5139 // The tricky part is that when a dylib is unloaded it may have a termination function that
5140 // can run and itself call dlclose() on yet another dylib. The problem is that this
5141 // sort of gabage collection is not re-entrant. Instead a terminator's call to dlclose()
5142 // which calls garbageCollectImages() will just set a flag to re-do the garbage collection
5143 // when the current pass is done.
5145 // Also note that this is done within the dyld global lock, so it is always single threaded.
5147 void garbageCollectImages()
5149 static bool sDoingGC
= false;
5150 static bool sRedo
= false;
5153 // GC is currently being run, just set a flag to have it run again.
5162 // mark phase: mark all images not-in-use
5163 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
5164 ImageLoader
* image
= *it
;
5165 //dyld::log("gc: neverUnload=%d name=%s\n", image->neverUnload(), image->getShortName());
5166 image
->markNotUsed();
5169 #pragma clang diagnostic push
5170 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
5171 // sweep phase: mark as in-use, images reachable from never-unload or in-use image
5172 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
5173 ImageLoader
* image
= *it
;
5174 if ( (image
->dlopenCount() != 0) || (image
->neverUnload() && (image
->getState() >= dyld_image_state_bound
)) || (image
== sMainExecutable
) ) {
5175 OSSpinLockLock(&sDynamicReferencesLock
);
5176 image
->markedUsedRecursive(sDynamicReferences
);
5177 OSSpinLockUnlock(&sDynamicReferencesLock
);
5180 #pragma clang diagnostic pop
5182 // collect phase: build array of images not marked in-use
5183 ImageLoader
* deadImages
[sAllImages
.size()];
5184 unsigned deadCount
= 0;
5185 int maxRangeCount
= 0;
5186 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
5187 ImageLoader
* image
= *it
;
5188 if ( ! image
->isMarkedInUse() ) {
5189 deadImages
[deadCount
++] = image
;
5190 if (gLogAPIs
) dyld::log("dlclose(), found unused image %p %s\n", image
, image
->getShortName());
5191 maxRangeCount
+= image
->segmentCount();
5195 // collect phase: run termination routines for images not marked in-use
5196 if ( maxRangeCount
!= 0 ) {
5197 __cxa_range_t ranges
[maxRangeCount
];
5199 for (unsigned i
=0; i
< deadCount
; ++i
) {
5200 ImageLoader
* image
= deadImages
[i
];
5201 for (unsigned int j
=0; j
< image
->segmentCount(); ++j
) {
5202 if ( !image
->segExecutable(j
) )
5204 if ( rangeCount
< maxRangeCount
) {
5205 ranges
[rangeCount
].addr
= (const void*)image
->segActualLoadAddress(j
);
5206 ranges
[rangeCount
].length
= image
->segSize(j
);
5211 runImageStaticTerminators(image
);
5213 catch (const char* msg
) {
5214 dyld::warn("problem running terminators for image: %s\n", msg
);
5218 // <rdar://problem/14718598> dyld should call __cxa_finalize_ranges()
5219 if ( (rangeCount
> 0) && (gLibSystemHelpers
!= NULL
) && (gLibSystemHelpers
->version
>= 13) )
5220 (*gLibSystemHelpers
->cxa_finalize_ranges
)(ranges
, rangeCount
);
5223 // collect phase: delete all images which are not marked in-use
5226 mightBeMore
= false;
5227 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
5228 ImageLoader
* image
= *it
;
5229 if ( ! image
->isMarkedInUse() ) {
5231 if (gLogAPIs
) dyld::log("dlclose(), deleting %p %s\n", image
, image
->getShortName());
5233 ImageLoader::deleteImage(image
);
5235 break; // interator in invalidated by this removal
5237 catch (const char* msg
) {
5238 dyld::warn("problem deleting image: %s\n", msg
);
5242 } while ( mightBeMore
);
5251 static void preflight_finally(ImageLoader
* image
)
5253 if ( image
->isBundle() ) {
5254 removeImageFromAllImages(image
->machHeader());
5255 ImageLoader::deleteImage(image
);
5257 sBundleBeingLoaded
= NULL
;
5258 dyld::garbageCollectImages();
5262 void preflight(ImageLoader
* image
, const ImageLoader::RPathChain
& loaderRPaths
, unsigned cacheIndex
)
5265 if ( image
->isBundle() )
5266 sBundleBeingLoaded
= image
; // hack
5267 const char* path
= image
->getPath();
5268 #if SUPPORT_ACCELERATE_TABLES
5269 if ( image
== sAllCacheImagesProxy
)
5270 path
= sAllCacheImagesProxy
->getIndexedPath(cacheIndex
);
5272 image
->link(gLinkContext
, false, true, false, loaderRPaths
, path
);
5274 catch (const char* msg
) {
5275 preflight_finally(image
);
5278 preflight_finally(image
);
5281 static void loadInsertedDylib(const char* path
)
5283 unsigned cacheIndex
;
5285 LoadContext context
;
5286 context
.useSearchPaths
= false;
5287 context
.useFallbackPaths
= false;
5288 context
.useLdLibraryPath
= false;
5289 context
.implicitRPath
= false;
5290 context
.matchByInstallName
= false;
5291 context
.dontLoad
= false;
5292 context
.mustBeBundle
= false;
5293 context
.mustBeDylib
= true;
5294 context
.canBePIE
= false;
5295 context
.origin
= NULL
; // can't use @loader_path with DYLD_INSERT_LIBRARIES
5296 context
.rpath
= NULL
;
5297 load(path
, context
, cacheIndex
);
5299 catch (const char* msg
) {
5300 if ( gLinkContext
.allowInsertFailures
)
5301 dyld::log("dyld: warning: could not load inserted library '%s' into hardened process because %s\n", path
, msg
);
5303 halt(dyld::mkstringf("could not load inserted library '%s' because %s\n", path
, msg
));
5306 halt(dyld::mkstringf("could not load inserted library '%s'\n", path
));
5311 static void configureProcessRestrictions(const macho_header
* mainExecutableMH
, const char* envp
[])
5313 uint64_t amfiInputFlags
= 0;
5314 #if TARGET_OS_SIMULATOR
5315 amfiInputFlags
|= AMFI_DYLD_INPUT_PROC_IN_SIMULATOR
;
5317 if ( hasRestrictedSegment(mainExecutableMH
) )
5318 amfiInputFlags
|= AMFI_DYLD_INPUT_PROC_HAS_RESTRICT_SEG
;
5319 #elif TARGET_OS_IPHONE
5320 if ( isFairPlayEncrypted(mainExecutableMH
) )
5321 amfiInputFlags
|= AMFI_DYLD_INPUT_PROC_IS_ENCRYPTED
;
5323 uint64_t amfiOutputFlags
= 0;
5324 const char* amfiFake
= nullptr;
5325 if constexpr(BUILD_FOR_TESTING
== 1) {
5326 amfiFake
= _simple_getenv(envp
, "DYLD_AMFI_FAKE");
5327 } else if ( dyld3::internalInstall() && dyld3::BootArgs::enableDyldTestMode() ) {
5328 amfiFake
= _simple_getenv(envp
, "DYLD_AMFI_FAKE");
5331 if ( amfiFake
!= nullptr ) {
5332 amfiOutputFlags
= hexToUInt64(amfiFake
, nullptr);
5334 if ( (amfiFake
!= nullptr) || (amfi_check_dyld_policy_self(amfiInputFlags
, &amfiOutputFlags
) == 0) ) {
5335 gLinkContext
.allowAtPaths
= (amfiOutputFlags
& AMFI_DYLD_OUTPUT_ALLOW_AT_PATH
);
5336 gLinkContext
.allowEnvVarsPrint
= (amfiOutputFlags
& AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS
);
5337 gLinkContext
.allowEnvVarsPath
= (amfiOutputFlags
& AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS
);
5338 gLinkContext
.allowEnvVarsSharedCache
= (amfiOutputFlags
& AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE
);
5339 gLinkContext
.allowClassicFallbackPaths
= (amfiOutputFlags
& AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS
);
5340 gLinkContext
.allowInsertFailures
= (amfiOutputFlags
& AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION
);
5341 #ifdef AMFI_RETURNS_INTERPOSING_FLAG
5342 gLinkContext
.allowInterposing
= (amfiOutputFlags
& AMFI_DYLD_OUTPUT_ALLOW_LIBRARY_INTERPOSING
);
5344 gLinkContext
.allowInterposing
= true;
5349 // support chrooting from old kernel
5350 bool isRestricted
= false;
5351 bool libraryValidation
= false;
5352 // any processes with setuid or setgid bit set or with __RESTRICT segment is restricted
5353 if ( issetugid() || hasRestrictedSegment(mainExecutableMH
) ) {
5354 isRestricted
= true;
5356 bool usingSIP
= (csr_check(CSR_ALLOW_TASK_FOR_PID
) != 0);
5358 if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) != -1 ) {
5359 // On OS X CS_RESTRICT means the program was signed with entitlements
5360 if ( ((flags
& CS_RESTRICT
) == CS_RESTRICT
) && usingSIP
) {
5361 isRestricted
= true;
5363 // Library Validation loosens searching but requires everything to be code signed
5364 if ( flags
& CS_REQUIRE_LV
) {
5365 isRestricted
= false;
5366 libraryValidation
= true;
5369 gLinkContext
.allowAtPaths
= !isRestricted
;
5370 gLinkContext
.allowEnvVarsPrint
= !isRestricted
;
5371 gLinkContext
.allowEnvVarsPath
= !isRestricted
;
5372 gLinkContext
.allowEnvVarsSharedCache
= !libraryValidation
|| !usingSIP
;
5373 gLinkContext
.allowClassicFallbackPaths
= !isRestricted
;
5374 gLinkContext
.allowInsertFailures
= false;
5375 gLinkContext
.allowInterposing
= true;
5377 halt("amfi_check_dyld_policy_self() failed\n");
5382 // called by _dyld_register_driverkit_main()
5383 void setMainEntry(void (*main
)())
5385 if ( sEntryOverride
== nullptr )
5386 sEntryOverride
= main
;
5388 halt("_dyld_register_driverkit_main() may only be called once");
5391 bool processIsRestricted()
5394 return !gLinkContext
.allowEnvVarsPath
;
5401 // <rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots
5402 static void addDyldImageToUUIDList()
5404 const struct macho_header
* mh
= (macho_header
*)&__dso_handle
;
5405 const uint32_t cmd_count
= mh
->ncmds
;
5406 const struct load_command
* const cmds
= (struct load_command
*)((char*)mh
+ sizeof(macho_header
));
5407 const struct load_command
* cmd
= cmds
;
5408 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
5411 uuid_command
* uc
= (uuid_command
*)cmd
;
5412 dyld_uuid_info info
;
5413 info
.imageLoadAddress
= (mach_header
*)mh
;
5414 memcpy(info
.imageUUID
, uc
->uuid
, 16);
5415 addNonSharedCacheImageUUID(info
);
5419 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
5423 void notifyKernelAboutImage(const struct macho_header
* mh
, const char* fileInfo
)
5425 const char *endptr
= nullptr;
5426 uint64_t tmp
= hexToUInt64(fileInfo
, &endptr
);
5427 fsid_t fsid
= *reinterpret_cast<fsid_t
*>(&tmp
);
5428 uint64_t fsobj_id_scalar
= 0;
5429 fsobj_id_t fsobj_id
= {0};
5430 if (endptr
!= nullptr) {
5431 fsobj_id_scalar
= hexToUInt64(endptr
+1, &endptr
);
5432 fsobj_id
= *reinterpret_cast<fsobj_id_t
*>(&fsobj_id_scalar
);
5434 const uint32_t cmd_count
= mh
->ncmds
;
5435 const struct load_command
* const cmds
= (struct load_command
*)((char*)mh
+ sizeof(macho_header
));
5436 const struct load_command
* cmd
= cmds
;
5437 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
5440 // Add dyld to the kernel image info
5441 uuid_command
* uc
= (uuid_command
*)cmd
;
5442 char path
[MAXPATHLEN
];
5443 if (fsgetpath(path
, MAXPATHLEN
, &fsid
, fsobj_id_scalar
) < 0) {
5446 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A
, path
, (const uuid_t
*)&uc
->uuid
[0], fsobj_id
, fsid
, (const mach_header
*)mh
);
5450 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
5455 static void* getProcessInfo() { return dyld::gProcessInfo
; }
5456 static const SyscallHelpers sSysCalls
= {
5458 // added in version 1
5477 &pthread_mutex_lock
,
5478 &pthread_mutex_unlock
,
5480 &mach_port_deallocate
,
5482 &mach_timebase_info
,
5483 &OSAtomicCompareAndSwapPtrBarrier
,
5487 &mach_absolute_time
,
5488 // added in version 2
5490 // added in version 3
5494 // added in version 4
5495 &coresymbolication_load_notifier
,
5496 &coresymbolication_unload_notifier
,
5497 // Added in version 5
5498 &proc_regionfilename
,
5500 &mach_port_insert_right
,
5501 &mach_port_allocate
,
5502 &mach_msg_sim_interposed
,
5503 // Added in version 6
5504 &abort_with_payload
,
5505 // Added in version 7
5506 &legacy_task_register_dyld_image_infos
,
5507 &legacy_task_unregister_dyld_image_infos
,
5508 &legacy_task_get_dyld_image_infos
,
5509 &legacy_task_register_dyld_shared_cache_image_info
,
5510 &legacy_task_register_dyld_set_dyld_state
,
5511 &legacy_task_register_dyld_get_process_state
,
5512 // Added in version 8
5517 // Added in version 9
5518 &kdebug_trace_string
,
5519 // Added in version 10
5520 &amfi_check_dyld_policy_self
,
5521 // Added in version 11
5522 ¬ifyMonitoringDyldMain
,
5523 ¬ifyMonitoringDyld
,
5524 // Add in version 12
5526 &mach_port_construct
,
5527 &mach_port_destruct
,
5528 // Added in version 13
5531 // Added in version 14
5532 &task_dyld_process_info_notify_get
5535 __attribute__((noinline
))
5536 static const char* useSimulatorDyld(int fd
, const macho_header
* mainExecutableMH
, const char* dyldPath
,
5537 int argc
, const char* argv
[], const char* envp
[], const char* apple
[],
5538 uintptr_t* startGlue
, uintptr_t* mainAddr
)
5543 // <rdar://problem/25311921> simulator does not support restricted processes
5545 if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) == -1 )
5546 return "csops() failed";
5547 if ( (flags
& CS_RESTRICT
) == CS_RESTRICT
)
5548 return "dyld_sim cannot be loaded in a restricted process";
5550 return "dyld_sim cannot be loaded in a setuid process";
5551 if ( hasRestrictedSegment(mainExecutableMH
) )
5552 return "dyld_sim cannot be loaded in a restricted process";
5554 // get file size of dyld_sim
5556 if ( fstat(fd
, &sb
) == -1 )
5557 return "stat(dyld_sim) failed";
5559 // read first page of dyld_sim file
5560 uint8_t firstPage
[4096];
5561 if ( pread(fd
, firstPage
, 4096, 0) != 4096 )
5562 return "pread(dyld_sim) failed";
5564 // if fat file, pick matching slice
5565 uint64_t fileOffset
= 0;
5566 uint64_t fileLength
= sb
.st_size
;
5567 const fat_header
* fileStartAsFat
= (fat_header
*)firstPage
;
5568 if ( fileStartAsFat
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
5569 if ( !fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) )
5570 return "no matching arch in dyld_sim";
5571 // re-read buffer from start of mach-o slice in fat file
5572 if ( pread(fd
, firstPage
, 4096, fileOffset
) != 4096 )
5573 return "pread(dyld_sim) failed";
5575 else if ( !isCompatibleMachO(firstPage
, dyldPath
, fd
, fileOffset
, fileLength
) ) {
5576 return "dyld_sim is not compatible with the loaded process, likely due to architecture mismatch";
5579 // calculate total size of dyld segments
5580 const macho_header
* mh
= (const macho_header
*)firstPage
;
5581 struct macho_segment_command
* lastSeg
= NULL
;
5582 struct macho_segment_command
* firstSeg
= NULL
;
5583 uintptr_t mappingSize
= 0;
5584 uintptr_t preferredLoadAddress
= 0;
5585 const uint32_t cmd_count
= mh
->ncmds
;
5586 if ( mh
->sizeofcmds
> 4096 )
5587 return "dyld_sim load commands to large";
5588 if ( (sizeof(macho_header
) + mh
->sizeofcmds
) > 4096 )
5589 return "dyld_sim load commands to large";
5590 struct linkedit_data_command
* codeSigCmd
= NULL
;
5591 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
5592 const struct load_command
* const endCmds
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
) + mh
->sizeofcmds
);
5593 const struct load_command
* cmd
= cmds
;
5594 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
5595 uint32_t cmdLength
= cmd
->cmdsize
;
5596 if ( cmdLength
< 8 )
5597 return "dyld_sim load command too small";
5598 const struct load_command
* const nextCmd
= (const struct load_command
*)(((char*)cmd
)+cmdLength
);
5599 if ( (nextCmd
> endCmds
) || (nextCmd
< cmd
) )
5600 return "dyld_sim load command too large";
5602 case LC_SEGMENT_COMMAND
:
5604 struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
5605 if ( seg
->vmaddr
+ seg
->vmsize
< seg
->vmaddr
)
5606 return "dyld_sim seg wraps address space";
5607 if ( seg
->vmsize
< seg
->filesize
)
5608 return "dyld_sim seg vmsize too small";
5609 if ( (seg
->fileoff
+ seg
->filesize
) < seg
->fileoff
)
5610 return "dyld_sim seg size wraps address space";
5611 if ( lastSeg
== NULL
) {
5612 // first segment must be __TEXT and start at beginning of file/slice
5614 if ( strcmp(seg
->segname
, "__TEXT") != 0 )
5615 return "dyld_sim first segment not __TEXT";
5616 if ( seg
->fileoff
!= 0 )
5617 return "dyld_sim first segment not at file offset zero";
5618 if ( seg
->filesize
< (sizeof(macho_header
) + mh
->sizeofcmds
) )
5619 return "dyld_sim first segment smaller than load commands";
5620 preferredLoadAddress
= seg
->vmaddr
;
5623 // other sements must be continguous with previous segment and not executable
5624 if ( lastSeg
->fileoff
+ lastSeg
->filesize
!= seg
->fileoff
)
5625 return "dyld_sim segments not contiguous";
5626 if ( lastSeg
->vmaddr
+ lastSeg
->vmsize
!= seg
->vmaddr
)
5627 return "dyld_sim segments not address contiguous";
5628 if ( (seg
->initprot
& VM_PROT_EXECUTE
) != 0 )
5629 return "dyld_sim non-first segment is executable";
5631 mappingSize
+= seg
->vmsize
;
5635 case LC_SEGMENT_COMMAND_WRONG
:
5636 return "dyld_sim wrong load segment load command";
5637 case LC_CODE_SIGNATURE
:
5638 codeSigCmd
= (struct linkedit_data_command
*)cmd
;
5643 // last segment must be named __LINKEDIT and not writable
5644 if ( lastSeg
== NULL
)
5645 return "dyld_sim has no segments";
5646 if ( strcmp(lastSeg
->segname
, "__LINKEDIT") != 0 )
5647 return "dyld_sim last segment not __LINKEDIT";
5648 if ( lastSeg
->initprot
& VM_PROT_WRITE
)
5649 return "dyld_sim __LINKEDIT segment writable";
5651 // must have code signature which is contained within LINKEDIT segment
5652 if ( codeSigCmd
== NULL
)
5653 return "dyld_sim not code signed";
5654 if ( codeSigCmd
->dataoff
< lastSeg
->fileoff
)
5655 return "dyld_sim code signature not in __LINKEDIT";
5656 if ( (codeSigCmd
->dataoff
+ codeSigCmd
->datasize
) < codeSigCmd
->dataoff
)
5657 return "dyld_sim code signature size wraps";
5658 if ( (codeSigCmd
->dataoff
+ codeSigCmd
->datasize
) > (lastSeg
->fileoff
+ lastSeg
->filesize
) )
5659 return "dyld_sim code signature extends beyond __LINKEDIT";
5661 // register code signature with kernel before mmap()ing segments
5662 fsignatures_t siginfo
;
5663 siginfo
.fs_file_start
=fileOffset
; // start of mach-o slice in fat file
5664 siginfo
.fs_blob_start
=(void*)(long)(codeSigCmd
->dataoff
); // start of code-signature in mach-o file
5665 siginfo
.fs_blob_size
=codeSigCmd
->datasize
; // size of code-signature
5666 int result
= fcntl(fd
, F_ADDFILESIGS_FOR_DYLD_SIM
, &siginfo
);
5667 if ( result
== -1 ) {
5668 return mkstringf("dyld_sim fcntl(F_ADDFILESIGS_FOR_DYLD_SIM) failed with errno=%d", errno
);
5670 // file range covered by code signature must extend up to code signature itself
5671 if ( siginfo
.fs_file_start
< codeSigCmd
->dataoff
)
5672 return mkstringf("dyld_sim code signature does not cover all of dyld_sim. Signature covers up to 0x%08lX. Signature starts at 0x%08X", (unsigned long)siginfo
.fs_file_start
, codeSigCmd
->dataoff
);
5674 // reserve space, then mmap each segment
5675 vm_address_t loadAddress
= 0;
5676 if ( ::vm_allocate(mach_task_self(), &loadAddress
, mappingSize
, VM_FLAGS_ANYWHERE
) != 0 )
5677 return "dyld_sim cannot allocate space";
5679 struct source_version_command
* dyldVersionCmd
= NULL
;
5680 struct uuid_command
* uuidCmd
= NULL
;
5681 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
5683 case LC_SEGMENT_COMMAND
:
5685 struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
5686 uintptr_t requestedLoadAddress
= seg
->vmaddr
- preferredLoadAddress
+ loadAddress
;
5687 void* segAddress
= ::mmap((void*)requestedLoadAddress
, seg
->filesize
, seg
->initprot
, MAP_FIXED
| MAP_PRIVATE
, fd
, fileOffset
+ seg
->fileoff
);
5688 //dyld::log("dyld_sim %s mapped at %p\n", seg->segname, segAddress);
5689 if ( segAddress
== (void*)(-1) )
5690 return "dyld_sim mmap() of segment failed";
5691 if ( ((uintptr_t)segAddress
< loadAddress
) || ((uintptr_t)segAddress
+seg
->filesize
> loadAddress
+mappingSize
) )
5692 return "dyld_sim mmap() to wrong location";
5695 case LC_SOURCE_VERSION
:
5696 dyldVersionCmd
= (struct source_version_command
*)cmd
;
5699 uuidCmd
= (uuid_command
*)cmd
;
5703 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
5707 // Walk newly mapped dyld_sim load commands to find entry point
5708 uintptr_t entry
= 0;
5709 bool unusedUsesCRT
= false;
5710 uint64_t entryOffset
= 0;
5711 if ( !((dyld3::MachOAnalyzer
*)loadAddress
)->getEntry(entryOffset
, unusedUsesCRT
) ) {
5712 return "dyld_sim entry not found";
5715 // Translate the load address by the entry offset in order to get the runtime address.
5716 entry
= (uintptr_t)loadAddress
;
5717 entry
+= entryOffset
;
5720 // It's necessary to sign the entry pointer.
5721 entry
= (uint64_t)__builtin_ptrauth_sign_unauthenticated((void*)entry
, ptrauth_key_asia
, 0);
5724 // notify debugger that dyld_sim is loaded
5725 dyld_image_info info
;
5726 info
.imageLoadAddress
= (mach_header
*)loadAddress
;
5727 info
.imageFilePath
= strdup(dyldPath
);
5728 info
.imageFileModDate
= sb
.st_mtime
;
5729 addImagesToAllImages(1, &info
);
5730 dyld::gProcessInfo
->notification(dyld_image_adding
, 1, &info
);
5732 fsid_t fsid
= {{0, 0}};
5733 fsobj_id_t fsobj
= {0};
5734 ino_t inode
= sb
.st_ino
;
5735 fsobj
.fid_objno
= (uint32_t)inode
;
5736 fsobj
.fid_generation
= (uint32_t)(inode
>>32);
5737 fsid
.val
[0] = sb
.st_dev
;
5738 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A
, dyldPath
, (const uuid_t
*)&uuidCmd
->uuid
[0], fsobj
, fsid
, (const mach_header
*)loadAddress
);
5740 const char** appleParams
= apple
;
5742 // <rdar://problem/5077374> have host dyld detach macOS shared cache from process before jumping into dyld_sim
5743 dyld3::deallocateExistingSharedCache();
5745 // jump into new simulator dyld
5746 typedef uintptr_t (*sim_entry_proc_t
)(int argc
, const char* argv
[], const char* envp
[], const char* apple
[],
5747 const macho_header
* mainExecutableMH
, const macho_header
* dyldMH
, uintptr_t dyldSlide
,
5748 const dyld::SyscallHelpers
* vtable
, uintptr_t* startGlue
);
5749 sim_entry_proc_t newDyld
= (sim_entry_proc_t
)entry
;
5750 *mainAddr
= (*newDyld
)(argc
, argv
, envp
, appleParams
, mainExecutableMH
, (macho_header
*)loadAddress
,
5751 loadAddress
- preferredLoadAddress
,
5752 &sSysCalls
, startGlue
);
5758 // If the DYLD_SKIP_MAIN environment is set to 1, dyld will return the
5759 // address of this function instead of main() in the target program which
5760 // __dyld_start jumps to. Useful for qualifying dyld itself.
5770 #if !TARGET_OS_SIMULATOR
5772 static bool envVarMatches(const dyld3::closure::LaunchClosure
* mainClosure
, const char* envp
[], const char* varName
)
5774 __block
const char* valueFromClosure
= nullptr;
5775 mainClosure
->forEachEnvVar(^(const char* keyEqualValue
, bool& stop
) {
5776 size_t keyLen
= strlen(varName
);
5777 if ( (strncmp(varName
, keyEqualValue
, keyLen
) == 0) && (keyEqualValue
[keyLen
] == '=') ) {
5778 valueFromClosure
= &keyEqualValue
[keyLen
+1];
5783 const char* valueFromEnv
= _simple_getenv(envp
, varName
);
5785 bool inClosure
= (valueFromClosure
!= nullptr);
5786 bool inEnv
= (valueFromEnv
!= nullptr);
5787 if ( inClosure
!= inEnv
)
5789 if ( !inClosure
&& !inEnv
)
5791 return ( strcmp(valueFromClosure
, valueFromEnv
) == 0 );
5794 static const char* const sEnvVarsToCheck
[] = {
5795 "DYLD_LIBRARY_PATH",
5796 "DYLD_FRAMEWORK_PATH",
5797 "DYLD_FALLBACK_LIBRARY_PATH",
5798 "DYLD_FALLBACK_FRAMEWORK_PATH",
5799 "DYLD_INSERT_LIBRARIES",
5800 "DYLD_IMAGE_SUFFIX",
5801 "DYLD_VERSIONED_FRAMEWORK_PATH",
5802 "DYLD_VERSIONED_LIBRARY_PATH",
5806 static bool envVarsMatch(const dyld3::closure::LaunchClosure
* mainClosure
, const char* envp
[])
5808 for (const char* envVar
: sEnvVarsToCheck
) {
5809 if ( !envVarMatches(mainClosure
, envp
, envVar
) ) {
5810 if ( gLinkContext
.verboseWarnings
)
5811 dyld::log("dyld: closure %p not used because %s changed\n", mainClosure
, envVar
);
5816 // FIXME: dyld3 doesn't support versioned paths so we need to fall back to dyld2 if we have them.
5817 // <rdar://problem/37004660> dyld3: support DYLD_VERSIONED_*_PATHs ?
5818 if ( sEnv
.DYLD_VERSIONED_LIBRARY_PATH
!= nullptr ) {
5819 if ( gLinkContext
.verboseWarnings
)
5820 dyld::log("dyld: closure %p not used because DYLD_VERSIONED_LIBRARY_PATH used\n", mainClosure
);
5823 if ( sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
!= nullptr ) {
5824 if ( gLinkContext
.verboseWarnings
)
5825 dyld::log("dyld: closure %p not used because DYLD_VERSIONED_FRAMEWORK_PATH used\n", mainClosure
);
5832 static bool closureValid(const dyld3::closure::LaunchClosure
* mainClosure
, const dyld3::closure::LoadedFileInfo
& mainFileInfo
,
5833 const uint8_t* mainExecutableCDHash
, bool closureInCache
, const char* envp
[])
5835 if ( closureInCache
) {
5836 // We can only use the cache closure if the cache version is the same as dyld
5837 if (sSharedCacheLoadInfo
.loadAddress
->header
.formatVersion
!= dyld3::closure::kFormatVersion
) {
5838 if ( gLinkContext
.verboseWarnings
)
5839 dyld::log("dyld: dyld closure version 0x%08X does not match dyld cache version 0x%08X\n",
5840 dyld3::closure::kFormatVersion
, sSharedCacheLoadInfo
.loadAddress
->header
.formatVersion
);
5843 if (sForceInvalidSharedCacheClosureFormat
) {
5844 if ( gLinkContext
.verboseWarnings
)
5845 dyld::log("dyld: closure %p dyld cache version forced invalid\n", mainClosure
);
5849 // verify current dyld cache is same as expected
5850 uuid_t expectedCacheUUID
;
5851 if ( mainClosure
->builtAgainstDyldCache(expectedCacheUUID
) ) {
5852 if ( sSharedCacheLoadInfo
.loadAddress
== nullptr ) {
5853 if ( gLinkContext
.verboseWarnings
)
5854 dyld::log("dyld: closure %p dyld cache not loaded\n", mainClosure
);
5858 uuid_t actualCacheUUID
;
5859 sSharedCacheLoadInfo
.loadAddress
->getUUID(actualCacheUUID
);
5860 if ( memcmp(expectedCacheUUID
, actualCacheUUID
, sizeof(uuid_t
)) != 0 ) {
5861 if ( gLinkContext
.verboseWarnings
)
5862 dyld::log("dyld: closure %p not used because built against different dyld cache\n", mainClosure
);
5868 // closure built assume there is no dyld cache
5869 if ( sSharedCacheLoadInfo
.loadAddress
!= nullptr ) {
5870 if ( gLinkContext
.verboseWarnings
)
5871 dyld::log("dyld: closure %p built expecting no dyld cache\n", mainClosure
);
5877 // verify all mach-o files have not changed since closure was built
5878 __block
bool foundFileThatInvalidatesClosure
= false;
5879 mainClosure
->images()->forEachImage(^(const dyld3::closure::Image
* image
, bool& stop
) {
5880 __block
uint64_t expectedInode
;
5881 __block
uint64_t expectedMtime
;
5882 if ( image
->hasFileModTimeAndInode(expectedInode
, expectedMtime
) ) {
5883 struct stat statBuf
;
5884 if ( dyld3::stat(image
->path(), &statBuf
) == 0 ) {
5885 if ( (statBuf
.st_mtime
!= expectedMtime
) || (statBuf
.st_ino
!= expectedInode
) ) {
5886 if ( gLinkContext
.verboseWarnings
)
5887 dyld::log("dyld: closure %p not used because mtime/inode for '%s' has changed since closure was built\n", mainClosure
, image
->path());
5888 foundFileThatInvalidatesClosure
= true;
5893 if ( gLinkContext
.verboseWarnings
)
5894 dyld::log("dyld: closure %p not used because '%s' is needed by closure but is missing\n", mainClosure
, image
->path());
5895 foundFileThatInvalidatesClosure
= true;
5900 if ( foundFileThatInvalidatesClosure
)
5903 // verify cdHash of main executable is same as recorded in closure
5904 const dyld3::closure::Image
* mainImage
= mainClosure
->topImage();
5906 __block
bool foundCDHash
= false;
5907 __block
bool foundValidCDHash
= false;
5908 mainImage
->forEachCDHash(^(const uint8_t *expectedHash
, bool& stop
) {
5909 if ( mainExecutableCDHash
== nullptr ) {
5910 if ( gLinkContext
.verboseWarnings
)
5911 dyld::log("dyld: closure %p not used because main executable is not code signed but was expected to be\n", mainClosure
);
5916 if ( memcmp(mainExecutableCDHash
, expectedHash
, 20) == 0 ) {
5917 // found a match, so lets use this one.
5918 foundValidCDHash
= true;
5924 // If we found cd hashes, but they were all invalid, then print them out
5925 if ( foundCDHash
&& !foundValidCDHash
) {
5926 auto getCDHashString
= [](const uint8_t cdHash
[20], char* cdHashBuffer
) {
5927 for (int i
=0; i
< 20; ++i
) {
5928 uint8_t byte
= cdHash
[i
];
5929 uint8_t nibbleL
= byte
& 0x0F;
5930 uint8_t nibbleH
= byte
>> 4;
5931 if ( nibbleH
< 10 ) {
5932 *cdHashBuffer
= '0' + nibbleH
;
5935 *cdHashBuffer
= 'a' + (nibbleH
-10);
5938 if ( nibbleL
< 10 ) {
5939 *cdHashBuffer
= '0' + nibbleL
;
5942 *cdHashBuffer
= 'a' + (nibbleL
-10);
5947 if ( gLinkContext
.verboseWarnings
) {
5948 mainImage
->forEachCDHash(^(const uint8_t *expectedHash
, bool &stop
) {
5949 char mainExecutableCDHashBuffer
[128] = { '\0' };
5950 char expectedCDHashBuffer
[128] = { '\0' };
5952 getCDHashString(mainExecutableCDHash
, mainExecutableCDHashBuffer
);
5953 getCDHashString(expectedHash
, expectedCDHashBuffer
);
5955 dyld::log("dyld: closure %p not used because main executable cd-hash (%s) changed since closure was built with (%s)\n",
5956 mainClosure
, mainExecutableCDHashBuffer
, expectedCDHashBuffer
);
5963 // verify UUID of main executable is same as recorded in closure
5964 uuid_t expectedUUID
;
5965 bool hasExpect
= mainImage
->getUuid(expectedUUID
);
5967 const dyld3::MachOLoaded
* mainExecutableMH
= (const dyld3::MachOLoaded
*)mainFileInfo
.fileContent
;
5968 bool hasActual
= mainExecutableMH
->getUuid(actualUUID
);
5969 if ( hasExpect
!= hasActual
) {
5970 if ( gLinkContext
.verboseWarnings
)
5971 dyld::log("dyld: closure %p not used because UUID of executable changed since closure was built\n", mainClosure
);
5974 if ( hasExpect
&& hasActual
&& memcmp(actualUUID
, expectedUUID
, sizeof(uuid_t
)) != 0 ) {
5975 if ( gLinkContext
.verboseWarnings
)
5976 dyld::log("dyld: closure %p not used because UUID of executable changed since closure was built\n", mainClosure
);
5980 // verify DYLD_* env vars are same as when closure was built
5981 if ( !envVarsMatch(mainClosure
, envp
) ) {
5985 // verify files that are supposed to be missing actually are missing
5986 mainClosure
->forEachMustBeMissingFile(^(const char* path
, bool& stop
) {
5987 struct stat statBuf
;
5988 if ( dyld3::stat(path
, &statBuf
) == 0 ) {
5990 foundFileThatInvalidatesClosure
= true;
5991 if ( gLinkContext
.verboseWarnings
)
5992 dyld::log("dyld: closure %p not used because found unexpected file '%s'\n", mainClosure
, path
);
5996 // verify files that are supposed to exist are there with the
5997 mainClosure
->forEachSkipIfExistsFile(^(const dyld3::closure::LaunchClosure::SkippedFile
&file
, bool &stop
) {
5998 struct stat statBuf
;
5999 if ( dyld3::stat(file
.path
, &statBuf
) == 0 ) {
6000 if ( (statBuf
.st_mtime
!= file
.mtime
) || (statBuf
.st_ino
!= file
.inode
) ) {
6001 if ( gLinkContext
.verboseWarnings
)
6002 dyld::log("dyld: closure %p not used because mtime/inode for '%s' has changed since closure was built\n", mainClosure
, file
.path
);
6003 foundFileThatInvalidatesClosure
= true;
6009 // verify closure did not require anything unavailable
6010 if ( mainClosure
->usedAtPaths() && !gLinkContext
.allowAtPaths
) {
6011 if ( gLinkContext
.verboseWarnings
)
6012 dyld::log("dyld: closure %p not used because is used @paths, but process does not allow that\n", mainClosure
);
6015 if ( mainClosure
->usedFallbackPaths() && !gLinkContext
.allowClassicFallbackPaths
) {
6016 if ( gLinkContext
.verboseWarnings
)
6017 dyld::log("dyld: closure %p not used because is used default fallback paths, but process does not allow that\n", mainClosure
);
6020 if ( mainClosure
->usedInterposing() && !gLinkContext
.allowInterposing
) {
6021 if ( gLinkContext
.verboseWarnings
)
6022 dyld::log("dyld: closure %p not used because is uses interposing, but process does not allow that\n", mainClosure
);
6025 return !foundFileThatInvalidatesClosure
;
6028 static bool nolog(const char* format
, ...)
6033 static bool dolog(const char* format
, ...)
6036 va_start(list
, format
);
6042 static bool launchWithClosure(const dyld3::closure::LaunchClosure
* mainClosure
,
6043 const DyldSharedCache
* dyldCache
,
6044 const dyld3::MachOLoaded
* mainExecutableMH
, uintptr_t mainExecutableSlide
,
6045 int argc
, const char* argv
[], const char* envp
[], const char* apple
[], Diagnostics
& diag
,
6046 uintptr_t* entry
, uintptr_t* startGlue
, bool* closureOutOfDate
, bool* recoverable
)
6048 *closureOutOfDate
= false;
6049 *recoverable
= true;
6051 // build list of all known ImageArrays (at most three: cached dylibs, other OS dylibs, and main prog)
6052 STACK_ALLOC_ARRAY(const dyld3::closure::ImageArray
*, imagesArrays
, 3);
6053 const dyld3::closure::ImageArray
* mainClosureImages
= mainClosure
->images();
6054 if ( dyldCache
!= nullptr ) {
6055 imagesArrays
.push_back(dyldCache
->cachedDylibsImageArray());
6056 if ( auto others
= dyldCache
->otherOSImageArray() )
6057 imagesArrays
.push_back(others
);
6059 imagesArrays
.push_back(mainClosureImages
);
6061 // allocate space for Array<LoadedImage>
6062 STACK_ALLOC_ARRAY(dyld3::LoadedImage
, allImages
, mainClosure
->initialLoadCount());
6063 STACK_ALLOC_ARRAY(dyld3::LoadedImage
, noImages
, 1);
6065 // Get the pre-optimized Objective-C so that we can bind the selectors
6066 const dyld3::closure::ObjCSelectorOpt
* selectorOpt
= nullptr;
6067 dyld3::Array
<dyld3::closure::Image::ObjCSelectorImage
> selectorImages
;
6068 mainClosure
->selectorHashTable(selectorImages
, selectorOpt
);
6070 __block
dyld3::Loader
loader(noImages
, allImages
, dyldCache
, imagesArrays
,
6071 selectorOpt
, selectorImages
, sRootsChecker
,
6072 (dyld3::Platform
)gProcessInfo
->platform
,
6073 (gLinkContext
.verboseLoading
? &dolog
: &nolog
),
6074 (gLinkContext
.verboseMapping
? &dolog
: &nolog
),
6075 (gLinkContext
.verboseBind
? &dolog
: &nolog
),
6076 (gLinkContext
.verboseDOF
? &dolog
: &nolog
),
6077 (sClosureKind
== ClosureKind::minimal
),
6078 (dyld3::LaunchErrorInfo
*)&gProcessInfo
->errorKind
);
6079 dyld3::closure::ImageNum mainImageNum
= mainClosure
->topImageNum();
6080 mainClosureImages
->forEachImage(^(const dyld3::closure::Image
* image
, bool& stop
) {
6081 if ( image
->imageNum() == mainImageNum
) {
6082 // add main executable (which is already mapped by kernel) to list
6083 dyld3::LoadedImage mainLoadedImage
= dyld3::LoadedImage::make(image
, mainExecutableMH
);
6084 mainLoadedImage
.setState(dyld3::LoadedImage::State::mapped
);
6085 mainLoadedImage
.markLeaveMapped();
6086 loader
.addImage(mainLoadedImage
);
6090 // add inserted library to initial list
6091 loader
.addImage(dyld3::LoadedImage::make(image
));
6095 // recursively load all dependents and fill in allImages array
6096 bool someCacheImageOverridden
= false;
6097 loader
.completeAllDependents(diag
, someCacheImageOverridden
);
6098 if ( diag
.noError() )
6099 loader
.mapAndFixupAllImages(diag
, dyld3::Loader::dtraceUserProbesEnabled(), false, closureOutOfDate
, recoverable
);
6100 if ( diag
.hasError() ) {
6101 if ( gLinkContext
.verboseWarnings
)
6102 dyld::log("dyld: %s\n", diag
.errorMessage());
6103 if ( !*recoverable
) {
6104 // we won't make it to libDyldEntry, so the image list will never be set up
6105 // hack together an image list here so crash reports show the binaries involved
6106 __block
unsigned loadImageCount
= 0;
6107 loader
.forEachImage(^(const dyld3::LoadedImage
& li
, bool& stop
) {
6110 dyld_image_info
* tempArray
= new dyld_image_info
[loadImageCount
];
6111 __block
unsigned i
= 0;
6112 loader
.forEachImage(^(const dyld3::LoadedImage
& li
, bool& stop
) {
6113 tempArray
[i
].imageFilePath
= li
.image()->path();
6114 tempArray
[i
].imageLoadAddress
= li
.loadedAddress();
6115 tempArray
[i
].imageFileModDate
= 0;
6118 dyld::gProcessInfo
->infoArray
= tempArray
;
6119 dyld::gProcessInfo
->infoArrayCount
= loadImageCount
;
6120 dyld::gProcessInfo
->initialImageCount
= loadImageCount
;
6121 dyld::gProcessInfo
->infoArrayChangeTimestamp
= mach_absolute_time();
6126 //dyld::log("loaded image list:\n");
6127 //for (const dyld3::LoadedImage& info : allImages) {
6128 // dyld::log("mh=%p, path=%s\n", info.loadedAddress(), info.image()->path());
6131 // find libdyld entry
6132 dyld3::closure::Image::ResolvedSymbolTarget dyldEntry
;
6133 mainClosure
->libDyldEntry(dyldEntry
);
6134 const dyld3::LibDyldEntryVector
* libDyldEntry
= (dyld3::LibDyldEntryVector
*)loader
.resolveTarget(dyldEntry
);
6136 // Set the logging function first so that libdyld can log from inside all other entry vector functions
6137 #if !TARGET_OS_SIMULATOR
6138 if ( libDyldEntry
->vectorVersion
> 3 )
6139 libDyldEntry
->setLogFunction(&dyld::vlog
);
6142 // send info on all images to libdyld.dylb
6143 libDyldEntry
->setVars(mainExecutableMH
, argc
, argv
, envp
, apple
, sKeysDisabled
, sOnlyPlatformArm64e
, gEnableSharedCacheDataConst
);
6145 uint32_t progVarsOffset
;
6146 if ( mainClosure
->hasProgramVars(progVarsOffset
) ) {
6147 if ( libDyldEntry
->vectorVersion
>= 8 ) {
6148 // main executable contains globals to hold argc, argv, envp, and progname, but they need to be filled in
6149 ProgramVars
* vars
= (ProgramVars
*)((uint8_t*)mainExecutableMH
+ progVarsOffset
);
6150 *vars
->NXArgcPtr
= argc
;
6151 *vars
->NXArgvPtr
= argv
;
6152 *vars
->environPtr
= envp
;
6153 *vars
->__prognamePtr
= (argv
[0] != NULL
) ? basename(argv
[0]) : "";
6154 // set up so libSystem gets ProgramVars struct embedded in main executable
6155 libDyldEntry
->setProgramVars(vars
);
6159 if ( libDyldEntry
->vectorVersion
> 4 )
6160 libDyldEntry
->setRestrictions(gLinkContext
.allowAtPaths
, gLinkContext
.allowEnvVarsPath
, gLinkContext
.allowClassicFallbackPaths
);
6161 libDyldEntry
->setHaltFunction(&halt
);
6162 if ( libDyldEntry
->vectorVersion
> 5 ) {
6163 libDyldEntry
->setNotifyMonitoringDyldMain(¬ifyMonitoringDyldMain
);
6164 libDyldEntry
->setNotifyMonitoringDyld(¬ifyMonitoringDyld
);
6167 if ( libDyldEntry
->vectorVersion
> 6 )
6168 libDyldEntry
->setHasCacheOverrides(someCacheImageOverridden
);
6170 if ( libDyldEntry
->vectorVersion
> 2 )
6171 libDyldEntry
->setChildForkFunction(&_dyld_fork_child
);
6172 if ( libDyldEntry
->vectorVersion
>= 9 )
6173 libDyldEntry
->setLaunchMode(sLaunchModeUsed
);
6176 libDyldEntry
->setOldAllImageInfo(gProcessInfo
);
6177 dyld3::LoadedImage
* libSys
= loader
.findImage(mainClosure
->libSystemImageNum());
6178 libDyldEntry
->setInitialImageList(mainClosure
, dyldCache
, sSharedCacheLoadInfo
.path
, allImages
, *libSys
,
6181 CRSetCrashLogMessage("dyld3: launch, running initializers");
6182 libDyldEntry
->runInitialzersBottomUp((mach_header
*)mainExecutableMH
);
6183 //dyld::log("returned from runInitialzersBottomUp()\n");
6185 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
)) {
6186 dyld3::kdebug_trace_dyld_duration_end(launchTraceID
, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
, 0, 0, 3);
6189 if ( gLinkContext
.driverKit
) {
6190 if (libDyldEntry
->vectorVersion
>= 10)
6191 *entry
= (uintptr_t)libDyldEntry
->getDriverkitMain();
6193 halt("no entry point registered");
6194 if ( sClosureKind
!= ClosureKind::minimal
)
6195 halt("driverkit process should run with minimal closures");
6196 *startGlue
= (uintptr_t)(libDyldEntry
->startFunc
);
6201 dyld3::closure::Image::ResolvedSymbolTarget progEntry
;
6202 if ( mainClosure
->mainEntry(progEntry
) ) {
6203 // modern app with LC_MAIN
6204 // set startGlue to "start" function in libdyld.dylib
6205 // set entry to "main" function in program
6206 *startGlue
= (uintptr_t)(libDyldEntry
->startFunc
);
6207 *entry
= loader
.resolveTarget(progEntry
);
6208 #if __has_feature(ptrauth_calls)
6209 // start() calls the result pointer as a function pointer so we need to sign it.
6210 *entry
= (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)*entry
, 0, 0);
6213 else if ( mainClosure
->startEntry(progEntry
) ) {
6214 // old style app linked with crt1.o
6215 // entry is "start" function in program
6217 *entry
= loader
.resolveTarget(progEntry
);
6223 CRSetCrashLogMessage("dyld3 mode");
6228 static const dyld3::closure::LaunchClosure
* mapClosureFile(const char* closurePath
)
6230 struct stat statbuf
;
6231 if ( dyld3::stat(closurePath
, &statbuf
) == -1 )
6234 // check for tombstone file
6235 if ( statbuf
.st_size
== 0 )
6238 int fd
= dyld3::open(closurePath
, O_RDONLY
, 0);
6242 const dyld3::closure::LaunchClosure
* closure
= (dyld3::closure::LaunchClosure
*)::mmap(NULL
, (size_t)statbuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
6245 if ( closure
== MAP_FAILED
)
6251 static bool needsDyld2ErrorMessage(const char* msg
)
6253 if ( strcmp(msg
, "lazy bind opcodes missing binds") == 0 )
6258 // Note: buildLaunchClosure calls halt() if there is an error building the closure
6259 static const dyld3::closure::LaunchClosure
* buildLaunchClosure(const uint8_t* mainExecutableCDHash
,
6260 const dyld3::closure::LoadedFileInfo
& mainFileInfo
,
6262 const dyld3::Array
<uint8_t>& bootToken
)
6264 const dyld3::MachOLoaded
* mainExecutableMH
= (const dyld3::MachOLoaded
*)mainFileInfo
.fileContent
;
6265 dyld3::closure::PathOverrides pathOverrides
;
6266 pathOverrides
.setFallbackPathHandling(gLinkContext
.allowClassicFallbackPaths
? dyld3::closure::PathOverrides::FallbackPathMode::classic
: dyld3::closure::PathOverrides::FallbackPathMode::restricted
);
6267 pathOverrides
.setEnvVars(envp
, mainExecutableMH
, mainFileInfo
.path
);
6268 STACK_ALLOC_ARRAY(const dyld3::closure::ImageArray
*, imagesArrays
, 3);
6269 if ( sSharedCacheLoadInfo
.loadAddress
!= nullptr ) {
6270 imagesArrays
.push_back(sSharedCacheLoadInfo
.loadAddress
->cachedDylibsImageArray());
6271 if ( auto others
= sSharedCacheLoadInfo
.loadAddress
->otherOSImageArray() )
6272 imagesArrays
.push_back(others
);
6275 char closurePath
[PATH_MAX
];
6276 bool canSaveClosureToDisk
= !bootToken
.empty() && dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo
.path
, envp
, true, closurePath
);
6277 dyld3::LaunchErrorInfo
* errorInfo
= (dyld3::LaunchErrorInfo
*)&gProcessInfo
->errorKind
;
6278 const dyld3::GradedArchs
& archs
= dyld3::GradedArchs::forCurrentOS(sKeysDisabled
, sOnlyPlatformArm64e
);
6279 dyld3::closure::FileSystemPhysical fileSystem
;
6280 dyld3::closure::ClosureBuilder::AtPath atPathHanding
= (gLinkContext
.allowAtPaths
? dyld3::closure::ClosureBuilder::AtPath::all
: dyld3::closure::ClosureBuilder::AtPath::none
);
6281 dyld3::closure::ClosureBuilder
builder(dyld3::closure::kFirstLaunchClosureImageNum
, fileSystem
, sRootsChecker
, sSharedCacheLoadInfo
.loadAddress
, true,
6282 archs
, pathOverrides
, atPathHanding
, gLinkContext
.allowEnvVarsPath
, errorInfo
, (dyld3::Platform
)gProcessInfo
->platform
);
6283 if (sForceInvalidSharedCacheClosureFormat
)
6284 builder
.setDyldCacheInvalidFormatVersion();
6285 if (sClosureKind
== ClosureKind::minimal
)
6286 builder
.makeMinimalClosures();
6287 else if ( canSaveClosureToDisk
)
6288 builder
.setCanSkipEncodingRebases(); // <rdar://problem/56172089> large iOS apps with massive number of rebases can overflow 16MB closure file limit
6289 if ( !gLinkContext
.allowInterposing
)
6290 builder
.disableInterposing();
6292 const dyld3::closure::LaunchClosure
* result
= builder
.makeLaunchClosure(mainFileInfo
, gLinkContext
.allowInsertFailures
);
6293 if ( builder
.diagnostics().hasError() ) {
6294 const char* errMsg
= builder
.diagnostics().errorMessage();
6295 // let apps with this error fallback to dyld2 mode
6296 if ( needsDyld2ErrorMessage(errMsg
) ) {
6297 if ( canSaveClosureToDisk
) {
6298 // create empty file as a tombstone to not keep trying
6299 int fd
= dyld3::open(closurePath
, O_WRONLY
|O_CREAT
, S_IRUSR
|S_IWUSR
);
6301 ::fchmod(fd
, S_IRUSR
);
6303 if ( gLinkContext
.verboseWarnings
)
6304 dyld::log("dyld: just built tombstone closure for %s\n", sExecPath
);
6305 // We only care about closure failures that do not also cause dyld2 to fail, so defer logging
6306 // until after dyld2 has tried to launch the binary
6307 sLogClosureFailure
= true;
6312 // terminate process
6316 if ( result
== nullptr )
6319 if ( !closureValid(result
, mainFileInfo
, mainExecutableCDHash
, false, envp
) ) {
6320 // some how the freshly generated closure is invalid...
6321 result
->deallocate();
6322 if ( gLinkContext
.verboseWarnings
)
6323 dyld::log("dyld: somehow just built closure is invalid\n");
6327 // write closure file but only if we have boot-token
6328 if ( canSaveClosureToDisk
) {
6329 if ( const dyld3::closure::LaunchClosure
* existingClosure
= mapClosureFile(closurePath
) ) {
6330 if ( (existingClosure
->size() == result
->size()) && (memcmp(existingClosure
, result
, result
->size()) == 0) ) {
6331 // closure file already exists and has same content, so re-use file by altering boot-token
6332 ::chmod(closurePath
, S_IRUSR
|S_IWUSR
); // file has to be writable to alter attributes
6333 // handle both attribute size change and missing attribute
6334 if ( ::setxattr(closurePath
, DYLD_CLOSURE_XATTR_NAME
, bootToken
.begin(), bootToken
.count(), 0, XATTR_REPLACE
) != 0 )
6335 ::setxattr(closurePath
, DYLD_CLOSURE_XATTR_NAME
, bootToken
.begin(), bootToken
.count(), 0, 0);
6336 ::chmod(closurePath
, S_IRUSR
);
6337 result
->deallocate();
6338 if ( gLinkContext
.verboseWarnings
)
6339 dyld::log("dyld: reusing previous boot %s closure %p (size=%lu) for %s\n", existingClosure
->topImage()->variantString(), existingClosure
, existingClosure
->size(), sExecPath
);
6340 return existingClosure
;
6344 char closurePathTemp
[PATH_MAX
];
6345 strlcpy(closurePathTemp
, closurePath
, PATH_MAX
);
6346 int mypid
= getpid();
6350 putHexByte(mypid
>> 24, s
);
6351 putHexByte(mypid
>> 16, s
);
6352 putHexByte(mypid
>> 8, s
);
6353 putHexByte(mypid
, s
);
6355 strlcat(closurePathTemp
, pidBuf
, PATH_MAX
);
6357 int fd
= dyld3::open(closurePathTemp
, O_WRONLY
|O_CREAT
, S_IRUSR
|S_IWUSR
);
6359 int fd
= ::open_dprotected_np(closurePathTemp
, O_WRONLY
|O_CREAT
, PROTECTION_CLASS_D
, 0, S_IRUSR
|S_IWUSR
);
6362 ::ftruncate(fd
, result
->size());
6363 ::write(fd
, result
, result
->size());
6364 ::fsetxattr(fd
, DYLD_CLOSURE_XATTR_NAME
, bootToken
.begin(), bootToken
.count(), 0, 0);
6365 ::fchmod(fd
, S_IRUSR
);
6367 ::rename(closurePathTemp
, closurePath
);
6368 // free built closure and mmap file() to reduce dirty memory
6369 result
->deallocate();
6370 result
= mapClosureFile(closurePath
);
6371 sLaunchModeUsed
|= DYLD_LAUNCH_MODE_CLOSURE_SAVED_TO_FILE
;
6373 else if ( gLinkContext
.verboseWarnings
) {
6374 dyld::log("could not save closure (errno=%d) to: %s\n", errno
, closurePathTemp
);
6378 if ( gLinkContext
.verboseWarnings
)
6379 dyld::log("dyld: just built %s closure %p (size=%lu) for %s\n", result
->topImage()->variantString(), result
, result
->size(), sExecPath
);
6384 static const dyld3::closure::LaunchClosure
* findCachedLaunchClosure(const uint8_t* mainExecutableCDHash
,
6385 const dyld3::closure::LoadedFileInfo
& mainFileInfo
,
6387 const dyld3::Array
<uint8_t>& bootToken
)
6389 // get path to where closure file will be store for this program
6390 char closurePath
[PATH_MAX
];
6391 if ( !dyld3::closure::LaunchClosure::buildClosureCachePath(mainFileInfo
.path
, envp
, false, closurePath
) ) {
6392 // if cannot construct path to use/store closure file, then use minimal closures
6393 if ( sClosureKind
== ClosureKind::unset
)
6394 sClosureKind
= ClosureKind::minimal
;
6398 // if file exists, but extended attribute is wrong, ignore file (might be re-used later)
6399 if ( bootToken
.empty() )
6401 uint8_t filesBootToken
[bootToken
.count()];
6402 ssize_t attrSize
= ::getxattr(closurePath
, DYLD_CLOSURE_XATTR_NAME
, filesBootToken
, bootToken
.count(), 0, 0);
6403 if ( attrSize
!= bootToken
.count() )
6405 if ( memcmp(bootToken
.begin(), filesBootToken
, bootToken
.count()) != 0 )
6408 const dyld3::closure::LaunchClosure
* closure
= mapClosureFile(closurePath
);
6409 if ( closure
== nullptr )
6412 if ( !closureValid(closure
, mainFileInfo
, mainExecutableCDHash
, false, envp
) ) {
6413 ::munmap((void*)closure
, closure
->size());
6417 if ( gLinkContext
.verboseWarnings
)
6418 dyld::log("dyld: used cached %s closure %p (size=%lu) for %s\n", closure
->topImage()->variantString(), closure
, closure
->size(), sExecPath
);
6423 #endif // !TARGET_OS_SIMULATOR
6426 static ClosureMode
getPlatformDefaultClosureMode() {
6429 // rdar://problem/32701418: Don't use dyld3 for i386 for now.
6430 return ClosureMode::Off
;
6432 // x86_64 defaults to using the shared cache closures
6433 return ClosureMode::PreBuiltOnly
;
6437 // <rdar://problem/33171968> enable dyld3 mode for all OS programs when using customer dyld cache (no roots)
6438 if ( (sSharedCacheLoadInfo
.loadAddress
!= nullptr) && (sSharedCacheLoadInfo
.loadAddress
->header
.cacheType
== kDyldSharedCacheTypeProduction
) )
6439 return ClosureMode::On
;
6441 return ClosureMode::Off
;
6442 #endif // TARGET_OS_OSX
6446 // Entry point for dyld. The kernel loads dyld and jumps to __dyld_start which
6447 // sets up some registers and call this function.
6449 // Returns address of main() in target program which __dyld_start jumps to
6452 _main(const macho_header
* mainExecutableMH
, uintptr_t mainExecutableSlide
,
6453 int argc
, const char* argv
[], const char* envp
[], const char* apple
[],
6454 uintptr_t* startGlue
)
6456 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
)) {
6457 launchTraceID
= dyld3::kdebug_trace_dyld_duration_start(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
, (uint64_t)mainExecutableMH
, 0, 0);
6460 //Check and see if there are any kernel flags
6461 dyld3::BootArgs::setFlags(hexToUInt64(_simple_getenv(apple
, "dyld_flags"), nullptr));
6463 #if __has_feature(ptrauth_calls)
6464 // Check and see if kernel disabled JOP pointer signing (which lets us load plain arm64 binaries)
6465 if ( const char* disableStr
= _simple_getenv(apple
, "ptrauth_disabled") ) {
6466 if ( strcmp(disableStr
, "1") == 0 )
6467 sKeysDisabled
= true;
6470 // needed until kernel passes ptrauth_disabled for arm64 main executables
6471 if ( (mainExecutableMH
->cpusubtype
== CPU_SUBTYPE_ARM64_V8
) || (mainExecutableMH
->cpusubtype
== CPU_SUBTYPE_ARM64_ALL
) )
6472 sKeysDisabled
= true;
6476 // Grab the cdHash of the main executable from the environment
6477 uint8_t mainExecutableCDHashBuffer
[20];
6478 const uint8_t* mainExecutableCDHash
= nullptr;
6479 if ( const char* mainExeCdHashStr
= _simple_getenv(apple
, "executable_cdhash") ) {
6480 unsigned bufferLenUsed
;
6481 if ( hexStringToBytes(mainExeCdHashStr
, mainExecutableCDHashBuffer
, sizeof(mainExecutableCDHashBuffer
), bufferLenUsed
) )
6482 mainExecutableCDHash
= mainExecutableCDHashBuffer
;
6485 getHostInfo(mainExecutableMH
, mainExecutableSlide
);
6487 #if !TARGET_OS_SIMULATOR
6488 // Trace dyld's load
6489 notifyKernelAboutImage((macho_header
*)&__dso_handle
, _simple_getenv(apple
, "dyld_file"));
6490 // Trace the main executable's load
6491 notifyKernelAboutImage(mainExecutableMH
, _simple_getenv(apple
, "executable_file"));
6494 uintptr_t result
= 0;
6495 sMainExecutableMachHeader
= mainExecutableMH
;
6496 sMainExecutableSlide
= mainExecutableSlide
;
6499 // Set the platform ID in the all image infos so debuggers can tell the process type
6500 // FIXME: This can all be removed once we make the kernel handle it in rdar://43369446
6501 // The host may not have the platform field in its struct, but there's space for it in the padding, so always set it
6503 __block
bool platformFound
= false;
6504 ((dyld3::MachOFile
*)mainExecutableMH
)->forEachSupportedPlatform(^(dyld3::Platform platform
, uint32_t minOS
, uint32_t sdk
) {
6505 if (platformFound
) {
6506 halt("MH_EXECUTE binaries may only specify one platform");
6508 gProcessInfo
->platform
= (uint32_t)platform
;
6509 platformFound
= true;
6511 if (gProcessInfo
->platform
== (uint32_t)dyld3::Platform::unknown
) {
6512 // There were no platforms found in the binary. This may occur on macOS for alternate toolchains and old binaries.
6513 // It should never occur on any of our embedded platforms.
6515 gProcessInfo
->platform
= (uint32_t)dyld3::Platform::macOS
;
6517 halt("MH_EXECUTE binaries must specify a minimum supported OS version");
6523 // Check to see if we need to override the platform
6524 const char* forcedPlatform
= _simple_getenv(envp
, "DYLD_FORCE_PLATFORM");
6525 if (forcedPlatform
) {
6526 dyld_platform_t forcedPlatformType
= 0;
6527 if (strncmp(forcedPlatform
, "6", 1) == 0) {
6528 forcedPlatformType
= PLATFORM_MACCATALYST
;
6529 } else if (strncmp(forcedPlatform
, "2", 1) == 0) {
6530 forcedPlatformType
= PLATFORM_IOS
;
6532 halt("DYLD_FORCE_PLATFORM is only supported for platform 2 or 6.");
6534 const dyld3::MachOFile
* mf
= (dyld3::MachOFile
*)sMainExecutableMachHeader
;
6535 if (mf
->allowsAlternatePlatform()) {
6536 gProcessInfo
->platform
= forcedPlatformType
;
6540 // if this is host dyld, check to see if iOS simulator is being run
6541 const char* rootPath
= _simple_getenv(envp
, "DYLD_ROOT_PATH");
6542 if ( (rootPath
!= NULL
) ) {
6543 // look to see if simulator has its own dyld
6544 char simDyldPath
[PATH_MAX
];
6545 strlcpy(simDyldPath
, rootPath
, PATH_MAX
);
6546 strlcat(simDyldPath
, "/usr/lib/dyld_sim", PATH_MAX
);
6547 int fd
= dyld3::open(simDyldPath
, O_RDONLY
, 0);
6549 const char* errMessage
= useSimulatorDyld(fd
, mainExecutableMH
, simDyldPath
, argc
, argv
, envp
, apple
, startGlue
, &result
);
6550 if ( errMessage
!= NULL
)
6556 ((dyld3::MachOFile
*)mainExecutableMH
)->forEachSupportedPlatform(^(dyld3::Platform platform
, uint32_t minOS
, uint32_t sdk
) {
6557 if ( dyld3::MachOFile::isSimulatorPlatform(platform
) )
6558 halt("attempt to run simulator program outside simulator (DYLD_ROOT_PATH not set)");
6563 CRSetCrashLogMessage("dyld: launch started");
6565 setContext(mainExecutableMH
, argc
, argv
, envp
, apple
);
6567 // Pickup the pointer to the exec path.
6568 sExecPath
= _simple_getenv(apple
, "executable_path");
6570 // <rdar://problem/13868260> Remove interim apple[0] transition code from dyld
6571 if (!sExecPath
) sExecPath
= apple
[0];
6573 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
6574 // <rdar://54095622> kernel is not passing a real path for main executable
6575 if ( strncmp(sExecPath
, "/var/containers/Bundle/Application/", 35) == 0 ) {
6576 if ( char* newPath
= (char*)malloc(strlen(sExecPath
)+10) ) {
6577 strcpy(newPath
, "/private");
6578 strcat(newPath
, sExecPath
);
6579 sExecPath
= newPath
;
6584 if ( sExecPath
[0] != '/' ) {
6585 // have relative path, use cwd to make absolute
6586 char cwdbuff
[MAXPATHLEN
];
6587 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
6588 // maybe use static buffer to avoid calling malloc so early...
6589 char* s
= new char[strlen(cwdbuff
) + strlen(sExecPath
) + 2];
6592 strcat(s
, sExecPath
);
6597 // Remember short name of process for later logging
6598 sExecShortName
= ::strrchr(sExecPath
, '/');
6599 if ( sExecShortName
!= NULL
)
6602 sExecShortName
= sExecPath
;
6604 #if TARGET_OS_OSX && __has_feature(ptrauth_calls)
6605 // on Apple Silicon macOS, only Apple signed ("platform binary") arm64e can be loaded
6606 sOnlyPlatformArm64e
= true;
6608 // internal builds, or if boot-arg is set, then non-platform-binary arm64e slices can be run
6609 if ( const char* abiMode
= _simple_getenv(apple
, "arm64e_abi") ) {
6610 if ( strcmp(abiMode
, "all") == 0 )
6611 sOnlyPlatformArm64e
= false;
6615 configureProcessRestrictions(mainExecutableMH
, envp
);
6617 // Check if we should force dyld3. Note we have to do this outside of the regular env parsing due to AMFI
6618 if ( dyld3::internalInstall() ) {
6619 if (const char* useClosures
= _simple_getenv(envp
, "DYLD_USE_CLOSURES")) {
6620 if ( strcmp(useClosures
, "0") == 0 ) {
6621 sClosureMode
= ClosureMode::Off
;
6622 } else if ( strcmp(useClosures
, "1") == 0 ) {
6623 #if !__i386__ // don't support dyld3 for 32-bit macOS
6624 sClosureMode
= ClosureMode::On
;
6625 sClosureKind
= ClosureKind::full
;
6627 } else if ( strcmp(useClosures
, "2") == 0 ) {
6628 sClosureMode
= ClosureMode::On
;
6629 sClosureKind
= ClosureKind::minimal
;
6631 dyld::warn("unknown option to DYLD_USE_CLOSURES. Valid options are: 0 and 1\n");
6637 // Check if we should force the shared cache __DATA_CONST to read-only or read-write
6638 if ( dyld3::BootArgs::forceReadWriteDataConst() ) {
6639 gEnableSharedCacheDataConst
= false;
6640 } else if ( dyld3::BootArgs::forceReadOnlyDataConst() ) {
6641 gEnableSharedCacheDataConst
= true;
6643 // __DATA_CONST is enabled by default for arm64(e) for now
6644 #if __arm64__ && __LP64__
6645 gEnableSharedCacheDataConst
= true;
6647 gEnableSharedCacheDataConst
= false;
6650 bool sharedCacheDataConstIsEnabled
= gEnableSharedCacheDataConst
;
6652 if ( dyld3::internalInstall() ) {
6653 if (const char* dataConst
= _simple_getenv(envp
, "DYLD_SHARED_REGION_DATA_CONST")) {
6654 if ( strcmp(dataConst
, "RW") == 0 ) {
6655 gEnableSharedCacheDataConst
= false;
6656 } else if ( strcmp(dataConst
, "RO") == 0 ) {
6657 gEnableSharedCacheDataConst
= true;
6659 dyld::warn("unknown option to DYLD_SHARED_REGION_DATA_CONST. Valid options are: RW and RO\n");
6667 if ( !gLinkContext
.allowEnvVarsPrint
&& !gLinkContext
.allowEnvVarsPath
&& !gLinkContext
.allowEnvVarsSharedCache
) {
6668 pruneEnvironmentVariables(envp
, &apple
);
6669 // set again because envp and apple may have changed or moved
6670 setContext(mainExecutableMH
, argc
, argv
, envp
, apple
);
6675 checkEnvironmentVariables(envp
);
6676 defaultUninitializedFallbackPaths(envp
);
6679 switch (gProcessInfo
->platform
) {
6680 #if (TARGET_OS_OSX && TARGET_CPU_ARM64)
6682 sClosureMode
= ClosureMode::On
; // <rdar://problem/56792308> Run iOS apps on macOS in dyld3 mode
6683 [[clang::fallthrough]];
6685 case PLATFORM_MACCATALYST
:
6686 gLinkContext
.rootPaths
= parseColonList("/System/iOSSupport", NULL
);
6687 gLinkContext
.iOSonMac
= true;
6688 if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH
== sLibraryFallbackPaths
)
6689 sEnv
.DYLD_FALLBACK_LIBRARY_PATH
= sRestrictedLibraryFallbackPaths
;
6690 if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
== sFrameworkFallbackPaths
)
6691 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
= sRestrictedFrameworkFallbackPaths
;
6693 case PLATFORM_DRIVERKIT
:
6694 gLinkContext
.driverKit
= true;
6695 gLinkContext
.sharedRegionMode
= ImageLoader::kDontUseSharedRegion
;
6699 if ( sEnv
.DYLD_PRINT_OPTS
)
6701 if ( sEnv
.DYLD_PRINT_ENV
)
6702 printEnvironmentVariables(envp
);
6704 // Parse this envirionment variable outside of the regular logic as we want to accept
6705 // this on binaries without an entitelment
6706 #if !TARGET_OS_SIMULATOR
6707 if ( _simple_getenv(envp
, "DYLD_JUST_BUILD_CLOSURE") != nullptr ) {
6708 #if TARGET_OS_IPHONE
6709 char tempClosurePath
[PATH_MAX
];
6710 if ( dyld3::closure::LaunchClosure::buildClosureCachePath(sExecPath
, envp
, false, tempClosurePath
) )
6711 sJustBuildClosure
= true;
6713 // If the env vars for the data contain look wrong, don't want to launch the app as that would bring up the UI
6714 if (!sJustBuildClosure
) {
6715 _exit(EXIT_SUCCESS
);
6720 if ( sJustBuildClosure
)
6721 sClosureMode
= ClosureMode::On
;
6723 // load shared cache
6724 checkSharedRegionDisable((dyld3::MachOLoaded
*)mainExecutableMH
, mainExecutableSlide
);
6725 if ( gLinkContext
.sharedRegionMode
!= ImageLoader::kDontUseSharedRegion
) {
6726 #if TARGET_OS_SIMULATOR
6727 if ( sSharedCacheOverrideDir
)
6728 mapSharedCache(mainExecutableSlide
);
6730 mapSharedCache(mainExecutableSlide
);
6733 // If this process wants a different __DATA_CONST state from the shared region, then override that now
6734 if ( (sSharedCacheLoadInfo
.loadAddress
!= nullptr) && (gEnableSharedCacheDataConst
!= sharedCacheDataConstIsEnabled
) ) {
6735 uint32_t permissions
= gEnableSharedCacheDataConst
? VM_PROT_READ
: (VM_PROT_READ
| VM_PROT_WRITE
);
6736 sSharedCacheLoadInfo
.loadAddress
->changeDataConstPermissions(mach_task_self(), permissions
,
6737 (gLinkContext
.verboseMapping
? &dyld::log
: nullptr));
6741 #if !TARGET_OS_SIMULATOR
6742 if ( getpid() == 1 ) {
6743 // Get the value as set by the boot-args
6744 uint64_t commPageValue
= 0;
6745 size_t commPageValueSize
= sizeof(commPageValue
);
6746 if ( sysctlbyname("kern.dyld_flags", &commPageValue
, &commPageValueSize
, nullptr, 0) != 0 ) {
6747 // Try again with the old name
6748 // TODO: Remove this when we are always on new enough kernels
6749 sysctlbyname("kern.dyld_system_flags", &commPageValue
, &commPageValueSize
, nullptr, 0);
6752 commPageValue
&= CommPageBootArgMask
;
6753 // logToConsole("dyld: got comm page flags 0x%llx\n", commPageValue);
6755 // If we are PID 1 (launchd) and on macOS, then we should check if the simulator support dylibs
6756 // are roots or not.
6757 // If they are not roots at launchd time, and the file system is read-only, then we know for sure
6758 // they will not be roots later
6759 #if DYLD_SIMULATOR_ROOTS_SUPPORT
6760 bool fileSystemIsWritable
= true;
6762 // logToConsole("dyld: in launchd\n");
6763 struct statfs statBuffer
;
6764 int statResult
= statfs("/", &statBuffer
);
6765 if ( statResult
== 0 ) {
6766 if ( !strcmp(statBuffer
.f_fstypename
, "apfs") ) {
6767 if ( (statBuffer
.f_flags
& (MNT_RDONLY
| MNT_SNAPSHOT
)) == (MNT_RDONLY
| MNT_SNAPSHOT
) ) {
6768 // logToConsole("dyld: got statfs flags 0x%llx\n", statBuffer.f_flags);
6769 fileSystemIsWritable
= false;
6774 logToConsole("dyld: could not stat '/', errno = %d\n", error
);
6777 // If the file system is read-only, then we can check now whether any of the simulator support
6779 bool libsystemKernelIsRoot
= false;
6780 bool libsystemPlatformIsRoot
= false;
6781 bool libsystemPThreadIsRoot
= false;
6782 if ( !fileSystemIsWritable
&& (sSharedCacheLoadInfo
.loadAddress
!= nullptr)) {
6783 dyld3::closure::FileSystemPhysical fileSystem
;
6784 libsystemKernelIsRoot
= !dyld3::RootsChecker::uuidMatchesSharedCache("/usr/lib/system/libsystem_kernel.dylib",
6785 &fileSystem
, sSharedCacheLoadInfo
.loadAddress
);
6786 libsystemPlatformIsRoot
= !dyld3::RootsChecker::uuidMatchesSharedCache("/usr/lib/system/libsystem_platform.dylib",
6787 &fileSystem
, sSharedCacheLoadInfo
.loadAddress
);
6788 libsystemPThreadIsRoot
= !dyld3::RootsChecker::uuidMatchesSharedCache("/usr/lib/system/libsystem_pthread.dylib",
6789 &fileSystem
, sSharedCacheLoadInfo
.loadAddress
);
6791 commPageValue
|= (fileSystemIsWritable
? CommPageFlags::fileSystemCanBeModified
: CommPageFlags::None
);
6792 commPageValue
|= (libsystemKernelIsRoot
? CommPageFlags::libsystemKernelIsRoot
: CommPageFlags::None
);
6793 commPageValue
|= (libsystemPlatformIsRoot
? CommPageFlags::libsystemPlatformIsRoot
: CommPageFlags::None
);
6794 commPageValue
|= (libsystemPThreadIsRoot
? CommPageFlags::libsystemPThreadIsRoot
: CommPageFlags::None
);
6795 #endif // DYLD_SIMULATOR_ROOTS_SUPPORT
6797 logToConsole("dyld: setting comm page to 0x%llx\n", commPageValue
);
6798 if ( sysctlbyname("kern.dyld_flags", nullptr, 0, &commPageValue
, sizeof(commPageValue
)) != 0 ) {
6799 // Try again with the old name
6800 // TODO: Remove this when we are always on new enough kernels
6801 sysctlbyname("kern.dyld_system_flags", nullptr, 0, &commPageValue
, sizeof(commPageValue
));
6805 #if DYLD_SIMULATOR_ROOTS_SUPPORT
6806 // Set the roots checker to the state from the comm page
6808 uint64_t dyldFlags
= *((uint64_t*)_COMM_PAGE_DYLD_SYSTEM_FLAGS
);
6809 bool fileSystemCanBeModified
= dyldFlags
& CommPageFlags::fileSystemCanBeModified
;
6810 bool libsystemKernelIsRoot
= dyldFlags
& CommPageFlags::libsystemKernelIsRoot
;
6811 bool libsystemPlatformIsRoot
= dyldFlags
& CommPageFlags::libsystemPlatformIsRoot
;
6812 bool libsystemPThreadIsRoot
= dyldFlags
& CommPageFlags::libsystemPThreadIsRoot
;
6813 sRootsChecker
.setFileSystemCanBeModified(fileSystemCanBeModified
);
6814 sRootsChecker
.setLibsystemKernelIsRoot(libsystemKernelIsRoot
);
6815 sRootsChecker
.setLibsystemPlatformIsRoot(libsystemPlatformIsRoot
);
6816 sRootsChecker
.setLibsystemPThreadIsRoot(libsystemPThreadIsRoot
);
6818 #endif // DYLD_SIMULATOR_ROOTS_SUPPORT
6820 #endif // !TARGET_OS_SIMULATOR
6822 // If we haven't got a closure mode yet, then check the environment and cache type
6823 if ( sClosureMode
== ClosureMode::Unset
) {
6824 // First test to see if we forced in dyld2 via a kernel boot-arg
6825 if ( dyld3::BootArgs::forceDyld2() ) {
6826 sClosureMode
= ClosureMode::Off
;
6827 } else if ( inDenyList(sExecPath
) ) {
6828 sClosureMode
= ClosureMode::Off
;
6829 } else if ( sEnv
.hasOverride
) {
6830 sClosureMode
= ClosureMode::Off
;
6831 } else if ( dyld3::BootArgs::forceDyld3() ) {
6832 sClosureMode
= ClosureMode::On
;
6834 sClosureMode
= getPlatformDefaultClosureMode();
6838 #if !TARGET_OS_SIMULATOR
6839 if ( sClosureMode
== ClosureMode::Off
) {
6840 if ( gLinkContext
.verboseWarnings
)
6841 dyld::log("dyld: not using closures\n");
6843 sLaunchModeUsed
= DYLD_LAUNCH_MODE_USING_CLOSURE
;
6844 const dyld3::closure::LaunchClosure
* mainClosure
= nullptr;
6845 dyld3::closure::LoadedFileInfo mainFileInfo
;
6846 mainFileInfo
.fileContent
= mainExecutableMH
;
6847 mainFileInfo
.path
= sExecPath
;
6848 // FIXME: If we are saving this closure, this slice offset/length is probably wrong in the case of FAT files.
6849 mainFileInfo
.sliceOffset
= 0;
6850 mainFileInfo
.sliceLen
= -1;
6851 struct stat mainExeStatBuf
;
6852 if ( dyld3::stat(sExecPath
, &mainExeStatBuf
) == 0 ) {
6853 mainFileInfo
.inode
= mainExeStatBuf
.st_ino
;
6854 mainFileInfo
.mtime
= mainExeStatBuf
.st_mtime
;
6856 // check for closure in cache first
6857 if ( sSharedCacheLoadInfo
.loadAddress
!= nullptr ) {
6858 mainClosure
= sSharedCacheLoadInfo
.loadAddress
->findClosure(sExecPath
);
6859 if ( gLinkContext
.verboseWarnings
&& (mainClosure
!= nullptr) )
6860 dyld::log("dyld: found closure %p (size=%lu) in dyld shared cache\n", mainClosure
, mainClosure
->size());
6861 if ( mainClosure
!= nullptr )
6862 sLaunchModeUsed
|= DYLD_LAUNCH_MODE_CLOSURE_FROM_OS
;
6865 // We only want to try build a closure at runtime if its an iOS third party binary, or a macOS binary from the shared cache
6866 bool allowClosureRebuilds
= false;
6867 if ( sClosureMode
== ClosureMode::On
) {
6868 allowClosureRebuilds
= true;
6869 } else if ( (sClosureMode
== ClosureMode::PreBuiltOnly
) && (mainClosure
!= nullptr) ) {
6870 allowClosureRebuilds
= true;
6873 if ( (mainClosure
!= nullptr) && !closureValid(mainClosure
, mainFileInfo
, mainExecutableCDHash
, true, envp
) ) {
6874 mainClosure
= nullptr;
6875 sLaunchModeUsed
&= ~DYLD_LAUNCH_MODE_CLOSURE_FROM_OS
;
6878 // <rdar://60333505> bootToken is a concat of boot-hash kernel passes down for app and dyld's uuid
6879 uint8_t bootTokenBufer
[128];
6880 unsigned bootTokenBufferLen
= 0;
6881 if ( const char* bootHashStr
= _simple_getenv(apple
, "executable_boothash") ) {
6882 if ( hexStringToBytes(bootHashStr
, bootTokenBufer
, sizeof(bootTokenBufer
), bootTokenBufferLen
) ) {
6883 if ( ((dyld3::MachOFile
*)&__dso_handle
)->getUuid(&bootTokenBufer
[bootTokenBufferLen
]) )
6884 bootTokenBufferLen
+= sizeof(uuid_t
);
6887 dyld3::Array
<uint8_t> bootToken(bootTokenBufer
, bootTokenBufferLen
, bootTokenBufferLen
);
6889 // If we didn't find a valid cache closure then try build a new one
6890 if ( (mainClosure
== nullptr) && allowClosureRebuilds
) {
6891 // if forcing closures, and no closure in cache, or it is invalid, check for cached closure
6892 if ( !sForceInvalidSharedCacheClosureFormat
)
6893 mainClosure
= findCachedLaunchClosure(mainExecutableCDHash
, mainFileInfo
, envp
, bootToken
);
6894 if ( mainClosure
== nullptr ) {
6895 // if no cached closure found, build new one
6896 mainClosure
= buildLaunchClosure(mainExecutableCDHash
, mainFileInfo
, envp
, bootToken
);
6897 if ( mainClosure
!= nullptr )
6898 sLaunchModeUsed
|= DYLD_LAUNCH_MODE_BUILT_CLOSURE_AT_LAUNCH
;
6902 // exit dyld after closure is built, without running program
6903 if ( sJustBuildClosure
)
6904 _exit(EXIT_SUCCESS
);
6906 // try using launch closure
6907 if ( mainClosure
!= nullptr ) {
6908 CRSetCrashLogMessage("dyld3: launch started");
6909 if ( mainClosure
->topImage()->fixupsNotEncoded() )
6910 sLaunchModeUsed
|= DYLD_LAUNCH_MODE_MINIMAL_CLOSURE
;
6912 bool closureOutOfDate
;
6914 bool launched
= launchWithClosure(mainClosure
, sSharedCacheLoadInfo
.loadAddress
, (dyld3::MachOLoaded
*)mainExecutableMH
,
6915 mainExecutableSlide
, argc
, argv
, envp
, apple
, diag
, &result
, startGlue
, &closureOutOfDate
, &recoverable
);
6916 if ( !launched
&& closureOutOfDate
&& allowClosureRebuilds
) {
6917 // closure is out of date, build new one
6918 mainClosure
= buildLaunchClosure(mainExecutableCDHash
, mainFileInfo
, envp
, bootToken
);
6919 if ( mainClosure
!= nullptr ) {
6921 sLaunchModeUsed
|= DYLD_LAUNCH_MODE_BUILT_CLOSURE_AT_LAUNCH
;
6922 if ( mainClosure
->topImage()->fixupsNotEncoded() )
6923 sLaunchModeUsed
|= DYLD_LAUNCH_MODE_MINIMAL_CLOSURE
;
6925 sLaunchModeUsed
&= ~DYLD_LAUNCH_MODE_MINIMAL_CLOSURE
;
6926 launched
= launchWithClosure(mainClosure
, sSharedCacheLoadInfo
.loadAddress
, (dyld3::MachOLoaded
*)mainExecutableMH
,
6927 mainExecutableSlide
, argc
, argv
, envp
, apple
, diag
, &result
, startGlue
, &closureOutOfDate
, &recoverable
);
6931 gLinkContext
.startedInitializingMainExecutable
= true;
6933 result
= (uintptr_t)&fake_main
;
6937 if ( gLinkContext
.verboseWarnings
) {
6938 dyld::log("dyld: unable to use closure %p\n", mainClosure
);
6941 halt(diag
.errorMessage());
6945 #endif // TARGET_OS_SIMULATOR
6946 // could not use closure info, launch old way
6947 sLaunchModeUsed
= 0;
6950 // install gdb notifier
6951 stateToHandlers(dyld_image_state_dependents_mapped
, sBatchHandlers
)->push_back(notifyGDB
);
6952 stateToHandlers(dyld_image_state_mapped
, sSingleHandlers
)->push_back(updateAllImages
);
6953 // make initial allocations large enough that it is unlikely to need to be re-alloced
6954 sImageRoots
.reserve(16);
6955 sAddImageCallbacks
.reserve(4);
6956 sRemoveImageCallbacks
.reserve(4);
6957 sAddLoadImageCallbacks
.reserve(4);
6958 sImageFilesNeedingTermination
.reserve(16);
6959 sImageFilesNeedingDOFUnregistration
.reserve(8);
6961 #if !TARGET_OS_SIMULATOR
6962 #ifdef WAIT_FOR_SYSTEM_ORDER_HANDSHAKE
6963 // <rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process
6964 WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld::gProcessInfo
->systemOrderFlag
);
6970 // add dyld itself to UUID list
6971 addDyldImageToUUIDList();
6973 #if SUPPORT_ACCELERATE_TABLES
6975 // Disable accelerator tables when we have threaded rebase/bind, which is arm64e executables only for now.
6976 if ((sMainExecutableMachHeader
->cpusubtype
& ~CPU_SUBTYPE_MASK
) == CPU_SUBTYPE_ARM64E
)
6977 sDisableAcceleratorTables
= true;
6979 bool mainExcutableAlreadyRebased
= false;
6980 if ( (sSharedCacheLoadInfo
.loadAddress
!= nullptr) && !dylibsCanOverrideCache() && !sDisableAcceleratorTables
&& (sSharedCacheLoadInfo
.loadAddress
->header
.accelerateInfoAddr
!= 0) ) {
6981 struct stat statBuf
;
6982 if ( dyld3::stat(IPHONE_DYLD_SHARED_CACHE_DIR
"no-dyld2-accelerator-tables", &statBuf
) != 0 )
6983 sAllCacheImagesProxy
= ImageLoaderMegaDylib::makeImageLoaderMegaDylib(&sSharedCacheLoadInfo
.loadAddress
->header
, sSharedCacheLoadInfo
.slide
, mainExecutableMH
, gLinkContext
);
6991 gLinkContext
.strictMachORequired
= false;
6992 // <rdar://problem/22805519> be less strict about old macOS mach-o binaries
6993 ((dyld3::MachOFile
*)mainExecutableMH
)->forEachSupportedPlatform(^(dyld3::Platform platform
, uint32_t minOS
, uint32_t sdk
) {
6994 if ( (platform
== dyld3::Platform::macOS
) && (sdk
>= DYLD_PACKED_VERSION(10,15,0)) ) {
6995 gLinkContext
.strictMachORequired
= true;
6998 if ( gLinkContext
.iOSonMac
)
6999 gLinkContext
.strictMachORequired
= true;
7001 // simulators, iOS, tvOS, watchOS, are always strict
7002 gLinkContext
.strictMachORequired
= true;
7006 CRSetCrashLogMessage(sLoadingCrashMessage
);
7007 // instantiate ImageLoader for main executable
7008 sMainExecutable
= instantiateFromLoadedImage(mainExecutableMH
, mainExecutableSlide
, sExecPath
);
7009 gLinkContext
.mainExecutable
= sMainExecutable
;
7010 gLinkContext
.mainExecutableCodeSigned
= hasCodeSignatureLoadCommand(mainExecutableMH
);
7012 #if TARGET_OS_SIMULATOR
7013 // check main executable is not too new for this OS
7015 if ( ! isSimulatorBinary((uint8_t*)mainExecutableMH
, sExecPath
) ) {
7016 throwf("program was built for a platform that is not supported by this runtime");
7018 uint32_t mainMinOS
= sMainExecutable
->minOSVersion();
7020 // dyld is always built for the current OS, so we can get the current OS version
7021 // from the load command in dyld itself.
7022 uint32_t dyldMinOS
= ImageLoaderMachO::minOSVersion((const mach_header
*)&__dso_handle
);
7023 if ( mainMinOS
> dyldMinOS
) {
7025 throwf("app was built for watchOS %d.%d which is newer than this simulator %d.%d",
7026 mainMinOS
>> 16, ((mainMinOS
>> 8) & 0xFF),
7027 dyldMinOS
>> 16, ((dyldMinOS
>> 8) & 0xFF));
7029 throwf("app was built for tvOS %d.%d which is newer than this simulator %d.%d",
7030 mainMinOS
>> 16, ((mainMinOS
>> 8) & 0xFF),
7031 dyldMinOS
>> 16, ((dyldMinOS
>> 8) & 0xFF));
7033 throwf("app was built for iOS %d.%d which is newer than this simulator %d.%d",
7034 mainMinOS
>> 16, ((mainMinOS
>> 8) & 0xFF),
7035 dyldMinOS
>> 16, ((dyldMinOS
>> 8) & 0xFF));
7042 #if SUPPORT_ACCELERATE_TABLES
7043 sAllImages
.reserve((sAllCacheImagesProxy
!= NULL
) ? 16 : INITIAL_IMAGE_COUNT
);
7045 sAllImages
.reserve(INITIAL_IMAGE_COUNT
);
7048 #if defined(__x86_64__) && !TARGET_OS_SIMULATOR
7049 if (dyld::isTranslated()) {
7050 struct dyld_all_runtime_info
{
7051 uint32_t image_count
;
7052 dyld_image_info
* images
;
7053 uint32_t uuid_count
;
7054 dyld_uuid_info
* uuids
;
7055 uint32_t aot_image_count
;
7056 dyld_aot_image_info
* aots
;
7057 dyld_aot_shared_cache_info aot_cache_info
;
7060 dyld_all_runtime_info
* runtime_info
;
7061 int ret
= syscall(0x7000004, &runtime_info
);
7063 for (int i
= 0; i
< runtime_info
->uuid_count
; i
++) {
7064 dyld_image_info image_info
= runtime_info
->images
[i
];
7065 dyld_uuid_info uuid_info
= runtime_info
->uuids
[i
];
7067 // add the arm64 cambria runtime to uuid info
7068 addNonSharedCacheImageUUID(uuid_info
);
7071 if (stat(image_info
.imageFilePath
, &sb
) == 0) {
7072 fsid_t fsid
= {{0, 0}};
7073 fsobj_id_t fsobj
= {0};
7074 ino_t inode
= sb
.st_ino
;
7075 fsobj
.fid_objno
= (uint32_t)inode
;
7076 fsobj
.fid_generation
= (uint32_t)(inode
>>32);
7077 fsid
.val
[0] = sb
.st_dev
;
7079 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A
, image_info
.imageFilePath
, &(uuid_info
.imageUUID
), fsobj
, fsid
, image_info
.imageLoadAddress
);
7083 // add aot images to dyld_all_image_info
7084 addAotImagesToAllAotImages(runtime_info
->aot_image_count
, runtime_info
->aots
);
7086 // add the arm64 cambria runtime to dyld_all_image_info
7087 addImagesToAllImages(runtime_info
->image_count
, runtime_info
->images
);
7089 // set the aot shared cache info in dyld_all_image_info
7090 dyld::gProcessInfo
->aotSharedCacheBaseAddress
= runtime_info
->aot_cache_info
.cacheBaseAddress
;
7091 memcpy(dyld::gProcessInfo
->aotSharedCacheUUID
, runtime_info
->aot_cache_info
.cacheUUID
, sizeof(uuid_t
));
7096 // Now that shared cache is loaded, setup an versioned dylib overrides
7097 #if SUPPORT_VERSIONED_PATHS
7098 checkVersionedPaths();
7102 // dyld_all_image_infos image list does not contain dyld
7103 // add it as dyldPath field in dyld_all_image_infos
7104 // for simulator, dyld_sim is in image list, need host dyld added
7105 #if TARGET_OS_SIMULATOR
7106 // get path of host dyld from table of syscall vectors in host dyld
7107 void* addressInDyld
= gSyscallHelpers
;
7109 // get path of dyld itself
7110 void* addressInDyld
= (void*)&__dso_handle
;
7112 char dyldPathBuffer
[MAXPATHLEN
+1];
7113 int len
= proc_regionfilename(getpid(), (uint64_t)(long)addressInDyld
, dyldPathBuffer
, MAXPATHLEN
);
7115 dyldPathBuffer
[len
] = '\0'; // proc_regionfilename() does not zero terminate returned string
7116 if ( strcmp(dyldPathBuffer
, gProcessInfo
->dyldPath
) != 0 )
7117 gProcessInfo
->dyldPath
= strdup(dyldPathBuffer
);
7120 // load any inserted libraries
7121 if ( sEnv
.DYLD_INSERT_LIBRARIES
!= NULL
) {
7122 for (const char* const* lib
= sEnv
.DYLD_INSERT_LIBRARIES
; *lib
!= NULL
; ++lib
)
7123 loadInsertedDylib(*lib
);
7125 // record count of inserted libraries so that a flat search will look at
7126 // inserted libraries, then main, then others.
7127 sInsertedDylibCount
= sAllImages
.size()-1;
7129 // link main executable
7130 gLinkContext
.linkingMainExecutable
= true;
7131 #if SUPPORT_ACCELERATE_TABLES
7132 if ( mainExcutableAlreadyRebased
) {
7133 // previous link() on main executable has already adjusted its internal pointers for ASLR
7134 // work around that by rebasing by inverse amount
7135 sMainExecutable
->rebase(gLinkContext
, -mainExecutableSlide
);
7138 link(sMainExecutable
, sEnv
.DYLD_BIND_AT_LAUNCH
, true, ImageLoader::RPathChain(NULL
, NULL
), -1);
7139 sMainExecutable
->setNeverUnloadRecursive();
7140 if ( sMainExecutable
->forceFlat() ) {
7141 gLinkContext
.bindFlat
= true;
7142 gLinkContext
.prebindUsage
= ImageLoader::kUseNoPrebinding
;
7145 // link any inserted libraries
7146 // do this after linking main executable so that any dylibs pulled in by inserted
7147 // dylibs (e.g. libSystem) will not be in front of dylibs the program uses
7148 if ( sInsertedDylibCount
> 0 ) {
7149 for(unsigned int i
=0; i
< sInsertedDylibCount
; ++i
) {
7150 ImageLoader
* image
= sAllImages
[i
+1];
7151 link(image
, sEnv
.DYLD_BIND_AT_LAUNCH
, true, ImageLoader::RPathChain(NULL
, NULL
), -1);
7152 image
->setNeverUnloadRecursive();
7154 if ( gLinkContext
.allowInterposing
) {
7155 // only INSERTED libraries can interpose
7156 // register interposing info after all inserted libraries are bound so chaining works
7157 for(unsigned int i
=0; i
< sInsertedDylibCount
; ++i
) {
7158 ImageLoader
* image
= sAllImages
[i
+1];
7159 image
->registerInterposing(gLinkContext
);
7164 if ( gLinkContext
.allowInterposing
) {
7165 // <rdar://problem/19315404> dyld should support interposition even without DYLD_INSERT_LIBRARIES
7166 for (long i
=sInsertedDylibCount
+1; i
< sAllImages
.size(); ++i
) {
7167 ImageLoader
* image
= sAllImages
[i
];
7168 if ( image
->inSharedCache() )
7170 image
->registerInterposing(gLinkContext
);
7173 #if SUPPORT_ACCELERATE_TABLES
7174 if ( (sAllCacheImagesProxy
!= NULL
) && ImageLoader::haveInterposingTuples() ) {
7175 // Accelerator tables cannot be used with implicit interposing, so relaunch with accelerator tables disabled
7176 ImageLoader::clearInterposingTuples();
7177 // unmap all loaded dylibs (but not main executable)
7178 for (long i
=1; i
< sAllImages
.size(); ++i
) {
7179 ImageLoader
* image
= sAllImages
[i
];
7180 if ( image
== sMainExecutable
)
7182 if ( image
== sAllCacheImagesProxy
)
7184 image
->setCanUnload();
7185 ImageLoader::deleteImage(image
);
7187 // note: we don't need to worry about inserted images because if DYLD_INSERT_LIBRARIES was set we would not be using the accelerator table
7189 sImageRoots
.clear();
7190 sImageFilesNeedingTermination
.clear();
7191 sImageFilesNeedingDOFUnregistration
.clear();
7192 sAddImageCallbacks
.clear();
7193 sRemoveImageCallbacks
.clear();
7194 sAddLoadImageCallbacks
.clear();
7195 sAddBulkLoadImageCallbacks
.clear();
7196 sDisableAcceleratorTables
= true;
7197 sAllCacheImagesProxy
= NULL
;
7198 sMappedRangesStart
= NULL
;
7199 mainExcutableAlreadyRebased
= true;
7200 gLinkContext
.linkingMainExecutable
= false;
7202 goto reloadAllImages
;
7206 // apply interposing to initial set of images
7207 for(int i
=0; i
< sImageRoots
.size(); ++i
) {
7208 sImageRoots
[i
]->applyInterposing(gLinkContext
);
7210 ImageLoader::applyInterposingToDyldCache(gLinkContext
);
7212 // Bind and notify for the main executable now that interposing has been registered
7213 uint64_t bindMainExecutableStartTime
= mach_absolute_time();
7214 sMainExecutable
->recursiveBindWithAccounting(gLinkContext
, sEnv
.DYLD_BIND_AT_LAUNCH
, true);
7215 uint64_t bindMainExecutableEndTime
= mach_absolute_time();
7216 ImageLoaderMachO::fgTotalBindTime
+= bindMainExecutableEndTime
- bindMainExecutableStartTime
;
7217 gLinkContext
.notifyBatch(dyld_image_state_bound
, false);
7219 // Bind and notify for the inserted images now interposing has been registered
7220 if ( sInsertedDylibCount
> 0 ) {
7221 for(unsigned int i
=0; i
< sInsertedDylibCount
; ++i
) {
7222 ImageLoader
* image
= sAllImages
[i
+1];
7223 image
->recursiveBind(gLinkContext
, sEnv
.DYLD_BIND_AT_LAUNCH
, true, nullptr);
7227 // <rdar://problem/12186933> do weak binding only after all inserted images linked
7228 sMainExecutable
->weakBind(gLinkContext
);
7229 gLinkContext
.linkingMainExecutable
= false;
7231 sMainExecutable
->recursiveMakeDataReadOnly(gLinkContext
);
7233 CRSetCrashLogMessage("dyld: launch, running initializers");
7234 #if SUPPORT_OLD_CRT_INITIALIZATION
7235 // Old way is to run initializers via a callback from crt1.o
7236 if ( ! gRunInitializersOldWay
)
7237 initializeMainExecutable();
7239 // run all initializers
7240 initializeMainExecutable();
7243 // notify any montoring proccesses that this process is about to enter main()
7244 notifyMonitoringDyldMain();
7245 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
)) {
7246 dyld3::kdebug_trace_dyld_duration_end(launchTraceID
, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
, 0, 0, 2);
7248 ARIADNEDBG_CODE(220, 1);
7251 if ( gLinkContext
.driverKit
) {
7252 result
= (uintptr_t)sEntryOverride
;
7254 halt("no entry point registered");
7255 *startGlue
= (uintptr_t)gLibSystemHelpers
->startGlueToCallExit
;
7260 // find entry point for main executable
7261 result
= (uintptr_t)sMainExecutable
->getEntryFromLC_MAIN();
7262 if ( result
!= 0 ) {
7263 // main executable uses LC_MAIN, we need to use helper in libdyld to call into main()
7264 if ( (gLibSystemHelpers
!= NULL
) && (gLibSystemHelpers
->version
>= 9) )
7265 *startGlue
= (uintptr_t)gLibSystemHelpers
->startGlueToCallExit
;
7267 halt("libdyld.dylib support not present for LC_MAIN");
7270 // main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main()
7271 result
= (uintptr_t)sMainExecutable
->getEntryFromLC_UNIXTHREAD();
7276 catch(const char* message
) {
7281 dyld::log("dyld: launch failed\n");
7284 CRSetCrashLogMessage("dyld2 mode");
7285 #if !TARGET_OS_SIMULATOR
7286 if (sLogClosureFailure
) {
7287 // We failed to launch in dyld3, but dyld2 can handle it. synthesize a crash report for analytics
7288 dyld3::syntheticBacktrace("Could not generate launchClosure, falling back to dyld2", true);
7293 notifyMonitoringDyldMain();
7294 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
)) {
7295 dyld3::kdebug_trace_dyld_duration_end(launchTraceID
, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE
, 0, 0, 2);
7297 ARIADNEDBG_CODE(220, 1);
7298 result
= (uintptr_t)&fake_main
;
7299 *startGlue
= (uintptr_t)gLibSystemHelpers
->startGlueToCallExit
;