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@ 
  33 #include <sys/param.h> 
  34 #include <mach/mach_time.h> // mach_absolute_time() 
  35 #include <mach/mach_init.h>  
  36 #include <sys/types.h> 
  38 #include <sys/syscall.h> 
  39 #include <sys/socket.h> 
  41 #include <sys/syslog.h> 
  43 #include <mach/mach.h> 
  44 #include <mach-o/fat.h> 
  45 #include <mach-o/loader.h>  
  46 #include <mach-o/ldsyms.h>  
  47 #include <libkern/OSByteOrder.h>  
  48 #include <libkern/OSAtomic.h> 
  49 #include <mach/mach.h> 
  50 #include <sys/sysctl.h> 
  52 #include <sys/dtrace.h> 
  53 #include <libkern/OSAtomic.h> 
  54 #include <Availability.h> 
  55 #include <System/sys/codesign.h> 
  56 #include <System/sys/csr.h> 
  58 #include <os/lock_private.h> 
  59 #include <System/machine/cpu_capabilities.h> 
  60 #include <System/sys/reason.h> 
  61 #include <kern/kcdata.h> 
  63 #include <sandbox/private.h> 
  65 extern "C" int __fork(); 
  71 #ifndef CPU_SUBTYPE_ARM_V5TEJ 
  72         #define CPU_SUBTYPE_ARM_V5TEJ           ((cpu_subtype_t) 7) 
  74 #ifndef CPU_SUBTYPE_ARM_XSCALE 
  75         #define CPU_SUBTYPE_ARM_XSCALE          ((cpu_subtype_t) 8) 
  77 #ifndef CPU_SUBTYPE_ARM_V7 
  78         #define CPU_SUBTYPE_ARM_V7                      ((cpu_subtype_t) 9) 
  80 #ifndef CPU_SUBTYPE_ARM_V7F 
  81         #define CPU_SUBTYPE_ARM_V7F                     ((cpu_subtype_t) 10) 
  83 #ifndef CPU_SUBTYPE_ARM_V7S 
  84         #define CPU_SUBTYPE_ARM_V7S                     ((cpu_subtype_t) 11) 
  86 #ifndef CPU_SUBTYPE_ARM_V7K 
  87         #define CPU_SUBTYPE_ARM_V7K                     ((cpu_subtype_t) 12) 
  89 #ifndef LC_DYLD_ENVIRONMENT 
  90         #define LC_DYLD_ENVIRONMENT                     0x27 
  93 #ifndef CPU_SUBTYPE_X86_64_H 
  94         #define CPU_SUBTYPE_X86_64_H            ((cpu_subtype_t) 8)  
  97 #ifndef CPU_SUBTYPE_ARM64_E 
  98         #define CPU_SUBTYPE_ARM64_E    2 
 101 #ifndef VM_PROT_SLIDE    
 102     #define VM_PROT_SLIDE 0x20 
 105 #include "mach-o/dyld_gdb.h" 
 108 #include "ImageLoader.h" 
 109 #include "ImageLoaderMachO.h" 
 110 #include "dyldLibSystemInterface.h" 
 111 #include "dyld_cache_format.h" 
 112 #include "dyld_process_info_internal.h" 
 113 #include <coreSymbolicationDyldSupport.h> 
 114 #if TARGET_IPHONE_SIMULATOR 
 115         extern "C" void xcoresymbolication_load_notifier(void *connection
, uint64_t load_timestamp
, const char *image_path
, const struct mach_header 
*mach_header
); 
 116         extern "C" void xcoresymbolication_unload_notifier(void *connection
, uint64_t unload_timestamp
, const char *image_path
, const struct mach_header 
*mach_header
); 
 117         #define coresymbolication_load_notifier(c, t, p, h) xcoresymbolication_load_notifier(c, t, p, h) 
 118         #define coresymbolication_unload_notifier(c, t, p, h) xcoresymbolication_unload_notifier(c, t, p, h) 
 121 #if SUPPORT_ACCELERATE_TABLES 
 122         #include "ImageLoaderMegaDylib.h" 
 125 #if TARGET_IPHONE_SIMULATOR 
 126         extern "C" void* gSyscallHelpers
; 
 128         #include "dyldSyscallInterface.h" 
 131 #include "LaunchCache.h" 
 132 #include "libdyldEntryVector.h" 
 133 #include "MachOParser.h" 
 135 #include "DyldSharedCache.h" 
 136 #include "SharedCacheRuntime.h" 
 137 #include "StringUtils.h" 
 139 #include "DyldCacheParser.h" 
 142     #include "closuredProtocol.h" 
 146 // not libc header for send() syscall interface 
 147 extern "C" ssize_t 
__sendto(int, const void *, size_t, int, const struct sockaddr 
*, socklen_t
); 
 150 // ARM and x86_64 are the only architecture that use cpu-sub-types 
 151 #define CPU_SUBTYPES_SUPPORTED  ((__arm__ || __arm64__ || __x86_64__) && !TARGET_IPHONE_SIMULATOR) 
 154         #define LC_SEGMENT_COMMAND              LC_SEGMENT_64 
 155         #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT 
 156         #define LC_ENCRYPT_COMMAND              LC_ENCRYPTION_INFO 
 157         #define macho_segment_command   segment_command_64 
 158         #define macho_section                   section_64 
 160         #define LC_SEGMENT_COMMAND              LC_SEGMENT 
 161         #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64 
 162         #define LC_ENCRYPT_COMMAND              LC_ENCRYPTION_INFO_64 
 163         #define macho_segment_command   segment_command 
 164         #define macho_section                   section 
 169 #define CPU_TYPE_MASK 0x00FFFFFF        /* complement of CPU_ARCH_MASK */ 
 172 /* implemented in dyld_gdb.cpp */ 
 173 extern void resetAllImages(); 
 174 extern void addImagesToAllImages(uint32_t infoCount
, const dyld_image_info info
[]); 
 175 extern void removeImageFromAllImages(const mach_header
* mh
); 
 176 extern void addNonSharedCacheImageUUID(const dyld_uuid_info
& info
); 
 177 extern const char* notifyGDB(enum dyld_image_states state
, uint32_t infoCount
, const dyld_image_info info
[]); 
 178 extern size_t allImagesCount(); 
 180 // magic so CrashReporter logs message 
 182         char error_string
[1024]; 
 185 // magic linker symbol for start of dyld binary 
 186 extern "C" const macho_header __dso_handle
; 
 190 // The file contains the core of dyld used to get a process to main().   
 191 // The API's that dyld supports are implemented in dyldAPIs.cpp. 
 198         struct RegisteredDOF 
{ const mach_header
* mh
; int registrationID
; }; 
 199         struct DylibOverride 
{ const char* installName
; const char* override
; }; 
 203 VECTOR_NEVER_DESTRUCTED(ImageLoader
*); 
 204 VECTOR_NEVER_DESTRUCTED(dyld::RegisteredDOF
); 
 205 VECTOR_NEVER_DESTRUCTED(dyld::ImageCallback
); 
 206 VECTOR_NEVER_DESTRUCTED(dyld::DylibOverride
); 
 207 VECTOR_NEVER_DESTRUCTED(ImageLoader::DynamicReference
); 
 209 VECTOR_NEVER_DESTRUCTED(dyld_image_state_change_handler
); 
 215 // state of all environment variables dyld uses 
 217 struct EnvironmentVariables 
{ 
 218         const char* const *                     DYLD_FRAMEWORK_PATH
; 
 219         const char* const *                     DYLD_FALLBACK_FRAMEWORK_PATH
; 
 220         const char* const *                     DYLD_LIBRARY_PATH
; 
 221         const char* const *                     DYLD_FALLBACK_LIBRARY_PATH
; 
 222         const char* const *                     DYLD_INSERT_LIBRARIES
; 
 223         const char* const *                     LD_LIBRARY_PATH
;                        // for unix conformance 
 224         const char* const *                     DYLD_VERSIONED_LIBRARY_PATH
; 
 225         const char* const *                     DYLD_VERSIONED_FRAMEWORK_PATH
; 
 226         bool                                            DYLD_PRINT_LIBRARIES_POST_LAUNCH
; 
 227         bool                                            DYLD_BIND_AT_LAUNCH
; 
 228         bool                                            DYLD_PRINT_STATISTICS
; 
 229         bool                                            DYLD_PRINT_STATISTICS_DETAILS
; 
 230         bool                                            DYLD_PRINT_OPTS
; 
 232         bool                                            DYLD_DISABLE_DOFS
; 
 233         bool                                            DYLD_PRINT_CS_NOTIFICATIONS
; 
 234                             //  DYLD_SHARED_CACHE_DIR           ==> sSharedCacheOverrideDir 
 235                                                         //      DYLD_ROOT_PATH                                  ==> gLinkContext.rootPaths 
 236                                                         //      DYLD_IMAGE_SUFFIX                               ==> gLinkContext.imageSuffix 
 237                                                         //      DYLD_PRINT_OPTS                                 ==> gLinkContext.verboseOpts 
 238                                                         //      DYLD_PRINT_ENV                                  ==> gLinkContext.verboseEnv 
 239                                                         //      DYLD_FORCE_FLAT_NAMESPACE               ==> gLinkContext.bindFlat 
 240                                                         //      DYLD_PRINT_INITIALIZERS                 ==> gLinkContext.verboseInit 
 241                                                         //      DYLD_PRINT_SEGMENTS                             ==> gLinkContext.verboseMapping 
 242                                                         //      DYLD_PRINT_BINDINGS                             ==> gLinkContext.verboseBind 
 243                                                         //  DYLD_PRINT_WEAK_BINDINGS            ==> gLinkContext.verboseWeakBind 
 244                                                         //      DYLD_PRINT_REBASINGS                    ==> gLinkContext.verboseRebase 
 245                                                         //      DYLD_PRINT_DOFS                                 ==> gLinkContext.verboseDOF 
 246                                                         //      DYLD_PRINT_APIS                                 ==> gLogAPIs 
 247                                                         //      DYLD_IGNORE_PREBINDING                  ==> gLinkContext.prebindUsage 
 248                                                         //      DYLD_PREBIND_DEBUG                              ==> gLinkContext.verbosePrebinding 
 249                                                         //      DYLD_NEW_LOCAL_SHARED_REGIONS   ==> gLinkContext.sharedRegionMode 
 250                                                         //      DYLD_SHARED_REGION                              ==> gLinkContext.sharedRegionMode 
 251                                                         //      DYLD_PRINT_WARNINGS                             ==> gLinkContext.verboseWarnings 
 252                                                         //      DYLD_PRINT_RPATHS                               ==> gLinkContext.verboseRPaths 
 253                                                         //      DYLD_PRINT_INTERPOSING                  ==> gLinkContext.verboseInterposing 
 254                                                         //  DYLD_PRINT_LIBRARIES                        ==> gLinkContext.verboseLoading 
 259 typedef std::vector
<dyld_image_state_change_handler
> StateHandlers
; 
 262 enum EnvVarMode 
{ envNone
, envPrintOnly
, envAll 
}; 
 265 static const char*                                      sExecPath 
= NULL
; 
 266 static const char*                                      sExecShortName 
= NULL
; 
 267 static const macho_header
*                      sMainExecutableMachHeader 
= NULL
; 
 268 static uintptr_t                                        sMainExecutableSlide 
= 0; 
 269 #if CPU_SUBTYPES_SUPPORTED 
 270 static cpu_type_t                                       sHostCPU
; 
 271 static cpu_subtype_t                            sHostCPUsubtype
; 
 273 static ImageLoaderMachO
*                        sMainExecutable 
= NULL
; 
 274 static EnvVarMode                                       sEnvMode 
= envNone
; 
 275 static size_t                                           sInsertedDylibCount 
= 0; 
 276 static std::vector
<ImageLoader
*>        sAllImages
; 
 277 static std::vector
<ImageLoader
*>        sImageRoots
; 
 278 static std::vector
<ImageLoader
*>        sImageFilesNeedingTermination
; 
 279 static std::vector
<RegisteredDOF
>       sImageFilesNeedingDOFUnregistration
; 
 280 static std::vector
<ImageCallback
>   sAddImageCallbacks
; 
 281 static std::vector
<ImageCallback
>   sRemoveImageCallbacks
; 
 282 static bool                                                     sRemoveImageCallbacksInUse 
= false; 
 283 static void*                                            sSingleHandlers
[7][3]; 
 284 static void*                                            sBatchHandlers
[7][3]; 
 285 static ImageLoader
*                                     sLastImageByAddressCache
; 
 286 static EnvironmentVariables                     sEnv
; 
 287 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
 288 static const char*                                      sFrameworkFallbackPaths
[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL 
}; 
 289 static const char*                                      sLibraryFallbackPaths
[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL 
}; 
 290 static const char*                                      sRestrictedFrameworkFallbackPaths
[] = { "/System/Library/Frameworks", NULL 
}; 
 291 static const char*                                      sRestrictedLibraryFallbackPaths
[] = { "/usr/lib", NULL 
}; 
 293 static const char*                                      sFrameworkFallbackPaths
[] = { "/System/Library/Frameworks", NULL 
}; 
 294 static const char*                                      sLibraryFallbackPaths
[] = { "/usr/local/lib", "/usr/lib", NULL 
}; 
 296 static UndefinedHandler                         sUndefinedHandler 
= NULL
; 
 297 static ImageLoader
*                                     sBundleBeingLoaded 
= NULL
;      // hack until OFI is reworked 
 298 static dyld3::SharedCacheLoadInfo       sSharedCacheLoadInfo
; 
 299 static const char*                                      sSharedCacheOverrideDir
; 
 300        bool                                                     gSharedCacheOverridden 
= false; 
 301 ImageLoader::LinkContext                        gLinkContext
; 
 302 bool                                                            gLogAPIs 
= false; 
 303 #if SUPPORT_ACCELERATE_TABLES 
 304 bool                                                            gLogAppAPIs 
= false; 
 306 const struct LibSystemHelpers
*          gLibSystemHelpers 
= NULL
; 
 307 #if SUPPORT_OLD_CRT_INITIALIZATION 
 308 bool                                                            gRunInitializersOldWay 
= false; 
 310 static std::vector
<DylibOverride
>       sDylibOverrides
; 
 311 #if !TARGET_IPHONE_SIMULATOR     
 312 static int                                                      sLogSocket 
= -1; 
 314 static bool                                                     sFrameworksFoundAsDylibs 
= false; 
 315 #if __x86_64__ && !TARGET_IPHONE_SIMULATOR 
 316 static bool                                                     sHaswell 
= false; 
 318 static std::vector
<ImageLoader::DynamicReference
> sDynamicReferences
; 
 319 static OSSpinLock                                       sDynamicReferencesLock 
= 0; 
 320 #if !TARGET_IPHONE_SIMULATOR 
 321 static bool                                                     sLogToFile 
= false; 
 323 static char                                                     sLoadingCrashMessage
[1024] = "dyld: launch, loading dependent libraries"; 
 324 static bool                                                     sSafeMode 
= false; 
 325 static _dyld_objc_notify_mapped         sNotifyObjCMapped
; 
 326 static _dyld_objc_notify_init           sNotifyObjCInit
; 
 327 static _dyld_objc_notify_unmapped       sNotifyObjCUnmapped
; 
 329 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR 
 330 static bool                                                     sForceStderr 
= false; 
 334 #if SUPPORT_ACCELERATE_TABLES 
 335 static ImageLoaderMegaDylib
*            sAllCacheImagesProxy 
= NULL
; 
 336 static bool                                                     sDisableAcceleratorTables 
= false; 
 339 bool                                                            gUseDyld3 
= false; 
 340 static bool                                                     sSkipMain 
= false; 
 341 static bool                                                     sEnableClosures 
= false; 
 344 // The MappedRanges structure is used for fast address->image lookups. 
 345 // The table is only updated when the dyld lock is held, so we don't 
 346 // need to worry about multiple writers.  But readers may look at this 
 347 // data without holding the lock. Therefore, all updates must be done 
 348 // in an order that will never cause readers to see inconsistent data. 
 349 // The general rule is that if the image field is non-NULL then 
 350 // the other fields are valid. 
 363 static MappedRanges
*    sMappedRangesStart
; 
 365 void addMappedRange(ImageLoader
* image
, uintptr_t start
, uintptr_t end
) 
 367         //dyld::log("addMappedRange(0x%lX->0x%lX) for %s\n", start, end, image->getShortName()); 
 368         for (MappedRanges
* p 
= sMappedRangesStart
; p 
!= NULL
; p 
= p
->next
) { 
 369                 for (unsigned long i
=0; i 
< p
->count
; ++i
) { 
 370                         if ( p
->array
[i
].image 
== NULL 
) { 
 371                                 p
->array
[i
].start 
= start
; 
 372                                 p
->array
[i
].end 
= end
; 
 373                                 // add image field last with a barrier so that any reader will see consistent records 
 375                                 p
->array
[i
].image 
= image
; 
 380         // table must be full, chain another 
 381 #if SUPPORT_ACCELERATE_TABLES 
 382         unsigned count 
= (sAllCacheImagesProxy 
!= NULL
) ? 16 : 400; 
 384         unsigned count 
= 400; 
 386         size_t allocationSize 
= sizeof(MappedRanges
) + (count
-1)*3*sizeof(void*); 
 387         MappedRanges
* newRanges 
= (MappedRanges
*)malloc(allocationSize
); 
 388         bzero(newRanges
, allocationSize
); 
 389         newRanges
->count 
= count
; 
 390         newRanges
->array
[0].start 
= start
; 
 391         newRanges
->array
[0].end 
= end
; 
 392         newRanges
->array
[0].image 
= image
; 
 394         if ( sMappedRangesStart 
== NULL 
) { 
 395                 sMappedRangesStart 
= newRanges
; 
 398                 for (MappedRanges
* p 
= sMappedRangesStart
; p 
!= NULL
; p 
= p
->next
) { 
 399                         if ( p
->next 
== NULL 
) { 
 408 void removedMappedRanges(ImageLoader
* image
) 
 410         for (MappedRanges
* p 
= sMappedRangesStart
; p 
!= NULL
; p 
= p
->next
) { 
 411                 for (unsigned long i
=0; i 
< p
->count
; ++i
) { 
 412                         if ( p
->array
[i
].image 
== image 
) { 
 413                                 // clear with a barrier so that any reader will see consistent records 
 415                                 p
->array
[i
].image 
= NULL
; 
 421 ImageLoader
* findMappedRange(uintptr_t target
) 
 423         for (MappedRanges
* p 
= sMappedRangesStart
; p 
!= NULL
; p 
= p
->next
) { 
 424                 for (unsigned long i
=0; i 
< p
->count
; ++i
) { 
 425                         if ( p
->array
[i
].image 
!= NULL 
) { 
 426                                 if ( (p
->array
[i
].start 
<= target
) && (target 
< p
->array
[i
].end
) ) 
 427                                         return p
->array
[i
].image
; 
 436 const char* mkstringf(const char* format
, ...) 
 438         _SIMPLE_STRING buf 
= _simple_salloc(); 
 441                 va_start(list
, format
); 
 442                 _simple_vsprintf(buf
, format
, list
); 
 444                 const char*     t 
= strdup(_simple_string(buf
)); 
 449         return "mkstringf, out of memory error"; 
 453 void throwf(const char* format
, ...)  
 455         _SIMPLE_STRING buf 
= _simple_salloc(); 
 458                 va_start(list
, format
); 
 459                 _simple_vsprintf(buf
, format
, list
); 
 461                 const char*     t 
= strdup(_simple_string(buf
)); 
 466         throw "throwf, out of memory error"; 
 470 #if !TARGET_IPHONE_SIMULATOR 
 471 static int sLogfile 
= STDERR_FILENO
; 
 474 #if !TARGET_IPHONE_SIMULATOR     
 475 // based on CFUtilities.c: also_do_stderr() 
 476 static bool useSyslog() 
 478         // Use syslog() for processes managed by launchd 
 479         static bool launchdChecked 
= false; 
 480         static bool launchdOwned 
= false; 
 481         if ( !launchdChecked 
&& gProcessInfo
->libSystemInitialized 
) { 
 482                 if ( (gLibSystemHelpers 
!= NULL
) && (gLibSystemHelpers
->version 
>= 11) ) { 
 483                         // <rdar://problem/23520449> only call isLaunchdOwned() after libSystem is initialized 
 484                         launchdOwned 
= (*gLibSystemHelpers
->isLaunchdOwned
)(); 
 485                         launchdChecked 
= true; 
 488         if ( launchdChecked 
&& launchdOwned 
) 
 491         // If stderr is not available, use syslog() 
 493         int result 
= fstat(STDERR_FILENO
, &sb
); 
 495                 return true; // file descriptor 2 is closed 
 501 static void socket_syslogv(int priority
, const char* format
, va_list list
) 
 503         // lazily create socket and connection to syslogd 
 504         if ( sLogSocket 
== -1 ) { 
 505                 sLogSocket 
= ::socket(AF_UNIX
, SOCK_DGRAM
, 0); 
 506                 if (sLogSocket 
== -1) 
 507                         return;  // cannot log 
 508                 ::fcntl(sLogSocket
, F_SETFD
, 1); 
 510                 struct sockaddr_un addr
; 
 511                 addr
.sun_family 
= AF_UNIX
; 
 512                 strncpy(addr
.sun_path
, _PATH_LOG
, sizeof(addr
.sun_path
)); 
 513                 if ( ::connect(sLogSocket
, (struct sockaddr 
*)&addr
, sizeof(addr
)) == -1 ) { 
 520         // format message to syslogd like: "<priority>Process[pid]: message" 
 521         _SIMPLE_STRING buf 
= _simple_salloc(); 
 524         if ( _simple_sprintf(buf
, "<%d>%s[%d]: ", LOG_USER
|LOG_NOTICE
, sExecShortName
, getpid()) == 0 ) { 
 525                 if ( _simple_vsprintf(buf
, format
, list
) == 0 ) { 
 526                         const char* p 
= _simple_string(buf
); 
 527                         ::__sendto(sLogSocket
, p
, strlen(p
), 0, NULL
, 0); 
 535 void vlog(const char* format
, va_list list
) 
 537 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR 
 538         // <rdar://problem/25965832> log to console when running iOS app from Xcode 
 539         if ( !sLogToFile 
&& !sForceStderr 
&& useSyslog() ) 
 541         if ( !sLogToFile 
&& useSyslog() ) 
 543                 socket_syslogv(LOG_ERR
, format
, list
); 
 545                 _simple_vdprintf(sLogfile
, format
, list
); 
 549 void log(const char* format
, ...) 
 552         va_start(list
, format
); 
 558 void vwarn(const char* format
, va_list list
)  
 560         _simple_dprintf(sLogfile
, "dyld: warning, "); 
 561         _simple_vdprintf(sLogfile
, format
, list
); 
 564 void warn(const char* format
, ...)  
 567         va_start(list
, format
); 
 573         extern void vlog(const char* format
, va_list list
); 
 574 #endif // !TARGET_IPHONE_SIMULATOR       
 577 // <rdar://problem/8867781> control access to sAllImages through a lock  
 578 // because global dyld lock is not held during initialization phase of dlopen() 
 579 // <rdar://problem/16145518> Use OSSpinLockLock to allow yielding 
 580 static OSSpinLock sAllImagesLock 
= 0; 
 582 static void allImagesLock() 
 584         OSSpinLockLock(&sAllImagesLock
); 
 587 static void allImagesUnlock() 
 589         OSSpinLockUnlock(&sAllImagesLock
); 
 593 // utility class to assure files are closed when an exception is thrown 
 596         FileOpener(const char* path
); 
 598         int getFileDescriptor() { return fd
; } 
 603 FileOpener::FileOpener(const char* path
) 
 606         fd 
= my_open(path
, O_RDONLY
, 0); 
 609 FileOpener::~FileOpener() 
 616 static void     registerDOFs(const std::vector
<ImageLoader::DOFInfo
>& dofs
) 
 618         const size_t dofSectionCount 
= dofs
.size(); 
 619         if ( !sEnv
.DYLD_DISABLE_DOFS 
&& (dofSectionCount 
!= 0) ) { 
 620                 int fd 
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
); 
 622                         //dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n"); 
 625                         // allocate a buffer on the stack for the variable length dof_ioctl_data_t type 
 626                         uint8_t buffer
[sizeof(dof_ioctl_data_t
) + dofSectionCount
*sizeof(dof_helper_t
)]; 
 627                         dof_ioctl_data_t
* ioctlData 
= (dof_ioctl_data_t
*)buffer
; 
 629                         // fill in buffer with one dof_helper_t per DOF section 
 630                         ioctlData
->dofiod_count 
= dofSectionCount
; 
 631                         for (unsigned int i
=0; i 
< dofSectionCount
; ++i
) { 
 632                                 strlcpy(ioctlData
->dofiod_helpers
[i
].dofhp_mod
, dofs
[i
].imageShortName
, DTRACE_MODNAMELEN
); 
 633                                 ioctlData
->dofiod_helpers
[i
].dofhp_dof 
= (uintptr_t)(dofs
[i
].dof
); 
 634                                 ioctlData
->dofiod_helpers
[i
].dofhp_addr 
= (uintptr_t)(dofs
[i
].dof
); 
 637                         // tell kernel about all DOF sections en mas 
 638                         // pass pointer to ioctlData because ioctl() only copies a fixed size amount of data into kernel 
 639                         user_addr_t val 
= (user_addr_t
)(unsigned long)ioctlData
; 
 640                         if ( ioctl(fd
, DTRACEHIOC_ADDDOF
, &val
) != -1 ) { 
 641                                 // kernel returns a unique identifier for each section in the dofiod_helpers[].dofhp_dof field. 
 642                                 for (unsigned int i
=0; i 
< dofSectionCount
; ++i
) { 
 644                                         info
.mh 
= dofs
[i
].imageHeader
; 
 645                                         info
.registrationID 
= (int)(ioctlData
->dofiod_helpers
[i
].dofhp_dof
); 
 646                                         sImageFilesNeedingDOFUnregistration
.push_back(info
); 
 647                                         if ( gLinkContext
.verboseDOF 
) { 
 648                                                 dyld::log("dyld: registering DOF section %p in %s with dtrace, ID=0x%08X\n",  
 649                                                         dofs
[i
].dof
, dofs
[i
].imageShortName
, info
.registrationID
); 
 654                                 //dyld::log( "dyld: ioctl to register dtrace DOF section failed\n"); 
 661 static void     unregisterDOF(int registrationID
) 
 663         int fd 
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
); 
 665                 dyld::warn("can't open /dev/" DTRACEMNR_HELPER 
" to unregister dtrace DOF section\n"); 
 668                 ioctl(fd
, DTRACEHIOC_REMOVE
, registrationID
); 
 670                 if ( gLinkContext
.verboseInit 
) 
 671                         dyld::warn("unregistering DOF section ID=0x%08X with dtrace\n", registrationID
); 
 677 // _dyld_register_func_for_add_image() is implemented as part of the general image state change notification 
 679 static void notifyAddImageCallbacks(ImageLoader
* image
) 
 681         // use guard so that we cannot notify about the same image twice 
 682         if ( ! image
->addFuncNotified() ) { 
 683                 for (std::vector
<ImageCallback
>::iterator it
=sAddImageCallbacks
.begin(); it 
!= sAddImageCallbacks
.end(); it
++) 
 684                         (*it
)(image
->machHeader(), image
->getSlide()); 
 685                 image
->setAddFuncNotified(); 
 691 // notify gdb about these new images 
 692 static const char* updateAllImages(enum dyld_image_states state
, uint32_t infoCount
, const struct dyld_image_info info
[]) 
 694         // <rdar://problem/8812589> don't add images without paths to all-image-info-list 
 695         if ( info
[0].imageFilePath 
!= NULL 
) 
 696                 addImagesToAllImages(infoCount
, info
); 
 701 static StateHandlers
* stateToHandlers(dyld_image_states state
, void* handlersArray
[7][3]) 
 704                 case dyld_image_state_mapped
: 
 705                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[0]); 
 707                 case dyld_image_state_dependents_mapped
: 
 708                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[1]); 
 710                 case dyld_image_state_rebased
: 
 711                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[2]); 
 713                 case dyld_image_state_bound
: 
 714                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[3]); 
 716                 case dyld_image_state_dependents_initialized
: 
 717                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[4]); 
 719                 case dyld_image_state_initialized
: 
 720                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[5]); 
 722                 case dyld_image_state_terminated
: 
 723                         return reinterpret_cast<StateHandlers
*>(&handlersArray
[6]); 
 728 #if SUPPORT_ACCELERATE_TABLES 
 729 static dyld_image_state_change_handler 
getPreInitNotifyHandler(unsigned index
) 
 731         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(dyld_image_state_dependents_initialized
, sSingleHandlers
); 
 732         if ( index 
>= handlers
->size() ) 
 734         return (*handlers
)[index
]; 
 737 static dyld_image_state_change_handler 
getBoundBatchHandler(unsigned index
) 
 739         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(dyld_image_state_bound
, sBatchHandlers
); 
 740         if ( index 
>= handlers
->size() ) 
 742         return (*handlers
)[index
]; 
 745 static void notifySingleFromCache(dyld_image_states state
, const mach_header
* mh
, const char* path
) 
 747         //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath()); 
 748         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sSingleHandlers
); 
 749         if ( handlers 
!= NULL 
) { 
 750                 dyld_image_info info
; 
 751                 info
.imageLoadAddress   
= mh
; 
 752                 info
.imageFilePath              
= path
; 
 753                 info
.imageFileModDate   
= 0; 
 754                 for (dyld_image_state_change_handler handler 
: *handlers
) { 
 755                         const char* result 
= (*handler
)(state
, 1, &info
); 
 756                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_mapped
) ) { 
 757                                 //fprintf(stderr, "  image rejected by handler=%p\n", *it); 
 758                                 // make copy of thrown string so that later catch clauses can free it 
 759                                 const char* str 
= strdup(result
); 
 764         if ( (state 
== dyld_image_state_dependents_initialized
) && (sNotifyObjCInit 
!= NULL
) && (mh
->flags 
& MH_HAS_OBJC
) ) { 
 765                 (*sNotifyObjCInit
)(path
, mh
); 
 770 static mach_port_t sNotifyReplyPorts
[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
]; 
 771 static bool        sZombieNotifiers
[DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
]; 
 773 static void notifyMonitoringDyld(bool unloading
, unsigned portSlot
, unsigned imageCount
, const dyld_image_info infos
[]) 
 775         if ( sZombieNotifiers
[portSlot
] ) 
 778         unsigned entriesSize 
= imageCount
*sizeof(dyld_process_info_image_entry
); 
 779         unsigned pathsSize 
= 0; 
 780         for (unsigned j
=0; j 
< imageCount
; ++j
) { 
 781                 pathsSize 
+= (strlen(infos
[j
].imageFilePath
) + 1); 
 783         unsigned totalSize 
= (sizeof(dyld_process_info_notify_header
) + MAX_TRAILER_SIZE 
+ entriesSize 
+ pathsSize 
+ 127) & -128;   // align 
 784         if ( totalSize 
> DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE 
) { 
 785                 // Putting all image paths into one message would make buffer too big. 
 786                 // Instead split into two messages.  Recurse as needed until paths fit in buffer. 
 787                 unsigned imageHalfCount 
= imageCount
/2; 
 788                 notifyMonitoringDyld(unloading
, portSlot
, imageHalfCount
, infos
); 
 789                 notifyMonitoringDyld(unloading
, portSlot
, imageCount 
- imageHalfCount
, &infos
[imageHalfCount
]); 
 792         uint8_t buffer
[totalSize
]; 
 793         dyld_process_info_notify_header
* header 
= (dyld_process_info_notify_header
*)buffer
; 
 795         header
->imageCount              
= imageCount
; 
 796         header
->imagesOffset    
= sizeof(dyld_process_info_notify_header
); 
 797         header
->stringsOffset   
= sizeof(dyld_process_info_notify_header
) + entriesSize
; 
 798         header
->timestamp               
= dyld::gProcessInfo
->infoArrayChangeTimestamp
; 
 799         dyld_process_info_image_entry
* entries 
= (dyld_process_info_image_entry
*)&buffer
[header
->imagesOffset
]; 
 800         char* const pathPoolStart 
= (char*)&buffer
[header
->stringsOffset
]; 
 801         char* pathPool 
= pathPoolStart
; 
 802         for (unsigned j
=0; j 
< imageCount
; ++j
) { 
 803                 strcpy(pathPool
, infos
[j
].imageFilePath
); 
 804                 uint32_t len 
= (uint32_t)strlen(pathPool
); 
 805                 bzero(entries
->uuid
, 16); 
 806                 const ImageLoader
* image 
= findImageByMachHeader(infos
[j
].imageLoadAddress
); 
 807                 if ( image 
!= NULL 
) { 
 808                         image
->getUUID(entries
->uuid
); 
 810 #if SUPPORT_ACCELERATE_TABLES 
 811                 else if ( sAllCacheImagesProxy 
!= NULL 
) { 
 812                         const mach_header
* mh
; 
 815                         if ( sAllCacheImagesProxy
->addressInCache(infos
[j
].imageLoadAddress
, &mh
, &path
, &index
) ) { 
 816                                 sAllCacheImagesProxy
->getDylibUUID(index
, entries
->uuid
); 
 820                 entries
->loadAddress 
= (uint64_t)infos
[j
].imageLoadAddress
; 
 821                 entries
->pathStringOffset 
= (uint32_t)(pathPool 
- pathPoolStart
); 
 822                 entries
->pathLength  
= len
; 
 823                 pathPool 
+= (len 
+1); 
 827         if ( sNotifyReplyPorts
[portSlot
] == 0 ) { 
 828                 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[portSlot
]) ) 
 829                         mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[portSlot
], sNotifyReplyPorts
[portSlot
], MACH_MSG_TYPE_MAKE_SEND
); 
 830                 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[portSlot]); 
 832         //dyld::log("found port to send to\n"); 
 833         mach_msg_header_t
* h 
= (mach_msg_header_t
*)buffer
; 
 834         h
->msgh_bits            
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE 
 835         h
->msgh_id                      
= unloading 
? DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID 
: DYLD_PROCESS_INFO_NOTIFY_LOAD_ID
; 
 836         h
->msgh_local_port      
= sNotifyReplyPorts
[portSlot
]; 
 837         h
->msgh_remote_port 
= dyld::gProcessInfo
->notifyPorts
[portSlot
]; 
 838         h
->msgh_reserved        
= 0; 
 839         h
->msgh_size            
= (mach_msg_size_t
)sizeof(buffer
); 
 840         //dyld::log("sending to port[%d]=%d, size=%d, reply port=%d, id=0x%X\n", portSlot, dyld::gProcessInfo->notifyPorts[portSlot], h->msgh_size, sNotifyReplyPorts[portSlot], h->msgh_id); 
 841         kern_return_t sendResult 
= mach_msg(h
, MACH_SEND_MSG 
| MACH_RCV_MSG 
| MACH_RCV_TIMEOUT
, h
->msgh_size
, h
->msgh_size
, sNotifyReplyPorts
[portSlot
], 5000, MACH_PORT_NULL
); 
 842         //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size); 
 843         if ( sendResult 
== MACH_SEND_INVALID_DEST 
) { 
 844                 // sender is not responding, detatch 
 845                 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", dyld::gProcessInfo->notifyPorts[portSlot], sNotifyReplyPorts[portSlot]); 
 846                 mach_port_deallocate(mach_task_self(), dyld::gProcessInfo
->notifyPorts
[portSlot
]); 
 847                 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]); 
 848                 dyld::gProcessInfo
->notifyPorts
[portSlot
] = 0; 
 849                 sNotifyReplyPorts
[portSlot
] = 0; 
 851         else if ( sendResult 
== MACH_RCV_TIMED_OUT 
) { 
 852                 // client took too long, ignore him from now on 
 853                 sZombieNotifiers
[portSlot
] = true; 
 854                 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]); 
 855                 sNotifyReplyPorts
[portSlot
] = 0; 
 859 static void notifyMonitoringDyldMain() 
 861         for (int slot
=0; slot 
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) { 
 862                 if ( (dyld::gProcessInfo
->notifyPorts
[slot
] != 0 ) && !sZombieNotifiers
[slot
] ) { 
 863                         if ( sNotifyReplyPorts
[slot
] == 0 ) { 
 864                                 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[slot
]) ) 
 865                                         mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[slot
], sNotifyReplyPorts
[slot
], MACH_MSG_TYPE_MAKE_SEND
); 
 866                                 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[slot]); 
 868                         //dyld::log("found port to send to\n"); 
 869                         uint8_t messageBuffer
[sizeof(mach_msg_header_t
) + MAX_TRAILER_SIZE
]; 
 870                         mach_msg_header_t
* h 
= (mach_msg_header_t
*)messageBuffer
; 
 871                         h
->msgh_bits            
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE 
 872                         h
->msgh_id              
= DYLD_PROCESS_INFO_NOTIFY_MAIN_ID
; 
 873                         h
->msgh_local_port      
= sNotifyReplyPorts
[slot
]; 
 874                         h
->msgh_remote_port     
= dyld::gProcessInfo
->notifyPorts
[slot
]; 
 875                         h
->msgh_reserved        
= 0; 
 876                         h
->msgh_size            
= (mach_msg_size_t
)sizeof(messageBuffer
); 
 877                         //dyld::log("sending to port[%d]=%d, size=%d, reply port=%d, id=0x%X\n", slot, dyld::gProcessInfo->notifyPorts[slot], h->msgh_size, sNotifyReplyPorts[slot], h->msgh_id); 
 878                         kern_return_t sendResult 
= mach_msg(h
, MACH_SEND_MSG 
| MACH_RCV_MSG 
| MACH_RCV_TIMEOUT
, h
->msgh_size
, h
->msgh_size
, sNotifyReplyPorts
[slot
], 5000, MACH_PORT_NULL
); 
 879                         //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size); 
 880                         if ( sendResult 
== MACH_SEND_INVALID_DEST 
) { 
 881                                 // sender is not responding, detatch 
 882                                 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", dyld::gProcessInfo->notifyPorts[slot], sNotifyReplyPorts[slot]); 
 883                                 mach_port_deallocate(mach_task_self(), dyld::gProcessInfo
->notifyPorts
[slot
]); 
 884                                 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]); 
 885                                 dyld::gProcessInfo
->notifyPorts
[slot
] = 0; 
 886                                 sNotifyReplyPorts
[slot
] = 0; 
 888                         else if ( sendResult 
== MACH_RCV_TIMED_OUT 
) { 
 889                                 // client took too long, ignore him from now on 
 890                                 sZombieNotifiers
[slot
] = true; 
 891                                 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]); 
 892                                 sNotifyReplyPorts
[slot
] = 0; 
 898 void notifyKernel(const ImageLoader
& image
, bool loading
) { 
 899         if ( !image
.inSharedCache() ) { 
 900                 uint32_t baseCode 
= loading 
? DBG_DYLD_UUID_MAP_A 
: DBG_DYLD_UUID_UNMAP_A
; 
 902                 ino_t inode 
= image
.getInode(); 
 904                 dyld3::kdebug_trace_dyld_image(baseCode
, (const uuid_t 
*)&uuid
, *(fsobj_id_t
*)&inode
, {{ image
.getDevice(), 0 }}, image
.machHeader()); 
 908 static void notifySingle(dyld_image_states state
, const ImageLoader
* image
, ImageLoader::InitializerTimingList
* timingInfo
) 
 910         //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath()); 
 911         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sSingleHandlers
); 
 912         if ( handlers 
!= NULL 
) { 
 913                 dyld_image_info info
; 
 914                 info
.imageLoadAddress   
= image
->machHeader(); 
 915                 info
.imageFilePath              
= image
->getRealPath(); 
 916                 info
.imageFileModDate   
= image
->lastModified(); 
 917                 for (std::vector
<dyld_image_state_change_handler
>::iterator it 
= handlers
->begin(); it 
!= handlers
->end(); ++it
) { 
 918                         const char* result 
= (*it
)(state
, 1, &info
); 
 919                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_mapped
) ) { 
 920                                 //fprintf(stderr, "  image rejected by handler=%p\n", *it); 
 921                                 // make copy of thrown string so that later catch clauses can free it 
 922                                 const char* str 
= strdup(result
); 
 927         if ( state 
== dyld_image_state_mapped 
) { 
 928                 // <rdar://problem/7008875> Save load addr + UUID for images from outside the shared cache 
 929                 if ( !image
->inSharedCache() ) { 
 931                         if ( image
->getUUID(info
.imageUUID
) ) { 
 932                                 info
.imageLoadAddress 
= image
->machHeader(); 
 933                                 addNonSharedCacheImageUUID(info
); 
 937         if ( (state 
== dyld_image_state_dependents_initialized
) && (sNotifyObjCInit 
!= NULL
) && image
->notifyObjC() ) { 
 938                 uint64_t t0 
= mach_absolute_time(); 
 939                 (*sNotifyObjCInit
)(image
->getRealPath(), image
->machHeader()); 
 940                 uint64_t t1 
= mach_absolute_time(); 
 941                 uint64_t t2 
= mach_absolute_time(); 
 942                 uint64_t timeInObjC 
= t1
-t0
; 
 943                 uint64_t emptyTime 
= (t2
-t1
)*100; 
 944                 if ( (timeInObjC 
> emptyTime
) && (timingInfo 
!= NULL
) ) { 
 945                         timingInfo
->addTime(image
->getShortName(), timeInObjC
); 
 948     // mach message csdlc about dynamically unloaded images 
 949         if ( image
->addFuncNotified() && (state 
== dyld_image_state_terminated
) ) { 
 950                 notifyKernel(*image
, false); 
 952                 uint64_t loadTimestamp 
= mach_absolute_time(); 
 953                 if ( sEnv
.DYLD_PRINT_CS_NOTIFICATIONS 
) { 
 954                         dyld::log("dyld: coresymbolication_unload_notifier(%p, 0x%016llX, %p, %s)\n", 
 955                                           dyld::gProcessInfo
->coreSymbolicationShmPage
, loadTimestamp
, image
->machHeader(), image
->getPath()); 
 957                 if ( dyld::gProcessInfo
->coreSymbolicationShmPage 
!= NULL
) { 
 958                         coresymbolication_unload_notifier(dyld::gProcessInfo
->coreSymbolicationShmPage
, loadTimestamp
, image
->getPath(), image
->machHeader()); 
 960                 for (int slot
=0; slot 
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) { 
 961                         if ( dyld::gProcessInfo
->notifyPorts
[slot
] != 0 ) { 
 962                                 dyld_image_info info
; 
 963                                 info
.imageLoadAddress   
= image
->machHeader(); 
 964                                 info
.imageFilePath              
= image
->getPath(); 
 965                                 info
.imageFileModDate   
= 0; 
 966                                 notifyMonitoringDyld(true, slot
, 1, &info
); 
 968                         else if ( sNotifyReplyPorts
[slot
] != 0 ) { 
 969                                 // monitoring process detached from this process, so release reply port 
 970                                 //dyld::log("deallocated reply port %d\n", sNotifyReplyPorts[slot]); 
 971                                 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]); 
 972                                 sNotifyReplyPorts
[slot
] = 0; 
 973                                 sZombieNotifiers
[slot
] = false; 
 982 // Normally, dyld_all_image_infos is only updated in batches after an entire 
 983 // graph is loaded.  But if there is an error loading the initial set of 
 984 // dylibs needed by the main executable, dyld_all_image_infos is not yet set  
 985 // up, leading to usually brief crash logs. 
 987 // This function manually adds the images loaded so far to dyld::gProcessInfo. 
 988 // It should only be called before terminating. 
 992         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); ++it
) { 
 993                 dyld_image_info info
; 
 994                 ImageLoader
* image 
= *it
; 
 995                 info
.imageLoadAddress 
= image
->machHeader(); 
 996                 info
.imageFilePath 
= image
->getRealPath(); 
 997                 info
.imageFileModDate 
= image
->lastModified(); 
 998                 // add to all_image_infos if not already there 
1000                 int existingCount 
= dyld::gProcessInfo
->infoArrayCount
; 
1001                 const dyld_image_info
* existing 
= dyld::gProcessInfo
->infoArray
; 
1002                 if ( existing 
!= NULL 
) { 
1003                         for (int i
=0; i 
< existingCount
; ++i
) { 
1004                                 if ( existing
[i
].imageLoadAddress 
== info
.imageLoadAddress 
) { 
1005                                         //dyld::log("not adding %s\n", info.imageFilePath); 
1012                         //dyld::log("adding %s\n", info.imageFilePath); 
1013                         addImagesToAllImages(1, &info
); 
1019 static int imageSorter(const void* l
, const void* r
) 
1021         const ImageLoader
* left 
= *((ImageLoader
**)l
); 
1022         const ImageLoader
* right
= *((ImageLoader
**)r
); 
1023         return left
->compare(right
); 
1026 static void notifyBatchPartial(dyld_image_states state
, bool orLater
, dyld_image_state_change_handler onlyHandler
, bool preflightOnly
, bool onlyObjCMappedNotification
) 
1028         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sBatchHandlers
); 
1029         if ( (handlers 
!= NULL
) || ((state 
== dyld_image_state_bound
) && (sNotifyObjCMapped 
!= NULL
)) ) { 
1030                 // don't use a vector because it will use malloc/free and we want notifcation to be low cost 
1032                 dyld_image_info infos
[allImagesCount()+1]; 
1033         ImageLoader
* images
[allImagesCount()+1]; 
1034         ImageLoader
** end 
= images
; 
1035         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
1036             dyld_image_states imageState 
= (*it
)->getState(); 
1037             if ( (imageState 
== state
) || (orLater 
&& (imageState 
> state
)) ) 
1040                 if ( sBundleBeingLoaded 
!= NULL 
) { 
1041                         dyld_image_states imageState 
= sBundleBeingLoaded
->getState(); 
1042                         if ( (imageState 
== state
) || (orLater 
&& (imageState 
> state
)) ) 
1043                                 *end
++ = sBundleBeingLoaded
; 
1045         const char* dontLoadReason 
= NULL
; 
1046                 uint32_t imageCount 
= (uint32_t)(end
-images
); 
1047                 if ( imageCount 
!= 0 ) { 
1049                         qsort(images
, imageCount
, sizeof(ImageLoader
*), &imageSorter
); 
1051                         for (unsigned int i
=0; i 
< imageCount
; ++i
) { 
1052                                 dyld_image_info
* p 
= &infos
[i
]; 
1053                                 ImageLoader
* image 
= images
[i
]; 
1054                                 //dyld::log("  state=%d, name=%s\n", state, image->getPath()); 
1055                                 p
->imageLoadAddress 
= image
->machHeader(); 
1056                                 p
->imageFilePath    
= image
->getRealPath(); 
1057                                 p
->imageFileModDate 
= image
->lastModified(); 
1058                                 // get these registered with the kernel as early as possible 
1059                                 if ( state 
== dyld_image_state_dependents_mapped
) 
1060                                         notifyKernel(*image
, true); 
1061                                 // special case for add_image hook 
1062                                 if ( state 
== dyld_image_state_bound 
) 
1063                                         notifyAddImageCallbacks(image
); 
1066 #if SUPPORT_ACCELERATE_TABLES 
1067                 if ( sAllCacheImagesProxy 
!= NULL 
) { 
1068                         unsigned cacheCount 
= sAllCacheImagesProxy
->appendImagesToNotify(state
, orLater
, &infos
[imageCount
]); 
1069                         // support _dyld_register_func_for_add_image() 
1070                         if ( state 
== dyld_image_state_bound 
) { 
1071                                 for (ImageCallback callback 
: sAddImageCallbacks
) { 
1072                                         for (unsigned i
=0; i 
< cacheCount
; ++i
) 
1073                                                 (*callback
)(infos
[imageCount
+i
].imageLoadAddress
, sSharedCacheLoadInfo
.slide
); 
1076                         imageCount 
+= cacheCount
; 
1079                 if ( imageCount 
!= 0 ) { 
1080                         if ( !onlyObjCMappedNotification 
) { 
1081                                 if ( onlyHandler 
!= NULL 
) { 
1082                                         const char* result 
= NULL
; 
1083                                         if ( result 
== NULL 
) { 
1084                                                 result 
= (*onlyHandler
)(state
, imageCount
, infos
); 
1086                                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_dependents_mapped
) ) { 
1087                                                 //fprintf(stderr, "  images rejected by handler=%p\n", onlyHandler); 
1088                                                 // make copy of thrown string so that later catch clauses can free it 
1089                                                 dontLoadReason 
= strdup(result
); 
1093                                         // call each handler with whole array 
1094                                         if ( handlers 
!= NULL 
) { 
1095                                                 for (std::vector
<dyld_image_state_change_handler
>::iterator it 
= handlers
->begin(); it 
!= handlers
->end(); ++it
) { 
1096                                                         const char* result 
= (*it
)(state
, imageCount
, infos
); 
1097                                                         if ( (result 
!= NULL
) && (state 
== dyld_image_state_dependents_mapped
) ) { 
1098                                                                 //fprintf(stderr, "  images rejected by handler=%p\n", *it); 
1099                                                                 // make copy of thrown string so that later catch clauses can free it 
1100                                                                 dontLoadReason 
= strdup(result
); 
1107                         // tell objc about new images 
1108                         if ( (onlyHandler 
== NULL
) && ((state 
== dyld_image_state_bound
) || (orLater 
&& (dyld_image_state_bound 
> state
))) && (sNotifyObjCMapped 
!= NULL
) ) { 
1109                                 const char* paths
[imageCount
]; 
1110                                 const mach_header
* mhs
[imageCount
]; 
1111                                 unsigned objcImageCount 
= 0; 
1112                                 for (int i
=0; i 
< imageCount
; ++i
) { 
1113                                         const ImageLoader
* image 
= findImageByMachHeader(infos
[i
].imageLoadAddress
); 
1114                                         bool hasObjC 
= false; 
1115                                         if ( image 
!= NULL 
) { 
1116                                                 hasObjC 
= image
->notifyObjC(); 
1118 #if SUPPORT_ACCELERATE_TABLES 
1119                                         else if ( sAllCacheImagesProxy 
!= NULL 
) { 
1120                                                 const mach_header
* mh
; 
1123                                                 if ( sAllCacheImagesProxy
->addressInCache(infos
[i
].imageLoadAddress
, &mh
, &path
, &index
) ) { 
1124                                                         hasObjC 
= (mh
->flags 
& MH_HAS_OBJC
); 
1129                                                 paths
[objcImageCount
] = infos
[i
].imageFilePath
; 
1130                                                 mhs
[objcImageCount
]   = infos
[i
].imageLoadAddress
; 
1134                                 if ( objcImageCount 
!= 0 ) { 
1135                                         uint64_t t0 
= mach_absolute_time(); 
1136                                         (*sNotifyObjCMapped
)(objcImageCount
, paths
, mhs
); 
1137                                         uint64_t t1 
= mach_absolute_time(); 
1138                                         ImageLoader::fgTotalObjCSetupTime 
+= (t1
-t0
); 
1143         if ( dontLoadReason 
!= NULL 
) 
1144             throw dontLoadReason
; 
1145                 if ( !preflightOnly 
&& (state 
== dyld_image_state_dependents_mapped
) ) { 
1146                         if ( (dyld::gProcessInfo
->coreSymbolicationShmPage 
!= NULL
) || sEnv
.DYLD_PRINT_CS_NOTIFICATIONS 
) { 
1147                                 // mach message csdlc about loaded images 
1148                                 uint64_t loadTimestamp 
= mach_absolute_time(); 
1149                                 for (unsigned j
=0; j 
< imageCount
; ++j
) { 
1150                                         if ( sEnv
.DYLD_PRINT_CS_NOTIFICATIONS 
) { 
1151                                                 dyld::log("dyld: coresymbolication_load_notifier(%p, 0x%016llX, %p, %s)\n", 
1152                                                                   dyld::gProcessInfo
->coreSymbolicationShmPage
, loadTimestamp
, infos
[j
].imageLoadAddress
, infos
[j
].imageFilePath
); 
1154                                         coresymbolication_load_notifier(dyld::gProcessInfo
->coreSymbolicationShmPage
, loadTimestamp
, infos
[j
].imageFilePath
, infos
[j
].imageLoadAddress
); 
1157                         for (int slot
=0; slot 
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) { 
1158                                 if ( dyld::gProcessInfo
->notifyPorts
[slot
] ) 
1159                                         notifyMonitoringDyld(false, slot
, imageCount
, infos
); 
1167 static void notifyBatch(dyld_image_states state
, bool preflightOnly
) 
1169         notifyBatchPartial(state
, false, NULL
, preflightOnly
, false); 
1172 // In order for register_func_for_add_image() callbacks to to be called bottom up, 
1173 // we need to maintain a list of root images. The main executable is usally the 
1174 // first root. Any images dynamically added are also roots (unless already loaded). 
1175 // If DYLD_INSERT_LIBRARIES is used, those libraries are first. 
1176 static void addRootImage(ImageLoader
* image
) 
1178         //dyld::log("addRootImage(%p, %s)\n", image, image->getPath()); 
1179         // add to list of roots 
1180         sImageRoots
.push_back(image
); 
1184 static void clearAllDepths() 
1186         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) 
1187                 (*it
)->clearDepth(); 
1190 static void printAllDepths() 
1192         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) 
1193                 dyld::log("%03d %s\n",  (*it
)->getDepth(), (*it
)->getShortName()); 
1197 static unsigned int imageCount() 
1200                 unsigned int result 
= (unsigned int)sAllImages
.size(); 
1206 static void setNewProgramVars(const ProgramVars
& newVars
) 
1208         // make a copy of the pointers to program variables 
1209         gLinkContext
.programVars 
= newVars
; 
1211         // now set each program global to their initial value 
1212         *gLinkContext
.programVars
.NXArgcPtr 
= gLinkContext
.argc
; 
1213         *gLinkContext
.programVars
.NXArgvPtr 
= gLinkContext
.argv
; 
1214         *gLinkContext
.programVars
.environPtr 
= gLinkContext
.envp
; 
1215         *gLinkContext
.programVars
.__prognamePtr 
= gLinkContext
.progname
; 
1218 #if SUPPORT_OLD_CRT_INITIALIZATION 
1219 static void setRunInitialzersOldWay() 
1221         gRunInitializersOldWay 
= true;           
1225 static bool sandboxBlocked(const char* path
, const char* kind
) 
1227 #if TARGET_IPHONE_SIMULATOR 
1228         // sandbox calls not yet supported in simulator runtime 
1231         sandbox_filter_type filter 
= (sandbox_filter_type
)(SANDBOX_FILTER_PATH 
| SANDBOX_CHECK_NO_REPORT
); 
1232         return ( sandbox_check(getpid(), kind
, filter
, path
) > 0 ); 
1236 bool sandboxBlockedMmap(const char* path
) 
1238         return sandboxBlocked(path
, "file-map-executable"); 
1241 bool sandboxBlockedOpen(const char* path
) 
1243         return sandboxBlocked(path
, "file-read-data"); 
1246 bool sandboxBlockedStat(const char* path
) 
1248         return sandboxBlocked(path
, "file-read-metadata"); 
1252 static void addDynamicReference(ImageLoader
* from
, ImageLoader
* to
) { 
1253         // don't add dynamic reference if target is in the shared cache (since it can't be unloaded) 
1254         if ( to
->inSharedCache() ) 
1257         // don't add dynamic reference if there already is a static one 
1258         if ( from
->dependsOn(to
) ) 
1261         // don't add if this combination already exists 
1262         OSSpinLockLock(&sDynamicReferencesLock
); 
1263         for (std::vector
<ImageLoader::DynamicReference
>::iterator it
=sDynamicReferences
.begin(); it 
!= sDynamicReferences
.end(); ++it
) { 
1264                 if ( (it
->from 
== from
) && (it
->to 
== to
) ) { 
1265                         OSSpinLockUnlock(&sDynamicReferencesLock
); 
1270         //dyld::log("addDynamicReference(%s, %s\n", from->getShortName(), to->getShortName()); 
1271         ImageLoader::DynamicReference t
; 
1274         sDynamicReferences
.push_back(t
); 
1275         OSSpinLockUnlock(&sDynamicReferencesLock
); 
1278 static void addImage(ImageLoader
* image
) 
1280         // add to master list 
1282         sAllImages
.push_back(image
); 
1285         // update mapped ranges 
1286         uintptr_t lastSegStart 
= 0; 
1287         uintptr_t lastSegEnd 
= 0; 
1288         for(unsigned int i
=0, e
=image
->segmentCount(); i 
< e
; ++i
) { 
1289                 if ( image
->segUnaccessible(i
) )  
1291                 uintptr_t start 
= image
->segActualLoadAddress(i
); 
1292                 uintptr_t end 
= image
->segActualEndAddress(i
); 
1293                 if ( start 
== lastSegEnd 
) { 
1294                         // two segments are contiguous, just record combined segments 
1298                         // non-contiguous segments, record last (if any) 
1299                         if ( lastSegEnd 
!= 0 ) 
1300                                 addMappedRange(image
, lastSegStart
, lastSegEnd
); 
1301                         lastSegStart 
= start
; 
1305         if ( lastSegEnd 
!= 0 ) 
1306                 addMappedRange(image
, lastSegStart
, lastSegEnd
); 
1309         if ( gLinkContext
.verboseLoading 
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH 
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) { 
1310                 dyld::log("dyld: loaded: %s\n", image
->getPath()); 
1316 // Helper for std::remove_if 
1318 class RefUsesImage 
{ 
1320         RefUsesImage(ImageLoader
* image
) : _image(image
) {} 
1321         bool operator()(const ImageLoader::DynamicReference
& ref
) const { 
1322                 return ( (ref
.from 
== _image
) || (ref
.to 
== _image
) ); 
1325         ImageLoader
* _image
; 
1330 void removeImage(ImageLoader
* image
) 
1332         // if has dtrace DOF section, tell dtrace it is going away, then remove from sImageFilesNeedingDOFUnregistration 
1333         for (std::vector
<RegisteredDOF
>::iterator it
=sImageFilesNeedingDOFUnregistration
.begin(); it 
!= sImageFilesNeedingDOFUnregistration
.end(); ) { 
1334                 if ( it
->mh 
== image
->machHeader() ) { 
1335                         unregisterDOF(it
->registrationID
); 
1336                         sImageFilesNeedingDOFUnregistration
.erase(it
); 
1337                         // don't increment iterator, the erase caused next element to be copied to where this iterator points 
1344         // tell all registered remove image handlers about this 
1345         // do this before removing image from internal data structures so that the callback can query dyld about the image 
1346         if ( image
->getState() >= dyld_image_state_bound 
) { 
1347                 sRemoveImageCallbacksInUse 
= true; // This only runs inside dyld's global lock, so ok to use a global for the in-use flag. 
1348                 for (std::vector
<ImageCallback
>::iterator it
=sRemoveImageCallbacks
.begin(); it 
!= sRemoveImageCallbacks
.end(); it
++) { 
1349                         (*it
)(image
->machHeader(), image
->getSlide()); 
1351                 sRemoveImageCallbacksInUse 
= false; 
1353                 if ( sNotifyObjCUnmapped 
!=  NULL 
&& image
->notifyObjC() ) 
1354                         (*sNotifyObjCUnmapped
)(image
->getRealPath(), image
->machHeader()); 
1358         notifySingle(dyld_image_state_terminated
, image
, NULL
); 
1360         // remove from mapped images table 
1361         removedMappedRanges(image
); 
1363         // remove from master list 
1365         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
1366             if ( *it 
== image 
) { 
1367                 sAllImages
.erase(it
); 
1373         // remove from sDynamicReferences 
1374         OSSpinLockLock(&sDynamicReferencesLock
); 
1375                 sDynamicReferences
.erase(std::remove_if(sDynamicReferences
.begin(), sDynamicReferences
.end(), RefUsesImage(image
)), sDynamicReferences
.end()); 
1376         OSSpinLockUnlock(&sDynamicReferencesLock
); 
1378         // flush find-by-address cache (do this after removed from master list, so there is no chance it can come back) 
1379         if ( sLastImageByAddressCache 
== image 
) 
1380                 sLastImageByAddressCache 
= NULL
; 
1382         // if in root list, pull it out  
1383         for (std::vector
<ImageLoader
*>::iterator it
=sImageRoots
.begin(); it 
!= sImageRoots
.end(); it
++) { 
1384                 if ( *it 
== image 
) { 
1385                         sImageRoots
.erase(it
); 
1391         if ( gLinkContext
.verboseLoading 
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH 
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) { 
1392                 dyld::log("dyld: unloaded: %s\n", image
->getPath()); 
1395         // tell gdb, new way 
1396         removeImageFromAllImages(image
->machHeader()); 
1400 void runImageStaticTerminators(ImageLoader
* image
) 
1402         // if in termination list, pull it out and run terminator 
1405                 mightBeMore 
= false; 
1406                 for (std::vector
<ImageLoader
*>::iterator it
=sImageFilesNeedingTermination
.begin(); it 
!= sImageFilesNeedingTermination
.end(); it
++) { 
1407                         if ( *it 
== image 
) { 
1408                                 sImageFilesNeedingTermination
.erase(it
); 
1409                                 if (gLogAPIs
) dyld::log("dlclose(), running static terminators for %p %s\n", image
, image
->getShortName()); 
1410                                 image
->doTermination(gLinkContext
); 
1415         } while ( mightBeMore 
); 
1418 static void terminationRecorder(ImageLoader
* image
) 
1420         sImageFilesNeedingTermination
.push_back(image
); 
1423 const char* getExecutablePath() 
1428 static void runAllStaticTerminators(void* extra
) 
1431                 const size_t imageCount 
= sImageFilesNeedingTermination
.size(); 
1432                 for(size_t i
=imageCount
; i 
> 0; --i
){ 
1433                         ImageLoader
* image 
= sImageFilesNeedingTermination
[i
-1]; 
1434                         image
->doTermination(gLinkContext
); 
1436                 sImageFilesNeedingTermination
.clear(); 
1437                 notifyBatch(dyld_image_state_terminated
, false); 
1439         catch (const char* msg
) { 
1444 void initializeMainExecutable() 
1446         // record that we've reached this step 
1447         gLinkContext
.startedInitializingMainExecutable 
= true; 
1449         // run initialzers for any inserted dylibs 
1450         ImageLoader::InitializerTimingList initializerTimes
[allImagesCount()]; 
1451         initializerTimes
[0].count 
= 0; 
1452         const size_t rootCount 
= sImageRoots
.size(); 
1453         if ( rootCount 
> 1 ) { 
1454                 for(size_t i
=1; i 
< rootCount
; ++i
) { 
1455                         sImageRoots
[i
]->runInitializers(gLinkContext
, initializerTimes
[0]); 
1459         // run initializers for main executable and everything it brings up  
1460         sMainExecutable
->runInitializers(gLinkContext
, initializerTimes
[0]); 
1462         // register cxa_atexit() handler to run static terminators in all loaded images when this process exits 
1463         if ( gLibSystemHelpers 
!= NULL 
)  
1464                 (*gLibSystemHelpers
->cxa_atexit
)(&runAllStaticTerminators
, NULL
, NULL
); 
1466         // dump info if requested 
1467         if ( sEnv
.DYLD_PRINT_STATISTICS 
) 
1468                 ImageLoader::printStatistics((unsigned int)allImagesCount(), initializerTimes
[0]); 
1469         if ( sEnv
.DYLD_PRINT_STATISTICS_DETAILS 
) 
1470                 ImageLoaderMachO::printStatisticsDetails((unsigned int)allImagesCount(), initializerTimes
[0]); 
1473 bool mainExecutablePrebound() 
1475         return sMainExecutable
->usablePrebinding(gLinkContext
); 
1478 ImageLoader
* mainExecutable() 
1480         return sMainExecutable
; 
1486 #if SUPPORT_VERSIONED_PATHS 
1488 // forward reference 
1489 static bool getDylibVersionAndInstallname(const char* dylibPath
, uint32_t* version
, char* installName
); 
1493 // Examines a dylib file and if its current_version is newer than the installed 
1494 // dylib at its install_name, then add the dylib file to sDylibOverrides. 
1496 static void checkDylibOverride(const char* dylibFile
) 
1498         //dyld::log("checkDylibOverride('%s')\n", dylibFile); 
1499         uint32_t altVersion
; 
1500         char sysInstallName
[PATH_MAX
]; 
1501         if ( getDylibVersionAndInstallname(dylibFile
, &altVersion
, sysInstallName
) && (sysInstallName
[0] =='/') ) { 
1502                 //dyld::log("%s has version 0x%08X and install name %s\n", dylibFile, altVersion, sysInstallName); 
1503                 uint32_t sysVersion
; 
1504                 if ( getDylibVersionAndInstallname(sysInstallName
, &sysVersion
, NULL
) ) { 
1505                         //dyld::log("%s has version 0x%08X\n", sysInstallName, sysVersion); 
1506                         if ( altVersion 
> sysVersion 
) { 
1507                                 //dyld::log("override found: %s -> %s\n", sysInstallName, dylibFile); 
1508                                 // see if there already is an override for this dylib 
1509                                 bool entryExists 
= false; 
1510                                 for (std::vector
<DylibOverride
>::iterator it 
= sDylibOverrides
.begin(); it 
!= sDylibOverrides
.end(); ++it
) { 
1511                                         if ( strcmp(it
->installName
, sysInstallName
) == 0 ) { 
1513                                                 uint32_t prevVersion
; 
1514                                                 if ( getDylibVersionAndInstallname(it
->override
, &prevVersion
, NULL
) ) { 
1515                                                         if ( altVersion 
> prevVersion 
) { 
1516                                                                 // found an even newer override 
1517                                                                 free((void*)(it
->override
)); 
1518                                                                 char resolvedPath
[PATH_MAX
]; 
1519                                                                 if ( realpath(dylibFile
, resolvedPath
) != NULL 
) 
1520                                                                         it
->override 
= strdup(resolvedPath
); 
1522                                                                         it
->override 
= strdup(dylibFile
); 
1528                                 if ( ! entryExists 
) { 
1529                                         DylibOverride entry
; 
1530                                         entry
.installName 
= strdup(sysInstallName
); 
1531                                         char resolvedPath
[PATH_MAX
]; 
1532                                         if ( realpath(dylibFile
, resolvedPath
) != NULL 
) 
1533                                                 entry
.override 
= strdup(resolvedPath
); 
1535                                                 entry
.override 
= strdup(dylibFile
); 
1536                                         sDylibOverrides
.push_back(entry
); 
1537                                         //dyld::log("added override: %s -> %s\n", entry.installName, entry.override); 
1545 static void checkDylibOverridesInDir(const char* dirPath
) 
1547         //dyld::log("checkDylibOverridesInDir('%s')\n", dirPath); 
1548         char dylibPath
[PATH_MAX
]; 
1549         long dirPathLen 
= strlcpy(dylibPath
, dirPath
, PATH_MAX
-1); 
1550         if ( dirPathLen 
>= PATH_MAX 
) 
1552         DIR* dirp 
= opendir(dirPath
); 
1553         if ( dirp 
!= NULL
) { 
1555                 dirent
* entp 
= NULL
; 
1556                 while ( readdir_r(dirp
, &entry
, &entp
) == 0 ) { 
1559                         if ( entp
->d_type 
!= DT_REG 
)  
1561                         dylibPath
[dirPathLen
] = '/'; 
1562                         dylibPath
[dirPathLen
+1] = '\0'; 
1563                         if ( strlcat(dylibPath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX 
) 
1565                         checkDylibOverride(dylibPath
); 
1572 static void checkFrameworkOverridesInDir(const char* dirPath
) 
1574         //dyld::log("checkFrameworkOverridesInDir('%s')\n", dirPath); 
1575         char frameworkPath
[PATH_MAX
]; 
1576         long dirPathLen 
= strlcpy(frameworkPath
, dirPath
, PATH_MAX
-1); 
1577         if ( dirPathLen 
>= PATH_MAX 
) 
1579         DIR* dirp 
= opendir(dirPath
); 
1580         if ( dirp 
!= NULL
) { 
1582                 dirent
* entp 
= NULL
; 
1583                 while ( readdir_r(dirp
, &entry
, &entp
) == 0 ) { 
1586                         if ( entp
->d_type 
!= DT_DIR 
)  
1588                         frameworkPath
[dirPathLen
] = '/'; 
1589                         frameworkPath
[dirPathLen
+1] = '\0'; 
1590                         int dirNameLen 
= (int)strlen(entp
->d_name
); 
1591                         if ( dirNameLen 
< 11 ) 
1593                         if ( strcmp(&entp
->d_name
[dirNameLen
-10], ".framework") != 0 ) 
1595                         if ( strlcat(frameworkPath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX 
) 
1597                         if ( strlcat(frameworkPath
, "/", PATH_MAX
) >= PATH_MAX 
) 
1599                         if ( strlcat(frameworkPath
, entp
->d_name
, PATH_MAX
) >= PATH_MAX 
) 
1601                         frameworkPath
[strlen(frameworkPath
)-10] = '\0'; 
1602                         checkDylibOverride(frameworkPath
); 
1607 #endif // SUPPORT_VERSIONED_PATHS 
1611 // Turns a colon separated list of strings into a NULL terminated array  
1612 // of string pointers. If mainExecutableDir param is not NULL, 
1613 // substitutes @loader_path with main executable's dir. 
1615 static const char** parseColonList(const char* list
, const char* mainExecutableDir
) 
1617         static const char* sEmptyList
[] = { NULL 
}; 
1619         if ( list
[0] == '\0' )  
1623         for(const char* s
=list
; *s 
!= '\0'; ++s
) { 
1629         const char* start 
= list
; 
1630         char** result 
= new char*[colonCount
+2]; 
1631         for(const char* s
=list
; *s 
!= '\0'; ++s
) { 
1633                         size_t len 
= s
-start
; 
1634                         if ( (mainExecutableDir 
!= NULL
) && (strncmp(start
, "@loader_path/", 13) == 0) ) { 
1635 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
1636                                 if ( gLinkContext
.processIsRestricted 
) { 
1637                                         dyld::log("dyld: warning: @loader_path/ ignored in restricted process\n"); 
1641                                 size_t mainExecDirLen 
= strlen(mainExecutableDir
); 
1642                                 char* str 
= new char[mainExecDirLen
+len
+1]; 
1643                                 strcpy(str
, mainExecutableDir
); 
1644                                 strlcat(str
, &start
[13], mainExecDirLen
+len
+1); 
1645                                 str
[mainExecDirLen
+len
-13] = '\0'; 
1647                                 result
[index
++] = str
; 
1649                         else if ( (mainExecutableDir 
!= NULL
) && (strncmp(start
, "@executable_path/", 17) == 0) ) { 
1650 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
1651                                 if ( gLinkContext
.processIsRestricted 
) { 
1652                                         dyld::log("dyld: warning: @executable_path/ ignored in restricted process\n"); 
1656                                 size_t mainExecDirLen 
= strlen(mainExecutableDir
); 
1657                                 char* str 
= new char[mainExecDirLen
+len
+1]; 
1658                                 strcpy(str
, mainExecutableDir
); 
1659                                 strlcat(str
, &start
[17], mainExecDirLen
+len
+1); 
1660                                 str
[mainExecDirLen
+len
-17] = '\0'; 
1662                                 result
[index
++] = str
; 
1665                                 char* str 
= new char[len
+1]; 
1666                                 strncpy(str
, start
, len
); 
1669                                 result
[index
++] = str
; 
1673         size_t len 
= strlen(start
); 
1674         if ( (mainExecutableDir 
!= NULL
) && (strncmp(start
, "@loader_path/", 13) == 0) ) { 
1675 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
1676                 if ( gLinkContext
.processIsRestricted 
) { 
1677                         dyld::log("dyld: warning: @loader_path/ ignored in restricted process\n"); 
1682                         size_t mainExecDirLen 
= strlen(mainExecutableDir
); 
1683                         char* str 
= new char[mainExecDirLen
+len
+1]; 
1684                         strcpy(str
, mainExecutableDir
); 
1685                         strlcat(str
, &start
[13], mainExecDirLen
+len
+1); 
1686                         str
[mainExecDirLen
+len
-13] = '\0'; 
1687                         result
[index
++] = str
; 
1690         else if ( (mainExecutableDir 
!= NULL
) && (strncmp(start
, "@executable_path/", 17) == 0) ) { 
1691 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
1692                 if ( gLinkContext
.processIsRestricted 
) { 
1693                         dyld::log("dyld: warning: @executable_path/ ignored in restricted process\n"); 
1698                         size_t mainExecDirLen 
= strlen(mainExecutableDir
); 
1699                         char* str 
= new char[mainExecDirLen
+len
+1]; 
1700                         strcpy(str
, mainExecutableDir
); 
1701                         strlcat(str
, &start
[17], mainExecDirLen
+len
+1); 
1702                         str
[mainExecDirLen
+len
-17] = '\0'; 
1703                         result
[index
++] = str
; 
1707                 char* str 
= new char[len
+1]; 
1709                 result
[index
++] = str
; 
1711         result
[index
] = NULL
; 
1713         //dyld::log("parseColonList(%s)\n", list); 
1714         //for(int i=0; result[i] != NULL; ++i) 
1715         //      dyld::log("  %s\n", result[i]); 
1716         return (const char**)result
; 
1719 static void     appendParsedColonList(const char* list
, const char* mainExecutableDir
, const char* const ** storage
) 
1721         const char** newlist 
= parseColonList(list
, mainExecutableDir
); 
1722         if ( *storage 
== NULL 
) { 
1723                 // first time, just set 
1727                 // need to append to existing list 
1728                 const char* const* existing 
= *storage
; 
1730                 for(int i
=0; existing
[i
] != NULL
; ++i
) 
1732                 for(int i
=0; newlist
[i
] != NULL
; ++i
) 
1734                 const char** combinedList 
= new const char*[count
+2]; 
1736                 for(int i
=0; existing
[i
] != NULL
; ++i
) 
1737                         combinedList
[index
++] = existing
[i
]; 
1738                 for(int i
=0; newlist
[i
] != NULL
; ++i
) 
1739                         combinedList
[index
++] = newlist
[i
]; 
1740                 combinedList
[index
] = NULL
; 
1742                 *storage 
= combinedList
; 
1746 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
1747 static void paths_expand_roots(const char **paths
, const char *key
, const char *val
) 
1749 //      assert(val != NULL); 
1750 //      assert(paths != NULL); 
1752                 size_t keyLen 
= strlen(key
); 
1753                 for(int i
=0; paths
[i
] != NULL
; ++i
) { 
1754                         if ( strncmp(paths
[i
], key
, keyLen
) == 0 ) { 
1755                                 char* newPath 
= new char[strlen(val
) + (strlen(paths
[i
]) - keyLen
) + 1]; 
1756                                 strcpy(newPath
, val
); 
1757                                 strcat(newPath
, &paths
[i
][keyLen
]); 
1765 static void removePathWithPrefix(const char* paths
[], const char* prefix
) 
1767     size_t prefixLen 
= strlen(prefix
); 
1770     for(i 
= 0; paths
[i
] != NULL
; ++i
) { 
1771         if ( strncmp(paths
[i
], prefix
, prefixLen
) == 0 ) 
1774             paths
[i
-skip
] = paths
[i
]; 
1776     paths
[i
-skip
] = NULL
; 
1782 static void paths_dump(const char **paths
) 
1784 //   assert(paths != NULL); 
1785   const char **strs 
= paths
; 
1786   while(*strs 
!= NULL
) 
1788     dyld::log("\"%s\"\n", *strs
); 
1797 static void printOptions(const char* argv
[]) 
1800         while ( NULL 
!= argv
[i
] ) { 
1801                 dyld::log("opt[%i] = \"%s\"\n", i
, argv
[i
]); 
1806 static void printEnvironmentVariables(const char* envp
[]) 
1808         while ( NULL 
!= *envp 
) { 
1809                 dyld::log("%s\n", *envp
); 
1814 void processDyldEnvironmentVariable(const char* key
, const char* value
, const char* mainExecutableDir
) 
1816         if ( strcmp(key
, "DYLD_FRAMEWORK_PATH") == 0 ) { 
1817                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FRAMEWORK_PATH
); 
1819         else if ( strcmp(key
, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) { 
1820                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
); 
1822         else if ( strcmp(key
, "DYLD_LIBRARY_PATH") == 0 ) { 
1823                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_LIBRARY_PATH
); 
1825         else if ( strcmp(key
, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) { 
1826                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FALLBACK_LIBRARY_PATH
); 
1828 #if SUPPORT_ROOT_PATH 
1829         else if ( (strcmp(key
, "DYLD_ROOT_PATH") == 0) || (strcmp(key
, "DYLD_PATHS_ROOT") == 0) ) { 
1830                 if ( strcmp(value
, "/") != 0 ) { 
1831                         gLinkContext
.rootPaths 
= parseColonList(value
, mainExecutableDir
); 
1832                         for (int i
=0; gLinkContext
.rootPaths
[i
] != NULL
; ++i
) { 
1833                                 if ( gLinkContext
.rootPaths
[i
][0] != '/' ) { 
1834                                         dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n"); 
1835                                         gLinkContext
.rootPaths 
= NULL
; 
1842         else if ( strcmp(key
, "DYLD_IMAGE_SUFFIX") == 0 ) { 
1843                 gLinkContext
.imageSuffix 
= value
; 
1845         else if ( strcmp(key
, "DYLD_INSERT_LIBRARIES") == 0 ) { 
1846                 sEnv
.DYLD_INSERT_LIBRARIES 
= parseColonList(value
, NULL
); 
1847 #if SUPPORT_ACCELERATE_TABLES 
1848                 sDisableAcceleratorTables 
= true; 
1851         else if ( strcmp(key
, "DYLD_PRINT_OPTS") == 0 ) { 
1852                 sEnv
.DYLD_PRINT_OPTS 
= true; 
1854         else if ( strcmp(key
, "DYLD_PRINT_ENV") == 0 ) { 
1855                 sEnv
.DYLD_PRINT_ENV 
= true; 
1857         else if ( strcmp(key
, "DYLD_DISABLE_DOFS") == 0 ) { 
1858                 sEnv
.DYLD_DISABLE_DOFS 
= true; 
1860         else if ( strcmp(key
, "DYLD_DISABLE_PREFETCH") == 0 ) { 
1861                 gLinkContext
.preFetchDisabled 
= true; 
1863         else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES") == 0 ) { 
1864                 gLinkContext
.verboseLoading 
= true; 
1866         else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) { 
1867                 sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH 
= true; 
1869         else if ( strcmp(key
, "DYLD_BIND_AT_LAUNCH") == 0 ) { 
1870                 sEnv
.DYLD_BIND_AT_LAUNCH 
= true; 
1872         else if ( strcmp(key
, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) { 
1873                 gLinkContext
.bindFlat 
= true; 
1875         else if ( strcmp(key
, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) { 
1876                 // ignore, no longer relevant but some scripts still set it 
1878         else if ( strcmp(key
, "DYLD_NO_FIX_PREBINDING") == 0 ) { 
1880         else if ( strcmp(key
, "DYLD_PREBIND_DEBUG") == 0 ) { 
1881                 gLinkContext
.verbosePrebinding 
= true; 
1883         else if ( strcmp(key
, "DYLD_PRINT_INITIALIZERS") == 0 ) { 
1884                 gLinkContext
.verboseInit 
= true; 
1886         else if ( strcmp(key
, "DYLD_PRINT_DOFS") == 0 ) { 
1887                 gLinkContext
.verboseDOF 
= true; 
1889         else if ( strcmp(key
, "DYLD_PRINT_STATISTICS") == 0 ) { 
1890                 sEnv
.DYLD_PRINT_STATISTICS 
= true; 
1891 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR 
1892                 // <rdar://problem/26614838> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps 
1893                 sForceStderr 
= true; 
1896         else if ( strcmp(key
, "DYLD_PRINT_TO_STDERR") == 0 ) { 
1897 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR 
1898                 // <rdar://problem/26633440> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps 
1899                 sForceStderr 
= true; 
1902         else if ( strcmp(key
, "DYLD_PRINT_STATISTICS_DETAILS") == 0 ) { 
1903                 sEnv
.DYLD_PRINT_STATISTICS_DETAILS 
= true; 
1905         else if ( strcmp(key
, "DYLD_PRINT_SEGMENTS") == 0 ) { 
1906                 gLinkContext
.verboseMapping 
= true; 
1908         else if ( strcmp(key
, "DYLD_PRINT_BINDINGS") == 0 ) { 
1909                 gLinkContext
.verboseBind 
= true; 
1911         else if ( strcmp(key
, "DYLD_PRINT_WEAK_BINDINGS") == 0 ) { 
1912                 gLinkContext
.verboseWeakBind 
= true; 
1914         else if ( strcmp(key
, "DYLD_PRINT_REBASINGS") == 0 ) { 
1915                 gLinkContext
.verboseRebase 
= true; 
1917         else if ( strcmp(key
, "DYLD_PRINT_APIS") == 0 ) { 
1920 #if SUPPORT_ACCELERATE_TABLES 
1921         else if ( strcmp(key
, "DYLD_PRINT_APIS_APP") == 0 ) { 
1925         else if ( strcmp(key
, "DYLD_PRINT_WARNINGS") == 0 ) { 
1926                 gLinkContext
.verboseWarnings 
= true; 
1928         else if ( strcmp(key
, "DYLD_PRINT_RPATHS") == 0 ) { 
1929                 gLinkContext
.verboseRPaths 
= true; 
1931         else if ( strcmp(key
, "DYLD_PRINT_CS_NOTIFICATIONS") == 0 ) { 
1932                 sEnv
.DYLD_PRINT_CS_NOTIFICATIONS 
= true; 
1934         else if ( strcmp(key
, "DYLD_PRINT_INTERPOSING") == 0 ) { 
1935                 gLinkContext
.verboseInterposing 
= true; 
1937         else if ( strcmp(key
, "DYLD_PRINT_CODE_SIGNATURES") == 0 ) { 
1938                 gLinkContext
.verboseCodeSignatures 
= true; 
1940         else if ( (strcmp(key
, "DYLD_SHARED_REGION") == 0) && !sSafeMode 
) { 
1941                 if ( strcmp(value
, "private") == 0 ) { 
1942                         gLinkContext
.sharedRegionMode 
= ImageLoader::kUsePrivateSharedRegion
; 
1944                 else if ( strcmp(value
, "avoid") == 0 ) { 
1945                         gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
1947                 else if ( strcmp(value
, "use") == 0 ) { 
1948                         gLinkContext
.sharedRegionMode 
= ImageLoader::kUseSharedRegion
; 
1950                 else if ( value
[0] == '\0' ) { 
1951                         gLinkContext
.sharedRegionMode 
= ImageLoader::kUseSharedRegion
; 
1954                         dyld::warn("unknown option to DYLD_SHARED_REGION.  Valid options are: use, private, avoid\n"); 
1957         else if ( (strcmp(key
, "DYLD_SHARED_CACHE_DIR") == 0) && !sSafeMode  
) { 
1958                 sSharedCacheOverrideDir 
= value
; 
1960         else if ( strcmp(key
, "DYLD_USE_CLOSURES") == 0 ) { 
1961                 if ( dyld3::loader::internalInstall() ) 
1962                         sEnableClosures 
= true; 
1964         else if ( strcmp(key
, "DYLD_IGNORE_PREBINDING") == 0 ) { 
1965                 if ( strcmp(value
, "all") == 0 ) { 
1966                         gLinkContext
.prebindUsage 
= ImageLoader::kUseNoPrebinding
; 
1968                 else if ( strcmp(value
, "app") == 0 ) { 
1969                         gLinkContext
.prebindUsage 
= ImageLoader::kUseAllButAppPredbinding
; 
1971                 else if ( strcmp(value
, "nonsplit") == 0 ) { 
1972                         gLinkContext
.prebindUsage 
= ImageLoader::kUseSplitSegPrebinding
; 
1974                 else if ( value
[0] == '\0' ) { 
1975                         gLinkContext
.prebindUsage 
= ImageLoader::kUseSplitSegPrebinding
; 
1978                         dyld::warn("unknown option to DYLD_IGNORE_PREBINDING.  Valid options are: all, app, nonsplit\n"); 
1981 #if SUPPORT_VERSIONED_PATHS 
1982         else if ( strcmp(key
, "DYLD_VERSIONED_LIBRARY_PATH") == 0 ) { 
1983                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_VERSIONED_LIBRARY_PATH
); 
1984         #if SUPPORT_ACCELERATE_TABLES 
1985                 sDisableAcceleratorTables 
= true; 
1988         else if ( strcmp(key
, "DYLD_VERSIONED_FRAMEWORK_PATH") == 0 ) { 
1989                 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
); 
1990         #if SUPPORT_ACCELERATE_TABLES 
1991                 sDisableAcceleratorTables 
= true; 
1995 #if !TARGET_IPHONE_SIMULATOR 
1996         else if ( (strcmp(key
, "DYLD_PRINT_TO_FILE") == 0) && (mainExecutableDir 
== NULL
) && !sSafeMode 
) { 
1997                 int fd 
= open(value
, O_WRONLY 
| O_CREAT 
| O_APPEND
, 0644); 
2003                         dyld::log("dyld: could not open DYLD_PRINT_TO_FILE='%s', errno=%d\n", value
, errno
); 
2006         else if ( (strcmp(key
, "DYLD_SKIP_MAIN") == 0)) { 
2007                 if ( dyld3::loader::internalInstall() ) 
2012                 dyld::warn("unknown environment variable: %s\n", key
); 
2017 #if SUPPORT_LC_DYLD_ENVIRONMENT 
2018 static void checkLoadCommandEnvironmentVariables() 
2020         // <rdar://problem/8440934> Support augmenting dyld environment variables in load commands 
2021         const uint32_t cmd_count 
= sMainExecutableMachHeader
->ncmds
; 
2022         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)sMainExecutableMachHeader
)+sizeof(macho_header
)); 
2023         const struct load_command
* cmd 
= cmds
; 
2024         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2026                         case LC_DYLD_ENVIRONMENT
: 
2028                                 const struct dylinker_command
* envcmd 
= (struct dylinker_command
*)cmd
; 
2029                                 const char* keyEqualsValue 
= (char*)envcmd 
+ envcmd
->name
.offset
; 
2030                                 char mainExecutableDir
[strlen(sExecPath
)+2]; 
2031                                 strcpy(mainExecutableDir
, sExecPath
); 
2032                                 char* lastSlash 
= strrchr(mainExecutableDir
, '/'); 
2033                                 if ( lastSlash 
!= NULL
) 
2034                                         lastSlash
[1] = '\0'; 
2035                                 // only process variables that start with DYLD_ and end in _PATH 
2036                                 if ( (strncmp(keyEqualsValue
, "DYLD_", 5) == 0) ) { 
2037                                         const char* equals 
= strchr(keyEqualsValue
, '='); 
2038                                         if ( equals 
!= NULL 
) { 
2039                                                 if ( strncmp(&equals
[-5], "_PATH", 5) == 0 ) { 
2040                                                         const char* value 
= &equals
[1]; 
2041                                                         const size_t keyLen 
= equals
-keyEqualsValue
; 
2042                                                         // <rdar://problem/22799635> don't let malformed load command overflow stack 
2043                                                         if ( keyLen 
< 40 ) { 
2045                                                                 strncpy(key
, keyEqualsValue
, keyLen
); 
2047                                                                 //dyld::log("processing: %s\n", keyEqualsValue); 
2048                                                                 //dyld::log("mainExecutableDir: %s\n", mainExecutableDir); 
2049                                                                 processDyldEnvironmentVariable(key
, value
, mainExecutableDir
); 
2057                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2060 #endif // SUPPORT_LC_DYLD_ENVIRONMENT    
2063 static bool hasCodeSignatureLoadCommand(const macho_header
* mh
) 
2065         const uint32_t cmd_count 
= mh
->ncmds
; 
2066         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
2067         const struct load_command
* cmd 
= cmds
; 
2068         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2069                 if (cmd
->cmd 
== LC_CODE_SIGNATURE
)  
2071                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2077 #if SUPPORT_VERSIONED_PATHS 
2078 static void checkVersionedPaths() 
2080         // search DYLD_VERSIONED_LIBRARY_PATH directories for dylibs and check if they are newer 
2081         if ( sEnv
.DYLD_VERSIONED_LIBRARY_PATH 
!= NULL 
) { 
2082                 for(const char* const* lp 
= sEnv
.DYLD_VERSIONED_LIBRARY_PATH
; *lp 
!= NULL
; ++lp
) { 
2083                         checkDylibOverridesInDir(*lp
); 
2087         // search DYLD_VERSIONED_FRAMEWORK_PATH directories for dylibs and check if they are newer 
2088         if ( sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH 
!= NULL 
) { 
2089                 for(const char* const* fp 
= sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
; *fp 
!= NULL
; ++fp
) { 
2090                         checkFrameworkOverridesInDir(*fp
); 
2097 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
2099 // For security, setuid programs ignore DYLD_* environment variables. 
2100 // Additionally, the DYLD_* enviroment variables are removed 
2101 // from the environment, so that any child processes don't see them. 
2103 static void pruneEnvironmentVariables(const char* envp
[], const char*** applep
) 
2105 #if SUPPORT_LC_DYLD_ENVIRONMENT 
2106         checkLoadCommandEnvironmentVariables(); 
2109     // Are we testing dyld on an internal config? 
2110     if ( _simple_getenv(envp
, "DYLD_SKIP_MAIN") != NULL 
) { 
2111                 if ( dyld3::loader::internalInstall() ) 
2115         // delete all DYLD_* and LD_LIBRARY_PATH environment variables 
2116         int removedCount 
= 0; 
2117         const char** d 
= envp
; 
2118         for(const char** s 
= envp
; *s 
!= NULL
; s
++) { 
2120             if ( (strncmp(*s
, "DYLD_", 5) != 0) && (strncmp(*s
, "LD_LIBRARY_PATH=", 16) != 0) ) { 
2128         // slide apple parameters 
2129         if ( removedCount 
> 0 ) { 
2132                         *d 
= d
[removedCount
]; 
2133                 } while ( *d
++ != NULL 
); 
2134                 for(int i
=0; i 
< removedCount
; ++i
) 
2138         // disable framework and library fallback paths for setuid binaries rdar://problem/4589305 
2139         sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= NULL
; 
2140         sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= NULL
; 
2142         if ( removedCount 
> 0 ) 
2143                 strlcat(sLoadingCrashMessage
, ", ignoring DYLD_* env vars", sizeof(sLoadingCrashMessage
)); 
2147 static void defaultUninitializedFallbackPaths(const char* envp
[]) 
2149 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
2150         if ( gLinkContext
.processIsRestricted 
) { 
2151                 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= sRestrictedFrameworkFallbackPaths
; 
2152                 sEnv
.DYLD_FALLBACK_LIBRARY_PATH   
= sRestrictedLibraryFallbackPaths
; 
2156         // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment 
2157         const char* home 
= _simple_getenv(envp
, "HOME");; 
2158         if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
== NULL 
) { 
2159                 const char** fpaths 
= sFrameworkFallbackPaths
; 
2161                         removePathWithPrefix(fpaths
, "$HOME"); 
2163                         paths_expand_roots(fpaths
, "$HOME", home
); 
2164                 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= fpaths
; 
2167     // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment 
2168         if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
== NULL 
) { 
2169                 const char** lpaths 
= sLibraryFallbackPaths
; 
2171                         removePathWithPrefix(lpaths
, "$HOME"); 
2173                         paths_expand_roots(lpaths
, "$HOME", home
); 
2174                 sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= lpaths
; 
2177         if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
== NULL 
) 
2178                 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
= sFrameworkFallbackPaths
; 
2180         if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
== NULL 
) 
2181                 sEnv
.DYLD_FALLBACK_LIBRARY_PATH 
= sLibraryFallbackPaths
; 
2186 static void checkEnvironmentVariables(const char* envp
[]) 
2188         if ( sEnvMode 
== envNone 
) 
2191         for(p 
= envp
; *p 
!= NULL
; p
++) { 
2192                 const char* keyEqualsValue 
= *p
; 
2193             if ( strncmp(keyEqualsValue
, "DYLD_", 5) == 0 ) { 
2194                         const char* equals 
= strchr(keyEqualsValue
, '='); 
2195                         if ( equals 
!= NULL 
) { 
2196                                 strlcat(sLoadingCrashMessage
, "\n", sizeof(sLoadingCrashMessage
)); 
2197                                 strlcat(sLoadingCrashMessage
, keyEqualsValue
, sizeof(sLoadingCrashMessage
)); 
2198                                 const char* value 
= &equals
[1]; 
2199                                 const size_t keyLen 
= equals
-keyEqualsValue
; 
2201                                 strncpy(key
, keyEqualsValue
, keyLen
); 
2203                                 if ( (sEnvMode 
== envPrintOnly
) && (strncmp(key
, "DYLD_PRINT_", 11) != 0) ) 
2205                                 processDyldEnvironmentVariable(key
, value
, NULL
); 
2208                 else if ( strncmp(keyEqualsValue
, "LD_LIBRARY_PATH=", 16) == 0 ) { 
2209                         const char* path 
= &keyEqualsValue
[16]; 
2210                         sEnv
.LD_LIBRARY_PATH 
= parseColonList(path
, NULL
); 
2214 #if SUPPORT_LC_DYLD_ENVIRONMENT 
2215         checkLoadCommandEnvironmentVariables(); 
2216 #endif // SUPPORT_LC_DYLD_ENVIRONMENT    
2218 #if SUPPORT_ROOT_PATH 
2219         // <rdar://problem/11281064> DYLD_IMAGE_SUFFIX and DYLD_ROOT_PATH cannot be used together 
2220         if ( (gLinkContext
.imageSuffix 
!= NULL
) && (gLinkContext
.rootPaths 
!= NULL
) ) { 
2221                 dyld::warn("Ignoring DYLD_IMAGE_SUFFIX because DYLD_ROOT_PATH is used.\n"); 
2222                 gLinkContext
.imageSuffix 
= NULL
; 
2227 #if __x86_64__ && !TARGET_IPHONE_SIMULATOR 
2228 static bool isGCProgram(const macho_header
* mh
, uintptr_t slide
) 
2230         const uint32_t cmd_count 
= mh
->ncmds
; 
2231         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
2232         const struct load_command
* cmd 
= cmds
; 
2233         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2235                         case LC_SEGMENT_COMMAND
: 
2237                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
2238                                 if (strcmp(seg
->segname
, "__DATA") == 0) { 
2239                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
2240                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
2241                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
2242                                                 if (strncmp(sect
->sectname
, "__objc_imageinfo", 16) == 0) { 
2243                                                         const uint32_t*  objcInfo 
= (uint32_t*)(sect
->addr 
+ slide
); 
2244                                                         return (objcInfo
[1] & 6); // 6 = (OBJC_IMAGE_SUPPORTS_GC | OBJC_IMAGE_REQUIRES_GC) 
2251                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2257 static void getHostInfo(const macho_header
* mainExecutableMH
, uintptr_t mainExecutableSlide
) 
2259 #if CPU_SUBTYPES_SUPPORTED 
2261         sHostCPU                
= CPU_TYPE_ARM
; 
2262         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V7K
; 
2263 #elif __ARM_ARCH_7A__ 
2264         sHostCPU                
= CPU_TYPE_ARM
; 
2265         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V7
; 
2266 #elif __ARM_ARCH_6K__ 
2267         sHostCPU                
= CPU_TYPE_ARM
; 
2268         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V6
; 
2269 #elif __ARM_ARCH_7F__ 
2270         sHostCPU                
= CPU_TYPE_ARM
; 
2271         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V7F
; 
2272 #elif __ARM_ARCH_7S__ 
2273         sHostCPU                
= CPU_TYPE_ARM
; 
2274         sHostCPUsubtype 
= CPU_SUBTYPE_ARM_V7S
; 
2276         sHostCPU                
= CPU_TYPE_ARM64
; 
2277         sHostCPUsubtype 
= CPU_SUBTYPE_ARM64_E
; 
2279         sHostCPU                
= CPU_TYPE_ARM64
; 
2280         sHostCPUsubtype 
= CPU_SUBTYPE_ARM64_V8
; 
2282         struct host_basic_info info
; 
2283         mach_msg_type_number_t count 
= HOST_BASIC_INFO_COUNT
; 
2284         mach_port_t hostPort 
= mach_host_self(); 
2285         kern_return_t result 
= host_info(hostPort
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
); 
2286         if ( result 
!= KERN_SUCCESS 
) 
2287                 throw "host_info() failed"; 
2288         sHostCPU                
= info
.cpu_type
; 
2289         sHostCPUsubtype 
= info
.cpu_subtype
; 
2290         mach_port_deallocate(mach_task_self(), hostPort
); 
2292           // host_info returns CPU_TYPE_I386 even for x86_64.  Override that here so that 
2293           // we don't need to mask the cpu type later. 
2294           sHostCPU 
= CPU_TYPE_X86_64
; 
2295         #if !TARGET_IPHONE_SIMULATOR 
2296           sHaswell 
= (sHostCPUsubtype 
== CPU_SUBTYPE_X86_64_H
); 
2297           // <rdar://problem/18528074> x86_64h: Fall back to the x86_64 slice if an app requires GC. 
2299                 if ( isGCProgram(mainExecutableMH
, mainExecutableSlide
) ) { 
2300                         // When running a GC program on a haswell machine, don't use and 'h slices 
2301                         sHostCPUsubtype 
= CPU_SUBTYPE_X86_64_ALL
; 
2303                         gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
2312 static void checkSharedRegionDisable(const mach_header
* mainExecutableMH
) 
2314 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
2315         // if main executable has segments that overlap the shared region, 
2316         // then disable using the shared region 
2317         dyld3::MachOParser 
parser(mainExecutableMH
); 
2318         uintptr_t slide 
= parser
.getSlide(); 
2319         dyld3::launch_cache::MemoryRange sharedRegion 
= { (void*)(long)(SHARED_REGION_BASE
),  SHARED_REGION_SIZE 
}; 
2320         __block 
bool disable 
= false; 
2321         parser
.forEachSegment(^(const char *segName
, uint32_t fileOffset
, uint32_t fileSize
, uint64_t vmAddr
, uint64_t vmSize
, uint8_t protections
, bool &stop
) { 
2322                 dyld3::launch_cache::MemoryRange segRegion 
= { (void*)(long)(vmAddr
+slide
),  vmSize 
}; 
2323                 if ( segRegion
.intersects(sharedRegion
) ) 
2327                 gLinkContext
.sharedRegionMode 
= ImageLoader::kDontUseSharedRegion
; 
2328                 if ( gLinkContext
.verboseMapping 
) 
2329                         dyld::warn("disabling shared region because main executable overlaps\n"); 
2332         if ( gLinkContext
.processIsRestricted 
) { 
2333                 // <rdar://problem/15280847> use private or no shared region for suid processes 
2334                 gLinkContext
.sharedRegionMode 
= ImageLoader::kUsePrivateSharedRegion
; 
2338         // iOS cannot run without shared region 
2341 bool validImage(const ImageLoader
* possibleImage
) 
2343     const size_t imageCount 
= sAllImages
.size(); 
2344     for(size_t i
=0; i 
< imageCount
; ++i
) { 
2345         if ( possibleImage 
== sAllImages
[i
] ) { 
2352 uint32_t getImageCount() 
2354         return (uint32_t)sAllImages
.size(); 
2357 ImageLoader
* getIndexedImage(unsigned int index
) 
2359         if ( index 
< sAllImages
.size() ) 
2360                 return sAllImages
[index
]; 
2364 ImageLoader
* findImageByMachHeader(const struct mach_header
* target
) 
2366         return findMappedRange((uintptr_t)target
); 
2370 ImageLoader
* findImageContainingAddress(const void* addr
) 
2372   #if SUPPORT_ACCELERATE_TABLES 
2373         if ( sAllCacheImagesProxy 
!= NULL 
) { 
2374                 const mach_header
* mh
; 
2377                 if ( sAllCacheImagesProxy
->addressInCache(addr
, &mh
, &path
, &index
) ) 
2378                         return sAllCacheImagesProxy
; 
2381         return findMappedRange((uintptr_t)addr
); 
2385 ImageLoader
* findImageContainingSymbol(const void* symbol
) 
2387         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
2388                 ImageLoader
* anImage 
= *it
; 
2389                 if ( anImage
->containsSymbol(symbol
) ) 
2397 void forEachImageDo( void (*callback
)(ImageLoader
*, void* userData
), void* userData
) 
2399         const size_t imageCount 
= sAllImages
.size(); 
2400         for(size_t i
=0; i 
< imageCount
; ++i
) { 
2401                 ImageLoader
* anImage 
= sAllImages
[i
]; 
2402                 (*callback
)(anImage
, userData
); 
2406 ImageLoader
* findLoadedImage(const struct stat
& stat_buf
) 
2408         const size_t imageCount 
= sAllImages
.size(); 
2409         for(size_t i
=0; i 
< imageCount
; ++i
){ 
2410                 ImageLoader
* anImage 
= sAllImages
[i
]; 
2411                 if ( anImage
->statMatch(stat_buf
) ) 
2417 // based on ANSI-C strstr() 
2418 static const char* strrstr(const char* str
, const char* sub
)  
2420         const size_t sublen 
= strlen(sub
); 
2421         for(const char* p 
= &str
[strlen(str
)]; p 
!= str
; --p
) { 
2422                 if ( strncmp(p
, sub
, sublen
) == 0 ) 
2430 // Find framework path 
2432 //  /path/foo.framework/foo                                                             =>   foo.framework/foo   
2433 //  /path/foo.framework/Versions/A/foo                                  =>   foo.framework/Versions/A/foo 
2434 //  /path/foo.framework/Frameworks/bar.framework/bar    =>   bar.framework/bar 
2435 //  /path/foo.framework/Libraries/bar.dylb                              =>   NULL 
2436 //  /path/foo.framework/bar                                                             =>   NULL 
2438 // Returns NULL if not a framework path 
2440 static const char* getFrameworkPartialPath(const char* path
) 
2442         const char* dirDot 
= strrstr(path
, ".framework/"); 
2443         if ( dirDot 
!= NULL 
) { 
2444                 const char* dirStart 
= dirDot
; 
2445                 for ( ; dirStart 
>= path
; --dirStart
) { 
2446                         if ( (*dirStart 
== '/') || (dirStart 
== path
) ) { 
2447                                 const char* frameworkStart 
= &dirStart
[1]; 
2448                                 if ( dirStart 
== path 
) 
2450                                 size_t len 
= dirDot 
- frameworkStart
; 
2451                                 char framework
[len
+1]; 
2452                                 strncpy(framework
, frameworkStart
, len
); 
2453                                 framework
[len
] = '\0'; 
2454                                 const char* leaf 
= strrchr(path
, '/'); 
2455                                 if ( leaf 
!= NULL 
) { 
2456                                         if ( strcmp(framework
, &leaf
[1]) == 0 ) { 
2457                                                 return frameworkStart
; 
2459                                         if (  gLinkContext
.imageSuffix 
!= NULL 
) { 
2460                                                 // some debug frameworks have install names that end in _debug 
2461                                                 if ( strncmp(framework
, &leaf
[1], len
) == 0 ) { 
2462                                                         if ( strcmp( gLinkContext
.imageSuffix
, &leaf
[len
+1]) == 0 ) 
2463                                                                 return frameworkStart
; 
2474 static const char* getLibraryLeafName(const char* path
) 
2476         const char* start 
= strrchr(path
, '/'); 
2477         if ( start 
!= NULL 
) 
2484 // only for architectures that use cpu-sub-types 
2485 #if CPU_SUBTYPES_SUPPORTED  
2487 const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST 
= -1; 
2491 //      A fat file may contain multiple sub-images for the same CPU type. 
2492 //      In that case, dyld picks which sub-image to use by scanning a table 
2493 //      of preferred cpu-sub-types for the running cpu.   
2495 //      There is one row in the table for each cpu-sub-type on which dyld might run. 
2496 //  The first entry in a row is that cpu-sub-type.  It is followed by all 
2497 //      cpu-sub-types that can run on that cpu, if preferred order.  Each row ends with  
2498 //      a "SUBTYPE_ALL" (to denote that images written to run on any cpu-sub-type are usable),  
2499 //  followed by one or more CPU_SUBTYPE_END_OF_LIST to pad out this row. 
2505 //     ARM sub-type lists 
2507 const int kARM_RowCount 
= 8; 
2508 static const cpu_subtype_t kARM
[kARM_RowCount
][9] = {  
2510         // armv7f can run: v7f, v7, v6, v5, and v4 
2511         {  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 
}, 
2513         // armv7k can run: v7k 
2514         {  CPU_SUBTYPE_ARM_V7K
, CPU_SUBTYPE_END_OF_LIST 
}, 
2516         // armv7s can run: v7s, v7, v7f, v7k, v6, v5, and v4 
2517         {  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 
}, 
2519         // armv7 can run: v7, v6, v5, and v4 
2520         {  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 
}, 
2522         // armv6 can run: v6, v5, and v4 
2523         {  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 
}, 
2525         // xscale can run: xscale, v5, and v4 
2526         {  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 
}, 
2528         // armv5 can run: v5 and v4 
2529         {  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 
}, 
2531         // armv4 can run: v4 
2532         {  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 
}, 
2538 //     ARM64 sub-type lists 
2540 const int kARM64_RowCount 
= 2; 
2541 static const cpu_subtype_t kARM64
[kARM64_RowCount
][4] = { 
2543         // armv64e can run: 64e, 64 
2544         {  CPU_SUBTYPE_ARM64_E
, CPU_SUBTYPE_ARM64_V8
, CPU_SUBTYPE_ARM64_ALL
, CPU_SUBTYPE_END_OF_LIST 
}, 
2546         // armv64 can run: 64 
2547         {  CPU_SUBTYPE_ARM64_V8
, CPU_SUBTYPE_ARM64_ALL
, CPU_SUBTYPE_END_OF_LIST 
}, 
2553 //     x86_64 sub-type lists 
2555 const int kX86_64_RowCount 
= 2; 
2556 static const cpu_subtype_t kX86_64
[kX86_64_RowCount
][5] = { 
2558         // x86_64h can run: x86_64h, x86_64h(lib), x86_64(lib), and x86_64 
2559         { 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 
}, 
2561         // x86_64 can run: x86_64(lib) and x86_64 
2562         { CPU_SUBTYPE_X86_64_ALL
, (cpu_subtype_t
)(CPU_SUBTYPE_LIB64
|CPU_SUBTYPE_X86_64_ALL
), CPU_SUBTYPE_END_OF_LIST 
}, 
2568 // scan the tables above to find the cpu-sub-type-list for this machine 
2569 static const cpu_subtype_t
* findCPUSubtypeList(cpu_type_t cpu
, cpu_subtype_t subtype
) 
2574                         for (int i
=0; i 
< kARM_RowCount 
; ++i
) { 
2575                                 if ( kARM
[i
][0] == subtype 
) 
2581                 case CPU_TYPE_ARM64
: 
2582                         for (int i
=0; i 
< kARM64_RowCount 
; ++i
) { 
2583                                 if ( kARM64
[i
][0] == subtype 
) 
2589                 case CPU_TYPE_X86_64
: 
2590                         for (int i
=0; i 
< kX86_64_RowCount 
; ++i
) { 
2591                                 if ( kX86_64
[i
][0] == subtype 
) 
2603 // scan fat table-of-contents for best most preferred subtype 
2604 static bool fatFindBestFromOrderedList(cpu_type_t cpu
, const cpu_subtype_t list
[], const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
2606         const fat_arch
* const archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2607         for (uint32_t subTypeIndex
=0; list
[subTypeIndex
] != CPU_SUBTYPE_END_OF_LIST
; ++subTypeIndex
) { 
2608                 for(uint32_t fatIndex
=0; fatIndex 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++fatIndex
) { 
2609                         if ( ((cpu_type_t
)OSSwapBigToHostInt32(archs
[fatIndex
].cputype
) == cpu
)  
2610                                 && (list
[subTypeIndex
] == (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[fatIndex
].cpusubtype
)) ) { 
2611                                 *offset 
= OSSwapBigToHostInt32(archs
[fatIndex
].offset
); 
2612                                 *len 
= OSSwapBigToHostInt32(archs
[fatIndex
].size
); 
2620 // scan fat table-of-contents for exact match of cpu and cpu-sub-type 
2621 static bool fatFindExactMatch(cpu_type_t cpu
, cpu_subtype_t subtype
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
2623         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2624         for(uint32_t i
=0; i 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) { 
2625                 if ( ((cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
) 
2626                         && ((cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == subtype
) ) { 
2627                         *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2628                         *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2635 // scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types 
2636 static bool fatFindRunsOnAllCPUs(cpu_type_t cpu
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
2638         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2639         for(uint32_t i
=0; i 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) { 
2640                 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
) { 
2644                                         if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_ARM_ALL 
) { 
2645                                                 *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2646                                                 *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2652                                 case CPU_TYPE_ARM64
: 
2653                                         if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_ARM64_ALL 
) { 
2654                                                 *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2655                                                 *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2661                                 case CPU_TYPE_X86_64
: 
2662                                         if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_X86_64_ALL 
) { 
2663                                                 *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2664                                                 *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2675 #endif // CPU_SUBTYPES_SUPPORTED 
2679 // Validate the fat_header and fat_arch array: 
2681 // 1) arch count would not cause array to extend past 4096 byte read buffer 
2682 // 2) no slice overlaps the fat_header and arch array 
2683 // 3) arch list does not contain duplicate cputype/cpusubtype tuples 
2684 // 4) arch list does not have two overlapping slices. 
2686 static bool fatValidate(const fat_header
* fh
) 
2688         if ( fh
->magic 
!= OSSwapBigToHostInt32(FAT_MAGIC
) ) 
2691         // since only first 4096 bytes of file read, we can only handle up to 204 slices. 
2692         const uint32_t sliceCount 
= OSSwapBigToHostInt32(fh
->nfat_arch
); 
2693         if ( sliceCount 
> 204 ) 
2696         // compare all slices looking for conflicts 
2697         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2698         for (uint32_t i
=0; i 
< sliceCount
; ++i
) { 
2699                 uint32_t i_offset     
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2700                 uint32_t i_size       
= OSSwapBigToHostInt32(archs
[i
].size
); 
2701                 uint32_t i_cputype    
= OSSwapBigToHostInt32(archs
[i
].cputype
); 
2702                 uint32_t i_cpusubtype 
= OSSwapBigToHostInt32(archs
[i
].cpusubtype
); 
2703                 uint32_t i_end        
= i_offset 
+ i_size
; 
2704                 // slice cannot overlap with header 
2705                 if ( i_offset 
< 4096 ) 
2707                 // slice size cannot overflow 
2708                 if ( i_end 
< i_offset 
) 
2710                 for (uint32_t j
=i
+1; j 
< sliceCount
; ++j
) { 
2711                         uint32_t j_offset     
= OSSwapBigToHostInt32(archs
[j
].offset
); 
2712                         uint32_t j_size       
= OSSwapBigToHostInt32(archs
[j
].size
); 
2713                         uint32_t j_cputype    
= OSSwapBigToHostInt32(archs
[j
].cputype
); 
2714                         uint32_t j_cpusubtype 
= OSSwapBigToHostInt32(archs
[j
].cpusubtype
); 
2715                         uint32_t j_end        
= j_offset 
+ j_size
; 
2716                         // duplicate slices types not allowed 
2717                         if ( (i_cputype 
== j_cputype
) && (i_cpusubtype 
== j_cpusubtype
) ) 
2719                         // slice size cannot overflow 
2720                         if ( j_end 
< j_offset 
) 
2722                         // check for overlap of slices 
2723                         if ( i_offset 
<= j_offset 
) { 
2724                                 if ( j_offset 
< i_end 
) 
2725                                         return false; //  j overlaps end of i 
2728                                 //  j overlaps end of i 
2729                                 if ( i_offset 
< j_end 
) 
2730                                         return false;  //  i overlaps end of j 
2738 // A fat file may contain multiple sub-images for the same cpu-type, 
2739 // each optimized for a different cpu-sub-type (e.g G3 or G5). 
2740 // This routine picks the optimal sub-image. 
2742 static bool fatFindBest(const fat_header
* fh
, uint64_t* offset
, uint64_t* len
) 
2744         if ( !fatValidate(fh
) ) 
2747 #if CPU_SUBTYPES_SUPPORTED 
2748         // assume all dylibs loaded must have same cpu type as main executable 
2749         const cpu_type_t cpu 
= sMainExecutableMachHeader
->cputype
; 
2751         // We only know the subtype to use if the main executable cpu type matches the host 
2752         if ( cpu 
== sHostCPU 
) { 
2753                 // get preference ordered list of subtypes 
2754                 const cpu_subtype_t
* subTypePreferenceList 
= findCPUSubtypeList(cpu
, sHostCPUsubtype
); 
2756                 // use ordered list to find best sub-image in fat file 
2757                 if ( subTypePreferenceList 
!= NULL 
) { 
2758                         if ( fatFindBestFromOrderedList(cpu
, subTypePreferenceList
, fh
, offset
, len
) ) 
2762                 // if running cpu is not in list, try for an exact match 
2763                 if ( fatFindExactMatch(cpu
, sHostCPUsubtype
, fh
, offset
, len
) ) 
2767         // running on an uknown cpu, can only load generic code 
2768         return fatFindRunsOnAllCPUs(cpu
, fh
, offset
, len
); 
2770         // just find first slice with matching architecture 
2771         const fat_arch
* archs 
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
)); 
2772         for(uint32_t i
=0; i 
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) { 
2773                 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == sMainExecutableMachHeader
->cputype
) { 
2774                         *offset 
= OSSwapBigToHostInt32(archs
[i
].offset
); 
2775                         *len 
= OSSwapBigToHostInt32(archs
[i
].size
); 
2786 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used 
2787 // on the current processor. // 
2788 bool isCompatibleMachO(const uint8_t* firstPage
, const char* path
) 
2790 #if CPU_SUBTYPES_SUPPORTED 
2791         // It is deemed compatible if any of the following are true: 
2792         //  1) mach_header subtype is in list of compatible subtypes for running processor 
2793         //  2) mach_header subtype is same as running processor subtype 
2794         //  3) mach_header subtype runs on all processor variants 
2795         const mach_header
* mh 
= (mach_header
*)firstPage
; 
2796         if ( mh
->magic 
== sMainExecutableMachHeader
->magic 
) { 
2797                 if ( mh
->cputype 
== sMainExecutableMachHeader
->cputype 
) { 
2798                         if ( mh
->cputype 
== sHostCPU 
) { 
2799                                 // get preference ordered list of subtypes that this machine can use 
2800                                 const cpu_subtype_t
* subTypePreferenceList 
= findCPUSubtypeList(mh
->cputype
, sHostCPUsubtype
); 
2801                                 if ( subTypePreferenceList 
!= NULL 
) { 
2802                                         // if image's subtype is in the list, it is compatible 
2803                                         for (const cpu_subtype_t
* p 
= subTypePreferenceList
; *p 
!= CPU_SUBTYPE_END_OF_LIST
; ++p
) { 
2804                                                 if ( *p 
== mh
->cpusubtype 
) 
2807                                         // have list and not in list, so not compatible 
2808                                         throwf("incompatible cpu-subtype: 0x%08X in %s", mh
->cpusubtype
, path
); 
2810                                 // unknown cpu sub-type, but if exact match for current subtype then ok to use 
2811                                 if ( mh
->cpusubtype 
== sHostCPUsubtype 
)  
2815                         // cpu type has no ordered list of subtypes 
2816                         switch (mh
->cputype
) { 
2818                                 case CPU_TYPE_X86_64
: 
2819                                         // subtypes are not used or these architectures 
2825         // For architectures that don't support cpu-sub-types 
2826         // this just check the cpu type. 
2827         const mach_header
* mh 
= (mach_header
*)firstPage
; 
2828         if ( mh
->magic 
== sMainExecutableMachHeader
->magic 
) { 
2829                 if ( mh
->cputype 
== sMainExecutableMachHeader
->cputype 
) { 
2840 // The kernel maps in main executable before dyld gets control.  We need to  
2841 // make an ImageLoader* for the already mapped in main executable. 
2842 static ImageLoaderMachO
* instantiateFromLoadedImage(const macho_header
* mh
, uintptr_t slide
, const char* path
) 
2844         // try mach-o loader 
2845         if ( isCompatibleMachO((const uint8_t*)mh
, path
) ) { 
2846                 ImageLoader
* image 
= ImageLoaderMachO::instantiateMainExecutable(mh
, slide
, path
, gLinkContext
); 
2848                 return (ImageLoaderMachO
*)image
; 
2851         throw "main executable not a known format"; 
2854 #if SUPPORT_ACCELERATE_TABLES 
2855 static bool dylibsCanOverrideCache() 
2857         if ( !dyld3::loader::internalInstall() ) 
2859         return ( (sSharedCacheLoadInfo
.loadAddress 
!= nullptr) && (sSharedCacheLoadInfo
.loadAddress
->header
.cacheType 
== kDyldSharedCacheTypeDevelopment
) ); 
2863 const void* imMemorySharedCacheHeader() 
2865         return sSharedCacheLoadInfo
.loadAddress
; 
2869 const char* getStandardSharedCacheFilePath() 
2871         if ( sSharedCacheLoadInfo
.loadAddress 
!= nullptr ) 
2872                 return sSharedCacheLoadInfo
.path
; 
2878 static bool findInSharedCacheImage(const char* path
, bool searchByPath
, const struct stat
* stat_buf
, const macho_header
** mh
, const char** pathInCache
, long* slide
) 
2880         dyld3::SharedCacheFindDylibResults results
; 
2881         if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &results
) ) { 
2882                 *mh                      
= (macho_header
*)results
.mhInCache
; 
2883                 *pathInCache 
= results
.pathInCache
; 
2884                 *slide       
= results
.slideInCache
; 
2890 bool inSharedCache(const char* path
) 
2892         return dyld3::pathIsInSharedCacheImage(sSharedCacheLoadInfo
, path
); 
2896 static ImageLoader
* checkandAddImage(ImageLoader
* image
, const LoadContext
& context
) 
2898         // now sanity check that this loaded image does not have the same install path as any existing image 
2899         const char* loadedImageInstallPath 
= image
->getInstallPath(); 
2900         if ( image
->isDylib() && (loadedImageInstallPath 
!= NULL
) && (loadedImageInstallPath
[0] == '/') ) { 
2901                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
2902                         ImageLoader
* anImage 
= *it
; 
2903                         const char* installPath 
= anImage
->getInstallPath(); 
2904                         if ( installPath 
!= NULL
) { 
2905                                 if ( strcmp(loadedImageInstallPath
, installPath
) == 0 ) { 
2906                                         //dyld::log("duplicate(%s) => %p\n", installPath, anImage); 
2908                                         ImageLoader::deleteImage(image
); 
2915         // some API's restrict what they can load 
2916         if ( context
.mustBeBundle 
&& !image
->isBundle() ) 
2917                 throw "not a bundle"; 
2918         if ( context
.mustBeDylib 
&& !image
->isDylib() ) 
2919                 throw "not a dylib"; 
2921         // regular main executables cannot be loaded  
2922         if ( image
->isExecutable() ) { 
2923                 if ( !context
.canBePIE 
|| !image
->isPositionIndependentExecutable() ) 
2924                         throw "can't load a main executable"; 
2927         // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list 
2928         if ( ! image
->isBundle() )  
2934 #if TARGET_IPHONE_SIMULATOR      
2935 static bool isSimulatorBinary(const uint8_t* firstPages
, const char* path
) 
2937         const macho_header
* mh 
= (macho_header
*)firstPages
; 
2938         const uint32_t cmd_count 
= mh
->ncmds
; 
2939         const load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
2940         const load_command
* const cmdsEnd 
= (load_command
*)((char*)cmds 
+ mh
->sizeofcmds
); 
2941         const struct load_command
* cmd 
= cmds
; 
2942         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
2945                         case LC_VERSION_MIN_WATCHOS
: 
2948                         case LC_VERSION_MIN_TVOS
: 
2951                         case LC_VERSION_MIN_IPHONEOS
: 
2954                         case LC_VERSION_MIN_MACOSX
: 
2955                                 // grandfather in a few libSystem dylibs 
2956                                 if ((strcmp(path
, "/usr/lib/system/libsystem_kernel.dylib") == 0) || 
2957                                     (strcmp(path
, "/usr/lib/system/libsystem_platform.dylib") == 0) || 
2958                                     (strcmp(path
, "/usr/lib/system/libsystem_pthread.dylib") == 0)) 
2962                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
2963                 if ( cmd 
> cmdsEnd 
) 
2970 // map in file and instantiate an ImageLoader 
2971 static ImageLoader
* loadPhase6(int fd
, const struct stat
& stat_buf
, const char* path
, const LoadContext
& context
) 
2973         //dyld::log("%s(%s)\n", __func__ , path); 
2974         uint64_t fileOffset 
= 0; 
2975         uint64_t fileLength 
= stat_buf
.st_size
; 
2977         // validate it is a file (not directory) 
2978         if ( (stat_buf
.st_mode 
& S_IFMT
) != S_IFREG 
)  
2981         uint8_t firstPages
[MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE
]; 
2982         bool shortPage 
= false; 
2984         // min mach-o file is 4K 
2985         if ( fileLength 
< 4096 ) { 
2986                 if ( pread(fd
, firstPages
, (size_t)fileLength
, 0) != (ssize_t
)fileLength 
) 
2987                         throwf("pread of short file failed: %d", errno
); 
2991                 // optimistically read only first 4KB 
2992                 if ( pread(fd
, firstPages
, 4096, 0) != 4096 ) 
2993                         throwf("pread of first 4K failed: %d", errno
); 
2996         // if fat wrapper, find usable sub-file 
2997         const fat_header
* fileStartAsFat 
= (fat_header
*)firstPages
; 
2998         if ( fileStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
2999                 if ( OSSwapBigToHostInt32(fileStartAsFat
->nfat_arch
) > ((4096 - sizeof(fat_header
)) / sizeof(fat_arch
)) ) 
3000                         throwf("fat header too large: %u entries", OSSwapBigToHostInt32(fileStartAsFat
->nfat_arch
)); 
3001                 if ( fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) ) { 
3002                         if ( (fileOffset
+fileLength
) > (uint64_t)(stat_buf
.st_size
) ) 
3003                                 throwf("truncated fat file.  file length=%llu, but needed slice goes to %llu", stat_buf
.st_size
, fileOffset
+fileLength
); 
3004                         if (pread(fd
, firstPages
, 4096, fileOffset
) != 4096) 
3005                                 throwf("pread of fat file failed: %d", errno
); 
3008                         throw "no matching architecture in universal wrapper"; 
3012         // try mach-o loader 
3014                 throw "file too short"; 
3015         if ( isCompatibleMachO(firstPages
, path
) ) { 
3017                 // only MH_BUNDLE, MH_DYLIB, and some MH_EXECUTE can be dynamically loaded 
3018                 const mach_header
* mh 
= (mach_header
*)firstPages
; 
3019                 switch ( mh
->filetype 
) { 
3025                                 throw "mach-o, but wrong filetype"; 
3028                 uint32_t headerAndLoadCommandsSize 
= sizeof(macho_header
) + mh
->sizeofcmds
; 
3029                 if ( headerAndLoadCommandsSize 
> MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE 
) 
3030                         throwf("malformed mach-o: load commands size (%u) > %u", headerAndLoadCommandsSize
, MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE
); 
3032                 if ( headerAndLoadCommandsSize 
> fileLength 
) 
3033                         dyld::throwf("malformed mach-o: load commands size (%u) > mach-o file size (%llu)", headerAndLoadCommandsSize
, fileLength
); 
3035                 if ( headerAndLoadCommandsSize 
> 4096 ) { 
3037                         unsigned readAmount 
= headerAndLoadCommandsSize 
- 4096; 
3038                         if ( pread(fd
, &firstPages
[4096], readAmount
, fileOffset
+4096) != readAmount 
) 
3039                                 throwf("pread of extra load commands past 4KB failed: %d", errno
); 
3042 #if TARGET_IPHONE_SIMULATOR      
3043                 // <rdar://problem/14168872> dyld_sim should restrict loading osx binaries 
3044                 if ( !isSimulatorBinary(firstPages
, path
) ) { 
3046                         throw "mach-o, but not built for watchOS simulator"; 
3048                         throw "mach-o, but not built for tvOS simulator"; 
3050                         throw "mach-o, but not built for iOS simulator"; 
3055                 // instantiate an image 
3056                 ImageLoader
* image 
= ImageLoaderMachO::instantiateFromFile(path
, fd
, firstPages
, headerAndLoadCommandsSize
, fileOffset
, fileLength
, stat_buf
, gLinkContext
); 
3059                 return checkandAddImage(image
, context
); 
3062         // try other file formats here... 
3065         // throw error about what was found 
3066         switch (*(uint32_t*)firstPages
) { 
3071                         throw "mach-o, but wrong architecture"; 
3073                 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",  
3074                         firstPages
[0], firstPages
[1], firstPages
[2], firstPages
[3], firstPages
[4], firstPages
[5], firstPages
[6],firstPages
[7]); 
3079 static ImageLoader
* loadPhase5open(const char* path
, const LoadContext
& context
, const struct stat
& stat_buf
, std::vector
<const char*>* exceptions
) 
3081         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3083         // open file (automagically closed when this function exits) 
3084         FileOpener 
file(path
); 
3086         // just return NULL if file not found, but record any other errors 
3087         if ( file
.getFileDescriptor() == -1 ) { 
3089                 if ( err 
!= ENOENT 
) { 
3091                         if ( (err 
== EPERM
) && sandboxBlockedOpen(path
) ) 
3092                                 newMsg 
= dyld::mkstringf("file system sandbox blocked open() of '%s'", path
); 
3094                                 newMsg 
= dyld::mkstringf("%s: open() failed with errno=%d", path
, err
); 
3095                         exceptions
->push_back(newMsg
); 
3101                 return loadPhase6(file
.getFileDescriptor(), stat_buf
, path
, context
); 
3103         catch (const char* msg
) { 
3104                 const char* newMsg 
= dyld::mkstringf("%s: %s", path
, msg
); 
3105                 exceptions
->push_back(newMsg
); 
3114 static ImageLoader
* loadPhase5load(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3116         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3117 #if SUPPORT_ACCELERATE_TABLES 
3118         if ( sAllCacheImagesProxy 
!= NULL 
) { 
3119                 if ( sAllCacheImagesProxy
->hasDylib(path
, &cacheIndex
) ) 
3120                         return sAllCacheImagesProxy
; 
3123 #if TARGET_IPHONE_SIMULATOR 
3124         // in simulators, 'path' has DYLD_ROOT_PATH prepended, but cache index does not have the prefix, so use orgPath 
3125         const char* pathToFindInCache 
= orgPath
; 
3127         const char* pathToFindInCache 
= path
; 
3130         struct stat statBuf
; 
3131         bool didStat 
= false; 
3133         dyld3::SharedCacheFindDylibResults shareCacheResults
; 
3134         if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, pathToFindInCache
, &shareCacheResults
) ) { 
3135                 // see if this image in the cache was already loaded via a different path 
3136                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); ++it
) { 
3137                         ImageLoader
* anImage 
= *it
; 
3138                         if ( (const mach_header
*)anImage
->machHeader() == shareCacheResults
.mhInCache 
) 
3141                 // if RTLD_NOLOAD, do nothing if not already loaded 
3142                 if ( context
.dontLoad 
) 
3144                 bool useCache 
= false; 
3145                 if ( shareCacheResults
.imageData 
== nullptr ) { 
3146                         // HACK to support old caches 
3147                         existsOnDisk 
= ( my_stat(path
, &statBuf
) == 0 ); 
3150                         useCache 
= !existsOnDisk
; 
3153                         // <rdar://problem/7014995> zero out stat buffer so mtime, etc are zero for items from the shared cache 
3154                         bzero(&statBuf
, sizeof(statBuf
)); 
3155                         dyld3::launch_cache::Image 
image(shareCacheResults
.imageData
); 
3156                         if ( image
.overridableDylib() ) { 
3157                                 existsOnDisk 
= ( my_stat(path
, &statBuf
) == 0 ); 
3160                                 if ( sSharedCacheLoadInfo
.loadAddress
->header
.dylibsExpectedOnDisk 
) { 
3161                                         if ( (image
.fileModTime() == statBuf
.st_mtime
) && (image
.fileINode() == statBuf
.st_ino
) ) 
3165                                         if ( !existsOnDisk 
) 
3174                         ImageLoader
* imageLoader 
= ImageLoaderMachO::instantiateFromCache((macho_header
*)shareCacheResults
.mhInCache
, shareCacheResults
.pathInCache
, shareCacheResults
.slideInCache
, statBuf
, gLinkContext
); 
3175                         return checkandAddImage(imageLoader
, context
); 
3179         // not in cache or cache not usable 
3181                 existsOnDisk 
= ( my_stat(path
, &statBuf
) == 0 ); 
3184         if ( existsOnDisk 
) { 
3185                 // in case image was renamed or found via symlinks, check for inode match 
3186                 ImageLoader
* imageLoader 
= findLoadedImage(statBuf
); 
3187                 if ( imageLoader 
!= NULL 
) 
3189                 // do nothing if not already loaded and if RTLD_NOLOAD  
3190                 if ( context
.dontLoad 
) 
3193                 imageLoader 
= loadPhase5open(path
, context
, statBuf
, exceptions
); 
3194                 if ( imageLoader 
!= NULL 
) 
3198         // just return NULL if file not found, but record any other errors 
3199         if ( (statErrNo 
!= ENOENT
) && (statErrNo 
!= 0) ) { 
3200                 if ( (statErrNo 
== EPERM
) && sandboxBlockedStat(path
) ) 
3201                         exceptions
->push_back(dyld::mkstringf("%s: file system sandbox blocked stat()", path
)); 
3203                         exceptions
->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path
, statErrNo
)); 
3208 // look for path match with existing loaded images 
3209 static ImageLoader
* loadPhase5check(const char* path
, const char* orgPath
, const LoadContext
& context
) 
3211         //dyld::log("%s(%s, %s)\n", __func__ , path, orgPath); 
3212         // search path against load-path and install-path of all already loaded images 
3213         uint32_t hash 
= ImageLoader::hash(path
); 
3214         //dyld::log("check() hash=%d, path=%s\n", hash, path); 
3215         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
3216                 ImageLoader
* anImage 
= *it
; 
3217                 // check hash first to cut down on strcmp calls 
3218                 //dyld::log("    check() hash=%d, path=%s\n", anImage->getPathHash(), anImage->getPath()); 
3219                 if ( anImage
->getPathHash() == hash 
) { 
3220                         if ( strcmp(path
, anImage
->getPath()) == 0 ) { 
3221                                 // if we are looking for a dylib don't return something else 
3222                                 if ( !context
.mustBeDylib 
|| anImage
->isDylib() ) 
3226                 if ( context
.matchByInstallName 
|| anImage
->matchInstallPath() ) { 
3227                         const char* installPath 
= anImage
->getInstallPath(); 
3228                         if ( installPath 
!= NULL
) { 
3229                                 if ( strcmp(path
, installPath
) == 0 ) { 
3230                                         // if we are looking for a dylib don't return something else 
3231                                         if ( !context
.mustBeDylib 
|| anImage
->isDylib() ) 
3236                 // an install name starting with @rpath should match by install name, not just real path 
3237                 if ( (orgPath
[0] == '@') && (strncmp(orgPath
, "@rpath/", 7) == 0) ) { 
3238                         const char* installPath 
= anImage
->getInstallPath(); 
3239                         if ( installPath 
!= NULL
) { 
3240                                 if ( !context
.mustBeDylib 
|| anImage
->isDylib() ) { 
3241                                         if ( strcmp(orgPath
, installPath
) == 0 ) 
3248         //dyld::log("%s(%s) => NULL\n", __func__,   path); 
3253 // open or check existing 
3254 static ImageLoader
* loadPhase5(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3256         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3258         // check for specific dylib overrides 
3259         for (std::vector
<DylibOverride
>::iterator it 
= sDylibOverrides
.begin(); it 
!= sDylibOverrides
.end(); ++it
) { 
3260                 if ( strcmp(it
->installName
, path
) == 0 ) { 
3261                         path 
= it
->override
; 
3266         if ( exceptions 
!= NULL 
)  
3267                 return loadPhase5load(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3269                 return loadPhase5check(path
, orgPath
, context
); 
3272 // try with and without image suffix 
3273 static ImageLoader
* loadPhase4(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3275         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3276         ImageLoader
* image 
= NULL
; 
3277         if (  gLinkContext
.imageSuffix 
!= NULL 
) { 
3278                 char pathWithSuffix
[strlen(path
)+strlen( gLinkContext
.imageSuffix
)+2]; 
3279                 ImageLoader::addSuffix(path
,  gLinkContext
.imageSuffix
, pathWithSuffix
); 
3280                 image 
= loadPhase5(pathWithSuffix
, orgPath
, context
, cacheIndex
, exceptions
); 
3282         if ( image 
== NULL 
) 
3283                 image 
= loadPhase5(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3287 static ImageLoader
* loadPhase2(const char* path
, const char* orgPath
, const LoadContext
& context
, 
3288                                                            const char* const frameworkPaths
[], const char* const libraryPaths
[], 
3289                                                            unsigned& cacheIndex
, std::vector
<const char*>* exceptions
); // forward reference 
3292 // expand @ variables 
3293 static ImageLoader
* loadPhase3(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3295         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3296         ImageLoader
* image 
= NULL
; 
3297         if ( strncmp(path
, "@executable_path/", 17) == 0 ) { 
3298 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
3299                 // executable_path cannot be in used in any binary in a setuid process rdar://problem/4589305 
3300                 if ( gLinkContext
.processIsRestricted 
) 
3301                         throwf("unsafe use of @executable_path in %s with restricted binary", context
.origin
); 
3303                 // handle @executable_path path prefix 
3304                 const char* executablePath 
= sExecPath
; 
3305                 char newPath
[strlen(executablePath
) + strlen(path
)]; 
3306                 strcpy(newPath
, executablePath
); 
3307                 char* addPoint 
= strrchr(newPath
,'/'); 
3308                 if ( addPoint 
!= NULL 
) 
3309                         strcpy(&addPoint
[1], &path
[17]); 
3311                         strcpy(newPath
, &path
[17]); 
3312                 image 
= loadPhase4(newPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3313                 if ( image 
!= NULL 
)  
3316                 // perhaps main executable path is a sym link, find realpath and retry 
3317                 char resolvedPath
[PATH_MAX
]; 
3318                 if ( realpath(sExecPath
, resolvedPath
) != NULL 
) { 
3319                         char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
3320                         strcpy(newRealPath
, resolvedPath
); 
3321                         addPoint 
= strrchr(newRealPath
,'/'); 
3322                         if ( addPoint 
!= NULL 
) 
3323                                 strcpy(&addPoint
[1], &path
[17]); 
3325                                 strcpy(newRealPath
, &path
[17]); 
3326                         image 
= loadPhase4(newRealPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3327                         if ( image 
!= NULL 
)  
3331         else if ( (strncmp(path
, "@loader_path/", 13) == 0) && (context
.origin 
!= NULL
) ) { 
3332 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
3333                 // @loader_path cannot be used from the main executable of a setuid process rdar://problem/4589305 
3334                 if ( gLinkContext
.processIsRestricted 
&& (strcmp(context
.origin
, sExecPath
) == 0) ) 
3335                         throwf("unsafe use of @loader_path in %s with restricted binary", context
.origin
); 
3337                 // handle @loader_path path prefix 
3338                 char newPath
[strlen(context
.origin
) + strlen(path
)]; 
3339                 strcpy(newPath
, context
.origin
); 
3340                 char* addPoint 
= strrchr(newPath
,'/'); 
3341                 if ( addPoint 
!= NULL 
) 
3342                         strcpy(&addPoint
[1], &path
[13]); 
3344                         strcpy(newPath
, &path
[13]); 
3345                 image 
= loadPhase4(newPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3346                 if ( image 
!= NULL 
)  
3349                 // perhaps loader path is a sym link, find realpath and retry 
3350                 char resolvedPath
[PATH_MAX
]; 
3351                 if ( realpath(context
.origin
, resolvedPath
) != NULL 
) { 
3352                         char newRealPath
[strlen(resolvedPath
) + strlen(path
)]; 
3353                         strcpy(newRealPath
, resolvedPath
); 
3354                         addPoint 
= strrchr(newRealPath
,'/'); 
3355                         if ( addPoint 
!= NULL 
) 
3356                                 strcpy(&addPoint
[1], &path
[13]); 
3358                                 strcpy(newRealPath
, &path
[13]); 
3359                         image 
= loadPhase4(newRealPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3360                         if ( image 
!= NULL 
)  
3364         else if ( context
.implicitRPath 
|| (strncmp(path
, "@rpath/", 7) == 0) ) { 
3365                 const char* trailingPath 
= (strncmp(path
, "@rpath/", 7) == 0) ? &path
[7] : path
; 
3366                 // substitute @rpath with all -rpath paths up the load chain 
3367                 for(const ImageLoader::RPathChain
* rp
=context
.rpath
; rp 
!= NULL
; rp
=rp
->next
) { 
3368                         if (rp
->paths 
!= NULL 
) { 
3369                                 for(std::vector
<const char*>::iterator it
=rp
->paths
->begin(); it 
!= rp
->paths
->end(); ++it
) { 
3370                                         const char* anRPath 
= *it
; 
3371                                         char newPath
[strlen(anRPath
) + strlen(trailingPath
)+2]; 
3372                                         strcpy(newPath
, anRPath
); 
3373                                         if ( newPath
[strlen(newPath
)-1] != '/' ) 
3374                                                 strcat(newPath
, "/"); 
3375                                         strcat(newPath
, trailingPath
);  
3376                                         image 
= loadPhase4(newPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3377                                         if ( gLinkContext
.verboseRPaths 
&& (exceptions 
!= NULL
) ) { 
3378                                                 if ( image 
!= NULL 
)  
3379                                                         dyld::log("RPATH successful expansion of %s to: %s\n", orgPath
, newPath
); 
3381                                                         dyld::log("RPATH failed to expanding     %s to: %s\n", orgPath
, newPath
); 
3383                                         if ( image 
!= NULL 
)  
3389                 // substitute @rpath with LD_LIBRARY_PATH 
3390                 if ( sEnv
.LD_LIBRARY_PATH 
!= NULL 
) { 
3391                         image 
= loadPhase2(trailingPath
, orgPath
, context
, NULL
, sEnv
.LD_LIBRARY_PATH
, cacheIndex
, exceptions
); 
3392                         if ( image 
!= NULL 
) 
3396                 // if this is the "open" pass, don't try to open @rpath/... as a relative path 
3397                 if ( (exceptions 
!= NULL
) && (trailingPath 
!= path
) ) 
3400 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
3401         else if ( gLinkContext
.processIsRestricted 
&& (path
[0] != '/' ) ) { 
3402                 throwf("unsafe use of relative rpath %s in %s with restricted binary", path
, context
.origin
); 
3406         return loadPhase4(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3409 static ImageLoader
* loadPhase2cache(const char* path
, const char *orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) { 
3410         ImageLoader
* image 
= NULL
; 
3411 #if !TARGET_IPHONE_SIMULATOR 
3412         if ( exceptions 
!= NULL
) { 
3413                 char resolvedPath
[PATH_MAX
]; 
3414                 realpath(path
, resolvedPath
); 
3416                 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT 
3417                 if ( (myerr 
== ENOENT
) || (myerr 
== 0) ) 
3419                         image 
= loadPhase4(resolvedPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3428 static ImageLoader
* loadPhase2(const char* path
, const char* orgPath
, const LoadContext
& context
, 
3429                                                            const char* const frameworkPaths
[], const char* const libraryPaths
[],  
3430                                                            unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3432         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3433         ImageLoader
* image 
= NULL
; 
3434         const char* frameworkPartialPath 
= getFrameworkPartialPath(path
); 
3435         if ( frameworkPaths 
!= NULL 
) { 
3436                 if ( frameworkPartialPath 
!= NULL 
) { 
3437                         const size_t frameworkPartialPathLen 
= strlen(frameworkPartialPath
); 
3438                         for(const char* const* fp 
= frameworkPaths
; *fp 
!= NULL
; ++fp
) { 
3439                                 char npath
[strlen(*fp
)+frameworkPartialPathLen
+8]; 
3442                                 strcat(npath
, frameworkPartialPath
); 
3443                                 //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath); 
3444                                 image 
= loadPhase4(npath
, orgPath
, context
, cacheIndex
, exceptions
); 
3445                                 // Look in the cache if appropriate 
3447                                         image 
= loadPhase2cache(npath
, orgPath
, context
, cacheIndex
, exceptions
); 
3448                                 if ( image 
!= NULL 
) 
3453         // <rdar://problem/12649639> An executable with the same name as a framework & DYLD_LIBRARY_PATH pointing to it gets loaded twice 
3454         // <rdar://problem/14160846> Some apps depend on frameworks being found via library paths 
3455         if ( (libraryPaths 
!= NULL
) && ((frameworkPartialPath 
== NULL
) || sFrameworksFoundAsDylibs
) ) { 
3456                 const char* libraryLeafName 
= getLibraryLeafName(path
); 
3457                 const size_t libraryLeafNameLen 
= strlen(libraryLeafName
); 
3458                 for(const char* const* lp 
= libraryPaths
; *lp 
!= NULL
; ++lp
) { 
3459                         char libpath
[strlen(*lp
)+libraryLeafNameLen
+8]; 
3460                         strcpy(libpath
, *lp
); 
3461                         strcat(libpath
, "/"); 
3462                         strcat(libpath
, libraryLeafName
); 
3463                         //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath); 
3464                         image 
= loadPhase4(libpath
, orgPath
, context
, cacheIndex
, exceptions
); 
3465                         // Look in the cache if appropriate 
3467                                 image 
= loadPhase2cache(libpath
, orgPath
, context
, cacheIndex
, exceptions
); 
3468                         if ( image 
!= NULL 
) 
3475 // try search overrides and fallbacks 
3476 static ImageLoader
* loadPhase1(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3478         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3479         ImageLoader
* image 
= NULL
; 
3481         // handle LD_LIBRARY_PATH environment variables that force searching 
3482         if ( context
.useLdLibraryPath 
&& (sEnv
.LD_LIBRARY_PATH 
!= NULL
) ) { 
3483                 image 
= loadPhase2(path
, orgPath
, context
,  NULL
, sEnv
.LD_LIBRARY_PATH
, cacheIndex
,exceptions
); 
3484                 if ( image 
!= NULL 
) 
3488         // handle DYLD_ environment variables that force searching 
3489         if ( context
.useSearchPaths 
&& ((sEnv
.DYLD_FRAMEWORK_PATH 
!= NULL
) || (sEnv
.DYLD_LIBRARY_PATH 
!= NULL
)) ) { 
3490                 image 
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_FRAMEWORK_PATH
, sEnv
.DYLD_LIBRARY_PATH
, cacheIndex
, exceptions
); 
3491                 if ( image 
!= NULL 
) 
3496         image 
= loadPhase3(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3497         if ( image 
!= NULL 
) 
3500         // try fallback paths during second time (will open file) 
3501         const char* const* fallbackLibraryPaths 
= sEnv
.DYLD_FALLBACK_LIBRARY_PATH
; 
3502         if ( (fallbackLibraryPaths 
!= NULL
) && !context
.useFallbackPaths 
) 
3503                 fallbackLibraryPaths 
= NULL
; 
3504         if ( !context
.dontLoad  
&& (exceptions 
!= NULL
) && ((sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH 
!= NULL
) || (fallbackLibraryPaths 
!= NULL
)) ) { 
3505                 image 
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
, fallbackLibraryPaths
, cacheIndex
, exceptions
); 
3506                 if ( image 
!= NULL 
) 
3513 // try root substitutions 
3514 static ImageLoader
* loadPhase0(const char* path
, const char* orgPath
, const LoadContext
& context
, unsigned& cacheIndex
, std::vector
<const char*>* exceptions
) 
3516         //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions); 
3518 #if SUPPORT_ROOT_PATH 
3519         // handle DYLD_ROOT_PATH which forces absolute paths to use a new root 
3520         if ( (gLinkContext
.rootPaths 
!= NULL
) && (path
[0] == '/') ) { 
3521                 for(const char* const* rootPath 
= gLinkContext
.rootPaths 
; *rootPath 
!= NULL
; ++rootPath
) { 
3522                         char newPath
[strlen(*rootPath
) + strlen(path
)+2]; 
3523                         strcpy(newPath
, *rootPath
); 
3524                         strcat(newPath
, path
); 
3525                         ImageLoader
* image 
= loadPhase1(newPath
, orgPath
, context
, cacheIndex
, exceptions
); 
3526                         if ( image 
!= NULL 
) 
3533         return loadPhase1(path
, orgPath
, context
, cacheIndex
, exceptions
); 
3536 static bool cacheablePath(const char* path
) { 
3537         if (strncmp(path
, "/usr/lib/", 9) == 0) 
3539         if (strncmp(path
, "/System/Library/", 16) == 0) 
3545 // Given all the DYLD_ environment variables, the general case for loading libraries 
3546 // is that any given path expands into a list of possible locations to load.  We 
3547 // also must take care to ensure two copies of the "same" library are never loaded. 
3549 // The algorithm used here is that there is a separate function for each "phase" of the 
3550 // path expansion.  Each phase function calls the next phase with each possible expansion 
3551 // of that phase.  The result is the last phase is called with all possible paths.   
3553 // To catch duplicates the algorithm is run twice.  The first time, the last phase checks 
3554 // the path against all loaded images.  The second time, the last phase calls open() on  
3555 // the path.  Either time, if an image is found, the phases all unwind without checking 
3558 ImageLoader
* load(const char* path
, const LoadContext
& context
, unsigned& cacheIndex
) 
3560         CRSetCrashLogMessage2(path
); 
3561         const char* orgPath 
= path
; 
3562         cacheIndex 
= UINT32_MAX
; 
3564         //dyld::log("%s(%s)\n", __func__ , path); 
3565         char realPath
[PATH_MAX
]; 
3566         // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match 
3567         if ( context
.useSearchPaths 
&& ( gLinkContext
.imageSuffix 
!= NULL
) ) { 
3568                 if ( realpath(path
, realPath
) != NULL 
) 
3572         // try all path permutations and check against existing loaded images 
3574         ImageLoader
* image 
= loadPhase0(path
, orgPath
, context
, cacheIndex
, NULL
); 
3575         if ( image 
!= NULL 
) { 
3576                 CRSetCrashLogMessage2(NULL
); 
3580         // try all path permutations and try open() until first success 
3581         std::vector
<const char*> exceptions
; 
3582         image 
= loadPhase0(path
, orgPath
, context
, cacheIndex
, &exceptions
); 
3583 #if !TARGET_IPHONE_SIMULATOR 
3584         // <rdar://problem/16704628> support symlinks on disk to a path in dyld shared cache 
3586                 image 
= loadPhase2cache(path
, orgPath
, context
, cacheIndex
, &exceptions
); 
3588     CRSetCrashLogMessage2(NULL
); 
3589         if ( image 
!= NULL 
) { 
3590                 // <rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables 
3591                 for (std::vector
<const char*>::iterator it 
= exceptions
.begin(); it 
!= exceptions
.end(); ++it
) { 
3594                 // if loaded image is not from cache, but original path is in cache 
3595                 // set gSharedCacheOverridden flag to disable some ObjC optimizations 
3596                 if ( !gSharedCacheOverridden 
&& !image
->inSharedCache() && image
->isDylib() && cacheablePath(path
) && inSharedCache(path
) ) { 
3597                         gSharedCacheOverridden 
= true; 
3601         else if ( exceptions
.size() == 0 ) { 
3602                 if ( context
.dontLoad 
) { 
3606                         throw "image not found"; 
3609                 const char* msgStart 
= "no suitable image found.  Did find:"; 
3610                 const char* delim 
= "\n\t"; 
3611                 size_t allsizes 
= strlen(msgStart
)+8; 
3612                 for (size_t i
=0; i 
< exceptions
.size(); ++i
)  
3613                         allsizes 
+= (strlen(exceptions
[i
]) + strlen(delim
)); 
3614                 char* fullMsg 
= new char[allsizes
]; 
3615                 strcpy(fullMsg
, msgStart
); 
3616                 for (size_t i
=0; i 
< exceptions
.size(); ++i
) { 
3617                         strcat(fullMsg
, delim
); 
3618                         strcat(fullMsg
, exceptions
[i
]); 
3619                         free((void*)exceptions
[i
]); 
3621                 throw (const char*)fullMsg
; 
3629 static void mapSharedCache() 
3631         dyld3::SharedCacheOptions opts
; 
3632         opts
.cacheDirOverride   
= sSharedCacheOverrideDir
; 
3633         opts
.forcePrivate               
= (gLinkContext
.sharedRegionMode 
== ImageLoader::kUsePrivateSharedRegion
); 
3634 #if __x86_64__ && !TARGET_IPHONE_SIMULATOR 
3635         opts
.useHaswell                 
= sHaswell
; 
3637         opts
.useHaswell                 
= false; 
3639         opts
.verbose                    
= gLinkContext
.verboseMapping
; 
3640         loadDyldCache(opts
, &sSharedCacheLoadInfo
); 
3642         // update global state 
3643         if ( sSharedCacheLoadInfo
.loadAddress 
!= nullptr ) { 
3644                 dyld::gProcessInfo
->processDetachedFromSharedRegion 
= opts
.forcePrivate
; 
3645                 dyld::gProcessInfo
->sharedCacheSlide                
= sSharedCacheLoadInfo
.slide
; 
3646                 dyld::gProcessInfo
->sharedCacheBaseAddress          
= (unsigned long)sSharedCacheLoadInfo
.loadAddress
; 
3647                 sSharedCacheLoadInfo
.loadAddress
->getUUID(dyld::gProcessInfo
->sharedCacheUUID
); 
3648                 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_SHARED_CACHE_A
, (const uuid_t 
*)&dyld::gProcessInfo
->sharedCacheUUID
[0], {0,0}, {{ 0, 0 }}, (const mach_header 
*)sSharedCacheLoadInfo
.loadAddress
); 
3651 //#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR 
3652 // RAM disk booting does not have shared cache yet 
3653 // Don't make lack of a shared cache fatal in that case 
3654 //      if ( sSharedCacheLoadInfo.loadAddress == nullptr ) { 
3655 //              if ( sSharedCacheLoadInfo.errorMessage != nullptr ) 
3656 //                      halt(sSharedCacheLoadInfo.errorMessage); 
3658 //                      halt("error loading dyld shared cache"); 
3665 // create when NSLinkModule is called for a second time on a bundle 
3666 ImageLoader
* cloneImage(ImageLoader
* image
) 
3668         // open file (automagically closed when this function exits) 
3669         FileOpener 
file(image
->getPath()); 
3671         struct stat stat_buf
; 
3672         if ( fstat(file
.getFileDescriptor(), &stat_buf
) == -1) 
3675         dyld::LoadContext context
; 
3676         context
.useSearchPaths          
= false; 
3677         context
.useFallbackPaths        
= false; 
3678         context
.useLdLibraryPath        
= false; 
3679         context
.implicitRPath           
= false; 
3680         context
.matchByInstallName      
= false; 
3681         context
.dontLoad                        
= false; 
3682         context
.mustBeBundle            
= true; 
3683         context
.mustBeDylib                     
= false; 
3684         context
.canBePIE                        
= false; 
3685         context
.origin                          
= NULL
; 
3686         context
.rpath                           
= NULL
; 
3687         return loadPhase6(file
.getFileDescriptor(), stat_buf
, image
->getPath(), context
); 
3691 ImageLoader
* loadFromMemory(const uint8_t* mem
, uint64_t len
, const char* moduleName
) 
3693         // if fat wrapper, find usable sub-file 
3694         const fat_header
* memStartAsFat 
= (fat_header
*)mem
; 
3695         uint64_t fileOffset 
= 0; 
3696         uint64_t fileLength 
= len
; 
3697         if ( memStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
3698                 if ( fatFindBest(memStartAsFat
, &fileOffset
, &fileLength
) ) { 
3699                         mem 
= &mem
[fileOffset
]; 
3703                         throw "no matching architecture in universal wrapper"; 
3708         if ( isCompatibleMachO(mem
, moduleName
) ) { 
3709                 ImageLoader
* image 
= ImageLoaderMachO::instantiateFromMemory(moduleName
, (macho_header
*)mem
, len
, gLinkContext
); 
3710                 // don't add bundles to global list, they can be loaded but not linked.  When linked it will be added to list 
3711                 if ( ! image
->isBundle() )  
3716         // try other file formats here... 
3718         // throw error about what was found 
3719         switch (*(uint32_t*)mem
) { 
3724                         throw "mach-o, but wrong architecture"; 
3726                 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",  
3727                         mem
[0], mem
[1], mem
[2], mem
[3], mem
[4], mem
[5], mem
[6],mem
[7]); 
3732 void registerAddCallback(ImageCallback func
) 
3734         // now add to list to get notified when any more images are added 
3735         sAddImageCallbacks
.push_back(func
); 
3737         // call callback with all existing images 
3738         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
3739                 ImageLoader
* image 
= *it
; 
3740                 if ( image
->getState() >= dyld_image_state_bound 
&& image
->getState() < dyld_image_state_terminated 
) 
3741                         (*func
)(image
->machHeader(), image
->getSlide()); 
3743 #if SUPPORT_ACCELERATE_TABLES 
3744         if ( sAllCacheImagesProxy 
!= NULL 
) { 
3745                 dyld_image_info infos
[allImagesCount()+1]; 
3746                 unsigned cacheCount 
= sAllCacheImagesProxy
->appendImagesToNotify(dyld_image_state_bound
, true, infos
); 
3747                 for (unsigned i
=0; i 
< cacheCount
; ++i
) { 
3748                         (*func
)(infos
[i
].imageLoadAddress
, sSharedCacheLoadInfo
.slide
); 
3754 void registerRemoveCallback(ImageCallback func
) 
3756         // <rdar://problem/15025198> ignore calls to register a notification during a notification 
3757         if ( sRemoveImageCallbacksInUse 
) 
3759         sRemoveImageCallbacks
.push_back(func
); 
3762 void clearErrorMessage() 
3764         error_string
[0] = '\0'; 
3767 void setErrorMessage(const char* message
) 
3769         // save off error message in global buffer for CrashReporter to find 
3770         strlcpy(error_string
, message
, sizeof(error_string
)); 
3773 const char* getErrorMessage() 
3775         return error_string
; 
3778 void halt(const char* message
) 
3780         dyld::log("dyld: %s\n", message
); 
3781         setErrorMessage(message
); 
3782         dyld::gProcessInfo
->errorMessage 
= error_string
; 
3783         if ( !gLinkContext
.startedInitializingMainExecutable 
) 
3784                 dyld::gProcessInfo
->terminationFlags 
= 1; 
3786                 dyld::gProcessInfo
->terminationFlags 
= 0; 
3788         char payloadBuffer
[EXIT_REASON_PAYLOAD_MAX_LEN
]; 
3789         dyld_abort_payload
* payload 
= (dyld_abort_payload
*)payloadBuffer
; 
3790         payload
->version               
= 1; 
3791         payload
->flags                 
= gLinkContext
.startedInitializingMainExecutable 
? 0 : 1; 
3792         payload
->targetDylibPathOffset 
= 0; 
3793         payload
->clientPathOffset      
= 0; 
3794         payload
->symbolOffset          
= 0; 
3795         int payloadSize 
= sizeof(dyld_abort_payload
); 
3797         if ( dyld::gProcessInfo
->errorTargetDylibPath 
!= NULL 
) { 
3798                 payload
->targetDylibPathOffset 
= payloadSize
; 
3799                 payloadSize 
+= strlcpy(&payloadBuffer
[payloadSize
], dyld::gProcessInfo
->errorTargetDylibPath
, sizeof(payloadBuffer
)-payloadSize
) + 1; 
3801         if ( dyld::gProcessInfo
->errorClientOfDylibPath 
!= NULL 
) { 
3802                 payload
->clientPathOffset 
= payloadSize
; 
3803                 payloadSize 
+= strlcpy(&payloadBuffer
[payloadSize
], dyld::gProcessInfo
->errorClientOfDylibPath
, sizeof(payloadBuffer
)-payloadSize
) + 1; 
3805         if ( dyld::gProcessInfo
->errorSymbol 
!= NULL 
) { 
3806                 payload
->symbolOffset 
= payloadSize
; 
3807                 payloadSize 
+= strlcpy(&payloadBuffer
[payloadSize
], dyld::gProcessInfo
->errorSymbol
, sizeof(payloadBuffer
)-payloadSize
) + 1; 
3809         char truncMessage
[EXIT_REASON_USER_DESC_MAX_LEN
]; 
3810         strlcpy(truncMessage
, message
, EXIT_REASON_USER_DESC_MAX_LEN
); 
3811         abort_with_payload(OS_REASON_DYLD
, dyld::gProcessInfo
->errorKind 
? dyld::gProcessInfo
->errorKind 
: DYLD_EXIT_REASON_OTHER
, payloadBuffer
, payloadSize
, truncMessage
, 0); 
3814 static void setErrorStrings(unsigned errorCode
, const char* errorClientOfDylibPath
, 
3815                                                                 const char* errorTargetDylibPath
, const char* errorSymbol
) 
3817         dyld::gProcessInfo
->errorKind 
= errorCode
; 
3818         dyld::gProcessInfo
->errorClientOfDylibPath 
= errorClientOfDylibPath
; 
3819         dyld::gProcessInfo
->errorTargetDylibPath 
= errorTargetDylibPath
; 
3820         dyld::gProcessInfo
->errorSymbol 
= errorSymbol
; 
3824 uintptr_t bindLazySymbol(const mach_header
* mh
, uintptr_t* lazyPointer
) 
3826         uintptr_t result 
= 0; 
3827         // acquire read-lock on dyld's data structures 
3828 #if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved 
3829         if ( gLibSystemHelpers 
!= NULL 
)  
3830                 (*gLibSystemHelpers
->lockForReading
)(); 
3832         // lookup and bind lazy pointer and get target address 
3834                 ImageLoader
* target
; 
3836                 // fast stubs pass NULL for mh and image is instead found via the location of stub (aka lazyPointer) 
3838                         target 
= dyld::findImageContainingAddress(lazyPointer
); 
3840                         target 
= dyld::findImageByMachHeader(mh
); 
3842                 // note, target should always be mach-o, because only mach-o lazy handler wired up to this 
3843                 target 
= dyld::findImageByMachHeader(mh
); 
3845                 if ( target 
== NULL 
) 
3846                         throwf("image not found for lazy pointer at %p", lazyPointer
); 
3847                 result 
= target
->doBindLazySymbol(lazyPointer
, gLinkContext
); 
3849         catch (const char* message
) { 
3850                 dyld::log("dyld: lazy symbol binding failed: %s\n", message
); 
3853         // release read-lock on dyld's data structures 
3855         if ( gLibSystemHelpers 
!= NULL 
)  
3856                 (*gLibSystemHelpers
->unlockForReading
)(); 
3858         // return target address to glue which jumps to it with real parameters restored 
3863 uintptr_t fastBindLazySymbol(ImageLoader
** imageLoaderCache
, uintptr_t lazyBindingInfoOffset
) 
3865         uintptr_t result 
= 0; 
3867         if ( *imageLoaderCache 
== NULL 
) { 
3869                 *imageLoaderCache 
= dyld::findMappedRange((uintptr_t)imageLoaderCache
); 
3870                 if ( *imageLoaderCache 
== NULL 
) { 
3871 #if SUPPORT_ACCELERATE_TABLES 
3872                 if ( sAllCacheImagesProxy 
!= NULL 
) { 
3873                         const mach_header
* mh
; 
3876                         if ( sAllCacheImagesProxy
->addressInCache(imageLoaderCache
, &mh
, &path
, &index
) ) { 
3877                                 result 
= sAllCacheImagesProxy
->bindLazy(lazyBindingInfoOffset
, gLinkContext
, mh
, index
); 
3878                                 if ( result 
== 0 ) { 
3879                                         halt("dyld: lazy symbol binding failed for image in dyld shared\n"); 
3885                         const char* message 
= "fast lazy binding from unknown image"; 
3886                         dyld::log("dyld: %s\n", message
); 
3891         // bind lazy pointer and return it 
3893                 result 
= (*imageLoaderCache
)->doBindFastLazySymbol((uint32_t)lazyBindingInfoOffset
, gLinkContext
,  
3894                                                                 (dyld::gLibSystemHelpers 
!= NULL
) ? dyld::gLibSystemHelpers
->acquireGlobalDyldLock 
: NULL
, 
3895                                                                 (dyld::gLibSystemHelpers 
!= NULL
) ? dyld::gLibSystemHelpers
->releaseGlobalDyldLock 
: NULL
); 
3897         catch (const char* message
) { 
3898                 dyld::log("dyld: lazy symbol binding failed: %s\n", message
); 
3902         // return target address to glue which jumps to it with real parameters restored 
3908 void registerUndefinedHandler(UndefinedHandler handler
) 
3910         sUndefinedHandler 
= handler
; 
3913 static void undefinedHandler(const char* symboName
) 
3915         if ( sUndefinedHandler 
!= NULL 
) { 
3916                 (*sUndefinedHandler
)(symboName
); 
3920 static bool findExportedSymbol(const char* name
, bool onlyInCoalesced
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
3922         // search all images in order 
3923         const ImageLoader
* firstWeakImage 
= NULL
; 
3924         const ImageLoader::Symbol
* firstWeakSym 
= NULL
; 
3925         const size_t imageCount 
= sAllImages
.size(); 
3926         for(size_t i
=0; i 
< imageCount
; ++i
) { 
3927                 ImageLoader
* anImage 
= sAllImages
[i
]; 
3928                 // the use of inserted libraries alters search order 
3929                 // so that inserted libraries are found before the main executable 
3930                 if ( sInsertedDylibCount 
> 0 ) { 
3931                         if ( i 
< sInsertedDylibCount 
) 
3932                                 anImage 
= sAllImages
[i
+1]; 
3933                         else if ( i 
== sInsertedDylibCount 
) 
3934                                 anImage 
= sAllImages
[0]; 
3936                 if ( ! anImage
->hasHiddenExports() && (!onlyInCoalesced 
|| anImage
->hasCoalescedExports()) ) { 
3937                         *sym 
= anImage
->findExportedSymbol(name
, false, image
); 
3938                         if ( *sym 
!= NULL 
) { 
3939                                 // if weak definition found, record first one found 
3940                                 if ( ((*image
)->getExportedSymbolInfo(*sym
) & ImageLoader::kWeakDefinition
) != 0 ) { 
3941                                         if ( firstWeakImage 
== NULL 
) { 
3942                                                 firstWeakImage 
= *image
; 
3943                                                 firstWeakSym 
= *sym
; 
3947                                         // found non-weak, so immediately return with it 
3953         if ( firstWeakSym 
!= NULL 
) { 
3954                 // found a weak definition, but no non-weak, so return first weak found 
3955                 *sym 
= firstWeakSym
; 
3956                 *image 
= firstWeakImage
; 
3959 #if SUPPORT_ACCELERATE_TABLES 
3960         if ( sAllCacheImagesProxy 
!= NULL 
) { 
3961                 if ( sAllCacheImagesProxy
->flatFindSymbol(name
, onlyInCoalesced
, sym
, image
) ) 
3969 bool flatFindExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
3971         return findExportedSymbol(name
, false, sym
, image
); 
3974 bool findCoalescedExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
3976         return findExportedSymbol(name
, true, sym
, image
); 
3980 bool flatFindExportedSymbolWithHint(const char* name
, const char* librarySubstring
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
) 
3982         // search all images in order 
3983         const size_t imageCount 
= sAllImages
.size(); 
3984         for(size_t i
=0; i 
< imageCount
; ++i
){ 
3985                 ImageLoader
* anImage 
= sAllImages
[i
]; 
3986                 // only look at images whose paths contain the hint string (NULL hint string is wildcard) 
3987                 if ( ! anImage
->isBundle() && ((librarySubstring
==NULL
) || (strstr(anImage
->getPath(), librarySubstring
) != NULL
)) ) { 
3988                         *sym 
= anImage
->findExportedSymbol(name
, false, image
); 
3989                         if ( *sym 
!= NULL 
) { 
3998 unsigned int getCoalescedImages(ImageLoader
* images
[], unsigned imageIndex
[]) 
4000         unsigned int count 
= 0; 
4001         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4002                 ImageLoader
* image 
= *it
; 
4003                 if ( image
->participatesInCoalescing() ) { 
4004                         images
[count
] = *it
; 
4005                         imageIndex
[count
] = 0; 
4009 #if SUPPORT_ACCELERATE_TABLES 
4010         if ( sAllCacheImagesProxy 
!= NULL 
) { 
4011                 sAllCacheImagesProxy
->appendImagesNeedingCoalescing(images
, imageIndex
, count
); 
4018 static ImageLoader::MappedRegion
* getMappedRegions(ImageLoader::MappedRegion
* regions
) 
4020         ImageLoader::MappedRegion
* end 
= regions
; 
4021         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4022                 (*it
)->getMappedRegions(end
); 
4027 void registerImageStateSingleChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
) 
4029         // mark the image that the handler is in as never-unload because dyld has a reference into it 
4030         ImageLoader
* handlerImage 
= findImageContainingAddress((void*)handler
); 
4031         if ( handlerImage 
!= NULL 
) 
4032                 handlerImage
->setNeverUnload(); 
4034         // add to list of handlers 
4035         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sSingleHandlers
); 
4036         if ( handlers 
!= NULL 
) { 
4037         // <rdar://problem/10332417> need updateAllImages() to be last in dyld_image_state_mapped list 
4038         // so that if ObjC adds a handler that prevents a load, it happens before the gdb list is updated 
4039         if ( state 
== dyld_image_state_mapped 
) 
4040             handlers
->insert(handlers
->begin(), handler
); 
4042             handlers
->push_back(handler
); 
4044                 // call callback with all existing images 
4045                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4046                         ImageLoader
* image 
= *it
; 
4047                         dyld_image_info  info
; 
4048                         info
.imageLoadAddress   
= image
->machHeader(); 
4049                         info
.imageFilePath              
= image
->getRealPath(); 
4050                         info
.imageFileModDate   
= image
->lastModified(); 
4051                         // should only call handler if state == image->state 
4052                         if ( image
->getState() == state 
) 
4053                                 (*handler
)(state
, 1, &info
); 
4054                         // ignore returned string, too late to do anything 
4059 void registerImageStateBatchChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
) 
4061         // mark the image that the handler is in as never-unload because dyld has a reference into it 
4062         ImageLoader
* handlerImage 
= findImageContainingAddress((void*)handler
); 
4063         if ( handlerImage 
!= NULL 
) 
4064                 handlerImage
->setNeverUnload(); 
4066         // add to list of handlers 
4067         std::vector
<dyld_image_state_change_handler
>* handlers 
= stateToHandlers(state
, sBatchHandlers
); 
4068         if ( handlers 
!= NULL 
) { 
4069                 // insert at front, so that gdb handler is always last 
4070                 handlers
->insert(handlers
->begin(), handler
); 
4072                 // call callback with all existing images 
4074                         notifyBatchPartial(state
, true, handler
, false, false); 
4076                 catch (const char* msg
) { 
4077                         // ignore request to abort during registration 
4083 void registerObjCNotifiers(_dyld_objc_notify_mapped mapped
, _dyld_objc_notify_init init
, _dyld_objc_notify_unmapped unmapped
) 
4085         // record functions to call 
4086         sNotifyObjCMapped       
= mapped
; 
4087         sNotifyObjCInit         
= init
; 
4088         sNotifyObjCUnmapped 
= unmapped
; 
4090         // call 'mapped' function with all images mapped so far 
4092                 notifyBatchPartial(dyld_image_state_bound
, true, NULL
, false, true); 
4094         catch (const char* msg
) { 
4095                 // ignore request to abort during registration 
4098         // <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem) 
4099         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4100                 ImageLoader
* image 
= *it
; 
4101                 if ( (image
->getState() == dyld_image_state_initialized
) && image
->notifyObjC() ) { 
4102                         (*sNotifyObjCInit
)(image
->getRealPath(), image
->machHeader()); 
4107 bool sharedCacheUUID(uuid_t uuid
) 
4109         if ( sSharedCacheLoadInfo
.loadAddress 
== nullptr ) 
4112         sSharedCacheLoadInfo
.loadAddress
->getUUID(uuid
); 
4116 #if SUPPORT_ACCELERATE_TABLES 
4118 bool dlopenFromCache(const char* path
, int mode
, void** handle
) 
4120         if ( sAllCacheImagesProxy 
== NULL 
) 
4122         char fallbackPath
[PATH_MAX
]; 
4123         bool result 
= sAllCacheImagesProxy
->dlopenFromCache(gLinkContext
, path
, mode
, handle
); 
4124         if ( !result 
&& (strchr(path
, '/') == NULL
) ) { 
4125                 // POSIX says you can call dlopen() with a leaf name (e.g. dlopen("libz.dylb")) 
4126                 strcpy(fallbackPath
, "/usr/lib/"); 
4127                 strlcat(fallbackPath
, path
, PATH_MAX
); 
4128                 result 
= sAllCacheImagesProxy
->dlopenFromCache(gLinkContext
, fallbackPath
, mode
, handle
); 
4130                         path 
= fallbackPath
; 
4133                 // leaf name could be a symlink 
4134                 char resolvedPath
[PATH_MAX
]; 
4135                 realpath(path
, resolvedPath
); 
4136                 int realpathErrno 
= errno
; 
4137                 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT 
4138                 if ( (realpathErrno 
== ENOENT
) || (realpathErrno 
== 0) ) { 
4139                         result 
= sAllCacheImagesProxy
->dlopenFromCache(gLinkContext
, resolvedPath
, mode
, handle
); 
4146 bool makeCacheHandle(ImageLoader
* image
, unsigned cacheIndex
, int mode
, void** result
) 
4148         if ( sAllCacheImagesProxy 
== NULL 
) 
4150         return sAllCacheImagesProxy
->makeCacheHandle(gLinkContext
, cacheIndex
, mode
, result
); 
4153 bool isCacheHandle(void* handle
) 
4155         if ( sAllCacheImagesProxy 
== NULL 
) 
4157         return sAllCacheImagesProxy
->isCacheHandle(handle
, NULL
, NULL
); 
4160 bool isPathInCache(const char* path
) 
4162         if ( sAllCacheImagesProxy 
== NULL 
) 
4165         return sAllCacheImagesProxy
->hasDylib(path
, &index
); 
4168 const char* getPathFromIndex(unsigned cacheIndex
) 
4170         if ( sAllCacheImagesProxy 
== NULL 
) 
4172         return sAllCacheImagesProxy
->getIndexedPath(cacheIndex
); 
4175 void* dlsymFromCache(void* handle
, const char* symName
, unsigned index
) 
4177         if ( sAllCacheImagesProxy 
== NULL 
) 
4179         return sAllCacheImagesProxy
->dlsymFromCache(gLinkContext
, handle
, symName
, index
); 
4182 bool addressInCache(const void* address
, const mach_header
** mh
, const char** path
, unsigned* index
) 
4184         if ( sAllCacheImagesProxy 
== NULL 
) 
4187         return sAllCacheImagesProxy
->addressInCache(address
, mh
, path
, index 
? index 
: &ignore
); 
4190 bool findUnwindSections(const void* addr
, dyld_unwind_sections
* info
) 
4192         if ( sAllCacheImagesProxy 
== NULL 
) 
4194         return sAllCacheImagesProxy
->findUnwindSections(addr
, info
); 
4197 bool dladdrFromCache(const void* address
, Dl_info
* info
) 
4199         if ( sAllCacheImagesProxy 
== NULL 
) 
4201         return sAllCacheImagesProxy
->dladdrFromCache(address
, info
); 
4205 static ImageLoader
* libraryLocator(const char* libraryName
, bool search
, const char* origin
, const ImageLoader::RPathChain
* rpaths
, unsigned& cacheIndex
) 
4207         dyld::LoadContext context
; 
4208         context
.useSearchPaths          
= search
; 
4209         context
.useFallbackPaths        
= search
; 
4210         context
.useLdLibraryPath        
= false; 
4211         context
.implicitRPath           
= false; 
4212         context
.matchByInstallName      
= false; 
4213         context
.dontLoad                        
= false; 
4214         context
.mustBeBundle            
= false; 
4215         context
.mustBeDylib                     
= true; 
4216         context
.canBePIE                        
= false; 
4217         context
.origin                          
= origin
; 
4218         context
.rpath                           
= rpaths
; 
4219         return load(libraryName
, context
, cacheIndex
); 
4222 static const char* basename(const char* path
) 
4224     const char* last 
= path
; 
4225     for (const char* s 
= path
; *s 
!= '\0'; s
++) { 
4232 static void setContext(const macho_header
* mainExecutableMH
, int argc
, const char* argv
[], const char* envp
[], const char* apple
[]) 
4234         gLinkContext
.loadLibrary                        
= &libraryLocator
; 
4235         gLinkContext
.terminationRecorder        
= &terminationRecorder
; 
4236         gLinkContext
.flatExportFinder           
= &flatFindExportedSymbol
; 
4237         gLinkContext
.coalescedExportFinder      
= &findCoalescedExportedSymbol
; 
4238         gLinkContext
.getCoalescedImages         
= &getCoalescedImages
; 
4239         gLinkContext
.undefinedHandler           
= &undefinedHandler
; 
4240         gLinkContext
.getAllMappedRegions        
= &getMappedRegions
; 
4241         gLinkContext
.bindingHandler                     
= NULL
; 
4242         gLinkContext
.notifySingle                       
= ¬ifySingle
; 
4243         gLinkContext
.notifyBatch                        
= ¬ifyBatch
; 
4244         gLinkContext
.removeImage                        
= &removeImage
; 
4245         gLinkContext
.registerDOFs                       
= ®isterDOFs
; 
4246         gLinkContext
.clearAllDepths                     
= &clearAllDepths
; 
4247         gLinkContext
.printAllDepths                     
= &printAllDepths
; 
4248         gLinkContext
.imageCount                         
= &imageCount
; 
4249         gLinkContext
.setNewProgramVars          
= &setNewProgramVars
; 
4250         gLinkContext
.inSharedCache                      
= &inSharedCache
; 
4251         gLinkContext
.setErrorStrings            
= &setErrorStrings
; 
4252 #if SUPPORT_OLD_CRT_INITIALIZATION 
4253         gLinkContext
.setRunInitialzersOldWay
= &setRunInitialzersOldWay
; 
4255         gLinkContext
.findImageContainingAddress 
= &findImageContainingAddress
; 
4256         gLinkContext
.addDynamicReference        
= &addDynamicReference
; 
4257 #if SUPPORT_ACCELERATE_TABLES 
4258         gLinkContext
.notifySingleFromCache      
= ¬ifySingleFromCache
; 
4259         gLinkContext
.getPreInitNotifyHandler
= &getPreInitNotifyHandler
; 
4260         gLinkContext
.getBoundBatchHandler   
= &getBoundBatchHandler
; 
4262         gLinkContext
.bindingOptions                     
= ImageLoader::kBindingNone
; 
4263         gLinkContext
.argc                                       
= argc
; 
4264         gLinkContext
.argv                                       
= argv
; 
4265         gLinkContext
.envp                                       
= envp
; 
4266         gLinkContext
.apple                                      
= apple
; 
4267         gLinkContext
.progname                           
= (argv
[0] != NULL
) ? basename(argv
[0]) : ""; 
4268         gLinkContext
.programVars
.mh                     
= mainExecutableMH
; 
4269         gLinkContext
.programVars
.NXArgcPtr      
= &gLinkContext
.argc
; 
4270         gLinkContext
.programVars
.NXArgvPtr      
= &gLinkContext
.argv
; 
4271         gLinkContext
.programVars
.environPtr     
= &gLinkContext
.envp
; 
4272         gLinkContext
.programVars
.__prognamePtr
=&gLinkContext
.progname
; 
4273         gLinkContext
.mainExecutable                     
= NULL
; 
4274         gLinkContext
.imageSuffix                        
= NULL
; 
4275         gLinkContext
.dynamicInterposeArray      
= NULL
; 
4276         gLinkContext
.dynamicInterposeCount      
= 0; 
4277         gLinkContext
.prebindUsage                       
= ImageLoader::kUseAllPrebinding
; 
4278 #if TARGET_IPHONE_SIMULATOR 
4279         gLinkContext
.sharedRegionMode           
= ImageLoader::kUsePrivateSharedRegion
; 
4281         gLinkContext
.sharedRegionMode           
= ImageLoader::kUseSharedRegion
; 
4288 // Look for a special segment in the mach header.  
4289 // Its presences means that the binary wants to have DYLD ignore 
4290 // DYLD_ environment variables. 
4292 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
4293 static bool hasRestrictedSegment(const macho_header
* mh
) 
4295         const uint32_t cmd_count 
= mh
->ncmds
; 
4296         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
4297         const struct load_command
* cmd 
= cmds
; 
4298         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4300                         case LC_SEGMENT_COMMAND
: 
4302                                 const struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
4304                                 //dyld::log("seg name: %s\n", seg->segname); 
4305                                 if (strcmp(seg
->segname
, "__RESTRICT") == 0) { 
4306                                         const struct macho_section
* const sectionsStart 
= (struct macho_section
*)((char*)seg 
+ sizeof(struct macho_segment_command
)); 
4307                                         const struct macho_section
* const sectionsEnd 
= §ionsStart
[seg
->nsects
]; 
4308                                         for (const struct macho_section
* sect
=sectionsStart
; sect 
< sectionsEnd
; ++sect
) { 
4309                                                 if (strcmp(sect
->sectname
, "__restrict") == 0)  
4316                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
4323 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR 
4324 static bool isFairPlayEncrypted(const macho_header
* mh
) 
4326         const uint32_t cmd_count 
= mh
->ncmds
; 
4327         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
4328         const struct load_command
* cmd 
= cmds
; 
4329         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4330                 if ( cmd
->cmd 
== LC_ENCRYPT_COMMAND 
) { 
4331                         const encryption_info_command
* enc 
= (encryption_info_command
*)cmd
; 
4332                         return (enc
->cryptid 
!= 0); 
4334                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
4341 #if SUPPORT_VERSIONED_PATHS 
4343 static bool readFirstPage(const char* dylibPath
, uint8_t firstPage
[4096])  
4346         // open file (automagically closed when this function exits) 
4347         FileOpener 
file(dylibPath
); 
4349         if ( file
.getFileDescriptor() == -1 )  
4352         if ( pread(file
.getFileDescriptor(), firstPage
, 4096, 0) != 4096 ) 
4355         // if fat wrapper, find usable sub-file 
4356         const fat_header
* fileStartAsFat 
= (fat_header
*)firstPage
; 
4357         if ( fileStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
4358                 uint64_t fileOffset
; 
4359                 uint64_t fileLength
; 
4360                 if ( fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) ) { 
4361                         if ( pread(file
.getFileDescriptor(), firstPage
, 4096, fileOffset
) != 4096 ) 
4373 // Peeks at a dylib file and returns its current_version and install_name. 
4374 // Returns false on error. 
4376 static bool getDylibVersionAndInstallname(const char* dylibPath
, uint32_t* version
, char* installName
) 
4378         uint8_t firstPage
[4096]; 
4379         const macho_header
* mh 
= (macho_header
*)firstPage
; 
4380         if ( !readFirstPage(dylibPath
, firstPage
) ) { 
4381                 // If file cannot be read, check to see if path is in shared cache 
4382                 const macho_header
* mhInCache
; 
4383                 const char*                     pathInCache
; 
4385                 if ( !findInSharedCacheImage(dylibPath
, true, NULL
, &mhInCache
, &pathInCache
, &slideInCache
) ) 
4390         // check mach-o header 
4391         if ( mh
->magic 
!= sMainExecutableMachHeader
->magic 
)  
4393         if ( mh
->cputype 
!= sMainExecutableMachHeader
->cputype 
) 
4396         // scan load commands for LC_ID_DYLIB 
4397         const uint32_t cmd_count 
= mh
->ncmds
; 
4398         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
4399         const struct load_command
* const cmdsReadEnd 
= (struct load_command
*)(((char*)mh
)+4096); 
4400         const struct load_command
* cmd 
= cmds
; 
4401         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4405                                 const struct dylib_command
* id 
= (struct dylib_command
*)cmd
; 
4406                                 *version 
= id
->dylib
.current_version
; 
4407                                 if ( installName 
!= NULL 
) 
4408                                         strlcpy(installName
, (char *)id 
+ id
->dylib
.name
.offset
, PATH_MAX
); 
4413                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
4414                 if ( cmd 
> cmdsReadEnd 
) 
4420 #endif // SUPPORT_VERSIONED_PATHS 
4424 static void printAllImages() 
4426         dyld::log("printAllImages()\n"); 
4427         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4428                 ImageLoader
* image 
= *it
; 
4429                 dyld_image_states imageState 
= image
->getState(); 
4430                 dyld::log("  state=%d, dlopen-count=%d, never-unload=%d, in-use=%d, name=%s\n", 
4431                                   imageState
, image
->dlopenCount(), image
->neverUnload(), image
->isMarkedInUse(), image
->getShortName()); 
4436 void link(ImageLoader
* image
, bool forceLazysBound
, bool neverUnload
, const ImageLoader::RPathChain
& loaderRPaths
, unsigned cacheIndex
) 
4438         // add to list of known images.  This did not happen at creation time for bundles 
4439         if ( image
->isBundle() && !image
->isLinked() ) 
4442         // we detect root images as those not linked in yet  
4443         if ( !image
->isLinked() ) 
4444                 addRootImage(image
); 
4448                 const char* path 
= image
->getPath(); 
4449 #if SUPPORT_ACCELERATE_TABLES 
4450                 if ( image 
== sAllCacheImagesProxy 
) 
4451                         path 
= sAllCacheImagesProxy
->getIndexedPath(cacheIndex
); 
4453                 image
->link(gLinkContext
, forceLazysBound
, false, neverUnload
, loaderRPaths
, path
); 
4455         catch (const char* msg
) { 
4456                 garbageCollectImages(); 
4462 void runInitializers(ImageLoader
* image
) 
4464         // do bottom up initialization 
4465         ImageLoader::InitializerTimingList initializerTimes
[allImagesCount()]; 
4466         initializerTimes
[0].count 
= 0; 
4467         image
->runInitializers(gLinkContext
, initializerTimes
[0]); 
4470 // This function is called at the end of dlclose() when the reference count goes to zero. 
4471 // The dylib being unloaded may have brought in other dependent dylibs when it was loaded. 
4472 // Those dependent dylibs need to be unloaded, but only if they are not referenced by 
4473 // something else.  We use a standard mark and sweep garbage collection. 
4475 // The tricky part is that when a dylib is unloaded it may have a termination function that 
4476 // can run and itself call dlclose() on yet another dylib.  The problem is that this 
4477 // sort of gabage collection is not re-entrant.  Instead a terminator's call to dlclose() 
4478 // which calls garbageCollectImages() will just set a flag to re-do the garbage collection 
4479 // when the current pass is done. 
4481 // Also note that this is done within the dyld global lock, so it is always single threaded. 
4483 void garbageCollectImages() 
4485         static bool sDoingGC 
= false; 
4486         static bool sRedo 
= false; 
4489                 // GC is currently being run, just set a flag to have it run again. 
4498                 // mark phase: mark all images not-in-use 
4499                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4500                         ImageLoader
* image 
= *it
; 
4501                         //dyld::log("gc: neverUnload=%d name=%s\n", image->neverUnload(), image->getShortName()); 
4502                         image
->markNotUsed(); 
4505                 // sweep phase: mark as in-use, images reachable from never-unload or in-use image 
4506                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4507                         ImageLoader
* image 
= *it
; 
4508                         if ( (image
->dlopenCount() != 0) || image
->neverUnload() || (image 
== sMainExecutable
) ) { 
4509                                 OSSpinLockLock(&sDynamicReferencesLock
); 
4510                                         image
->markedUsedRecursive(sDynamicReferences
); 
4511                                 OSSpinLockUnlock(&sDynamicReferencesLock
); 
4515                 // collect phase: build array of images not marked in-use 
4516                 ImageLoader
* deadImages
[sAllImages
.size()]; 
4517                 unsigned deadCount 
= 0; 
4518                 int maxRangeCount 
= 0; 
4519                 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4520                         ImageLoader
* image 
= *it
; 
4521                         if ( ! image
->isMarkedInUse() ) { 
4522                                 deadImages
[deadCount
++] = image
; 
4523                                 if (gLogAPIs
) dyld::log("dlclose(), found unused image %p %s\n", image
, image
->getShortName()); 
4524                                 maxRangeCount 
+= image
->segmentCount(); 
4528                 // collect phase: run termination routines for images not marked in-use 
4529                 __cxa_range_t ranges
[maxRangeCount
]; 
4531                 for (unsigned i
=0; i 
< deadCount
; ++i
) { 
4532                         ImageLoader
* image 
= deadImages
[i
]; 
4533                         for (unsigned int j
=0; j 
< image
->segmentCount(); ++j
) { 
4534                                 if ( !image
->segExecutable(j
) ) 
4536                                 if ( rangeCount 
< maxRangeCount 
) { 
4537                                         ranges
[rangeCount
].addr 
= (const void*)image
->segActualLoadAddress(j
); 
4538                                         ranges
[rangeCount
].length 
= image
->segSize(j
); 
4543                                 runImageStaticTerminators(image
); 
4545                         catch (const char* msg
) { 
4546                                 dyld::warn("problem running terminators for image: %s\n", msg
); 
4550                 // <rdar://problem/14718598> dyld should call __cxa_finalize_ranges() 
4551                 if ( (rangeCount 
> 0) && (gLibSystemHelpers 
!= NULL
) && (gLibSystemHelpers
->version 
>= 13) ) 
4552                         (*gLibSystemHelpers
->cxa_finalize_ranges
)(ranges
, rangeCount
); 
4554                 // collect phase: delete all images which are not marked in-use 
4557                         mightBeMore 
= false; 
4558                         for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it 
!= sAllImages
.end(); it
++) { 
4559                                 ImageLoader
* image 
= *it
; 
4560                                 if ( ! image
->isMarkedInUse() ) { 
4562                                                 if (gLogAPIs
) dyld::log("dlclose(), deleting %p %s\n", image
, image
->getShortName()); 
4564                                                 ImageLoader::deleteImage(image
); 
4566                                                 break;  // interator in invalidated by this removal 
4568                                         catch (const char* msg
) { 
4569                                                 dyld::warn("problem deleting image: %s\n", msg
); 
4573                 } while ( mightBeMore 
); 
4582 static void preflight_finally(ImageLoader
* image
) 
4584         if ( image
->isBundle() ) { 
4585                 removeImageFromAllImages(image
->machHeader()); 
4586                 ImageLoader::deleteImage(image
); 
4588         sBundleBeingLoaded 
= NULL
; 
4589         dyld::garbageCollectImages(); 
4593 void preflight(ImageLoader
* image
, const ImageLoader::RPathChain
& loaderRPaths
, unsigned cacheIndex
) 
4596                 if ( image
->isBundle() )  
4597                         sBundleBeingLoaded 
= image
;     // hack 
4598                 const char* path 
= image
->getPath(); 
4599 #if SUPPORT_ACCELERATE_TABLES 
4600                 if ( image 
== sAllCacheImagesProxy 
) 
4601                         path 
= sAllCacheImagesProxy
->getIndexedPath(cacheIndex
); 
4603                 image
->link(gLinkContext
, false, true, false, loaderRPaths
, path
); 
4605         catch (const char* msg
) {        
4606                 preflight_finally(image
); 
4609         preflight_finally(image
); 
4612 static void loadInsertedDylib(const char* path
) 
4614         ImageLoader
* image 
= NULL
; 
4615         unsigned cacheIndex
; 
4617                 LoadContext context
; 
4618                 context
.useSearchPaths          
= false; 
4619                 context
.useFallbackPaths        
= false; 
4620                 context
.useLdLibraryPath        
= false; 
4621                 context
.implicitRPath           
= false; 
4622                 context
.matchByInstallName      
= false; 
4623                 context
.dontLoad                        
= false; 
4624                 context
.mustBeBundle            
= false; 
4625                 context
.mustBeDylib                     
= true; 
4626                 context
.canBePIE                        
= false; 
4627                 context
.origin                          
= NULL
; // can't use @loader_path with DYLD_INSERT_LIBRARIES 
4628                 context
.rpath                           
= NULL
; 
4629                 image 
= load(path
, context
, cacheIndex
); 
4631         catch (const char* msg
) { 
4632 #if TARGET_IPHONE_SIMULATOR 
4633                 dyld::log("dyld: warning: could not load inserted library '%s' because %s\n", path
, msg
); 
4635 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
4636                 if ( gLinkContext
.processUsingLibraryValidation 
) 
4637                         dyld::log("dyld: warning: could not load inserted library '%s' into library validated process because %s\n", path
, msg
); 
4640                         halt(dyld::mkstringf("could not load inserted library '%s' because %s\n", path
, msg
)); 
4644                 halt(dyld::mkstringf("could not load inserted library '%s'\n", path
)); 
4652 //      gLinkContext.requireCodeSignature 
4653 //      gLinkContext.processIsRestricted                                // Mac OS X only 
4654 //      gLinkContext.processUsingLibraryValidation              // Mac OS X only 
4656 static void configureProcessRestrictions(const macho_header
* mainExecutableMH
) 
4658 #if TARGET_IPHONE_SIMULATOR 
4660         gLinkContext
.requireCodeSignature 
= true; 
4661 #elif __IPHONE_OS_VERSION_MIN_REQUIRED 
4663         gLinkContext
.requireCodeSignature 
= true; 
4665         if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) != -1 ) { 
4666                 if ( flags 
& CS_ENFORCEMENT 
) { 
4667                         if ( flags 
& CS_GET_TASK_ALLOW 
) { 
4668                                 // Xcode built app for Debug allowed to use DYLD_* variables 
4672                                 // Development kernel can use DYLD_PRINT_* variables on any FairPlay encrypted app 
4673                                 uint32_t secureValue 
= 0; 
4674                                 size_t   secureValueSize 
= sizeof(secureValue
); 
4675                                 if ( (sysctlbyname("kern.secure_kernel", &secureValue
, &secureValueSize
, NULL
, 0) == 0) && (secureValue 
== 0) && isFairPlayEncrypted(mainExecutableMH
) ) { 
4676                                         sEnvMode 
= envPrintOnly
; 
4681                         // Development kernel can run unsigned code 
4683                         gLinkContext
.requireCodeSignature 
= false; 
4686         if ( issetugid() ) { 
4689 #elif __MAC_OS_X_VERSION_MIN_REQUIRED 
4691         gLinkContext
.requireCodeSignature 
= false; 
4692         gLinkContext
.processIsRestricted 
= false; 
4693         gLinkContext
.processUsingLibraryValidation 
= false; 
4694         // any processes with setuid or setgid bit set or with __RESTRICT segment is restricted 
4695     if ( issetugid() || hasRestrictedSegment(mainExecutableMH
) ) { 
4696                 gLinkContext
.processIsRestricted 
= true; 
4698         bool usingSIP 
= (csr_check(CSR_ALLOW_TASK_FOR_PID
) != 0); 
4700         if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) != -1 ) { 
4701                 // On OS X CS_RESTRICT means the program was signed with entitlements 
4702                 if ( ((flags 
& CS_RESTRICT
) == CS_RESTRICT
) && usingSIP 
) { 
4703                         gLinkContext
.processIsRestricted 
= true; 
4705                 // Library Validation loosens searching but requires everything to be code signed 
4706                 if ( flags 
& CS_REQUIRE_LV 
) { 
4707                         gLinkContext
.processIsRestricted 
= false; 
4708                         //gLinkContext.requireCodeSignature = true; 
4709                         gLinkContext
.processUsingLibraryValidation 
= true; 
4710                         sSafeMode 
= usingSIP
; 
4717 bool processIsRestricted() 
4719 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
4720         return gLinkContext
.processIsRestricted
; 
4727 // <rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots 
4728 static void addDyldImageToUUIDList() 
4730         const struct macho_header
* mh 
= (macho_header
*)&__dso_handle
; 
4731         const uint32_t cmd_count 
= mh
->ncmds
; 
4732         const struct load_command
* const cmds 
= (struct load_command
*)((char*)mh 
+ sizeof(macho_header
)); 
4733         const struct load_command
* cmd 
= cmds
; 
4734         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4737                                 uuid_command
* uc 
= (uuid_command
*)cmd
; 
4738                                 dyld_uuid_info info
; 
4739                                 info
.imageLoadAddress 
= (mach_header
*)mh
; 
4740                                 memcpy(info
.imageUUID
, uc
->uuid
, 16); 
4741                                 addNonSharedCacheImageUUID(info
); 
4745                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
4749 void notifyKernelAboutImage(const struct macho_header
* mh
, const char* fileInfo
) 
4751         const char *endptr 
= nullptr; 
4752         uint64_t fsid_scalar 
= hexToUInt64(fileInfo
, &endptr
); 
4753         uint64_t fsobj_id_scalar 
= 0; 
4754         if (endptr 
!= nullptr) { 
4755                 fsobj_id_scalar 
= hexToUInt64(endptr
+1, &endptr
); 
4757         const uint32_t cmd_count 
= mh
->ncmds
; 
4758         const struct load_command
* const cmds 
= (struct load_command
*)((char*)mh 
+ sizeof(macho_header
)); 
4759         const struct load_command
* cmd 
= cmds
; 
4760         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4763                                 // Add dyld to the kernel image info 
4764                                 uuid_command
* uc 
= (uuid_command
*)cmd
; 
4765                                 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A
, (const uuid_t 
*)&uc
->uuid
[0], *reinterpret_cast<fsobj_id_t 
*>(&fsobj_id_scalar
), *reinterpret_cast<fsid_t 
*>(&fsid_scalar
), (const mach_header 
*)mh
); 
4769                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
4773 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
4774 typedef int (*open_proc_t
)(const char*, int, int); 
4775 typedef int (*fcntl_proc_t
)(int, int, void*); 
4776 typedef int (*ioctl_proc_t
)(int, unsigned long, void*); 
4777 static void* getProcessInfo() { return dyld::gProcessInfo
; } 
4778 static SyscallHelpers sSysCalls 
= { 
4780                 // added in version 1 
4789                 (fcntl_proc_t
)&fcntl
,  
4790                 (ioctl_proc_t
)&ioctl
,  
4799                 &pthread_mutex_lock
,  
4800                 &pthread_mutex_unlock
, 
4802                 &mach_port_deallocate
,  
4804                 &mach_timebase_info
, 
4805                 &OSAtomicCompareAndSwapPtrBarrier
,  
4809                 &mach_absolute_time
, 
4810                 // added in version 2 
4812                 // added in version 3 
4816                 // added in version 4 
4817                 &coresymbolication_load_notifier
, 
4818                 &coresymbolication_unload_notifier
, 
4819                 // Added in version 5 
4820                 &proc_regionfilename
, 
4822                 &mach_port_insert_right
, 
4823                 &mach_port_allocate
, 
4825                 // Added in version 6 
4826                 &abort_with_payload
, 
4827                 // Added in version 7 
4828                 &task_register_dyld_image_infos
, 
4829                 &task_unregister_dyld_image_infos
, 
4830                 &task_get_dyld_image_infos
, 
4831                 &task_register_dyld_shared_cache_image_info
, 
4832                 &task_register_dyld_set_dyld_state
, 
4833                 &task_register_dyld_get_process_state
, 
4834                 // Added in version 8 
4841 __attribute__((noinline
)) 
4842 static const char* useSimulatorDyld(int fd
, const macho_header
* mainExecutableMH
, const char* dyldPath
, 
4843                                                                 int argc
, const char* argv
[], const char* envp
[], const char* apple
[], 
4844                                                                 uintptr_t* startGlue
, uintptr_t* mainAddr
) 
4849         // <rdar://problem/25311921> simulator does not support restricted processes 
4851         if ( csops(0, CS_OPS_STATUS
, &flags
, sizeof(flags
)) == -1 ) 
4852                 return "csops() failed"; 
4853         if ( (flags 
& CS_RESTRICT
) == CS_RESTRICT 
) 
4854                 return "dyld_sim cannot be loaded in a restricted process"; 
4856                 return "dyld_sim cannot be loaded in a setuid process"; 
4857         if ( hasRestrictedSegment(mainExecutableMH
) ) 
4858                 return "dyld_sim cannot be loaded in a restricted process"; 
4860         // get file size of dyld_sim 
4862         if ( fstat(fd
, &sb
) == -1 ) 
4863                 return "stat(dyld_sim) failed"; 
4865         // read first page of dyld_sim file 
4866         uint8_t firstPage
[4096]; 
4867         if ( pread(fd
, firstPage
, 4096, 0) != 4096 ) 
4868                 return "pread(dyld_sim) failed"; 
4870         // if fat file, pick matching slice 
4871         uint64_t fileOffset 
= 0; 
4872         uint64_t fileLength 
= sb
.st_size
; 
4873         const fat_header
* fileStartAsFat 
= (fat_header
*)firstPage
; 
4874         if ( fileStartAsFat
->magic 
== OSSwapBigToHostInt32(FAT_MAGIC
) ) { 
4875                 if ( !fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) )  
4876                         return "no matching arch in dyld_sim"; 
4877                 // re-read buffer from start of mach-o slice in fat file 
4878                 if ( pread(fd
, firstPage
, 4096, fileOffset
) != 4096 ) 
4879                         return "pread(dyld_sim) failed"; 
4881         else if ( !isCompatibleMachO(firstPage
, dyldPath
) ) { 
4882                 return "dyld_sim is not compatible with the loaded process, likely due to architecture mismatch"; 
4885         // calculate total size of dyld segments 
4886         const macho_header
* mh 
= (const macho_header
*)firstPage
; 
4887         struct macho_segment_command
* lastSeg 
= NULL
; 
4888         struct macho_segment_command
* firstSeg 
= NULL
; 
4889         uintptr_t mappingSize 
= 0; 
4890         uintptr_t preferredLoadAddress 
= 0; 
4891         const uint32_t cmd_count 
= mh
->ncmds
; 
4892         if ( mh
->sizeofcmds 
> 4096 ) 
4893                 return "dyld_sim load commands to large"; 
4894         if ( (sizeof(macho_header
) + mh
->sizeofcmds
) > 4096 ) 
4895                 return "dyld_sim load commands to large"; 
4896         const struct load_command
* const cmds 
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
)); 
4897         const struct load_command
* const endCmds 
= (struct load_command
*)(((char*)mh
) + sizeof(macho_header
) + mh
->sizeofcmds
); 
4898         const struct load_command
* cmd 
= cmds
; 
4899         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4900                 uint32_t cmdLength 
= cmd
->cmdsize
; 
4901                 if ( cmdLength 
< 8 ) 
4902                         return "dyld_sim load command too small"; 
4903                 const struct load_command
* const nextCmd 
= (const struct load_command
*)(((char*)cmd
)+cmdLength
); 
4904                 if ( (nextCmd 
> endCmds
) || (nextCmd 
< cmd
) ) 
4905                         return "dyld_sim load command too large"; 
4907                         case LC_SEGMENT_COMMAND
: 
4909                                         struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
4910                                         if ( seg
->vmaddr 
+ seg
->vmsize 
< seg
->vmaddr 
) 
4911                                                 return "dyld_sim seg wraps address space"; 
4912                                         if ( seg
->vmsize 
< seg
->filesize 
) 
4913                                                 return "dyld_sim seg vmsize too small"; 
4914                                         if ( (seg
->fileoff 
+ seg
->filesize
) < seg
->fileoff 
) 
4915                                                 return "dyld_sim seg size wraps address space"; 
4916                                         if ( lastSeg 
== NULL 
) { 
4917                                                 // first segment must be __TEXT and start at beginning of file/slice 
4919                                                 if ( strcmp(seg
->segname
, "__TEXT") != 0 ) 
4920                                                         return "dyld_sim first segment not __TEXT"; 
4921                                                 if ( seg
->fileoff 
!= 0 ) 
4922                                                         return "dyld_sim first segment not at file offset zero"; 
4923                                                 if ( seg
->filesize 
< (sizeof(macho_header
) + mh
->sizeofcmds
) ) 
4924                                                         return "dyld_sim first segment smaller than load commands"; 
4925                                                 preferredLoadAddress 
= seg
->vmaddr
; 
4928                                                 // other sements must be continguous with previous segment and not executable 
4929                                                 if ( lastSeg
->fileoff 
+ lastSeg
->filesize 
!= seg
->fileoff 
) 
4930                                                         return "dyld_sim segments not contiguous"; 
4931                                                 if ( lastSeg
->vmaddr 
+ lastSeg
->vmsize 
!= seg
->vmaddr 
) 
4932                                                         return "dyld_sim segments not address contiguous"; 
4933                                                 if ( (seg
->initprot 
& VM_PROT_EXECUTE
) != 0 ) 
4934                                                         return "dyld_sim non-first segment is executable"; 
4936                                         mappingSize 
+= seg
->vmsize
; 
4940                         case LC_SEGMENT_COMMAND_WRONG
: 
4941                                 return "dyld_sim wrong load segment load command"; 
4945         // last segment must be named __LINKEDIT and not writable 
4946         if ( strcmp(lastSeg
->segname
, "__LINKEDIT") != 0 ) 
4947                 return "dyld_sim last segment not __LINKEDIT"; 
4948         if ( lastSeg
->initprot 
& VM_PROT_WRITE 
) 
4949                 return "dyld_sim __LINKEDIT segment writable"; 
4951         // reserve space, then mmap each segment 
4952         vm_address_t loadAddress 
= 0; 
4953         if ( ::vm_allocate(mach_task_self(), &loadAddress
, mappingSize
, VM_FLAGS_ANYWHERE
) != 0 ) 
4954                 return "dyld_sim cannot allocate space"; 
4956         struct linkedit_data_command
* codeSigCmd 
= NULL
; 
4957         struct source_version_command
* dyldVersionCmd 
= NULL
; 
4958         for (uint32_t i 
= 0; i 
< cmd_count
; ++i
) { 
4960                         case LC_SEGMENT_COMMAND
: 
4962                                         struct macho_segment_command
* seg 
= (struct macho_segment_command
*)cmd
; 
4963                                         uintptr_t requestedLoadAddress 
= seg
->vmaddr 
- preferredLoadAddress 
+ loadAddress
; 
4964                                         void* segAddress 
= ::mmap((void*)requestedLoadAddress
, seg
->filesize
, seg
->initprot
, MAP_FIXED 
| MAP_PRIVATE
, fd
, fileOffset 
+ seg
->fileoff
); 
4965                                         //dyld::log("dyld_sim %s mapped at %p\n", seg->segname, segAddress); 
4966                                         if ( segAddress 
== (void*)(-1) ) 
4967                                                 return "dyld_sim mmap() of segment failed"; 
4968                                         if ( ((uintptr_t)segAddress 
< loadAddress
) || ((uintptr_t)segAddress
+seg
->filesize 
> loadAddress
+mappingSize
) ) 
4969                                                 return "dyld_sim mmap() to wrong location"; 
4972                         case LC_CODE_SIGNATURE
: 
4973                                 codeSigCmd 
= (struct linkedit_data_command
*)cmd
; 
4975                         case LC_SOURCE_VERSION
: 
4976                                 dyldVersionCmd 
= (struct source_version_command
*)cmd
; 
4979                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
4982         // must have code signature which is contained within LINKEDIT segment 
4983         if ( codeSigCmd 
== NULL 
) 
4984                 return "dyld_sim not code signed"; 
4985         if ( codeSigCmd
->dataoff 
< lastSeg
->fileoff 
) 
4986                 return "dyld_sim code signature not in __LINKEDIT"; 
4987         if ( (codeSigCmd
->dataoff 
+ codeSigCmd
->datasize
) <  codeSigCmd
->dataoff 
) 
4988                 return "dyld_sim code signature size wraps"; 
4989         if ( (codeSigCmd
->dataoff 
+ codeSigCmd
->datasize
) > (lastSeg
->fileoff 
+ lastSeg
->filesize
) ) 
4990                 return "dyld_sim code signature extends beyond __LINKEDIT"; 
4992         fsignatures_t siginfo
; 
4993         siginfo
.fs_file_start
=fileOffset
;                                                       // start of mach-o slice in fat file  
4994         siginfo
.fs_blob_start
=(void*)(long)(codeSigCmd
->dataoff
);       // start of code-signature in mach-o file 
4995         siginfo
.fs_blob_size
=codeSigCmd
->datasize
;                                      // size of code-signature 
4996         int result 
= fcntl(fd
, F_ADDFILESIGS_FOR_DYLD_SIM
, &siginfo
); 
4997         if ( result 
== -1 ) { 
4998                 return mkstringf("dyld_sim fcntl(F_ADDFILESIGS_FOR_DYLD_SIM) failed with errno=%d", errno
); 
5001         // file range covered by code signature must extend up to code signature itself 
5002         if ( siginfo
.fs_file_start 
< codeSigCmd
->dataoff 
) 
5003                 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
); 
5005         // walk newly mapped dyld_sim __TEXT load commands to find entry point 
5006         uintptr_t entry 
= 0; 
5007         cmd 
= (struct load_command
*)(((char*)loadAddress
)+sizeof(macho_header
)); 
5008         const uint32_t count 
= ((macho_header
*)(loadAddress
))->ncmds
; 
5009         for (uint32_t i 
= 0; i 
< count
; ++i
) { 
5010                 if (cmd
->cmd 
== LC_UNIXTHREAD
) { 
5012                         const i386_thread_state_t
* registers 
= (i386_thread_state_t
*)(((char*)cmd
) + 16); 
5013                         // entry point must be in first segment 
5014                         if ( registers
->__eip 
< firstSeg
->vmaddr 
) 
5015                                 return "dyld_sim entry point not in __TEXT segment"; 
5016                         if ( registers
->__eip 
> (firstSeg
->vmaddr 
+ firstSeg
->vmsize
) ) 
5017                                 return "dyld_sim entry point not in __TEXT segment"; 
5018                         entry 
= (registers
->__eip 
+ loadAddress 
- preferredLoadAddress
); 
5020                         const x86_thread_state64_t
* registers 
= (x86_thread_state64_t
*)(((char*)cmd
) + 16); 
5021                         // entry point must be in first segment 
5022                         if ( registers
->__rip 
< firstSeg
->vmaddr 
) 
5023                                 return "dyld_sim entry point not in __TEXT segment"; 
5024                         if ( registers
->__rip 
> (firstSeg
->vmaddr 
+ firstSeg
->vmsize
) ) 
5025                                 return "dyld_sim entry point not in __TEXT segment"; 
5026                         entry 
= (registers
->__rip 
+ loadAddress 
- preferredLoadAddress
); 
5029                 cmd 
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
); 
5032         // notify debugger that dyld_sim is loaded 
5033         dyld_image_info info
; 
5034         info
.imageLoadAddress 
= (mach_header
*)loadAddress
; 
5035         info
.imageFilePath        
= strdup(dyldPath
); 
5036         info
.imageFileModDate 
= sb
.st_mtime
; 
5037         addImagesToAllImages(1, &info
); 
5038         dyld::gProcessInfo
->notification(dyld_image_adding
, 1, &info
); 
5040         const char** appleParams 
= apple
; 
5041         // jump into new simulator dyld 
5042         typedef uintptr_t (*sim_entry_proc_t
)(int argc
, const char* argv
[], const char* envp
[], const char* apple
[], 
5043                                                                 const macho_header
* mainExecutableMH
, const macho_header
* dyldMH
, uintptr_t dyldSlide
, 
5044                                                                 const dyld::SyscallHelpers
* vtable
, uintptr_t* startGlue
); 
5045         sim_entry_proc_t newDyld 
= (sim_entry_proc_t
)entry
; 
5046         *mainAddr 
= (*newDyld
)(argc
, argv
, envp
, appleParams
, mainExecutableMH
, (macho_header
*)loadAddress
, 
5047                                          loadAddress 
- preferredLoadAddress
,  
5048                                          &sSysCalls
, startGlue
); 
5054 // If the DYLD_SKIP_MAIN environment is set to 1, dyld will return the  
5055 // address of this function instead of main() in the target program which  
5056 // __dyld_start jumps to. Useful for qualifying dyld itself. 
5067 static bool envVarMatches(dyld3::launch_cache::Closure mainClosure
, const char* envp
[], const char* varName
) 
5069         __block 
const char* valueFromClosure 
= nullptr; 
5070         mainClosure
.forEachEnvVar(^(const char* keyEqualValue
, bool& stop
) { 
5071                 size_t keyLen 
= strlen(varName
); 
5072                 if ( (strncmp(varName
, keyEqualValue
, keyLen
) == 0) && (keyEqualValue
[keyLen
] == '=') ) { 
5073                         valueFromClosure 
= &keyEqualValue
[keyLen
+1]; 
5078         const char* valueFromEnv 
= _simple_getenv(envp
, varName
); 
5080         bool inClosure 
= (valueFromClosure 
!= nullptr); 
5081         bool inEnv     
= (valueFromEnv 
!= nullptr); 
5082         if ( inClosure 
!= inEnv 
) 
5084         if ( !inClosure 
&& !inEnv 
) 
5086         return ( strcmp(valueFromClosure
, valueFromEnv
) == 0 ); 
5089 static const char* const sEnvVarsToCheck
[] = { 
5090         "DYLD_LIBRARY_PATH", 
5091         "DYLD_FRAMEWORK_PATH", 
5092         "DYLD_FALLBACK_LIBRARY_PATH", 
5093         "DYLD_FALLBACK_FRAMEWORK_PATH", 
5094         "DYLD_INSERT_LIBRARIES", 
5095         "DYLD_IMAGE_SUFFIX", 
5096         "DYLD_VERSIONED_FRAMEWORK_PATH", 
5097         "DYLD_VERSIONED_LIBRARY_PATH", 
5101 static bool envVarsMatch(dyld3::launch_cache::Closure mainClosure
, const char* envp
[]) 
5103         for (const char* envVar 
: sEnvVarsToCheck
) { 
5104                 if ( !envVarMatches(mainClosure
, envp
, envVar
) ) { 
5105                         if ( gLinkContext
.verboseWarnings 
) 
5106                                 dyld::log("dyld: closure %p not used because %s changed\n", mainClosure
.binaryData(), envVar
); 
5114 static bool closureValid(const dyld3::launch_cache::BinaryClosureData
* mainClosureData
, const mach_header
* mainExecutableMH
, const uint8_t* mainExecutableCDHash
, bool closureInCache
, const char* envp
[]) 
5116         const dyld3::launch_cache::Closure    
mainClosure(mainClosureData
); 
5117         const dyld3::launch_cache::ImageGroup mainGroup 
= mainClosure
.group(); 
5119         // verify current dyld cache is same as expected 
5120         if ( sSharedCacheLoadInfo
.loadAddress 
== nullptr ) { 
5121                 if ( gLinkContext
.verboseWarnings 
) 
5122                         dyld::log("dyld: closure %p dyld cache not loaded\n", mainClosureData
); 
5125         if ( !closureInCache 
) { 
5126                 // closures in cache don't have cache's UUID 
5128                 sSharedCacheLoadInfo
.loadAddress
->getUUID(cacheUUID
); 
5129                 if ( memcmp(mainClosure
.dyldCacheUUID(), cacheUUID
, sizeof(uuid_t
)) != 0 ) { 
5130                         if ( gLinkContext
.verboseWarnings 
) 
5131                                 dyld::log("dyld: closure %p not used because built against different dyld cache\n", mainClosureData
); 
5135 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5137                 // HACK until closured for dlopen can run against live cache file 
5138                 int fd 
= my_open(sSharedCacheLoadInfo
.path
, O_RDONLY
, 0); 
5140                         dyld_cache_header fileHeader
; 
5141                         if ( pread(fd
, &fileHeader
, sizeof(fileHeader
), 0) == sizeof(fileHeader
) ) { 
5143                                 sSharedCacheLoadInfo
.loadAddress
->getUUID(cacheUUID
); 
5144                                 if ( memcmp(fileHeader
.uuid
, cacheUUID
, sizeof(uuid_t
)) != 0 ) { 
5145                                         if ( gLinkContext
.verboseWarnings 
) 
5146                                                 dyld::log("dyld: closure %p not used because current cache on disk is not they one being used\n", mainClosureData
); 
5156         // verify main executable file has not changed since closure was built 
5157         const dyld3::launch_cache::Image mainImage 
= mainGroup
.image(mainClosure
.mainExecutableImageIndex()); 
5158     if ( mainImage
.validateUsingModTimeAndInode() ) { 
5159         struct stat statBuf
; 
5160         if ( ::stat(mainImage
.path(), &statBuf
) != 0 ) { 
5161                         if ( gLinkContext
.verboseWarnings 
) 
5162                                 dyld::log("dyld: closure %p not used because stat() failed on main executable\n", mainClosureData
); 
5165         else if ( (statBuf
.st_mtime 
!= mainImage
.fileModTime()) || (statBuf
.st_ino 
!= mainImage
.fileINode()) ) { 
5166                         if ( gLinkContext
.verboseWarnings 
) 
5167                                 dyld::log("dyld: closure %p not used because mtime/inode changed since closure was built\n", mainClosureData
); 
5172         // verify cdHash of main executable is same as recorded in closure 
5173         if ( mainImage
.validateUsingCdHash() ) { 
5174                 if ( mainExecutableCDHash 
== nullptr ) { 
5175                         if ( gLinkContext
.verboseWarnings 
) 
5176                                 dyld::log("dyld: closure %p not used because main executable is not code signed but was expected to be\n", mainClosureData
); 
5179                 if ( memcmp(mainExecutableCDHash
, mainClosure
.cdHash(), 20) != 0 ) { 
5180                         if ( gLinkContext
.verboseWarnings 
) 
5181                                 dyld::log("dyld: closure %p not used because main executable cd-hash changed since closure was built\n", mainClosureData
); 
5186         // verify UUID of main executable is same as recorded in closure 
5187         const uuid_t
* closureMainUUID 
= mainImage
.uuid(); 
5188         dyld3::MachOParser 
parser(mainExecutableMH
); 
5190         parser
.getUuid(actualUUID
); 
5191         if ( memcmp(actualUUID
, closureMainUUID
, sizeof(uuid_t
)) != 0 ) { 
5192                 if ( gLinkContext
.verboseWarnings 
) 
5193                         dyld::log("dyld: closure %p not used because UUID of executable changed since closure was built\n", mainClosureData
); 
5197         // verify DYLD_* env vars are same as when closure was built 
5198         if ( !envVarsMatch(mainClosure
, envp
) ) { 
5202         // verify files that are supposed to be missing actually are missing 
5203         __block 
bool foundFileThatInvalidatesClosure 
= false; 
5204         mainClosure
.forEachMustBeMissingFile(^(const char* path
, bool& stop
) { 
5205                 struct stat statBuf
; 
5206                 if ( ::stat(path
, &statBuf
) == 0 ) { 
5208                         foundFileThatInvalidatesClosure 
= true; 
5209                         if ( gLinkContext
.verboseWarnings 
) 
5210                                 dyld::log("dyld: closure %p not used because found unexpected file '%s'\n", mainClosureData
, path
); 
5214 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5215         // verify no key frameworks have been overridden since cache was built 
5216         if ( dyld3::loader::internalInstall() ) { 
5217                 dyld3::loader::forEachLineInFile("/AppleInternal/Library/Preferences/dyld-potential-framework-overrides", ^(const char* path
, bool& stop
) { 
5218                         dyld3::SharedCacheFindDylibResults shareCacheResults
; 
5219                         if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo
, path
, &shareCacheResults
) ) { 
5220                                 dyld3::launch_cache::Image 
image(shareCacheResults
.imageData
); 
5221                                 struct stat statBuf
; 
5222                                 if ( ::stat(path
, &statBuf
) == 0 ) { 
5223                                         if ( (image
.fileModTime() != statBuf
.st_mtime
) || (image
.fileINode() != statBuf
.st_ino
)) { 
5224                                                 if ( gLinkContext
.verboseWarnings 
) 
5225                                                         dyld::log("dyld: closure %p not used because framework has changed: '%s'\n", mainClosureData
, path
); 
5226                                                 foundFileThatInvalidatesClosure 
= true; 
5235         return !foundFileThatInvalidatesClosure
; 
5238 static bool nolog(const char* format
, ...) 
5243 static bool dolog(const char* format
, ...) 
5246         va_start(list
, format
); 
5252 static bool launchWithClosure(const dyld3::launch_cache::BinaryClosureData
* mainClosureData
, 
5253                                                           const DyldSharedCache
* dyldCache
, 
5254                                                           const mach_header
* mainExecutableMH
, uintptr_t mainExecutableSlide
, 
5255                                                           int argc
, const char* argv
[], const char* envp
[], const char* apple
[], 
5256                                                           uintptr_t* entry
, uintptr_t* startGlue
) 
5258         dyld3::launch_cache::Closure                    
mainClosure(mainClosureData
); 
5259         const dyld3::launch_cache::ImageGroup   mainGroup           
= mainClosure
.group(); 
5260         const uint32_t                                                  mainExecutableIndex 
= mainClosure
.mainExecutableImageIndex(); 
5261         const dyld3::launch_cache::Image        mainImage           
= mainGroup
.image(mainExecutableIndex
); 
5262         const uint32_t                                                  loadedImageCount    
= mainClosure
.initialImageCount(); 
5264         // construct array of groups 
5265     dyld3::DyldCacheParser 
cacheParser(dyldCache
, false); 
5266         STACK_ALLOC_DYNARRAY(const dyld3::launch_cache::binary_format::ImageGroup
*, 3, theGroups
); 
5267         theGroups
[0] = cacheParser
.cachedDylibsGroup(); 
5268         theGroups
[1] = cacheParser
.otherDylibsGroup(); 
5269         theGroups
[2] = mainClosure
.group().binaryData(); 
5271         // construct array of all Image*, starting with any inserted dylibs, then main executable 
5272         const dyld3::launch_cache::BinaryImageData
*                     images
[loadedImageCount
]; 
5273         dyld3::launch_cache::SlowLoadSet 
imageSet(&images
[0], &images
[loadedImageCount
]); 
5274         for (uint32_t i
=0; i 
<= mainExecutableIndex
; ++i
) { 
5275                 imageSet
.add(mainGroup
.image(i
).binaryData()); 
5277         // add all dependents of main executable 
5278         if ( !mainImage
.recurseAllDependentImages(theGroups
, imageSet
, nullptr) ) { 
5279                 dyld::log("initial image list overflow, expected only %d\n", loadedImageCount
); 
5282         // add dependents of any inserted dylibs 
5283         for (uint32_t i
=0; i 
< mainExecutableIndex
; ++i
) { 
5284                 if ( !mainGroup
.image(i
).recurseAllDependentImages(theGroups
, imageSet
, nullptr) ) { 
5285                         dyld::log("initial image list overflow in inserted libraries, expected only %d\n", loadedImageCount
); 
5289         const uint32_t actualImageCount 
= (uint32_t)imageSet
.count(); 
5290         // construct array of allImages 
5291         STACK_ALLOC_DYNARRAY(dyld3::loader::ImageInfo
, actualImageCount
, allImages
); 
5292         for (int i
=0; i 
< actualImageCount
; ++i
) { 
5293                 dyld3::launch_cache::Image      
img(images
[i
]); 
5294                 dyld3::launch_cache::ImageGroup grp 
= img
.group(); 
5295                 allImages
[i
].imageData              
= img
.binaryData(); 
5296                 allImages
[i
].loadAddress            
= nullptr; 
5297                 allImages
[i
].groupNum               
= grp
.groupNum(); 
5298                 allImages
[i
].indexInGroup           
= grp
.indexInGroup(img
.binaryData()); 
5299                 allImages
[i
].previouslyFixedUp      
= false; 
5300                 allImages
[i
].justMapped             
= false; 
5301                 allImages
[i
].justUsedFromDyldCache  
= false; 
5302                 allImages
[i
].neverUnload            
= false; 
5304         // prefill address of main executable to mark it is already loaded 
5305         allImages
[mainExecutableIndex
].loadAddress 
= mainExecutableMH
; 
5307         // map new images and apply all fixups 
5309         mapAndFixupImages(diag
, allImages
, (const uint8_t*)dyldCache
, (gLinkContext
.verboseLoading 
? &dolog 
: &nolog
), 
5310                                                                                                                                   (gLinkContext
.verboseMapping 
? &dolog 
: &nolog
), 
5311                                                                                                                                   (gLinkContext
.verboseBind    
? &dolog 
: &nolog
), 
5312                                                                                                                                   (gLinkContext
.verboseDOF     
?  &dolog 
: &nolog
)); 
5313         if ( diag
.hasError() ) { 
5314                 if ( gLinkContext
.verboseWarnings 
) 
5315                         dyld::log("dyld: %s\n", diag
.errorMessage()); 
5319         //dyld::log("loaded image list:\n"); 
5320         //for (int i=0; i < allImages.count(); ++i) { 
5321         //      dyld3::launch_cache::Image img(allImages[i].imageData); 
5322         //      dyld::log("binImage[%d]=%p, mh=%p, path=%s\n", i, allImages[i].imageData, allImages[i].loadAddress, img.path()); 
5325         // find special images 
5326         const dyld3::launch_cache::BinaryImageData
*     libSystemImage 
= mainClosure
.libSystem(theGroups
); 
5327         const dyld3::launch_cache::BinaryImageData
*     libDyldImage   
= mainClosure
.libDyld(theGroups
); 
5328         const mach_header
*                                                      libdyldMH 
= nullptr; 
5329         const mach_header
*                                                      libSystemMH 
= nullptr; 
5330         for (int i
=0; i 
< allImages
.count(); ++i
) { 
5331                 if ( allImages
[i
].imageData 
== libSystemImage 
) 
5332                         libSystemMH 
= allImages
[i
].loadAddress
; 
5333                 else if ( allImages
[i
].imageData 
== libDyldImage 
) 
5334                         libdyldMH 
= allImages
[i
].loadAddress
; 
5337         // send info on all images to libdyld.dylb 
5338         const dyld3::LibDyldEntryVector
* libDyldEntry 
= (dyld3::LibDyldEntryVector
*)((uint8_t*)libdyldMH 
+ mainClosure
.libdyldVectorOffset()); 
5339         libDyldEntry
->setVars(mainExecutableMH
, argc
, argv
, envp
, apple
); 
5340         libDyldEntry
->setHaltFunction(&halt
); 
5341         if ( libDyldEntry
->vectorVersion 
> 2 ) 
5342                 libDyldEntry
->setChildForkFunction(&_dyld_fork_child
); 
5343 #if !TARGET_IPHONE_SIMULATOR 
5344         if ( libDyldEntry
->vectorVersion 
> 3 ) 
5345                 libDyldEntry
->setLogFunction(&dyld::vlog
); 
5347         libDyldEntry
->setOldAllImageInfo(gProcessInfo
); 
5348         libDyldEntry
->setInitialImageList(mainClosureData
, dyldCache
, sSharedCacheLoadInfo
.path
, allImages
, libSystemMH
, libSystemImage
); 
5350         CRSetCrashLogMessage("dyld3: launch, running initializers"); 
5351         libDyldEntry
->runInitialzersBottomUp((mach_header
*)mainExecutableMH
); 
5352         //dyld::log("returned from runInitialzersBottomUp()\n"); 
5354         dyld3::kdebug_trace_dyld_signpost(DBG_DYLD_SIGNPOST_START_MAIN
, 0, 0); 
5355         if ( mainClosure
.mainExecutableUsesCRT() ) { 
5356                 // old style app linked with crt1.o 
5357                 // entry is "start" function in program 
5359                 *entry 
= (uintptr_t)mainExecutableMH 
+ mainClosure
.mainExecutableEntryOffset(); 
5362                 // modern app with LC_MAIN 
5363                 // set startGlue to "start" function in libdyld.dylib 
5364                 // set entry to "main" function in program 
5365                 *startGlue 
= (uintptr_t)(libDyldEntry
->startFunc
); 
5366                 *entry 
=(uintptr_t)mainExecutableMH 
+ mainClosure
.mainExecutableEntryOffset(); 
5368         CRSetCrashLogMessage(NULL
); 
5372 static void putHexNibble(uint8_t value
, char*& p
) 
5377                 *p
++ = 'A' + value 
- 10; 
5380 static void putHexByte(uint8_t value
, char*& p
) 
5383         putHexNibble(value 
>> 4,   p
); 
5384         putHexNibble(value 
& 0x0F, p
); 
5387 static void makeHexLong(unsigned long value
, char* p
) 
5392         putHexByte(value 
>> 56, p
); 
5393         putHexByte(value 
>> 48, p
); 
5394         putHexByte(value 
>> 40, p
); 
5395         putHexByte(value 
>> 32, p
); 
5397         putHexByte(value 
>> 24, p
); 
5398         putHexByte(value 
>> 16, p
); 
5399         putHexByte(value 
>> 8, p
); 
5400         putHexByte(value
, p
); 
5404 static void makeUUID(uint8_t uuid
[16], char* p
) 
5406         putHexByte(uuid
[0], p
); 
5407         putHexByte(uuid
[1], p
); 
5408         putHexByte(uuid
[2], p
); 
5409         putHexByte(uuid
[3], p
); 
5411         putHexByte(uuid
[4], p
); 
5412         putHexByte(uuid
[5], p
); 
5414         putHexByte(uuid
[6], p
); 
5415         putHexByte(uuid
[7], p
); 
5417         putHexByte(uuid
[8], p
); 
5418         putHexByte(uuid
[9], p
); 
5420         putHexByte(uuid
[10], p
); 
5421         putHexByte(uuid
[11], p
); 
5422         putHexByte(uuid
[12], p
); 
5423         putHexByte(uuid
[13], p
); 
5424         putHexByte(uuid
[14], p
); 
5425         putHexByte(uuid
[15], p
); 
5429 #if !TARGET_IPHONE_SIMULATOR 
5430 static const dyld3::launch_cache::BinaryClosureData
* callClosureDaemon(const char* mainExecPath
, const char* envp
[]) 
5432         // temp, until we can get a bootstrap_lookup that works from dyld 
5436     if ( ::pipe(sockets
) < 0 ) { 
5437         dyld::log("error opening stream socket pair to closured\n"); 
5440         //dyld::log("created sockets %d and %d\n", sockets[0], sockets[1]); 
5441         // use fork/exec to launch closured 
5442     int child 
= ::__fork(); 
5443     if ( child 
== -1 ) { 
5444                 dyld::log("error forking, errno=%d\n", errno
); 
5449                 //dyld::log("parent side pid=%d\n", getpid()); 
5450                 ::close(sockets
[1]); 
5451                 SocketBasedClousureHeader header
; 
5452                 long amount 
= ::read(sockets
[0], &header
, sizeof(SocketBasedClousureHeader
)); 
5453                 if ( amount 
!= sizeof(SocketBasedClousureHeader
) ) { 
5454                         dyld::log("error reading, errno=%d\n", errno
); 
5457                 vm_address_t bufferAddress 
= 0; 
5458                 if ( ::vm_allocate(mach_task_self(), &bufferAddress
, header
.length
, VM_FLAGS_ANYWHERE
) != 0 ) { 
5459                         dyld::log("error allocating buffer\n"); 
5462                 amount 
= ::read(sockets
[0], (void*)bufferAddress
, header
.length
); 
5464                 if ( amount 
!= header
.length 
) { 
5465                         dyld::log("dyld: error reading buffer header from closured, amount=%ld, errno=%d\n", amount
, errno
); 
5468                 if ( header
.success 
) { 
5469                         // make buffer read-only 
5470                         vm_protect(mach_task_self(), bufferAddress
, header
.length
, VM_PROT_READ
, VM_PROT_READ
); 
5471                         return (const dyld3::launch_cache::BinaryClosureData
*)bufferAddress
; 
5474                         // buffer contains error message as to why closure could not be built 
5475                         dyld::log("%s", (char*)bufferAddress
); 
5476                         ::vm_deallocate(mach_task_self(), bufferAddress
, header
.length
); 
5482                 //dyld::log("child side pid=%d\n", getpid()); 
5484                 const char* closuredPath 
= "/usr/libexec/closured"; 
5486                 pipeStr
[0] = '0' + sockets
[1]; 
5488                 const char* argv
[32]; 
5489                 char cacheUuidString
[64]; 
5490                 char cacheAddrString
[64]; 
5491                 char cacheSizeString
[64]; 
5494                 sSharedCacheLoadInfo
.loadAddress
->getUUID(cacheUUID
); 
5495                 makeHexLong((long)sSharedCacheLoadInfo
.loadAddress
, cacheAddrString
); 
5496                 makeHexLong((long)sSharedCacheLoadInfo
.loadAddress
->mappedSize(), cacheSizeString
); 
5497                 makeUUID(cacheUUID
, cacheUuidString
); 
5498                 argv
[i
++] = closuredPath
; 
5499                 argv
[i
++] = "-create_closure"; 
5500                 argv
[i
++] = mainExecPath
; 
5501                 argv
[i
++] = "-pipefd"; 
5502                 argv
[i
++] = pipeStr
; 
5503                 argv
[i
++] = "-cache_uuid"; 
5504                 argv
[i
++] = cacheUuidString
; 
5505                 argv
[i
++] = "-cache_address"; 
5506                 argv
[i
++] = cacheAddrString
; 
5507                 argv
[i
++] = "-cache_size"; 
5508                 argv
[i
++] = cacheSizeString
; 
5509                 for (const char**p
=envp
; *p 
!= NULL
; ++p
) { 
5510                         const char* envToCheck 
= *p
; 
5511                         for (const char* dyldEnvVar 
: sEnvVarsToCheck
) { 
5512                                 size_t dyldEnvVarLen 
= strlen(dyldEnvVar
); 
5513                                 if ( (strncmp(dyldEnvVar
, envToCheck
, dyldEnvVarLen
) == 0) && (envToCheck
[dyldEnvVarLen
] == '=') ) { 
5515                                         argv
[i
++] = envToCheck
; 
5520                 //dyld::log("closured args:\n"); 
5521                 //for (int j=0; argv[j] != nullptr; ++j) 
5522                 //      dyld::log("  argv[%d]=%s\n", j, argv[j]); 
5523         execve(closuredPath
, (char**)argv
, nullptr); 
5524                 dyld::log("exec() of closured failed, errno=%d\n", errno
); 
5529         // get port to closured 
5530     mach_port_t serverPort 
= dyld3::loader::lookupClosuredPort(); 
5531         if ( serverPort 
== MACH_PORT_NULL 
) 
5534         // build env var list 
5535     char envBuffer
[2048]; 
5536         char* s 
= envBuffer
; 
5537         for (const char* envVar 
: sEnvVarsToCheck
) { 
5538                 if ( const char* valueFromEnv 
= _simple_getenv(envp
, envVar
) ) { 
5541                         strcat(s
, valueFromEnv
); 
5547         // get uuid of main executable 
5548         dyld3::MachOParser 
mainParser((mach_header
*)sMainExecutableMachHeader
); 
5550         mainParser
.getUuid(mainUuid
); 
5552         // message closured to build closure 
5553     bool success 
= false; 
5554     vm_offset_t reply 
= 0; 
5555     uint32_t  replySize 
= 0; 
5556     if ( closured_CreateLaunchClosure(serverPort
, sExecPath
, sSharedCachePath
, mainUuid
, envBuffer
, &success
, &reply
, &replySize
) != KERN_SUCCESS 
) 
5559         // release server port 
5560     mach_port_deallocate(mach_task_self(), serverPort
); 
5563                 return (const dyld3::launch_cache::BinaryClosureData
*)reply
; 
5565         dyld::log("closure failed to build: %s\n", (char*)reply
); 
5569 #endif // !TARGET_IPHONE_SIMULATOR 
5572 #if !__MAC_OS_X_VERSION_MIN_REQUIRED 
5573 static const char* sWhiteListDirs
[] = { 
5580 static bool inWhiteList(const char* execPath
) 
5582     // First test to see if we forced in dyld2 via a kernel boot-arg 
5583     if ( dyld3::loader::bootArgsContains("force_dyld2=1") ) 
5586 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5588         // rdar://problem/32701418: Don't use dyld3 for i386 for now. 
5595 #endif // #if __i386__ 
5598         // <rdar://problem/33171968> enable dyld3 mode for all OS programs when using customer dyld cache (no roots) 
5599         if ( (sSharedCacheLoadInfo
.loadAddress 
!= nullptr) && (sSharedCacheLoadInfo
.loadAddress
->header
.cacheType 
== kDyldSharedCacheTypeProduction
) ) 
5602         for (const char* dir 
: sWhiteListDirs
) { 
5603                 if ( strncmp(dir
, sExecPath
, strlen(dir
)) == 0 ) { 
5607         return dyld3::loader::bootArgsContains("force_dyld3=1"); 
5612 // Entry point for dyld.  The kernel loads dyld and jumps to __dyld_start which 
5613 // sets up some registers and call this function. 
5615 // Returns address of main() in target program which __dyld_start jumps to 
5618 _main(const macho_header
* mainExecutableMH
, uintptr_t mainExecutableSlide
,  
5619                 int argc
, const char* argv
[], const char* envp
[], const char* apple
[],  
5620                 uintptr_t* startGlue
) 
5622         dyld3::kdebug_trace_dyld_signpost(DBG_DYLD_SIGNPOST_START_DYLD
, 0, 0); 
5624         // Grab the cdHash of the main executable from the environment 
5625         uint8_t mainExecutableCDHashBuffer
[20]; 
5626         const uint8_t* mainExecutableCDHash 
= nullptr; 
5627         if ( hexToBytes(_simple_getenv(apple
, "executable_cdhash"), 40, mainExecutableCDHashBuffer
) ) 
5628                 mainExecutableCDHash 
= mainExecutableCDHashBuffer
; 
5630         // Trace dyld's load 
5631         notifyKernelAboutImage((macho_header
*)&__dso_handle
, _simple_getenv(apple
, "dyld_file")); 
5632 #if !TARGET_IPHONE_SIMULATOR 
5633         // Trace the main executable's load 
5634         notifyKernelAboutImage(mainExecutableMH
, _simple_getenv(apple
, "executable_file")); 
5637         uintptr_t result 
= 0; 
5638         sMainExecutableMachHeader 
= mainExecutableMH
; 
5639         sMainExecutableSlide 
= mainExecutableSlide
; 
5640 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5641         // if this is host dyld, check to see if iOS simulator is being run 
5642         const char* rootPath 
= _simple_getenv(envp
, "DYLD_ROOT_PATH"); 
5643         if ( rootPath 
!= NULL 
) { 
5645                 // look to see if simulator has its own dyld 
5646                 char simDyldPath
[PATH_MAX
];  
5647                 strlcpy(simDyldPath
, rootPath
, PATH_MAX
); 
5648                 strlcat(simDyldPath
, "/usr/lib/dyld_sim", PATH_MAX
); 
5649                 int fd 
= my_open(simDyldPath
, O_RDONLY
, 0); 
5651                         const char* errMessage 
= useSimulatorDyld(fd
, mainExecutableMH
, simDyldPath
, argc
, argv
, envp
, apple
, startGlue
, &result
); 
5652                         if ( errMessage 
!= NULL 
) 
5659         CRSetCrashLogMessage("dyld: launch started"); 
5661         setContext(mainExecutableMH
, argc
, argv
, envp
, apple
); 
5663         // Pickup the pointer to the exec path. 
5664         sExecPath 
= _simple_getenv(apple
, "executable_path"); 
5666         // <rdar://problem/13868260> Remove interim apple[0] transition code from dyld 
5667         if (!sExecPath
) sExecPath 
= apple
[0]; 
5669         if ( sExecPath
[0] != '/' ) { 
5670                 // have relative path, use cwd to make absolute 
5671                 char cwdbuff
[MAXPATHLEN
]; 
5672             if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL 
) { 
5673                         // maybe use static buffer to avoid calling malloc so early... 
5674                         char* s 
= new char[strlen(cwdbuff
) + strlen(sExecPath
) + 2]; 
5677                         strcat(s
, sExecPath
); 
5682         // Remember short name of process for later logging 
5683         sExecShortName 
= ::strrchr(sExecPath
, '/'); 
5684         if ( sExecShortName 
!= NULL 
) 
5687                 sExecShortName 
= sExecPath
; 
5689     configureProcessRestrictions(mainExecutableMH
); 
5691 #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5692     if ( gLinkContext
.processIsRestricted 
) { 
5693                 pruneEnvironmentVariables(envp
, &apple
); 
5694                 // set again because envp and apple may have changed or moved 
5695                 setContext(mainExecutableMH
, argc
, argv
, envp
, apple
); 
5700                 checkEnvironmentVariables(envp
); 
5701                 defaultUninitializedFallbackPaths(envp
); 
5703         if ( sEnv
.DYLD_PRINT_OPTS 
) 
5705         if ( sEnv
.DYLD_PRINT_ENV 
)  
5706                 printEnvironmentVariables(envp
); 
5707         getHostInfo(mainExecutableMH
, mainExecutableSlide
); 
5709         // load shared cache 
5710         checkSharedRegionDisable((mach_header
*)mainExecutableMH
); 
5711 #if TARGET_IPHONE_SIMULATOR 
5712         // <HACK> until <rdar://30773711> is fixed 
5713         gLinkContext
.sharedRegionMode 
= ImageLoader::kUsePrivateSharedRegion
; 
5716         if ( gLinkContext
.sharedRegionMode 
!= ImageLoader::kDontUseSharedRegion 
) { 
5720         if ( (sEnableClosures 
|| inWhiteList(sExecPath
)) && (sSharedCacheLoadInfo
.loadAddress 
!= nullptr) ) { 
5721                 if ( sSharedCacheLoadInfo
.loadAddress
->header
.formatVersion 
== dyld3::launch_cache::binary_format::kFormatVersion 
) { 
5722                         const dyld3::launch_cache::BinaryClosureData
* mainClosureData
; 
5723                         // check for closure in cache first 
5724                         dyld3::DyldCacheParser 
cacheParser(sSharedCacheLoadInfo
.loadAddress
, false); 
5725                         mainClosureData 
= cacheParser
.findClosure(sExecPath
); 
5726         #if __IPHONE_OS_VERSION_MIN_REQUIRED 
5727                         if ( mainClosureData 
== nullptr ) { 
5728                                 // see if this is an OS app that was moved 
5729                                 if ( strncmp(sExecPath
, "/var/containers/Bundle/Application/", 35) == 0 ) { 
5730                                         dyld3::MachOParser 
mainParser((mach_header
*)mainExecutableMH
); 
5731                                         uint32_t textOffset
; 
5733                                         if ( !mainParser
.isFairPlayEncrypted(textOffset
, textSize
) ) { 
5734                                                 __block 
bool hasEmbeddedDylibs 
= false; 
5735                                                 mainParser
.forEachDependentDylib(^(const char* loadPath
, bool, bool, bool, uint32_t, uint32_t, bool& stop
) { 
5736                                                         if ( loadPath
[0] == '@' ) { 
5737                                                                 hasEmbeddedDylibs 
= true; 
5741                                                 if ( !hasEmbeddedDylibs 
) { 
5743                                                         const char* lastSlash 
= strrchr(sExecPath
, '/'); 
5744                                                         if ( lastSlash 
!= nullptr ) { 
5745                                                                 strlcpy(altPath
, "/private/var/staged_system_apps", sizeof(altPath
)); 
5746                                                                 strlcat(altPath
, lastSlash
, sizeof(altPath
)); 
5747                                                                 strlcat(altPath
, ".app", sizeof(altPath
)); 
5748                                                                 strlcat(altPath
, lastSlash
, sizeof(altPath
)); 
5749                                                                 if ( gLinkContext
.verboseWarnings 
) 
5750                                                                         dyld::log("try path: %s\n", altPath
); 
5751                                                                 mainClosureData 
= cacheParser
.findClosure(altPath
); 
5758                         if ( gLinkContext
.verboseWarnings 
&& (mainClosureData 
!= nullptr) ) 
5759                                 dyld::log("dyld: found closure %p in dyld shared cache\n", mainClosureData
); 
5760         #if !TARGET_IPHONE_SIMULATOR 
5761                         if ( (mainClosureData 
== nullptr) || !closureValid(mainClosureData
, (mach_header
*)mainExecutableMH
, mainExecutableCDHash
, true, envp
) ) { 
5762                                 mainClosureData 
= nullptr; 
5763                                 if ( sEnableClosures 
) { 
5764                                         // if forcing closures, and no closure in cache, or it is invalid, then RPC to closured 
5765                                         mainClosureData 
= callClosureDaemon(sExecPath
, envp
); 
5766                                         if ( gLinkContext
.verboseWarnings 
) 
5767                                                 dyld::log("dyld: closured return %p for %s\n", mainClosureData
, sExecPath
); 
5768                                         if ( (mainClosureData 
!= nullptr) && !closureValid(mainClosureData
, (mach_header
*)mainExecutableMH
, mainExecutableCDHash
, false, envp
) ) { 
5769                                                 // some how freshly generated closure is invalid... 
5770                                                 mainClosureData 
= nullptr; 
5775                         // try using launch closure 
5776                         if ( mainClosureData 
!= nullptr ) { 
5777                                 CRSetCrashLogMessage("dyld3: launch started"); 
5778                                 if ( launchWithClosure(mainClosureData
, sSharedCacheLoadInfo
.loadAddress
, (mach_header
*)mainExecutableMH
, mainExecutableSlide
, 
5779                                                                            argc
, argv
, envp
, apple
, &result
, startGlue
) ) { 
5781                                                 result 
= (uintptr_t)&fake_main
; 
5785                                         if ( gLinkContext
.verboseWarnings 
) 
5786                                                 dyld::log("dyld: unable to use closure %p\n", mainClosureData
); 
5791                         if ( gLinkContext
.verboseWarnings 
) 
5792                                 dyld::log("dyld: not using closure because shared cache format version does not match dyld's\n"); 
5794                 // could not use closure info, launch old way 
5798         // install gdb notifier 
5799         stateToHandlers(dyld_image_state_dependents_mapped
, sBatchHandlers
)->push_back(notifyGDB
); 
5800         stateToHandlers(dyld_image_state_mapped
, sSingleHandlers
)->push_back(updateAllImages
); 
5801         // make initial allocations large enough that it is unlikely to need to be re-alloced 
5802         sImageRoots
.reserve(16); 
5803         sAddImageCallbacks
.reserve(4); 
5804         sRemoveImageCallbacks
.reserve(4); 
5805         sImageFilesNeedingTermination
.reserve(16); 
5806         sImageFilesNeedingDOFUnregistration
.reserve(8); 
5808 #if !TARGET_IPHONE_SIMULATOR 
5809 #ifdef WAIT_FOR_SYSTEM_ORDER_HANDSHAKE 
5810         // <rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process 
5811         WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld::gProcessInfo
->systemOrderFlag
); 
5817                 // add dyld itself to UUID list 
5818                 addDyldImageToUUIDList(); 
5820 #if SUPPORT_ACCELERATE_TABLES 
5821                 bool mainExcutableAlreadyRebased 
= false; 
5822                 if ( (sSharedCacheLoadInfo
.loadAddress 
!= nullptr) && !dylibsCanOverrideCache() && !sDisableAcceleratorTables 
&& (sSharedCacheLoadInfo
.loadAddress
->header
.accelerateInfoAddr 
!= 0) ) { 
5823                         struct stat statBuf
; 
5824                         if ( ::stat(IPHONE_DYLD_SHARED_CACHE_DIR 
"no-dyld2-accelerator-tables", &statBuf
) != 0 ) 
5825                                 sAllCacheImagesProxy 
= ImageLoaderMegaDylib::makeImageLoaderMegaDylib(&sSharedCacheLoadInfo
.loadAddress
->header
, sSharedCacheLoadInfo
.slide
, mainExecutableMH
, gLinkContext
); 
5831                 CRSetCrashLogMessage(sLoadingCrashMessage
); 
5832                 // instantiate ImageLoader for main executable 
5833                 sMainExecutable 
= instantiateFromLoadedImage(mainExecutableMH
, mainExecutableSlide
, sExecPath
); 
5834                 gLinkContext
.mainExecutable 
= sMainExecutable
; 
5835                 gLinkContext
.mainExecutableCodeSigned 
= hasCodeSignatureLoadCommand(mainExecutableMH
); 
5837 #if TARGET_IPHONE_SIMULATOR 
5838                 // check main executable is not too new for this OS 
5840                         if ( ! isSimulatorBinary((uint8_t*)mainExecutableMH
, sExecPath
) ) { 
5841                                 throwf("program was built for a platform that is not supported by this runtime"); 
5843                         uint32_t mainMinOS 
= sMainExecutable
->minOSVersion(); 
5845                         // dyld is always built for the current OS, so we can get the current OS version 
5846                         // from the load command in dyld itself. 
5847                         uint32_t dyldMinOS 
= ImageLoaderMachO::minOSVersion((const mach_header
*)&__dso_handle
); 
5848                         if ( mainMinOS 
> dyldMinOS 
) { 
5850                                 throwf("app was built for watchOS %d.%d which is newer than this simulator %d.%d", 
5851                                                 mainMinOS 
>> 16, ((mainMinOS 
>> 8) & 0xFF), 
5852                                                 dyldMinOS 
>> 16, ((dyldMinOS 
>> 8) & 0xFF)); 
5854                                 throwf("app was built for tvOS %d.%d which is newer than this simulator %d.%d", 
5855                                                 mainMinOS 
>> 16, ((mainMinOS 
>> 8) & 0xFF), 
5856                                                 dyldMinOS 
>> 16, ((dyldMinOS 
>> 8) & 0xFF)); 
5858                                 throwf("app was built for iOS %d.%d which is newer than this simulator %d.%d", 
5859                                                 mainMinOS 
>> 16, ((mainMinOS 
>> 8) & 0xFF), 
5860                                                 dyldMinOS 
>> 16, ((dyldMinOS 
>> 8) & 0xFF)); 
5867         #if __MAC_OS_X_VERSION_MIN_REQUIRED 
5868                 // <rdar://problem/22805519> be less strict about old mach-o binaries 
5869                 uint32_t mainSDK 
= sMainExecutable
->sdkVersion(); 
5870                 gLinkContext
.strictMachORequired 
= (mainSDK 
>= DYLD_MACOSX_VERSION_10_12
) || gLinkContext
.processUsingLibraryValidation
; 
5872                 // simulators, iOS, tvOS, and watchOS are always strict 
5873                 gLinkContext
.strictMachORequired 
= true; 
5876         #if SUPPORT_ACCELERATE_TABLES 
5877                 sAllImages
.reserve((sAllCacheImagesProxy 
!= NULL
) ? 16 : INITIAL_IMAGE_COUNT
); 
5879                 sAllImages
.reserve(INITIAL_IMAGE_COUNT
); 
5882                 // Now that shared cache is loaded, setup an versioned dylib overrides 
5883         #if SUPPORT_VERSIONED_PATHS 
5884                 checkVersionedPaths(); 
5888                 // dyld_all_image_infos image list does not contain dyld 
5889                 // add it as dyldPath field in dyld_all_image_infos 
5890                 // for simulator, dyld_sim is in image list, need host dyld added 
5891 #if TARGET_IPHONE_SIMULATOR 
5892                 // get path of host dyld from table of syscall vectors in host dyld 
5893                 void* addressInDyld 
= gSyscallHelpers
; 
5895                 // get path of dyld itself 
5896                 void*  addressInDyld 
= (void*)&__dso_handle
; 
5898                 char dyldPathBuffer
[MAXPATHLEN
+1]; 
5899                 int len 
= proc_regionfilename(getpid(), (uint64_t)(long)addressInDyld
, dyldPathBuffer
, MAXPATHLEN
); 
5901                         dyldPathBuffer
[len
] = '\0'; // proc_regionfilename() does not zero terminate returned string 
5902                         if ( strcmp(dyldPathBuffer
, gProcessInfo
->dyldPath
) != 0 ) 
5903                                 gProcessInfo
->dyldPath 
= strdup(dyldPathBuffer
); 
5906                 // load any inserted libraries 
5907                 if      ( sEnv
.DYLD_INSERT_LIBRARIES 
!= NULL 
) { 
5908                         for (const char* const* lib 
= sEnv
.DYLD_INSERT_LIBRARIES
; *lib 
!= NULL
; ++lib
)  
5909                                 loadInsertedDylib(*lib
); 
5911                 // record count of inserted libraries so that a flat search will look at  
5912                 // inserted libraries, then main, then others. 
5913                 sInsertedDylibCount 
= sAllImages
.size()-1; 
5915                 // link main executable 
5916                 gLinkContext
.linkingMainExecutable 
= true; 
5917 #if SUPPORT_ACCELERATE_TABLES 
5918                 if ( mainExcutableAlreadyRebased 
) { 
5919                         // previous link() on main executable has already adjusted its internal pointers for ASLR 
5920                         // work around that by rebasing by inverse amount 
5921                         sMainExecutable
->rebase(gLinkContext
, -mainExecutableSlide
); 
5924                 link(sMainExecutable
, sEnv
.DYLD_BIND_AT_LAUNCH
, true, ImageLoader::RPathChain(NULL
, NULL
), -1); 
5925                 sMainExecutable
->setNeverUnloadRecursive(); 
5926                 if ( sMainExecutable
->forceFlat() ) { 
5927                         gLinkContext
.bindFlat 
= true; 
5928                         gLinkContext
.prebindUsage 
= ImageLoader::kUseNoPrebinding
; 
5931                 // link any inserted libraries 
5932                 // do this after linking main executable so that any dylibs pulled in by inserted  
5933                 // dylibs (e.g. libSystem) will not be in front of dylibs the program uses 
5934                 if ( sInsertedDylibCount 
> 0 ) { 
5935                         for(unsigned int i
=0; i 
< sInsertedDylibCount
; ++i
) { 
5936                                 ImageLoader
* image 
= sAllImages
[i
+1]; 
5937                                 link(image
, sEnv
.DYLD_BIND_AT_LAUNCH
, true, ImageLoader::RPathChain(NULL
, NULL
), -1); 
5938                                 image
->setNeverUnloadRecursive(); 
5940                         // only INSERTED libraries can interpose 
5941                         // register interposing info after all inserted libraries are bound so chaining works 
5942                         for(unsigned int i
=0; i 
< sInsertedDylibCount
; ++i
) { 
5943                                 ImageLoader
* image 
= sAllImages
[i
+1]; 
5944                                 image
->registerInterposing(); 
5948                 // <rdar://problem/19315404> dyld should support interposition even without DYLD_INSERT_LIBRARIES 
5949                 for (long i
=sInsertedDylibCount
+1; i 
< sAllImages
.size(); ++i
) { 
5950                         ImageLoader
* image 
= sAllImages
[i
]; 
5951                         if ( image
->inSharedCache() ) 
5953                         image
->registerInterposing(); 
5955         #if SUPPORT_ACCELERATE_TABLES 
5956                 if ( (sAllCacheImagesProxy 
!= NULL
) && ImageLoader::haveInterposingTuples() ) { 
5957                         // Accelerator tables cannot be used with implicit interposing, so relaunch with accelerator tables disabled 
5958                         ImageLoader::clearInterposingTuples(); 
5959                         // unmap all loaded dylibs (but not main executable) 
5960                         for (long i
=1; i 
< sAllImages
.size(); ++i
) { 
5961                                 ImageLoader
* image 
= sAllImages
[i
]; 
5962                                 if ( image 
== sMainExecutable 
) 
5964                                 if ( image 
== sAllCacheImagesProxy 
) 
5966                                 image
->setCanUnload(); 
5967                                 ImageLoader::deleteImage(image
); 
5969                         // 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 
5971                         sImageRoots
.clear(); 
5972                         sImageFilesNeedingTermination
.clear(); 
5973                         sImageFilesNeedingDOFUnregistration
.clear(); 
5974                         sAddImageCallbacks
.clear(); 
5975                         sRemoveImageCallbacks
.clear(); 
5976                         sDisableAcceleratorTables 
= true; 
5977                         sAllCacheImagesProxy 
= NULL
; 
5978                         sMappedRangesStart 
= NULL
; 
5979                         mainExcutableAlreadyRebased 
= true; 
5980                         gLinkContext
.linkingMainExecutable 
= false; 
5982                         goto reloadAllImages
; 
5986                 // apply interposing to initial set of images 
5987                 for(int i
=0; i 
< sImageRoots
.size(); ++i
) { 
5988                         sImageRoots
[i
]->applyInterposing(gLinkContext
); 
5990                 gLinkContext
.linkingMainExecutable 
= false; 
5992                 // <rdar://problem/12186933> do weak binding only after all inserted images linked 
5993                 sMainExecutable
->weakBind(gLinkContext
); 
5995                 // If cache has branch island dylibs, tell debugger about them 
5996                 if ( (sSharedCacheLoadInfo
.loadAddress 
!= NULL
) && (sSharedCacheLoadInfo
.loadAddress
->header
.mappingOffset 
>= 0x78) && (sSharedCacheLoadInfo
.loadAddress
->header
.branchPoolsOffset 
!= 0) ) { 
5997                         uint32_t count 
= sSharedCacheLoadInfo
.loadAddress
->header
.branchPoolsCount
; 
5998                         dyld_image_info info
[count
]; 
5999                         const uint64_t* poolAddress 
= (uint64_t*)((char*)sSharedCacheLoadInfo
.loadAddress 
+ sSharedCacheLoadInfo
.loadAddress
->header
.branchPoolsOffset
); 
6000                         // <rdar://problem/20799203> empty branch pools can be in development cache 
6001                         if ( ((mach_header
*)poolAddress
)->magic 
== sMainExecutableMachHeader
->magic 
) { 
6002                                 for (int poolIndex
=0; poolIndex 
< count
; ++poolIndex
) { 
6003                                         uint64_t poolAddr 
= poolAddress
[poolIndex
] + sSharedCacheLoadInfo
.slide
; 
6004                                         info
[poolIndex
].imageLoadAddress 
= (mach_header
*)(long)poolAddr
; 
6005                                         info
[poolIndex
].imageFilePath 
= "dyld_shared_cache_branch_islands"; 
6006                                         info
[poolIndex
].imageFileModDate 
= 0; 
6008                                 // add to all_images list 
6009                                 addImagesToAllImages(count
, info
); 
6010                                 // tell gdb about new branch island images 
6011                                 gProcessInfo
->notification(dyld_image_adding
, count
, info
); 
6015                 CRSetCrashLogMessage("dyld: launch, running initializers"); 
6016         #if SUPPORT_OLD_CRT_INITIALIZATION 
6017                 // Old way is to run initializers via a callback from crt1.o 
6018                 if ( ! gRunInitializersOldWay 
)  
6019                         initializeMainExecutable();  
6021                 // run all initializers 
6022                 initializeMainExecutable();  
6025                 // notify any montoring proccesses that this process is about to enter main() 
6026                 dyld3::kdebug_trace_dyld_signpost(DBG_DYLD_SIGNPOST_START_MAIN_DYLD2
, 0, 0); 
6027                 notifyMonitoringDyldMain(); 
6029                 // find entry point for main executable 
6030                 result 
= (uintptr_t)sMainExecutable
->getThreadPC(); 
6031                 if ( result 
!= 0 ) { 
6032                         // main executable uses LC_MAIN, needs to return to glue in libdyld.dylib 
6033                         if ( (gLibSystemHelpers 
!= NULL
) && (gLibSystemHelpers
->version 
>= 9) ) 
6034                                 *startGlue 
= (uintptr_t)gLibSystemHelpers
->startGlueToCallExit
; 
6036                                 halt("libdyld.dylib support not present for LC_MAIN"); 
6039                         // main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main() 
6040                         result 
= (uintptr_t)sMainExecutable
->getMain(); 
6044         catch(const char* message
) { 
6049                 dyld::log("dyld: launch failed\n"); 
6052         CRSetCrashLogMessage(NULL
); 
6055                 dyld3::kdebug_trace_dyld_signpost(DBG_DYLD_SIGNPOST_START_MAIN
, 0, 0); 
6056                 result 
= (uintptr_t)&fake_main
; 
6057                 *startGlue 
= (uintptr_t)gLibSystemHelpers
->startGlueToCallExit
;