1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2010 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@
31 #include <sys/param.h>
32 #include <mach/mach_time.h> // mach_absolute_time()
33 #include <sys/types.h>
35 #include <sys/syscall.h>
36 #include <mach-o/fat.h>
37 #include <mach-o/loader.h>
38 #include <mach-o/ldsyms.h>
39 #include <libkern/OSByteOrder.h>
40 #include <libkern/OSAtomic.h>
41 #include <mach/mach.h>
42 #include <sys/sysctl.h>
44 #include <sys/dtrace.h>
45 #include <libkern/OSAtomic.h>
46 #include <Availability.h>
47 #include <Kernel/sys/codesign.h>
50 #ifndef CPU_SUBTYPE_ARM_V5TEJ
51 #define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7)
53 #ifndef CPU_SUBTYPE_ARM_XSCALE
54 #define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8)
56 #ifndef CPU_SUBTYPE_ARM_V7
57 #define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9)
59 #ifndef CPU_SUBTYPE_ARM_V7F
60 #define CPU_SUBTYPE_ARM_V7F ((cpu_subtype_t) 10)
62 #ifndef CPU_SUBTYPE_ARM_V7S
63 #define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t) 11)
65 #ifndef CPU_SUBTYPE_ARM_V7K
66 #define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12)
68 #ifndef LC_DYLD_ENVIRONMENT
69 #define LC_DYLD_ENVIRONMENT 0x27
73 #define VM_PROT_SLIDE 0x20
79 #include "mach-o/dyld_gdb.h"
82 #include "ImageLoader.h"
83 #include "ImageLoaderMachO.h"
84 #include "dyldLibSystemInterface.h"
85 #if DYLD_SHARED_CACHE_SUPPORT
86 #include "dyld_cache_format.h"
88 #if CORESYMBOLICATION_SUPPORT
89 #include "coreSymbolicationDyldSupport.hpp"
92 // from _simple.h in libc
93 typedef struct _SIMPLE
* _SIMPLE_STRING
;
94 extern "C" void _simple_vdprintf(int __fd
, const char *__fmt
, va_list __ap
);
95 extern "C" void _simple_dprintf(int __fd
, const char *__fmt
, ...);
96 extern "C" _SIMPLE_STRING
_simple_salloc(void);
97 extern "C" int _simple_vsprintf(_SIMPLE_STRING __b
, const char *__fmt
, va_list __ap
);
98 extern "C" void _simple_sfree(_SIMPLE_STRING __b
);
99 extern "C" char * _simple_string(_SIMPLE_STRING __b
);
103 // ARM is the only architecture that use cpu-sub-types
104 #define CPU_SUBTYPES_SUPPORTED __arm__
108 #define CPU_TYPE_MASK 0x00FFFFFF /* complement of CPU_ARCH_MASK */
111 /* implemented in dyld_gdb.cpp */
112 extern void addImagesToAllImages(uint32_t infoCount
, const dyld_image_info info
[]);
113 extern void removeImageFromAllImages(const mach_header
* mh
);
114 extern void setAlImageInfosHalt(const char* message
, uintptr_t flags
);
115 extern void addNonSharedCacheImageUUID(const dyld_uuid_info
& info
);
116 extern const char* notifyGDB(enum dyld_image_states state
, uint32_t infoCount
, const dyld_image_info info
[]);
118 // magic so CrashReporter logs message
120 char error_string
[1024];
122 // implemented in dyldStartup.s for CrashReporter
123 extern "C" void dyld_fatal_error(const char* errString
) __attribute__((noreturn
));
125 // magic linker symbol for start of dyld binary
126 extern "C" void* __dso_handle
;
130 // The file contains the core of dyld used to get a process to main().
131 // The API's that dyld supports are implemented in dyldAPIs.cpp.
143 // state of all environment variables dyld uses
145 struct EnvironmentVariables
{
146 const char* const * DYLD_FRAMEWORK_PATH
;
147 const char* const * DYLD_FALLBACK_FRAMEWORK_PATH
;
148 const char* const * DYLD_LIBRARY_PATH
;
149 const char* const * DYLD_FALLBACK_LIBRARY_PATH
;
150 const char* const * DYLD_INSERT_LIBRARIES
;
151 const char* const * LD_LIBRARY_PATH
; // for unix conformance
152 const char* const * DYLD_VERSIONED_LIBRARY_PATH
;
153 const char* const * DYLD_VERSIONED_FRAMEWORK_PATH
;
154 bool DYLD_PRINT_LIBRARIES
;
155 bool DYLD_PRINT_LIBRARIES_POST_LAUNCH
;
156 bool DYLD_BIND_AT_LAUNCH
;
157 bool DYLD_PRINT_STATISTICS
;
158 bool DYLD_PRINT_OPTS
;
160 bool DYLD_DISABLE_DOFS
;
161 bool DYLD_PRINT_CS_NOTIFICATIONS
;
162 // DYLD_SHARED_CACHE_DONT_VALIDATE ==> sSharedCacheIgnoreInodeAndTimeStamp
163 // DYLD_SHARED_CACHE_DIR ==> sSharedCacheDir
164 // DYLD_ROOT_PATH ==> gLinkContext.rootPaths
165 // DYLD_IMAGE_SUFFIX ==> gLinkContext.imageSuffix
166 // DYLD_PRINT_OPTS ==> gLinkContext.verboseOpts
167 // DYLD_PRINT_ENV ==> gLinkContext.verboseEnv
168 // DYLD_FORCE_FLAT_NAMESPACE ==> gLinkContext.bindFlat
169 // DYLD_PRINT_INITIALIZERS ==> gLinkContext.verboseInit
170 // DYLD_PRINT_SEGMENTS ==> gLinkContext.verboseMapping
171 // DYLD_PRINT_BINDINGS ==> gLinkContext.verboseBind
172 // DYLD_PRINT_WEAK_BINDINGS ==> gLinkContext.verboseWeakBind
173 // DYLD_PRINT_REBASINGS ==> gLinkContext.verboseRebase
174 // DYLD_PRINT_DOFS ==> gLinkContext.verboseDOF
175 // DYLD_PRINT_APIS ==> gLogAPIs
176 // DYLD_IGNORE_PREBINDING ==> gLinkContext.prebindUsage
177 // DYLD_PREBIND_DEBUG ==> gLinkContext.verbosePrebinding
178 // DYLD_NEW_LOCAL_SHARED_REGIONS ==> gLinkContext.sharedRegionMode
179 // DYLD_SHARED_REGION ==> gLinkContext.sharedRegionMode
180 // DYLD_PRINT_WARNINGS ==> gLinkContext.verboseWarnings
181 // DYLD_PRINT_RPATHS ==> gLinkContext.verboseRPaths
182 // DYLD_PRINT_INTERPOSING ==> gLinkContext.verboseInterposing
185 typedef std::vector
<dyld_image_state_change_handler
> StateHandlers
;
186 struct RegisteredDOF
{ const mach_header
* mh
; int registrationID
; };
187 struct DylibOverride
{ const char* installName
; const char* override
; };
189 enum RestrictedReason
{ restrictedNot
, restrictedBySetGUid
, restrictedBySegment
, restrictedByEntitlements
};
192 static const char* sExecPath
= NULL
;
193 static const macho_header
* sMainExecutableMachHeader
= NULL
;
194 #if CPU_SUBTYPES_SUPPORTED
195 static cpu_type_t sHostCPU
;
196 static cpu_subtype_t sHostCPUsubtype
;
198 static ImageLoader
* sMainExecutable
= NULL
;
199 static bool sProcessIsRestricted
= false;
200 static RestrictedReason sRestrictedReason
= restrictedNot
;
201 static unsigned int sInsertedDylibCount
= 0;
202 static std::vector
<ImageLoader
*> sAllImages
;
203 static std::vector
<ImageLoader
*> sImageRoots
;
204 static std::vector
<ImageLoader
*> sImageFilesNeedingTermination
;
205 static std::vector
<RegisteredDOF
> sImageFilesNeedingDOFUnregistration
;
206 static std::vector
<ImageCallback
> sAddImageCallbacks
;
207 static std::vector
<ImageCallback
> sRemoveImageCallbacks
;
208 static StateHandlers sSingleHandlers
[7];
209 static StateHandlers sBatchHandlers
[7];
210 static ImageLoader
* sLastImageByAddressCache
;
211 static EnvironmentVariables sEnv
;
212 static const char* sFrameworkFallbackPaths
[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL
};
213 static const char* sLibraryFallbackPaths
[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL
};
214 static UndefinedHandler sUndefinedHandler
= NULL
;
215 static ImageLoader
* sBundleBeingLoaded
= NULL
; // hack until OFI is reworked
216 #if DYLD_SHARED_CACHE_SUPPORT
217 static const dyld_cache_header
* sSharedCache
= NULL
;
218 static long sSharedCacheSlide
= 0;
219 static bool sSharedCacheIgnoreInodeAndTimeStamp
= false;
220 #if __IPHONE_OS_VERSION_MIN_REQUIRED
221 bool gSharedCacheOverridden
= false;
222 static const char* sSharedCacheDir
= IPHONE_DYLD_SHARED_CACHE_DIR
;
223 static bool sDylibsOverrideCache
= false;
225 static const char* sSharedCacheDir
= MACOSX_DYLD_SHARED_CACHE_DIR
;
228 ImageLoader::LinkContext gLinkContext
;
229 bool gLogAPIs
= false;
230 const struct LibSystemHelpers
* gLibSystemHelpers
= NULL
;
231 #if SUPPORT_OLD_CRT_INITIALIZATION
232 bool gRunInitializersOldWay
= false;
234 static std::vector
<DylibOverride
> sDylibOverrides
;
237 // The MappedRanges structure is used for fast address->image lookups.
238 // The table is only updated when the dyld lock is held, so we don't
239 // need to worry about multiple writers. But readers may look at this
240 // data without holding the lock. Therefore, all updates must be done
241 // in an order that will never cause readers to see inconsistent data.
242 // The general rule is that if the image field is non-NULL then
243 // the other fields are valid.
256 static MappedRanges sMappedRangesStart
;
258 void addMappedRange(ImageLoader
* image
, uintptr_t start
, uintptr_t end
)
260 //dyld::log("addMappedRange(0x%lX->0x%lX) for %s\n", start, end, image->getShortName());
261 for (MappedRanges
* p
= &sMappedRangesStart
; p
!= NULL
; p
= p
->next
) {
262 for (int i
=0; i
< MappedRanges::count
; ++i
) {
263 if ( p
->array
[i
].image
== NULL
) {
264 p
->array
[i
].start
= start
;
265 p
->array
[i
].end
= end
;
266 // add image field last with a barrier so that any reader will see consistent records
268 p
->array
[i
].image
= image
;
273 // table must be full, chain another
274 MappedRanges
* newRanges
= (MappedRanges
*)malloc(sizeof(MappedRanges
));
275 bzero(newRanges
, sizeof(MappedRanges
));
276 newRanges
->array
[0].start
= start
;
277 newRanges
->array
[0].end
= end
;
278 newRanges
->array
[0].image
= image
;
279 for (MappedRanges
* p
= &sMappedRangesStart
; p
!= NULL
; p
= p
->next
) {
280 if ( p
->next
== NULL
) {
288 void removedMappedRanges(ImageLoader
* image
)
290 for (MappedRanges
* p
= &sMappedRangesStart
; p
!= NULL
; p
= p
->next
) {
291 for (int i
=0; i
< MappedRanges::count
; ++i
) {
292 if ( p
->array
[i
].image
== image
) {
293 // clear with a barrier so that any reader will see consistent records
295 p
->array
[i
].image
= NULL
;
301 ImageLoader
* findMappedRange(uintptr_t target
)
303 for (MappedRanges
* p
= &sMappedRangesStart
; p
!= NULL
; p
= p
->next
) {
304 for (int i
=0; i
< MappedRanges::count
; ++i
) {
305 if ( p
->array
[i
].image
!= NULL
) {
306 if ( (p
->array
[i
].start
<= target
) && (target
< p
->array
[i
].end
) )
307 return p
->array
[i
].image
;
316 const char* mkstringf(const char* format
, ...)
318 _SIMPLE_STRING buf
= _simple_salloc();
321 va_start(list
, format
);
322 _simple_vsprintf(buf
, format
, list
);
324 const char* t
= strdup(_simple_string(buf
));
329 return "mkstringf, out of memory error";
333 void throwf(const char* format
, ...)
335 _SIMPLE_STRING buf
= _simple_salloc();
338 va_start(list
, format
);
339 _simple_vsprintf(buf
, format
, list
);
341 const char* t
= strdup(_simple_string(buf
));
346 throw "throwf, out of memory error";
350 //#define ALTERNATIVE_LOGFILE "/dev/console"
352 static int sLogfile
= STDERR_FILENO
;
355 static int sBindingsLogfile
= -1;
356 static void mysprintf(char* dst
, const char* format
, ...)
358 _SIMPLE_STRING buf
= _simple_salloc();
361 va_start(list
, format
);
362 _simple_vsprintf(buf
, format
, list
);
364 strcpy(dst
, _simple_string(buf
));
368 strcpy(dst
, "out of memory");
371 void logBindings(const char* format
, ...)
373 if ( sBindingsLogfile
!= -1 ) {
375 va_start(list
, format
);
376 _simple_vdprintf(sBindingsLogfile
, format
, list
);
383 void log(const char* format
, ...)
386 va_start(list
, format
);
387 _simple_vdprintf(sLogfile
, format
, list
);
391 void warn(const char* format
, ...)
393 _simple_dprintf(sLogfile
, "dyld: warning, ");
395 va_start(list
, format
);
396 _simple_vdprintf(sLogfile
, format
, list
);
401 // <rdar://problem/8867781> control access to sAllImages through a lock
402 // because global dyld lock is not held during initialization phase of dlopen()
403 static long sAllImagesLock
= 0;
405 static void allImagesLock()
407 //dyld::log("allImagesLock()\n");
408 while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)0, (void*)1, (void**)&sAllImagesLock
) ) {
413 static void allImagesUnlock()
415 //dyld::log("allImagesUnlock()\n");
416 while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)1, (void*)0, (void**)&sAllImagesLock
) ) {
424 // utility class to assure files are closed when an exception is thrown
427 FileOpener(const char* path
);
429 int getFileDescriptor() { return fd
; }
434 FileOpener::FileOpener(const char* path
)
437 fd
= open(path
, O_RDONLY
, 0);
440 FileOpener::~FileOpener()
447 static void registerDOFs(const std::vector
<ImageLoader::DOFInfo
>& dofs
)
449 const unsigned int dofSectionCount
= dofs
.size();
450 if ( !sEnv
.DYLD_DISABLE_DOFS
&& (dofSectionCount
!= 0) ) {
451 int fd
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
);
453 //dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n");
456 // allocate a buffer on the stack for the variable length dof_ioctl_data_t type
457 uint8_t buffer
[sizeof(dof_ioctl_data_t
) + dofSectionCount
*sizeof(dof_helper_t
)];
458 dof_ioctl_data_t
* ioctlData
= (dof_ioctl_data_t
*)buffer
;
460 // fill in buffer with one dof_helper_t per DOF section
461 ioctlData
->dofiod_count
= dofSectionCount
;
462 for (unsigned int i
=0; i
< dofSectionCount
; ++i
) {
463 strlcpy(ioctlData
->dofiod_helpers
[i
].dofhp_mod
, dofs
[i
].imageShortName
, DTRACE_MODNAMELEN
);
464 ioctlData
->dofiod_helpers
[i
].dofhp_dof
= (uintptr_t)(dofs
[i
].dof
);
465 ioctlData
->dofiod_helpers
[i
].dofhp_addr
= (uintptr_t)(dofs
[i
].dof
);
468 // tell kernel about all DOF sections en mas
469 // pass pointer to ioctlData because ioctl() only copies a fixed size amount of data into kernel
470 user_addr_t val
= (user_addr_t
)(unsigned long)ioctlData
;
471 if ( ioctl(fd
, DTRACEHIOC_ADDDOF
, &val
) != -1 ) {
472 // kernel returns a unique identifier for each section in the dofiod_helpers[].dofhp_dof field.
473 for (unsigned int i
=0; i
< dofSectionCount
; ++i
) {
475 info
.mh
= dofs
[i
].imageHeader
;
476 info
.registrationID
= (int)(ioctlData
->dofiod_helpers
[i
].dofhp_dof
);
477 sImageFilesNeedingDOFUnregistration
.push_back(info
);
478 if ( gLinkContext
.verboseDOF
) {
479 dyld::log("dyld: registering DOF section 0x%p in %s with dtrace, ID=0x%08X\n",
480 dofs
[i
].dof
, dofs
[i
].imageShortName
, info
.registrationID
);
485 dyld::log( "dyld: ioctl to register dtrace DOF section failed\n");
492 static void unregisterDOF(int registrationID
)
494 int fd
= open("/dev/" DTRACEMNR_HELPER
, O_RDWR
);
496 dyld::warn("can't open /dev/" DTRACEMNR_HELPER
" to unregister dtrace DOF section\n");
499 ioctl(fd
, DTRACEHIOC_REMOVE
, registrationID
);
501 if ( gLinkContext
.verboseInit
)
502 dyld::warn("unregistering DOF section ID=0x%08X with dtrace\n", registrationID
);
508 // _dyld_register_func_for_add_image() is implemented as part of the general image state change notification
510 static void notifyAddImageCallbacks(ImageLoader
* image
)
512 // use guard so that we cannot notify about the same image twice
513 if ( ! image
->addFuncNotified() ) {
514 for (std::vector
<ImageCallback
>::iterator it
=sAddImageCallbacks
.begin(); it
!= sAddImageCallbacks
.end(); it
++)
515 (*it
)(image
->machHeader(), image
->getSlide());
516 image
->setAddFuncNotified();
522 // notify gdb about these new images
523 static const char* updateAllImages(enum dyld_image_states state
, uint32_t infoCount
, const struct dyld_image_info info
[])
525 // <rdar://problem/8812589> don't add images without paths to all-image-info-list
526 if ( info
[0].imageFilePath
!= NULL
)
527 addImagesToAllImages(infoCount
, info
);
532 static StateHandlers
* stateToHandlers(dyld_image_states state
, StateHandlers handlersArray
[8])
535 case dyld_image_state_mapped
:
536 return &handlersArray
[0];
538 case dyld_image_state_dependents_mapped
:
539 return &handlersArray
[1];
541 case dyld_image_state_rebased
:
542 return &handlersArray
[2];
544 case dyld_image_state_bound
:
545 return &handlersArray
[3];
547 case dyld_image_state_dependents_initialized
:
548 return &handlersArray
[4];
550 case dyld_image_state_initialized
:
551 return &handlersArray
[5];
553 case dyld_image_state_terminated
:
554 return &handlersArray
[6];
560 static void notifySingle(dyld_image_states state
, const ImageLoader
* image
)
562 //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath());
563 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(state
, sSingleHandlers
);
564 if ( handlers
!= NULL
) {
565 dyld_image_info info
;
566 info
.imageLoadAddress
= image
->machHeader();
567 info
.imageFilePath
= image
->getRealPath();
568 info
.imageFileModDate
= image
->lastModified();
569 for (std::vector
<dyld_image_state_change_handler
>::iterator it
= handlers
->begin(); it
!= handlers
->end(); ++it
) {
570 const char* result
= (*it
)(state
, 1, &info
);
571 if ( (result
!= NULL
) && (state
== dyld_image_state_mapped
) ) {
572 //fprintf(stderr, " image rejected by handler=%p\n", *it);
573 // make copy of thrown string so that later catch clauses can free it
574 const char* str
= strdup(result
);
579 if ( state
== dyld_image_state_mapped
) {
580 // <rdar://problem/7008875> Save load addr + UUID for images from outside the shared cache
581 if ( !image
->inSharedCache() ) {
583 if ( image
->getUUID(info
.imageUUID
) ) {
584 info
.imageLoadAddress
= image
->machHeader();
585 addNonSharedCacheImageUUID(info
);
589 #if CORESYMBOLICATION_SUPPORT
590 // mach message csdlc about dynamically loaded images
591 if ( image
->addFuncNotified() && (state
== dyld_image_state_terminated
) ) {
592 if ( sEnv
.DYLD_PRINT_CS_NOTIFICATIONS
) {
593 dyld::log("dyld core symbolication unload notification: %p %s\n", image
->machHeader(), image
->getPath());
595 if ( dyld_all_image_infos
.coreSymbolicationShmPage
!= NULL
) {
596 CSCppDyldSharedMemoryPage
* connection
= (CSCppDyldSharedMemoryPage
*)dyld_all_image_infos
.coreSymbolicationShmPage
;
597 if ( connection
->is_valid_version() ) {
598 coresymbolication_unload_image(connection
, image
);
609 // Normally, dyld_all_image_infos is only updated in batches after an entire
610 // graph is loaded. But if there is an error loading the initial set of
611 // dylibs needed by the main executable, dyld_all_image_infos is not yet set
612 // up, leading to usually brief crash logs.
614 // This function manually adds the images loaded so far to dyld_all_image_infos.
615 // It should only be called before terminating.
619 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); ++it
) {
620 dyld_image_info info
;
621 ImageLoader
* image
= *it
;
622 info
.imageLoadAddress
= image
->machHeader();
623 info
.imageFilePath
= image
->getRealPath();
624 info
.imageFileModDate
= image
->lastModified();
625 // add to all_image_infos if not already there
627 int existingCount
= dyld_all_image_infos
.infoArrayCount
;
628 const dyld_image_info
* existing
= dyld_all_image_infos
.infoArray
;
629 if ( existing
!= NULL
) {
630 for (int i
=0; i
< existingCount
; ++i
) {
631 if ( existing
[i
].imageLoadAddress
== info
.imageLoadAddress
) {
632 //dyld::log("not adding %s\n", info.imageFilePath);
639 //dyld::log("adding %s\n", info.imageFilePath);
640 addImagesToAllImages(1, &info
);
646 static int imageSorter(const void* l
, const void* r
)
648 const ImageLoader
* left
= *((ImageLoader
**)l
);
649 const ImageLoader
* right
= *((ImageLoader
**)r
);
650 return left
->compare(right
);
653 static void notifyBatchPartial(dyld_image_states state
, bool orLater
, dyld_image_state_change_handler onlyHandler
)
655 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(state
, sBatchHandlers
);
656 if ( handlers
!= NULL
) {
657 // don't use a vector because it will use malloc/free and we want notifcation to be low cost
659 ImageLoader
* images
[sAllImages
.size()+1];
660 ImageLoader
** end
= images
;
661 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
662 dyld_image_states imageState
= (*it
)->getState();
663 if ( (imageState
== state
) || (orLater
&& (imageState
> state
)) )
666 if ( sBundleBeingLoaded
!= NULL
) {
667 dyld_image_states imageState
= sBundleBeingLoaded
->getState();
668 if ( (imageState
== state
) || (orLater
&& (imageState
> state
)) )
669 *end
++ = sBundleBeingLoaded
;
671 const char* dontLoadReason
= NULL
;
672 unsigned int count
= end
-images
;
673 if ( end
!= images
) {
675 qsort(images
, count
, sizeof(ImageLoader
*), &imageSorter
);
677 dyld_image_info infos
[count
];
678 for (unsigned int i
=0; i
< count
; ++i
) {
679 dyld_image_info
* p
= &infos
[i
];
680 ImageLoader
* image
= images
[i
];
681 //dyld::log(" state=%d, name=%s\n", state, image->getPath());
682 p
->imageLoadAddress
= image
->machHeader();
683 p
->imageFilePath
= image
->getRealPath();
684 p
->imageFileModDate
= image
->lastModified();
685 // special case for add_image hook
686 if ( state
== dyld_image_state_bound
)
687 notifyAddImageCallbacks(image
);
690 if ( onlyHandler
!= NULL
) {
691 const char* result
= (*onlyHandler
)(state
, count
, infos
);
692 if ( (result
!= NULL
) && (state
== dyld_image_state_dependents_mapped
) ) {
693 //fprintf(stderr, " images rejected by handler=%p\n", onlyHandler);
694 // make copy of thrown string so that later catch clauses can free it
695 dontLoadReason
= strdup(result
);
699 // call each handler with whole array
700 for (std::vector
<dyld_image_state_change_handler
>::iterator it
= handlers
->begin(); it
!= handlers
->end(); ++it
) {
701 const char* result
= (*it
)(state
, count
, infos
);
702 if ( (result
!= NULL
) && (state
== dyld_image_state_dependents_mapped
) ) {
703 //fprintf(stderr, " images rejected by handler=%p\n", *it);
704 // make copy of thrown string so that later catch clauses can free it
705 dontLoadReason
= strdup(result
);
712 if ( dontLoadReason
!= NULL
)
713 throw dontLoadReason
;
715 #if CORESYMBOLICATION_SUPPORT
716 if ( state
== dyld_image_state_rebased
) {
717 if ( sEnv
.DYLD_PRINT_CS_NOTIFICATIONS
) {
718 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
719 dyld_image_states imageState
= (*it
)->getState();
720 if ( (imageState
== dyld_image_state_rebased
) || (orLater
&& (imageState
> dyld_image_state_rebased
)) )
721 dyld::log("dyld core symbolication load notification: %p %s\n", (*it
)->machHeader(), (*it
)->getPath());
724 if ( dyld_all_image_infos
.coreSymbolicationShmPage
!= NULL
) {
725 CSCppDyldSharedMemoryPage
* connection
= (CSCppDyldSharedMemoryPage
*)dyld_all_image_infos
.coreSymbolicationShmPage
;
726 if ( connection
->is_valid_version() ) {
727 // This needs to be captured now
728 uint64_t load_timestamp
= mach_absolute_time();
729 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
730 dyld_image_states imageState
= (*it
)->getState();
731 if ( (imageState
== state
) || (orLater
&& (imageState
> state
)) )
732 coresymbolication_load_image(connection
, *it
, load_timestamp
);
742 static void notifyBatch(dyld_image_states state
)
744 notifyBatchPartial(state
, false, NULL
);
747 // In order for register_func_for_add_image() callbacks to to be called bottom up,
748 // we need to maintain a list of root images. The main executable is usally the
749 // first root. Any images dynamically added are also roots (unless already loaded).
750 // If DYLD_INSERT_LIBRARIES is used, those libraries are first.
751 static void addRootImage(ImageLoader
* image
)
753 //dyld::log("addRootImage(%p, %s)\n", image, image->getPath());
754 // add to list of roots
755 sImageRoots
.push_back(image
);
759 static void clearAllDepths()
761 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++)
765 static void printAllDepths()
767 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++)
768 dyld::log("%03d %s\n", (*it
)->getDepth(), (*it
)->getShortName());
772 static unsigned int imageCount()
774 return sAllImages
.size();
778 static void setNewProgramVars(const ProgramVars
& newVars
)
780 // make a copy of the pointers to program variables
781 gLinkContext
.programVars
= newVars
;
783 // now set each program global to their initial value
784 *gLinkContext
.programVars
.NXArgcPtr
= gLinkContext
.argc
;
785 *gLinkContext
.programVars
.NXArgvPtr
= gLinkContext
.argv
;
786 *gLinkContext
.programVars
.environPtr
= gLinkContext
.envp
;
787 *gLinkContext
.programVars
.__prognamePtr
= gLinkContext
.progname
;
790 #if SUPPORT_OLD_CRT_INITIALIZATION
791 static void setRunInitialzersOldWay()
793 gRunInitializersOldWay
= true;
797 static void addImage(ImageLoader
* image
)
799 // add to master list
801 sAllImages
.push_back(image
);
804 // update mapped ranges
805 uintptr_t lastSegStart
= 0;
806 uintptr_t lastSegEnd
= 0;
807 for(unsigned int i
=0, e
=image
->segmentCount(); i
< e
; ++i
) {
808 if ( image
->segUnaccessible(i
) )
810 uintptr_t start
= image
->segActualLoadAddress(i
);
811 uintptr_t end
= image
->segActualEndAddress(i
);
812 if ( start
== lastSegEnd
) {
813 // two segments are contiguous, just record combined segments
817 // non-contiguous segments, record last (if any)
818 if ( lastSegEnd
!= 0 )
819 addMappedRange(image
, lastSegStart
, lastSegEnd
);
820 lastSegStart
= start
;
824 if ( lastSegEnd
!= 0 )
825 addMappedRange(image
, lastSegStart
, lastSegEnd
);
828 if ( sEnv
.DYLD_PRINT_LIBRARIES
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) {
829 dyld::log("dyld: loaded: %s\n", image
->getPath());
834 void removeImage(ImageLoader
* image
)
836 // if in termination list, pull it out and run terminator
837 for (std::vector
<ImageLoader
*>::iterator it
=sImageFilesNeedingTermination
.begin(); it
!= sImageFilesNeedingTermination
.end(); it
++) {
838 if ( *it
== image
) {
839 sImageFilesNeedingTermination
.erase(it
);
840 image
->doTermination(gLinkContext
);
845 // if has dtrace DOF section, tell dtrace it is going away, then remove from sImageFilesNeedingDOFUnregistration
846 for (std::vector
<RegisteredDOF
>::iterator it
=sImageFilesNeedingDOFUnregistration
.begin(); it
!= sImageFilesNeedingDOFUnregistration
.end(); ) {
847 if ( it
->mh
== image
->machHeader() ) {
848 unregisterDOF(it
->registrationID
);
849 sImageFilesNeedingDOFUnregistration
.erase(it
);
850 // don't increment iterator, the erase caused next element to be copied to where this iterator points
857 // tell all registered remove image handlers about this
858 // do this before removing image from internal data structures so that the callback can query dyld about the image
859 if ( image
->getState() >= dyld_image_state_bound
) {
860 for (std::vector
<ImageCallback
>::iterator it
=sRemoveImageCallbacks
.begin(); it
!= sRemoveImageCallbacks
.end(); it
++) {
861 (*it
)(image
->machHeader(), image
->getSlide());
866 notifySingle(dyld_image_state_terminated
, image
);
868 // <rdar://problem/7740779> dyld should directly call __cxa_finalize()
869 if ( (gLibSystemHelpers
!= NULL
) && (gLibSystemHelpers
->version
>= 8) )
870 (*gLibSystemHelpers
->cxa_finalize
)(image
->machHeader());
872 // remove from mapped images table
873 removedMappedRanges(image
);
875 // remove from master list
877 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
878 if ( *it
== image
) {
879 sAllImages
.erase(it
);
885 // flush find-by-address cache (do this after removed from master list, so there is no chance it can come back)
886 if ( sLastImageByAddressCache
== image
)
887 sLastImageByAddressCache
= NULL
;
889 // if in root list, pull it out
890 for (std::vector
<ImageLoader
*>::iterator it
=sImageRoots
.begin(); it
!= sImageRoots
.end(); it
++) {
891 if ( *it
== image
) {
892 sImageRoots
.erase(it
);
898 if ( sEnv
.DYLD_PRINT_LIBRARIES
|| (sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH
&& (sMainExecutable
!=NULL
) && sMainExecutable
->isLinked()) ) {
899 dyld::log("dyld: unloaded: %s\n", image
->getPath());
903 removeImageFromAllImages(image
->machHeader());
907 static void terminationRecorder(ImageLoader
* image
)
909 sImageFilesNeedingTermination
.push_back(image
);
912 const char* getExecutablePath()
918 void initializeMainExecutable()
920 // apply interposing to initial set of images
921 // do this before making the __IMPORT segments in shared cache read-only
922 sMainExecutable
->applyInterposing(gLinkContext
);
924 // record that we've reached this step
925 gLinkContext
.startedInitializingMainExecutable
= true;
927 // run initialzers for any inserted dylibs
928 ImageLoader::InitializerTimingList initializerTimes
[sAllImages
.size()];
929 const int rootCount
= sImageRoots
.size();
930 if ( rootCount
> 1 ) {
931 for(int i
=1; i
< rootCount
; ++i
) {
932 initializerTimes
[0].count
= 0;
933 sImageRoots
[i
]->runInitializers(gLinkContext
, initializerTimes
[0]);
937 // run initializers for main executable and everything it brings up
938 initializerTimes
[0].count
= 0;
939 sMainExecutable
->runInitializers(gLinkContext
, initializerTimes
[0]);
941 // register atexit() handler to run terminators in all loaded images when this process exits
942 if ( gLibSystemHelpers
!= NULL
)
943 (*gLibSystemHelpers
->cxa_atexit
)(&runTerminators
, NULL
, NULL
);
945 // dump info if requested
946 if ( sEnv
.DYLD_PRINT_STATISTICS
)
947 ImageLoaderMachO::printStatistics(sAllImages
.size(), initializerTimes
[0]);
950 bool mainExecutablePrebound()
952 return sMainExecutable
->usablePrebinding(gLinkContext
);
955 ImageLoader
* mainExecutable()
957 return sMainExecutable
;
961 void runTerminators(void* extra
)
964 const unsigned int imageCount
= sImageFilesNeedingTermination
.size();
965 for(unsigned int i
=imageCount
; i
> 0; --i
){
966 ImageLoader
* image
= sImageFilesNeedingTermination
[i
-1];
967 image
->doTermination(gLinkContext
);
969 sImageFilesNeedingTermination
.clear();
970 notifyBatch(dyld_image_state_terminated
);
972 catch (const char* msg
) {
978 #if SUPPORT_VERSIONED_PATHS
981 static bool getDylibVersionAndInstallname(const char* dylibPath
, uint32_t* version
, char* installName
);
985 // Examines a dylib file and if its current_version is newer than the installed
986 // dylib at its install_name, then add the dylib file to sDylibOverrides.
988 static void checkDylibOverride(const char* dylibFile
)
990 //dyld::log("checkDylibOverride('%s')\n", dylibFile);
992 char sysInstallName
[PATH_MAX
];
993 if ( getDylibVersionAndInstallname(dylibFile
, &altVersion
, sysInstallName
) ) {
994 //dyld::log("%s has version 0x%08X and install name %s\n", dylibFile, altVersion, sysInstallName);
996 if ( getDylibVersionAndInstallname(sysInstallName
, &sysVersion
, NULL
) ) {
997 //dyld::log("%s has version 0x%08X\n", sysInstallName, sysVersion);
998 if ( altVersion
> sysVersion
) {
999 //dyld::log("override found: %s -> %s\n", sysInstallName, dylibFile);
1000 // see if there already is an override for this dylib
1001 bool entryExists
= false;
1002 for (std::vector
<DylibOverride
>::iterator it
= sDylibOverrides
.begin(); it
!= sDylibOverrides
.end(); ++it
) {
1003 if ( strcmp(it
->installName
, sysInstallName
) == 0 ) {
1005 uint32_t prevVersion
;
1006 if ( getDylibVersionAndInstallname(it
->override
, &prevVersion
, NULL
) ) {
1007 if ( altVersion
> prevVersion
) {
1008 // found an even newer override
1009 free((void*)(it
->override
));
1010 it
->override
= strdup(dylibFile
);
1016 if ( ! entryExists
) {
1017 DylibOverride entry
;
1018 entry
.installName
= strdup(sysInstallName
);
1019 entry
.override
= strdup(dylibFile
);
1020 sDylibOverrides
.push_back(entry
);
1021 //dyld::log("added override: %s -> %s\n", entry.installName, entry.override);
1029 static void checkDylibOverridesInDir(const char* dirPath
)
1031 //dyld::log("checkDylibOverridesInDir('%s')\n", dirPath);
1032 char dylibPath
[PATH_MAX
];
1033 int dirPathLen
= strlen(dirPath
);
1034 strlcpy(dylibPath
, dirPath
, PATH_MAX
);
1035 DIR* dirp
= opendir(dirPath
);
1036 if ( dirp
!= NULL
) {
1038 dirent
* entp
= NULL
;
1039 while ( readdir_r(dirp
, &entry
, &entp
) == 0 ) {
1042 if ( entp
->d_type
!= DT_REG
)
1044 dylibPath
[dirPathLen
] = '/';
1045 dylibPath
[dirPathLen
+1] = '\0';
1046 if ( strlcat(dylibPath
, entp
->d_name
, PATH_MAX
) > PATH_MAX
)
1048 checkDylibOverride(dylibPath
);
1055 static void checkFrameworkOverridesInDir(const char* dirPath
)
1057 //dyld::log("checkFrameworkOverridesInDir('%s')\n", dirPath);
1058 char frameworkPath
[PATH_MAX
];
1059 int dirPathLen
= strlen(dirPath
);
1060 strlcpy(frameworkPath
, dirPath
, PATH_MAX
);
1061 DIR* dirp
= opendir(dirPath
);
1062 if ( dirp
!= NULL
) {
1064 dirent
* entp
= NULL
;
1065 while ( readdir_r(dirp
, &entry
, &entp
) == 0 ) {
1068 if ( entp
->d_type
!= DT_DIR
)
1070 frameworkPath
[dirPathLen
] = '/';
1071 frameworkPath
[dirPathLen
+1] = '\0';
1072 int dirNameLen
= strlen(entp
->d_name
);
1073 if ( dirNameLen
< 11 )
1075 if ( strcmp(&entp
->d_name
[dirNameLen
-10], ".framework") != 0 )
1077 if ( strlcat(frameworkPath
, entp
->d_name
, PATH_MAX
) > PATH_MAX
)
1079 if ( strlcat(frameworkPath
, "/", PATH_MAX
) > PATH_MAX
)
1081 if ( strlcat(frameworkPath
, entp
->d_name
, PATH_MAX
) > PATH_MAX
)
1083 frameworkPath
[strlen(frameworkPath
)-10] = '\0';
1084 checkDylibOverride(frameworkPath
);
1089 #endif // SUPPORT_VERSIONED_PATHS
1093 // Turns a colon separated list of strings into a NULL terminated array
1094 // of string pointers. If mainExecutableDir param is not NULL,
1095 // substitutes @loader_path with main executable's dir.
1097 static const char** parseColonList(const char* list
, const char* mainExecutableDir
)
1099 static const char* sEmptyList
[] = { NULL
};
1101 if ( list
[0] == '\0' )
1105 for(const char* s
=list
; *s
!= '\0'; ++s
) {
1111 const char* start
= list
;
1112 char** result
= new char*[colonCount
+2];
1113 for(const char* s
=list
; *s
!= '\0'; ++s
) {
1116 if ( (mainExecutableDir
!= NULL
) && (strncmp(start
, "@loader_path/", 13) == 0) ) {
1117 int mainExecDirLen
= strlen(mainExecutableDir
);
1118 char* str
= new char[mainExecDirLen
+len
+1];
1119 strcpy(str
, mainExecutableDir
);
1120 strlcat(str
, &start
[13], mainExecDirLen
+len
+1);
1121 str
[mainExecDirLen
+len
-13] = '\0';
1123 result
[index
++] = str
;
1125 else if ( (mainExecutableDir
!= NULL
) && (strncmp(start
, "@executable_path/", 17) == 0) ) {
1126 int mainExecDirLen
= strlen(mainExecutableDir
);
1127 char* str
= new char[mainExecDirLen
+len
+1];
1128 strcpy(str
, mainExecutableDir
);
1129 strlcat(str
, &start
[17], mainExecDirLen
+len
+1);
1130 str
[mainExecDirLen
+len
-17] = '\0';
1132 result
[index
++] = str
;
1135 char* str
= new char[len
+1];
1136 strncpy(str
, start
, len
);
1139 result
[index
++] = str
;
1143 int len
= strlen(start
);
1144 if ( (mainExecutableDir
!= NULL
) && (strncmp(start
, "@loader_path/", 13) == 0) ) {
1145 int mainExecDirLen
= strlen(mainExecutableDir
);
1146 char* str
= new char[mainExecDirLen
+len
+1];
1147 strcpy(str
, mainExecutableDir
);
1148 strlcat(str
, &start
[13], mainExecDirLen
+len
+1);
1149 str
[mainExecDirLen
+len
-13] = '\0';
1150 result
[index
++] = str
;
1152 else if ( (mainExecutableDir
!= NULL
) && (strncmp(start
, "@executable_path/", 17) == 0) ) {
1153 int mainExecDirLen
= strlen(mainExecutableDir
);
1154 char* str
= new char[mainExecDirLen
+len
+1];
1155 strcpy(str
, mainExecutableDir
);
1156 strlcat(str
, &start
[17], mainExecDirLen
+len
+1);
1157 str
[mainExecDirLen
+len
-17] = '\0';
1158 result
[index
++] = str
;
1161 char* str
= new char[len
+1];
1163 result
[index
++] = str
;
1165 result
[index
] = NULL
;
1167 //dyld::log("parseColonList(%s)\n", list);
1168 //for(int i=0; result[i] != NULL; ++i)
1169 // dyld::log(" %s\n", result[i]);
1170 return (const char**)result
;
1173 static void appendParsedColonList(const char* list
, const char* mainExecutableDir
, const char* const ** storage
)
1175 const char** newlist
= parseColonList(list
, mainExecutableDir
);
1176 if ( *storage
== NULL
) {
1177 // first time, just set
1181 // need to append to existing list
1182 const char* const* existing
= *storage
;
1184 for(int i
=0; existing
[i
] != NULL
; ++i
)
1186 for(int i
=0; newlist
[i
] != NULL
; ++i
)
1188 const char** combinedList
= new const char*[count
+2];
1190 for(int i
=0; existing
[i
] != NULL
; ++i
)
1191 combinedList
[index
++] = existing
[i
];
1192 for(int i
=0; newlist
[i
] != NULL
; ++i
)
1193 combinedList
[index
++] = newlist
[i
];
1194 combinedList
[index
] = NULL
;
1196 *storage
= combinedList
;
1201 static void paths_expand_roots(const char **paths
, const char *key
, const char *val
)
1203 // assert(val != NULL);
1204 // assert(paths != NULL);
1206 size_t keyLen
= strlen(key
);
1207 for(int i
=0; paths
[i
] != NULL
; ++i
) {
1208 if ( strncmp(paths
[i
], key
, keyLen
) == 0 ) {
1209 char* newPath
= new char[strlen(val
) + (strlen(paths
[i
]) - keyLen
) + 1];
1210 strcpy(newPath
, val
);
1211 strcat(newPath
, &paths
[i
][keyLen
]);
1219 static void removePathWithPrefix(const char* paths
[], const char* prefix
)
1221 size_t prefixLen
= strlen(prefix
);
1224 for(i
= 0; paths
[i
] != NULL
; ++i
) {
1225 if ( strncmp(paths
[i
], prefix
, prefixLen
) == 0 )
1228 paths
[i
-skip
] = paths
[i
];
1230 paths
[i
-skip
] = NULL
;
1235 static void paths_dump(const char **paths
)
1237 // assert(paths != NULL);
1238 const char **strs
= paths
;
1239 while(*strs
!= NULL
)
1241 dyld::log("\"%s\"\n", *strs
);
1248 static void printOptions(const char* argv
[])
1251 while ( NULL
!= argv
[i
] ) {
1252 dyld::log("opt[%i] = \"%s\"\n", i
, argv
[i
]);
1257 static void printEnvironmentVariables(const char* envp
[])
1259 while ( NULL
!= *envp
) {
1260 dyld::log("%s\n", *envp
);
1265 void processDyldEnvironmentVariable(const char* key
, const char* value
, const char* mainExecutableDir
)
1267 if ( strcmp(key
, "DYLD_FRAMEWORK_PATH") == 0 ) {
1268 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FRAMEWORK_PATH
);
1270 else if ( strcmp(key
, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) {
1271 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
);
1273 else if ( strcmp(key
, "DYLD_LIBRARY_PATH") == 0 ) {
1274 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_LIBRARY_PATH
);
1276 else if ( strcmp(key
, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) {
1277 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_FALLBACK_LIBRARY_PATH
);
1279 else if ( (strcmp(key
, "DYLD_ROOT_PATH") == 0) || (strcmp(key
, "DYLD_PATHS_ROOT") == 0) ) {
1280 if ( strcmp(value
, "/") != 0 ) {
1281 gLinkContext
.rootPaths
= parseColonList(value
, mainExecutableDir
);
1282 for (int i
=0; gLinkContext
.rootPaths
[i
] != NULL
; ++i
) {
1283 if ( gLinkContext
.rootPaths
[i
][0] != '/' ) {
1284 dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n");
1285 gLinkContext
.rootPaths
= NULL
;
1291 else if ( strcmp(key
, "DYLD_IMAGE_SUFFIX") == 0 ) {
1292 gLinkContext
.imageSuffix
= value
;
1294 else if ( strcmp(key
, "DYLD_INSERT_LIBRARIES") == 0 ) {
1295 sEnv
.DYLD_INSERT_LIBRARIES
= parseColonList(value
, NULL
);
1297 else if ( strcmp(key
, "DYLD_PRINT_OPTS") == 0 ) {
1298 sEnv
.DYLD_PRINT_OPTS
= true;
1300 else if ( strcmp(key
, "DYLD_PRINT_ENV") == 0 ) {
1301 sEnv
.DYLD_PRINT_ENV
= true;
1303 else if ( strcmp(key
, "DYLD_DISABLE_DOFS") == 0 ) {
1304 sEnv
.DYLD_DISABLE_DOFS
= true;
1306 else if ( strcmp(key
, "DYLD_DISABLE_PREFETCH") == 0 ) {
1307 gLinkContext
.preFetchDisabled
= true;
1309 else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES") == 0 ) {
1310 sEnv
.DYLD_PRINT_LIBRARIES
= true;
1312 else if ( strcmp(key
, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) {
1313 sEnv
.DYLD_PRINT_LIBRARIES_POST_LAUNCH
= true;
1315 else if ( strcmp(key
, "DYLD_BIND_AT_LAUNCH") == 0 ) {
1316 sEnv
.DYLD_BIND_AT_LAUNCH
= true;
1318 else if ( strcmp(key
, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) {
1319 gLinkContext
.bindFlat
= true;
1321 else if ( strcmp(key
, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) {
1322 // ignore, no longer relevant but some scripts still set it
1324 else if ( strcmp(key
, "DYLD_NO_FIX_PREBINDING") == 0 ) {
1326 else if ( strcmp(key
, "DYLD_PREBIND_DEBUG") == 0 ) {
1327 gLinkContext
.verbosePrebinding
= true;
1329 else if ( strcmp(key
, "DYLD_PRINT_INITIALIZERS") == 0 ) {
1330 gLinkContext
.verboseInit
= true;
1332 else if ( strcmp(key
, "DYLD_PRINT_DOFS") == 0 ) {
1333 gLinkContext
.verboseDOF
= true;
1335 else if ( strcmp(key
, "DYLD_PRINT_STATISTICS") == 0 ) {
1336 sEnv
.DYLD_PRINT_STATISTICS
= true;
1338 else if ( strcmp(key
, "DYLD_PRINT_SEGMENTS") == 0 ) {
1339 gLinkContext
.verboseMapping
= true;
1341 else if ( strcmp(key
, "DYLD_PRINT_BINDINGS") == 0 ) {
1342 gLinkContext
.verboseBind
= true;
1344 else if ( strcmp(key
, "DYLD_PRINT_WEAK_BINDINGS") == 0 ) {
1345 gLinkContext
.verboseWeakBind
= true;
1347 else if ( strcmp(key
, "DYLD_PRINT_REBASINGS") == 0 ) {
1348 gLinkContext
.verboseRebase
= true;
1350 else if ( strcmp(key
, "DYLD_PRINT_APIS") == 0 ) {
1353 else if ( strcmp(key
, "DYLD_PRINT_WARNINGS") == 0 ) {
1354 gLinkContext
.verboseWarnings
= true;
1356 else if ( strcmp(key
, "DYLD_PRINT_RPATHS") == 0 ) {
1357 gLinkContext
.verboseRPaths
= true;
1359 else if ( strcmp(key
, "DYLD_PRINT_CS_NOTIFICATIONS") == 0 ) {
1360 sEnv
.DYLD_PRINT_CS_NOTIFICATIONS
= true;
1362 else if ( strcmp(key
, "DYLD_PRINT_INTERPOSING") == 0 ) {
1363 gLinkContext
.verboseInterposing
= true;
1365 else if ( strcmp(key
, "DYLD_SHARED_REGION") == 0 ) {
1366 if ( strcmp(value
, "private") == 0 ) {
1367 gLinkContext
.sharedRegionMode
= ImageLoader::kUsePrivateSharedRegion
;
1369 else if ( strcmp(value
, "avoid") == 0 ) {
1370 gLinkContext
.sharedRegionMode
= ImageLoader::kDontUseSharedRegion
;
1372 else if ( strcmp(value
, "use") == 0 ) {
1373 gLinkContext
.sharedRegionMode
= ImageLoader::kUseSharedRegion
;
1375 else if ( value
[0] == '\0' ) {
1376 gLinkContext
.sharedRegionMode
= ImageLoader::kUseSharedRegion
;
1379 dyld::warn("unknown option to DYLD_SHARED_REGION. Valid options are: use, private, avoid\n");
1382 #if DYLD_SHARED_CACHE_SUPPORT
1383 else if ( strcmp(key
, "DYLD_SHARED_CACHE_DIR") == 0 ) {
1384 sSharedCacheDir
= value
;
1386 else if ( strcmp(key
, "DYLD_SHARED_CACHE_DONT_VALIDATE") == 0 ) {
1387 sSharedCacheIgnoreInodeAndTimeStamp
= true;
1390 else if ( strcmp(key
, "DYLD_IGNORE_PREBINDING") == 0 ) {
1391 if ( strcmp(value
, "all") == 0 ) {
1392 gLinkContext
.prebindUsage
= ImageLoader::kUseNoPrebinding
;
1394 else if ( strcmp(value
, "app") == 0 ) {
1395 gLinkContext
.prebindUsage
= ImageLoader::kUseAllButAppPredbinding
;
1397 else if ( strcmp(value
, "nonsplit") == 0 ) {
1398 gLinkContext
.prebindUsage
= ImageLoader::kUseSplitSegPrebinding
;
1400 else if ( value
[0] == '\0' ) {
1401 gLinkContext
.prebindUsage
= ImageLoader::kUseSplitSegPrebinding
;
1404 dyld::warn("unknown option to DYLD_IGNORE_PREBINDING. Valid options are: all, app, nonsplit\n");
1407 #if SUPPORT_VERSIONED_PATHS
1408 else if ( strcmp(key
, "DYLD_VERSIONED_LIBRARY_PATH") == 0 ) {
1409 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_VERSIONED_LIBRARY_PATH
);
1411 else if ( strcmp(key
, "DYLD_VERSIONED_FRAMEWORK_PATH") == 0 ) {
1412 appendParsedColonList(value
, mainExecutableDir
, &sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
);
1416 dyld::warn("unknown environment variable: %s\n", key
);
1421 #if SUPPORT_LC_DYLD_ENVIRONMENT
1422 static void checkLoadCommandEnvironmentVariables()
1424 // <rdar://problem/8440934> Support augmenting dyld environment variables in load commands
1425 const uint32_t cmd_count
= sMainExecutableMachHeader
->ncmds
;
1426 const struct load_command
* const cmds
= (struct load_command
*)(((char*)sMainExecutableMachHeader
)+sizeof(macho_header
));
1427 const struct load_command
* cmd
= cmds
;
1428 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1430 case LC_DYLD_ENVIRONMENT
:
1432 const struct dylinker_command
* envcmd
= (struct dylinker_command
*)cmd
;
1433 const char* keyEqualsValue
= (char*)envcmd
+ envcmd
->name
.offset
;
1434 char mainExecutableDir
[strlen(sExecPath
)];
1435 strcpy(mainExecutableDir
, sExecPath
);
1436 char* lastSlash
= strrchr(mainExecutableDir
, '/');
1437 if ( lastSlash
!= NULL
)
1438 lastSlash
[1] = '\0';
1439 // only process variables that start with DYLD_ and end in _PATH
1440 if ( (strncmp(keyEqualsValue
, "DYLD_", 5) == 0) ) {
1441 const char* equals
= strchr(keyEqualsValue
, '=');
1442 if ( equals
!= NULL
) {
1443 if ( strncmp(&equals
[-5], "_PATH", 5) == 0 ) {
1444 const char* value
= &equals
[1];
1445 const int keyLen
= equals
-keyEqualsValue
;
1447 strncpy(key
, keyEqualsValue
, keyLen
);
1449 //dyld::log("processing: %s\n", keyEqualsValue);
1450 //dyld::log("mainExecutableDir: %s\n", mainExecutableDir);
1451 processDyldEnvironmentVariable(key
, value
, mainExecutableDir
);
1458 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1461 #endif // SUPPORT_LC_DYLD_ENVIRONMENT
1464 #if SUPPORT_VERSIONED_PATHS
1465 static void checkVersionedPaths()
1467 // search DYLD_VERSIONED_LIBRARY_PATH directories for dylibs and check if they are newer
1468 if ( sEnv
.DYLD_VERSIONED_LIBRARY_PATH
!= NULL
) {
1469 for(const char* const* lp
= sEnv
.DYLD_VERSIONED_LIBRARY_PATH
; *lp
!= NULL
; ++lp
) {
1470 checkDylibOverridesInDir(*lp
);
1474 // search DYLD_VERSIONED_FRAMEWORK_PATH directories for dylibs and check if they are newer
1475 if ( sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
!= NULL
) {
1476 for(const char* const* fp
= sEnv
.DYLD_VERSIONED_FRAMEWORK_PATH
; *fp
!= NULL
; ++fp
) {
1477 checkFrameworkOverridesInDir(*fp
);
1485 // For security, setuid programs ignore DYLD_* environment variables.
1486 // Additionally, the DYLD_* enviroment variables are removed
1487 // from the environment, so that any child processes don't see them.
1489 static void pruneEnvironmentVariables(const char* envp
[], const char*** applep
)
1491 // delete all DYLD_* and LD_LIBRARY_PATH environment variables
1492 int removedCount
= 0;
1493 const char** d
= envp
;
1494 for(const char** s
= envp
; *s
!= NULL
; s
++) {
1495 if ( (strncmp(*s
, "DYLD_", 5) != 0) && (strncmp(*s
, "LD_LIBRARY_PATH=", 16) != 0) ) {
1503 if ( removedCount
!= 0 ) {
1504 dyld::log("dyld: DYLD_ environment variables being ignored because ");
1505 switch (sRestrictedReason
) {
1508 case restrictedBySetGUid
:
1509 dyld::log("main executable (%s) is setuid or setgid\n", sExecPath
);
1511 case restrictedBySegment
:
1512 dyld::log("main executable (%s) has __RESTRICT/__restrict section\n", sExecPath
);
1514 case restrictedByEntitlements
:
1515 dyld::log("main executable (%s) is code signed with entitlements\n", sExecPath
);
1520 // slide apple parameters
1521 if ( removedCount
> 0 ) {
1524 *d
= d
[removedCount
];
1525 } while ( *d
++ != NULL
);
1526 for(int i
=0; i
< removedCount
; ++i
)
1530 // disable framework and library fallback paths for setuid binaries rdar://problem/4589305
1531 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
= NULL
;
1532 sEnv
.DYLD_FALLBACK_LIBRARY_PATH
= NULL
;
1536 static void checkEnvironmentVariables(const char* envp
[], bool ignoreEnviron
)
1538 const char* home
= NULL
;
1540 for(p
= envp
; *p
!= NULL
; p
++) {
1541 const char* keyEqualsValue
= *p
;
1542 if ( strncmp(keyEqualsValue
, "DYLD_", 5) == 0 ) {
1543 const char* equals
= strchr(keyEqualsValue
, '=');
1544 if ( (equals
!= NULL
) && !ignoreEnviron
) {
1545 const char* value
= &equals
[1];
1546 const int keyLen
= equals
-keyEqualsValue
;
1548 strncpy(key
, keyEqualsValue
, keyLen
);
1550 processDyldEnvironmentVariable(key
, value
, NULL
);
1553 else if ( strncmp(keyEqualsValue
, "HOME=", 5) == 0 ) {
1554 home
= &keyEqualsValue
[5];
1556 else if ( strncmp(keyEqualsValue
, "LD_LIBRARY_PATH=", 16) == 0 ) {
1557 const char* path
= &keyEqualsValue
[16];
1558 sEnv
.LD_LIBRARY_PATH
= parseColonList(path
, NULL
);
1562 #if SUPPORT_LC_DYLD_ENVIRONMENT
1563 checkLoadCommandEnvironmentVariables();
1564 #endif // SUPPORT_LC_DYLD_ENVIRONMENT
1566 // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
1567 if ( sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
== NULL
) {
1568 const char** paths
= sFrameworkFallbackPaths
;
1570 removePathWithPrefix(paths
, "$HOME");
1572 paths_expand_roots(paths
, "$HOME", home
);
1573 sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
= paths
;
1576 // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment
1577 if ( sEnv
.DYLD_FALLBACK_LIBRARY_PATH
== NULL
) {
1578 const char** paths
= sLibraryFallbackPaths
;
1580 removePathWithPrefix(paths
, "$HOME");
1582 paths_expand_roots(paths
, "$HOME", home
);
1583 sEnv
.DYLD_FALLBACK_LIBRARY_PATH
= paths
;
1586 #if SUPPORT_VERSIONED_PATHS
1587 checkVersionedPaths();
1592 static void getHostInfo()
1594 #if CPU_SUBTYPES_SUPPORTED
1596 sHostCPU
= CPU_TYPE_ARM
;
1597 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V7
;
1598 #elif __ARM_ARCH_6K__
1599 sHostCPU
= CPU_TYPE_ARM
;
1600 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V6
;
1601 #elif __ARM_ARCH_7F__
1602 sHostCPU
= CPU_TYPE_ARM
;
1603 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V7F
;
1604 #elif __ARM_ARCH_7S__
1605 sHostCPU
= CPU_TYPE_ARM
;
1606 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V7S
;
1607 #elif __ARM_ARCH_7K__
1608 sHostCPU
= CPU_TYPE_ARM
;
1609 sHostCPUsubtype
= CPU_SUBTYPE_ARM_V7K
;
1611 struct host_basic_info info
;
1612 mach_msg_type_number_t count
= HOST_BASIC_INFO_COUNT
;
1613 mach_port_t hostPort
= mach_host_self();
1614 kern_return_t result
= host_info(hostPort
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
);
1615 if ( result
!= KERN_SUCCESS
)
1616 throw "host_info() failed";
1617 sHostCPU
= info
.cpu_type
;
1618 sHostCPUsubtype
= info
.cpu_subtype
;
1623 static void checkSharedRegionDisable()
1625 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1626 // if main executable has segments that overlap the shared region,
1627 // then disable using the shared region
1628 if ( sMainExecutable
->overlapsWithAddressRange((void*)(uintptr_t)SHARED_REGION_BASE
, (void*)(uintptr_t)(SHARED_REGION_BASE
+ SHARED_REGION_SIZE
)) ) {
1629 gLinkContext
.sharedRegionMode
= ImageLoader::kDontUseSharedRegion
;
1630 if ( gLinkContext
.verboseMapping
)
1631 dyld::warn("disabling shared region because main executable overlaps\n");
1634 // iPhoneOS cannot run without shared region
1637 bool validImage(const ImageLoader
* possibleImage
)
1639 const unsigned int imageCount
= sAllImages
.size();
1640 for(unsigned int i
=0; i
< imageCount
; ++i
) {
1641 if ( possibleImage
== sAllImages
[i
] ) {
1648 uint32_t getImageCount()
1650 return sAllImages
.size();
1653 ImageLoader
* getIndexedImage(unsigned int index
)
1655 if ( index
< sAllImages
.size() )
1656 return sAllImages
[index
];
1660 ImageLoader
* findImageByMachHeader(const struct mach_header
* target
)
1662 return findMappedRange((uintptr_t)target
);
1666 ImageLoader
* findImageContainingAddress(const void* addr
)
1668 return findMappedRange((uintptr_t)addr
);
1672 ImageLoader
* findImageContainingSymbol(const void* symbol
)
1674 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
1675 ImageLoader
* anImage
= *it
;
1676 if ( anImage
->containsSymbol(symbol
) )
1684 void forEachImageDo( void (*callback
)(ImageLoader
*, void* userData
), void* userData
)
1686 const unsigned int imageCount
= sAllImages
.size();
1687 for(unsigned int i
=0; i
< imageCount
; ++i
) {
1688 ImageLoader
* anImage
= sAllImages
[i
];
1689 (*callback
)(anImage
, userData
);
1693 ImageLoader
* findLoadedImage(const struct stat
& stat_buf
)
1695 const unsigned int imageCount
= sAllImages
.size();
1696 for(unsigned int i
=0; i
< imageCount
; ++i
){
1697 ImageLoader
* anImage
= sAllImages
[i
];
1698 if ( anImage
->statMatch(stat_buf
) )
1704 // based on ANSI-C strstr()
1705 static const char* strrstr(const char* str
, const char* sub
)
1707 const int sublen
= strlen(sub
);
1708 for(const char* p
= &str
[strlen(str
)]; p
!= str
; --p
) {
1709 if ( strncmp(p
, sub
, sublen
) == 0 )
1717 // Find framework path
1719 // /path/foo.framework/foo => foo.framework/foo
1720 // /path/foo.framework/Versions/A/foo => foo.framework/Versions/A/foo
1721 // /path/foo.framework/Frameworks/bar.framework/bar => bar.framework/bar
1722 // /path/foo.framework/Libraries/bar.dylb => NULL
1723 // /path/foo.framework/bar => NULL
1725 // Returns NULL if not a framework path
1727 static const char* getFrameworkPartialPath(const char* path
)
1729 const char* dirDot
= strrstr(path
, ".framework/");
1730 if ( dirDot
!= NULL
) {
1731 const char* dirStart
= dirDot
;
1732 for ( ; dirStart
>= path
; --dirStart
) {
1733 if ( (*dirStart
== '/') || (dirStart
== path
) ) {
1734 const char* frameworkStart
= &dirStart
[1];
1735 if ( dirStart
== path
)
1737 int len
= dirDot
- frameworkStart
;
1738 char framework
[len
+1];
1739 strncpy(framework
, frameworkStart
, len
);
1740 framework
[len
] = '\0';
1741 const char* leaf
= strrchr(path
, '/');
1742 if ( leaf
!= NULL
) {
1743 if ( strcmp(framework
, &leaf
[1]) == 0 ) {
1744 return frameworkStart
;
1746 if ( gLinkContext
.imageSuffix
!= NULL
) {
1747 // some debug frameworks have install names that end in _debug
1748 if ( strncmp(framework
, &leaf
[1], len
) == 0 ) {
1749 if ( strcmp( gLinkContext
.imageSuffix
, &leaf
[len
+1]) == 0 )
1750 return frameworkStart
;
1761 static const char* getLibraryLeafName(const char* path
)
1763 const char* start
= strrchr(path
, '/');
1764 if ( start
!= NULL
)
1771 // only for architectures that use cpu-sub-types
1772 #if CPU_SUBTYPES_SUPPORTED
1774 const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST
= -1;
1778 // A fat file may contain multiple sub-images for the same CPU type.
1779 // In that case, dyld picks which sub-image to use by scanning a table
1780 // of preferred cpu-sub-types for the running cpu.
1782 // There is one row in the table for each cpu-sub-type on which dyld might run.
1783 // The first entry in a row is that cpu-sub-type. It is followed by all
1784 // cpu-sub-types that can run on that cpu, if preferred order. Each row ends with
1785 // a "SUBTYPE_ALL" (to denote that images written to run on any cpu-sub-type are usable),
1786 // followed by one or more CPU_SUBTYPE_END_OF_LIST to pad out this row.
1792 // ARM sub-type lists
1794 const int kARM_RowCount
= 8;
1795 static const cpu_subtype_t kARM
[kARM_RowCount
][9] = {
1797 // armv7f can run: v7f, v7, v6, v5, and v4
1798 { 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
},
1800 // armv7k can run: v7k, v6, v5, and v4
1801 { CPU_SUBTYPE_ARM_V7K
, CPU_SUBTYPE_ARM_V6
, CPU_SUBTYPE_ARM_V5TEJ
, CPU_SUBTYPE_ARM_V4T
, CPU_SUBTYPE_ARM_ALL
, CPU_SUBTYPE_END_OF_LIST
},
1803 // armv7 can run: v7, v6, v5, and v4
1804 { 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
},
1806 // armv6 can run: v6, v5, and v4
1807 { 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
},
1809 // xscale can run: xscale, v5, and v4
1810 { 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
},
1812 // armv5 can run: v5 and v4
1813 { 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
},
1815 // armv4 can run: v4
1816 { 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
},
1821 // scan the tables above to find the cpu-sub-type-list for this machine
1822 static const cpu_subtype_t
* findCPUSubtypeList(cpu_type_t cpu
, cpu_subtype_t subtype
)
1827 for (int i
=0; i
< kARM_RowCount
; ++i
) {
1828 if ( kARM
[i
][0] == subtype
)
1840 // scan fat table-of-contents for best most preferred subtype
1841 static bool fatFindBestFromOrderedList(cpu_type_t cpu
, const cpu_subtype_t list
[], const fat_header
* fh
, uint64_t* offset
, uint64_t* len
)
1843 const fat_arch
* const archs
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
));
1844 for (uint32_t subTypeIndex
=0; list
[subTypeIndex
] != CPU_SUBTYPE_END_OF_LIST
; ++subTypeIndex
) {
1845 for(uint32_t fatIndex
=0; fatIndex
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++fatIndex
) {
1846 if ( ((cpu_type_t
)OSSwapBigToHostInt32(archs
[fatIndex
].cputype
) == cpu
)
1847 && (list
[subTypeIndex
] == (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[fatIndex
].cpusubtype
)) ) {
1848 *offset
= OSSwapBigToHostInt32(archs
[fatIndex
].offset
);
1849 *len
= OSSwapBigToHostInt32(archs
[fatIndex
].size
);
1857 // scan fat table-of-contents for exact match of cpu and cpu-sub-type
1858 static bool fatFindExactMatch(cpu_type_t cpu
, cpu_subtype_t subtype
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
)
1860 const fat_arch
* archs
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
));
1861 for(uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1862 if ( ((cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
)
1863 && ((cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == subtype
) ) {
1864 *offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1865 *len
= OSSwapBigToHostInt32(archs
[i
].size
);
1872 // scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types
1873 static bool fatFindRunsOnAllCPUs(cpu_type_t cpu
, const fat_header
* fh
, uint64_t* offset
, uint64_t* len
)
1875 const fat_arch
* archs
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
));
1876 for(uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1877 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == cpu
) {
1881 if ( (cpu_subtype_t
)OSSwapBigToHostInt32(archs
[i
].cpusubtype
) == CPU_SUBTYPE_ARM_ALL
) {
1882 *offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1883 *len
= OSSwapBigToHostInt32(archs
[i
].size
);
1894 #endif // CPU_SUBTYPES_SUPPORTED
1897 // A fat file may contain multiple sub-images for the same cpu-type,
1898 // each optimized for a different cpu-sub-type (e.g G3 or G5).
1899 // This routine picks the optimal sub-image.
1901 static bool fatFindBest(const fat_header
* fh
, uint64_t* offset
, uint64_t* len
)
1903 #if CPU_SUBTYPES_SUPPORTED
1904 // assume all dylibs loaded must have same cpu type as main executable
1905 const cpu_type_t cpu
= sMainExecutableMachHeader
->cputype
;
1907 // We only know the subtype to use if the main executable cpu type matches the host
1908 if ( (cpu
& CPU_TYPE_MASK
) == sHostCPU
) {
1909 // get preference ordered list of subtypes
1910 const cpu_subtype_t
* subTypePreferenceList
= findCPUSubtypeList(cpu
, sHostCPUsubtype
);
1912 // use ordered list to find best sub-image in fat file
1913 if ( subTypePreferenceList
!= NULL
)
1914 return fatFindBestFromOrderedList(cpu
, subTypePreferenceList
, fh
, offset
, len
);
1916 // if running cpu is not in list, try for an exact match
1917 if ( fatFindExactMatch(cpu
, sHostCPUsubtype
, fh
, offset
, len
) )
1921 // running on an uknown cpu, can only load generic code
1922 return fatFindRunsOnAllCPUs(cpu
, fh
, offset
, len
);
1924 // just find first slice with matching architecture
1925 const fat_arch
* archs
= (fat_arch
*)(((char*)fh
)+sizeof(fat_header
));
1926 for(uint32_t i
=0; i
< OSSwapBigToHostInt32(fh
->nfat_arch
); ++i
) {
1927 if ( (cpu_type_t
)OSSwapBigToHostInt32(archs
[i
].cputype
) == sMainExecutableMachHeader
->cputype
) {
1928 *offset
= OSSwapBigToHostInt32(archs
[i
].offset
);
1929 *len
= OSSwapBigToHostInt32(archs
[i
].size
);
1940 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used
1941 // on the current processor. //
1942 bool isCompatibleMachO(const uint8_t* firstPage
, const char* path
)
1944 #if CPU_SUBTYPES_SUPPORTED
1945 // It is deemed compatible if any of the following are true:
1946 // 1) mach_header subtype is in list of compatible subtypes for running processor
1947 // 2) mach_header subtype is same as running processor subtype
1948 // 3) mach_header subtype runs on all processor variants
1949 const mach_header
* mh
= (mach_header
*)firstPage
;
1950 if ( mh
->magic
== sMainExecutableMachHeader
->magic
) {
1951 if ( mh
->cputype
== sMainExecutableMachHeader
->cputype
) {
1952 if ( (mh
->cputype
& CPU_TYPE_MASK
) == sHostCPU
) {
1953 // get preference ordered list of subtypes that this machine can use
1954 const cpu_subtype_t
* subTypePreferenceList
= findCPUSubtypeList(mh
->cputype
, sHostCPUsubtype
);
1955 if ( subTypePreferenceList
!= NULL
) {
1956 // if image's subtype is in the list, it is compatible
1957 for (const cpu_subtype_t
* p
= subTypePreferenceList
; *p
!= CPU_SUBTYPE_END_OF_LIST
; ++p
) {
1958 if ( *p
== mh
->cpusubtype
)
1961 // have list and not in list, so not compatible
1962 throwf("incompatible cpu-subtype: 0x%08X in %s", mh
->cpusubtype
, path
);
1964 // unknown cpu sub-type, but if exact match for current subtype then ok to use
1965 if ( mh
->cpusubtype
== sHostCPUsubtype
)
1969 // cpu type has no ordered list of subtypes
1970 switch (mh
->cputype
) {
1972 case CPU_TYPE_X86_64
:
1973 // subtypes are not used or these architectures
1979 // For architectures that don't support cpu-sub-types
1980 // this just check the cpu type.
1981 const mach_header
* mh
= (mach_header
*)firstPage
;
1982 if ( mh
->magic
== sMainExecutableMachHeader
->magic
) {
1983 if ( mh
->cputype
== sMainExecutableMachHeader
->cputype
) {
1994 // The kernel maps in main executable before dyld gets control. We need to
1995 // make an ImageLoader* for the already mapped in main executable.
1996 static ImageLoader
* instantiateFromLoadedImage(const macho_header
* mh
, uintptr_t slide
, const char* path
)
1998 // try mach-o loader
1999 if ( isCompatibleMachO((const uint8_t*)mh
, path
) ) {
2000 ImageLoader
* image
= ImageLoaderMachO::instantiateMainExecutable(mh
, slide
, path
, gLinkContext
);
2005 throw "main executable not a known format";
2009 #if DYLD_SHARED_CACHE_SUPPORT
2010 static bool findInSharedCacheImage(const char* path
, const struct stat
* stat_buf
, const macho_header
** mh
, const char** pathInCache
, long* slide
)
2012 if ( sSharedCache
!= NULL
) {
2013 #if __MAC_OS_X_VERSION_MIN_REQUIRED
2014 // Mac OS X always requires inode/mtime to valid cache
2015 // if stat() not done yet, do it now
2017 if ( stat_buf
== NULL
) {
2018 if ( stat(path
, &statb
) == -1 )
2023 // walk shared cache to see if there is a cached image that matches the inode/mtime/path desired
2024 const dyld_cache_image_info
* const start
= (dyld_cache_image_info
*)((uint8_t*)sSharedCache
+ sSharedCache
->imagesOffset
);
2025 const dyld_cache_image_info
* const end
= &start
[sSharedCache
->imagesCount
];
2026 for( const dyld_cache_image_info
* p
= start
; p
!= end
; ++p
) {
2027 #if __IPHONE_OS_VERSION_MIN_REQUIRED
2029 const char* aPath
= (char*)sSharedCache
+ p
->pathFileOffset
;
2030 if ( strcmp(path
, aPath
) == 0 ) {
2031 // found image in cache
2032 *mh
= (macho_header
*)(p
->address
+sSharedCacheSlide
);
2033 *pathInCache
= aPath
;
2034 *slide
= sSharedCacheSlide
;
2037 #elif __MAC_OS_X_VERSION_MIN_REQUIRED
2038 // check mtime and inode first because it is fast
2039 if ( sSharedCacheIgnoreInodeAndTimeStamp
2040 || ( ((time_t)p
->modTime
== stat_buf
->st_mtime
) && ((ino_t
)p
->inode
== stat_buf
->st_ino
) ) ) {
2041 // mod-time and inode match an image in the shared cache, now check path
2042 const char* aPath
= (char*)sSharedCache
+ p
->pathFileOffset
;
2043 bool cacheHit
= (strcmp(path
, aPath
) == 0);
2045 // path does not match install name of dylib in cache, but inode and mtime does match
2046 // perhaps path is a symlink to the cached dylib
2047 struct stat pathInCacheStatBuf
;
2048 if ( stat(aPath
, &pathInCacheStatBuf
) != -1 )
2049 cacheHit
= ( (pathInCacheStatBuf
.st_dev
== stat_buf
->st_dev
) && (pathInCacheStatBuf
.st_ino
== stat_buf
->st_ino
) );
2052 // found image in cache, return info
2053 *mh
= (macho_header
*)(p
->address
+sSharedCacheSlide
);
2054 //dyld::log("findInSharedCacheImage(), mh=%p, p->address=0x%0llX, slid=0x%0lX, path=%p\n",
2055 // *mh, p->address, sSharedCacheSlide, aPath);
2056 *pathInCache
= aPath
;
2057 *slide
= sSharedCacheSlide
;
2067 bool inSharedCache(const char* path
)
2069 const macho_header
* mhInCache
;
2070 const char* pathInCache
;
2072 return findInSharedCacheImage(path
, NULL
, &mhInCache
, &pathInCache
, &slide
);
2077 static ImageLoader
* checkandAddImage(ImageLoader
* image
, const LoadContext
& context
)
2079 // now sanity check that this loaded image does not have the same install path as any existing image
2080 const char* loadedImageInstallPath
= image
->getInstallPath();
2081 if ( image
->isDylib() && (loadedImageInstallPath
!= NULL
) && (loadedImageInstallPath
[0] == '/') ) {
2082 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
2083 ImageLoader
* anImage
= *it
;
2084 const char* installPath
= anImage
->getInstallPath();
2085 if ( installPath
!= NULL
) {
2086 if ( strcmp(loadedImageInstallPath
, installPath
) == 0 ) {
2087 //dyld::log("duplicate(%s) => %p\n", installPath, anImage);
2089 ImageLoader::deleteImage(image
);
2096 // some API's restrict what they can load
2097 if ( context
.mustBeBundle
&& !image
->isBundle() )
2098 throw "not a bundle";
2099 if ( context
.mustBeDylib
&& !image
->isDylib() )
2100 throw "not a dylib";
2102 // regular main executables cannot be loaded
2103 if ( image
->isExecutable() ) {
2104 if ( !context
.canBePIE
|| !image
->isPositionIndependentExecutable() )
2105 throw "can't load a main executable";
2108 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
2109 if ( ! image
->isBundle() )
2115 // map in file and instantiate an ImageLoader
2116 static ImageLoader
* loadPhase6(int fd
, const struct stat
& stat_buf
, const char* path
, const LoadContext
& context
)
2118 //dyld::log("%s(%s)\n", __func__ , path);
2119 uint64_t fileOffset
= 0;
2120 uint64_t fileLength
= stat_buf
.st_size
;
2122 // validate it is a file (not directory)
2123 if ( (stat_buf
.st_mode
& S_IFMT
) != S_IFREG
)
2126 uint8_t firstPage
[4096];
2127 bool shortPage
= false;
2129 // min mach-o file is 4K
2130 if ( fileLength
< 4096 ) {
2131 if ( pread(fd
, firstPage
, fileLength
, 0) != (ssize_t
)fileLength
)
2132 throwf("pread of short file failed: %d", errno
);
2136 if ( pread(fd
, firstPage
, 4096,0) != 4096 )
2137 throwf("pread of first 4K failed: %d", errno
);
2140 // if fat wrapper, find usable sub-file
2141 const fat_header
* fileStartAsFat
= (fat_header
*)firstPage
;
2142 if ( fileStartAsFat
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
2143 if ( fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) ) {
2144 if ( (fileOffset
+fileLength
) > (uint64_t)(stat_buf
.st_size
) )
2145 throwf("truncated fat file. file length=%llu, but needed slice goes to %llu", stat_buf
.st_size
, fileOffset
+fileLength
);
2146 if (pread(fd
, firstPage
, 4096, fileOffset
) != 4096)
2147 throwf("pread of fat file failed: %d", errno
);
2150 throw "no matching architecture in universal wrapper";
2154 // try mach-o loader
2156 throw "file too short";
2157 if ( isCompatibleMachO(firstPage
, path
) ) {
2159 // only MH_BUNDLE, MH_DYLIB, and some MH_EXECUTE can be dynamically loaded
2160 switch ( ((mach_header
*)firstPage
)->filetype
) {
2166 throw "mach-o, but wrong filetype";
2169 // instantiate an image
2170 ImageLoader
* image
= ImageLoaderMachO::instantiateFromFile(path
, fd
, firstPage
, fileOffset
, fileLength
, stat_buf
, gLinkContext
);
2173 return checkandAddImage(image
, context
);
2176 // try other file formats here...
2179 // throw error about what was found
2180 switch (*(uint32_t*)firstPage
) {
2185 throw "mach-o, but wrong architecture";
2187 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
2188 firstPage
[0], firstPage
[1], firstPage
[2], firstPage
[3], firstPage
[4], firstPage
[5], firstPage
[6],firstPage
[7]);
2193 static ImageLoader
* loadPhase5open(const char* path
, const LoadContext
& context
, const struct stat
& stat_buf
, std::vector
<const char*>* exceptions
)
2195 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2197 // open file (automagically closed when this function exits)
2198 FileOpener
file(path
);
2200 // just return NULL if file not found, but record any other errors
2201 if ( file
.getFileDescriptor() == -1 ) {
2203 if ( err
!= ENOENT
) {
2204 const char* newMsg
= dyld::mkstringf("%s: open() failed with errno=%d", path
, err
);
2205 exceptions
->push_back(newMsg
);
2211 return loadPhase6(file
.getFileDescriptor(), stat_buf
, path
, context
);
2213 catch (const char* msg
) {
2214 const char* newMsg
= dyld::mkstringf("%s: %s", path
, msg
);
2215 exceptions
->push_back(newMsg
);
2222 #if __MAC_OS_X_VERSION_MIN_REQUIRED
2223 static ImageLoader
* loadPhase5load(const char* path
, const char* orgPath
, const LoadContext
& context
, std::vector
<const char*>* exceptions
)
2225 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2226 ImageLoader
* image
= NULL
;
2228 // just return NULL if file not found, but record any other errors
2229 struct stat stat_buf
;
2230 if ( stat(path
, &stat_buf
) == -1 ) {
2232 if ( err
!= ENOENT
) {
2233 exceptions
->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path
, err
));
2238 // in case image was renamed or found via symlinks, check for inode match
2239 image
= findLoadedImage(stat_buf
);
2240 if ( image
!= NULL
)
2243 // do nothing if not already loaded and if RTLD_NOLOAD or NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
2244 if ( context
.dontLoad
)
2247 #if DYLD_SHARED_CACHE_SUPPORT
2248 // see if this image is in shared cache
2249 const macho_header
* mhInCache
;
2250 const char* pathInCache
;
2252 if ( findInSharedCacheImage(path
, &stat_buf
, &mhInCache
, &pathInCache
, &slideInCache
) ) {
2253 image
= ImageLoaderMachO::instantiateFromCache(mhInCache
, pathInCache
, slideInCache
, stat_buf
, gLinkContext
);
2254 return checkandAddImage(image
, context
);
2257 // file exists and is not in dyld shared cache, so open it
2258 return loadPhase5open(path
, context
, stat_buf
, exceptions
);
2260 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED
2264 #if __IPHONE_OS_VERSION_MIN_REQUIRED
2265 static ImageLoader
* loadPhase5stat(const char* path
, const LoadContext
& context
, struct stat
* stat_buf
,
2266 int* statErrNo
, bool* imageFound
, std::vector
<const char*>* exceptions
)
2268 ImageLoader
* image
= NULL
;
2269 *imageFound
= false;
2271 if ( stat(path
, stat_buf
) == 0 ) {
2272 // in case image was renamed or found via symlinks, check for inode match
2273 image
= findLoadedImage(*stat_buf
);
2274 if ( image
!= NULL
) {
2278 // do nothing if not already loaded and if RTLD_NOLOAD
2279 if ( context
.dontLoad
) {
2283 image
= loadPhase5open(path
, context
, *stat_buf
, exceptions
);
2284 if ( image
!= NULL
) {
2296 static ImageLoader
* loadPhase5load(const char* path
, const char* orgPath
, const LoadContext
& context
, std::vector
<const char*>* exceptions
)
2298 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2299 struct stat stat_buf
;
2303 #if DYLD_SHARED_CACHE_SUPPORT
2304 if ( sDylibsOverrideCache
) {
2305 // flag is set that allows installed framework roots to override dyld shared cache
2306 image
= loadPhase5stat(path
, context
, &stat_buf
, &statErrNo
, &imageFound
, exceptions
);
2310 // see if this image is in shared cache
2311 const macho_header
* mhInCache
;
2312 const char* pathInCache
;
2314 if ( findInSharedCacheImage(path
, NULL
, &mhInCache
, &pathInCache
, &slideInCache
) ) {
2315 // see if this image in the cache was already loaded via a different path
2316 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); ++it
) {
2317 ImageLoader
* anImage
= *it
;
2318 if ( (const macho_header
*)anImage
->machHeader() == mhInCache
)
2321 // do nothing if not already loaded and if RTLD_NOLOAD
2322 if ( context
.dontLoad
)
2324 // nope, so instantiate a new image from dyld shared cache
2325 // <rdar://problem/7014995> zero out stat buffer so mtime, etc are zero for items from the shared cache
2326 bzero(&stat_buf
, sizeof(stat_buf
));
2327 image
= ImageLoaderMachO::instantiateFromCache(mhInCache
, pathInCache
, slideInCache
, stat_buf
, gLinkContext
);
2328 return checkandAddImage(image
, context
);
2331 if ( !sDylibsOverrideCache
) {
2332 // flag is not set, and not in cache to try opening it
2333 image
= loadPhase5stat(path
, context
, &stat_buf
, &statErrNo
, &imageFound
, exceptions
);
2338 image
= loadPhase5stat(path
, context
, &stat_buf
, &statErrNo
, &imageFound
, exceptions
);
2342 // just return NULL if file not found, but record any other errors
2343 if ( (statErrNo
!= ENOENT
) && (statErrNo
!= 0) ) {
2344 exceptions
->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path
, statErrNo
));
2348 #endif // __IPHONE_OS_VERSION_MIN_REQUIRED
2351 // look for path match with existing loaded images
2352 static ImageLoader
* loadPhase5check(const char* path
, const char* orgPath
, const LoadContext
& context
)
2354 //dyld::log("%s(%s, %s)\n", __func__ , path, orgPath);
2355 // search path against load-path and install-path of all already loaded images
2356 uint32_t hash
= ImageLoader::hash(path
);
2357 //dyld::log("check() hash=%d, path=%s\n", hash, path);
2358 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
2359 ImageLoader
* anImage
= *it
;
2360 // check hash first to cut down on strcmp calls
2361 //dyld::log(" check() hash=%d, path=%s\n", anImage->getPathHash(), anImage->getPath());
2362 if ( anImage
->getPathHash() == hash
) {
2363 if ( strcmp(path
, anImage
->getPath()) == 0 ) {
2364 // if we are looking for a dylib don't return something else
2365 if ( !context
.mustBeDylib
|| anImage
->isDylib() )
2369 if ( context
.matchByInstallName
|| anImage
->matchInstallPath() ) {
2370 const char* installPath
= anImage
->getInstallPath();
2371 if ( installPath
!= NULL
) {
2372 if ( strcmp(path
, installPath
) == 0 ) {
2373 // if we are looking for a dylib don't return something else
2374 if ( !context
.mustBeDylib
|| anImage
->isDylib() )
2379 // an install name starting with @rpath should match by install name, not just real path
2380 if ( (orgPath
[0] == '@') && (strncmp(orgPath
, "@rpath/", 7) == 0) ) {
2381 const char* installPath
= anImage
->getInstallPath();
2382 if ( installPath
!= NULL
) {
2383 if ( !context
.mustBeDylib
|| anImage
->isDylib() ) {
2384 if ( strcmp(orgPath
, installPath
) == 0 )
2391 //dyld::log("%s(%s) => NULL\n", __func__, path);
2396 // open or check existing
2397 static ImageLoader
* loadPhase5(const char* path
, const char* orgPath
, const LoadContext
& context
, std::vector
<const char*>* exceptions
)
2399 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2401 // check for specific dylib overrides
2402 for (std::vector
<DylibOverride
>::iterator it
= sDylibOverrides
.begin(); it
!= sDylibOverrides
.end(); ++it
) {
2403 if ( strcmp(it
->installName
, path
) == 0 ) {
2404 path
= it
->override
;
2409 if ( exceptions
!= NULL
)
2410 return loadPhase5load(path
, orgPath
, context
, exceptions
);
2412 return loadPhase5check(path
, orgPath
, context
);
2415 // try with and without image suffix
2416 static ImageLoader
* loadPhase4(const char* path
, const char* orgPath
, const LoadContext
& context
, std::vector
<const char*>* exceptions
)
2418 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2419 ImageLoader
* image
= NULL
;
2420 if ( gLinkContext
.imageSuffix
!= NULL
) {
2421 char pathWithSuffix
[strlen(path
)+strlen( gLinkContext
.imageSuffix
)+2];
2422 ImageLoader::addSuffix(path
, gLinkContext
.imageSuffix
, pathWithSuffix
);
2423 image
= loadPhase5(pathWithSuffix
, orgPath
, context
, exceptions
);
2425 if ( image
== NULL
)
2426 image
= loadPhase5(path
, orgPath
, context
, exceptions
);
2430 static ImageLoader
* loadPhase2(const char* path
, const char* orgPath
, const LoadContext
& context
,
2431 const char* const frameworkPaths
[], const char* const libraryPaths
[],
2432 std::vector
<const char*>* exceptions
); // forward reference
2435 // expand @ variables
2436 static ImageLoader
* loadPhase3(const char* path
, const char* orgPath
, const LoadContext
& context
, std::vector
<const char*>* exceptions
)
2438 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2439 ImageLoader
* image
= NULL
;
2440 if ( strncmp(path
, "@executable_path/", 17) == 0 ) {
2441 // executable_path cannot be in used in any binary in a setuid process rdar://problem/4589305
2442 if ( sProcessIsRestricted
)
2443 throwf("unsafe use of @executable_path in %s with restricted binary", context
.origin
);
2444 // handle @executable_path path prefix
2445 const char* executablePath
= sExecPath
;
2446 char newPath
[strlen(executablePath
) + strlen(path
)];
2447 strcpy(newPath
, executablePath
);
2448 char* addPoint
= strrchr(newPath
,'/');
2449 if ( addPoint
!= NULL
)
2450 strcpy(&addPoint
[1], &path
[17]);
2452 strcpy(newPath
, &path
[17]);
2453 image
= loadPhase4(newPath
, orgPath
, context
, exceptions
);
2454 if ( image
!= NULL
)
2457 // perhaps main executable path is a sym link, find realpath and retry
2458 char resolvedPath
[PATH_MAX
];
2459 if ( realpath(sExecPath
, resolvedPath
) != NULL
) {
2460 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
2461 strcpy(newRealPath
, resolvedPath
);
2462 char* addPoint
= strrchr(newRealPath
,'/');
2463 if ( addPoint
!= NULL
)
2464 strcpy(&addPoint
[1], &path
[17]);
2466 strcpy(newRealPath
, &path
[17]);
2467 image
= loadPhase4(newRealPath
, orgPath
, context
, exceptions
);
2468 if ( image
!= NULL
)
2472 else if ( (strncmp(path
, "@loader_path/", 13) == 0) && (context
.origin
!= NULL
) ) {
2473 // @loader_path cannot be used from the main executable of a setuid process rdar://problem/4589305
2474 if ( sProcessIsRestricted
&& (strcmp(context
.origin
, sExecPath
) == 0) )
2475 throwf("unsafe use of @loader_path in %s with restricted binary", context
.origin
);
2476 // handle @loader_path path prefix
2477 char newPath
[strlen(context
.origin
) + strlen(path
)];
2478 strcpy(newPath
, context
.origin
);
2479 char* addPoint
= strrchr(newPath
,'/');
2480 if ( addPoint
!= NULL
)
2481 strcpy(&addPoint
[1], &path
[13]);
2483 strcpy(newPath
, &path
[13]);
2484 image
= loadPhase4(newPath
, orgPath
, context
, exceptions
);
2485 if ( image
!= NULL
)
2488 // perhaps loader path is a sym link, find realpath and retry
2489 char resolvedPath
[PATH_MAX
];
2490 if ( realpath(context
.origin
, resolvedPath
) != NULL
) {
2491 char newRealPath
[strlen(resolvedPath
) + strlen(path
)];
2492 strcpy(newRealPath
, resolvedPath
);
2493 char* addPoint
= strrchr(newRealPath
,'/');
2494 if ( addPoint
!= NULL
)
2495 strcpy(&addPoint
[1], &path
[13]);
2497 strcpy(newRealPath
, &path
[13]);
2498 image
= loadPhase4(newRealPath
, orgPath
, context
, exceptions
);
2499 if ( image
!= NULL
)
2503 else if ( context
.implicitRPath
|| (strncmp(path
, "@rpath/", 7) == 0) ) {
2504 const char* trailingPath
= (strncmp(path
, "@rpath/", 7) == 0) ? &path
[7] : path
;
2505 // substitute @rpath with all -rpath paths up the load chain
2506 for(const ImageLoader::RPathChain
* rp
=context
.rpath
; rp
!= NULL
; rp
=rp
->next
) {
2507 if (rp
->paths
!= NULL
) {
2508 for(std::vector
<const char*>::iterator it
=rp
->paths
->begin(); it
!= rp
->paths
->end(); ++it
) {
2509 const char* anRPath
= *it
;
2510 char newPath
[strlen(anRPath
) + strlen(trailingPath
)+2];
2511 strcpy(newPath
, anRPath
);
2512 strcat(newPath
, "/");
2513 strcat(newPath
, trailingPath
);
2514 image
= loadPhase4(newPath
, orgPath
, context
, exceptions
);
2515 if ( gLinkContext
.verboseRPaths
&& (exceptions
!= NULL
) ) {
2516 if ( image
!= NULL
)
2517 dyld::log("RPATH successful expansion of %s to: %s\n", orgPath
, newPath
);
2519 dyld::log("RPATH failed to expanding %s to: %s\n", orgPath
, newPath
);
2521 if ( image
!= NULL
)
2527 // substitute @rpath with LD_LIBRARY_PATH
2528 if ( sEnv
.LD_LIBRARY_PATH
!= NULL
) {
2529 image
= loadPhase2(trailingPath
, orgPath
, context
, NULL
, sEnv
.LD_LIBRARY_PATH
, exceptions
);
2530 if ( image
!= NULL
)
2534 // if this is the "open" pass, don't try to open @rpath/... as a relative path
2535 if ( (exceptions
!= NULL
) && (trailingPath
!= path
) )
2538 else if (sProcessIsRestricted
&& (path
[0] != '/' )) {
2539 throwf("unsafe use of relative rpath %s in %s with restricted binary", path
, context
.origin
);
2542 return loadPhase4(path
, orgPath
, context
, exceptions
);
2547 static ImageLoader
* loadPhase2(const char* path
, const char* orgPath
, const LoadContext
& context
,
2548 const char* const frameworkPaths
[], const char* const libraryPaths
[],
2549 std::vector
<const char*>* exceptions
)
2551 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2552 ImageLoader
* image
= NULL
;
2553 const char* frameworkPartialPath
= getFrameworkPartialPath(path
);
2554 if ( frameworkPaths
!= NULL
) {
2555 if ( frameworkPartialPath
!= NULL
) {
2556 const int frameworkPartialPathLen
= strlen(frameworkPartialPath
);
2557 for(const char* const* fp
= frameworkPaths
; *fp
!= NULL
; ++fp
) {
2558 char npath
[strlen(*fp
)+frameworkPartialPathLen
+8];
2561 strcat(npath
, frameworkPartialPath
);
2562 //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
2563 image
= loadPhase4(npath
, orgPath
, context
, exceptions
);
2564 if ( image
!= NULL
)
2569 if ( libraryPaths
!= NULL
) {
2570 const char* libraryLeafName
= getLibraryLeafName(path
);
2571 const int libraryLeafNameLen
= strlen(libraryLeafName
);
2572 for(const char* const* lp
= libraryPaths
; *lp
!= NULL
; ++lp
) {
2573 char libpath
[strlen(*lp
)+libraryLeafNameLen
+8];
2574 strcpy(libpath
, *lp
);
2575 strcat(libpath
, "/");
2576 strcat(libpath
, libraryLeafName
);
2577 //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
2578 image
= loadPhase4(libpath
, orgPath
, context
, exceptions
);
2579 if ( image
!= NULL
)
2586 // try search overrides and fallbacks
2587 static ImageLoader
* loadPhase1(const char* path
, const char* orgPath
, const LoadContext
& context
, std::vector
<const char*>* exceptions
)
2589 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2590 ImageLoader
* image
= NULL
;
2592 // handle LD_LIBRARY_PATH environment variables that force searching
2593 if ( context
.useLdLibraryPath
&& (sEnv
.LD_LIBRARY_PATH
!= NULL
) ) {
2594 image
= loadPhase2(path
, orgPath
, context
, NULL
, sEnv
.LD_LIBRARY_PATH
, exceptions
);
2595 if ( image
!= NULL
)
2599 // handle DYLD_ environment variables that force searching
2600 if ( context
.useSearchPaths
&& ((sEnv
.DYLD_FRAMEWORK_PATH
!= NULL
) || (sEnv
.DYLD_LIBRARY_PATH
!= NULL
)) ) {
2601 image
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_FRAMEWORK_PATH
, sEnv
.DYLD_LIBRARY_PATH
, exceptions
);
2602 if ( image
!= NULL
)
2607 image
= loadPhase3(path
, orgPath
, context
, exceptions
);
2608 if ( image
!= NULL
)
2611 // try fallback paths during second time (will open file)
2612 const char* const* fallbackLibraryPaths
= sEnv
.DYLD_FALLBACK_LIBRARY_PATH
;
2613 if ( (fallbackLibraryPaths
!= NULL
) && !context
.useFallbackPaths
)
2614 fallbackLibraryPaths
= NULL
;
2615 if ( !context
.dontLoad
&& (exceptions
!= NULL
) && ((sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
!= NULL
) || (fallbackLibraryPaths
!= NULL
)) ) {
2616 image
= loadPhase2(path
, orgPath
, context
, sEnv
.DYLD_FALLBACK_FRAMEWORK_PATH
, fallbackLibraryPaths
, exceptions
);
2617 if ( image
!= NULL
)
2624 // try root substitutions
2625 static ImageLoader
* loadPhase0(const char* path
, const char* orgPath
, const LoadContext
& context
, std::vector
<const char*>* exceptions
)
2627 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2629 // handle DYLD_ROOT_PATH which forces absolute paths to use a new root
2630 if ( (gLinkContext
.rootPaths
!= NULL
) && (path
[0] == '/') ) {
2631 for(const char* const* rootPath
= gLinkContext
.rootPaths
; *rootPath
!= NULL
; ++rootPath
) {
2632 char newPath
[strlen(*rootPath
) + strlen(path
)+2];
2633 strcpy(newPath
, *rootPath
);
2634 strcat(newPath
, path
);
2635 ImageLoader
* image
= loadPhase1(newPath
, orgPath
, context
, exceptions
);
2636 if ( image
!= NULL
)
2642 return loadPhase1(path
, orgPath
, context
, exceptions
);
2646 // Given all the DYLD_ environment variables, the general case for loading libraries
2647 // is that any given path expands into a list of possible locations to load. We
2648 // also must take care to ensure two copies of the "same" library are never loaded.
2650 // The algorithm used here is that there is a separate function for each "phase" of the
2651 // path expansion. Each phase function calls the next phase with each possible expansion
2652 // of that phase. The result is the last phase is called with all possible paths.
2654 // To catch duplicates the algorithm is run twice. The first time, the last phase checks
2655 // the path against all loaded images. The second time, the last phase calls open() on
2656 // the path. Either time, if an image is found, the phases all unwind without checking
2659 ImageLoader
* load(const char* path
, const LoadContext
& context
)
2661 CRSetCrashLogMessage2(path
);
2662 const char* orgPath
= path
;
2664 //dyld::log("%s(%s)\n", __func__ , path);
2665 char realPath
[PATH_MAX
];
2666 // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match
2667 if ( context
.useSearchPaths
&& ( gLinkContext
.imageSuffix
!= NULL
) ) {
2668 if ( realpath(path
, realPath
) != NULL
)
2672 // try all path permutations and check against existing loaded images
2673 ImageLoader
* image
= loadPhase0(path
, orgPath
, context
, NULL
);
2674 if ( image
!= NULL
) {
2675 CRSetCrashLogMessage2(NULL
);
2679 // try all path permutations and try open() until first success
2680 std::vector
<const char*> exceptions
;
2681 image
= loadPhase0(path
, orgPath
, context
, &exceptions
);
2682 CRSetCrashLogMessage2(NULL
);
2683 if ( image
!= NULL
) {
2684 // <rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables
2685 for (std::vector
<const char*>::iterator it
= exceptions
.begin(); it
!= exceptions
.end(); ++it
) {
2688 #if __IPHONE_OS_VERSION_MIN_REQUIRED
2689 // if loaded image is not from cache, but original path is in cache
2690 // set gSharedCacheOverridden flag to disable some ObjC optimizations
2691 if ( !gSharedCacheOverridden
) {
2692 if ( !image
->inSharedCache() && inSharedCache(path
) ) {
2693 gSharedCacheOverridden
= true;
2699 else if ( exceptions
.size() == 0 ) {
2700 if ( context
.dontLoad
) {
2704 throw "image not found";
2707 const char* msgStart
= "no suitable image found. Did find:";
2708 const char* delim
= "\n\t";
2709 size_t allsizes
= strlen(msgStart
)+8;
2710 for (unsigned int i
=0; i
< exceptions
.size(); ++i
)
2711 allsizes
+= (strlen(exceptions
[i
]) + strlen(delim
));
2712 char* fullMsg
= new char[allsizes
];
2713 strcpy(fullMsg
, msgStart
);
2714 for (unsigned int i
=0; i
< exceptions
.size(); ++i
) {
2715 strcat(fullMsg
, delim
);
2716 strcat(fullMsg
, exceptions
[i
]);
2717 free((void*)exceptions
[i
]);
2719 throw (const char*)fullMsg
;
2725 #if DYLD_SHARED_CACHE_SUPPORT
2730 #define ARCH_NAME "i386"
2731 #define ARCH_CACHE_MAGIC "dyld_v1 i386"
2733 #define ARCH_NAME "x86_64"
2734 #define ARCH_CACHE_MAGIC "dyld_v1 x86_64"
2735 #define SHARED_REGION_READ_ONLY_START 0x7FFF80000000LL
2736 #define SHARED_REGION_READ_ONLY_END 0x7FFFC0000000LL
2737 #define SHARED_REGION_WRITABLE_START 0x7FFF70000000LL
2738 #define SHARED_REGION_WRITABLE_END 0x7FFF80000000LL
2739 #define SLIDEABLE_CACHE_SUPPORT 1
2740 #elif __ARM_ARCH_5TEJ__
2741 #define ARCH_NAME "armv5"
2742 #define ARCH_CACHE_MAGIC "dyld_v1 armv5"
2743 #elif __ARM_ARCH_6K__
2744 #define ARCH_NAME "armv6"
2745 #define ARCH_CACHE_MAGIC "dyld_v1 armv6"
2746 #elif __ARM_ARCH_7F__
2747 #define ARCH_NAME "armv7f"
2748 #define ARCH_CACHE_MAGIC "dyld_v1 armv7f"
2749 #define SHARED_REGION_READ_ONLY_START 0x30000000
2750 #define SHARED_REGION_READ_ONLY_END 0x3E000000
2751 #define SHARED_REGION_WRITABLE_START 0x3E000000
2752 #define SHARED_REGION_WRITABLE_END 0x40000000
2753 #define SLIDEABLE_CACHE_SUPPORT 1
2754 #elif __ARM_ARCH_7A__
2755 #define ARCH_NAME "armv7"
2756 #define ARCH_CACHE_MAGIC "dyld_v1 armv7"
2757 #define SHARED_REGION_READ_ONLY_START 0x30000000
2758 #define SHARED_REGION_READ_ONLY_END 0x3E000000
2759 #define SHARED_REGION_WRITABLE_START 0x3E000000
2760 #define SHARED_REGION_WRITABLE_END 0x40000000
2761 #define SLIDEABLE_CACHE_SUPPORT 1
2762 #elif __ARM_ARCH_7K__
2763 #define ARCH_NAME "armv7k"
2764 #define ARCH_CACHE_MAGIC "dyld_v1 armv7k"
2765 #define SHARED_REGION_READ_ONLY_START 0x30000000
2766 #define SHARED_REGION_READ_ONLY_END 0x3E000000
2767 #define SHARED_REGION_WRITABLE_START 0x3E000000
2768 #define SHARED_REGION_WRITABLE_END 0x40000000
2769 #define SLIDEABLE_CACHE_SUPPORT 1
2773 static int __attribute__((noinline
)) _shared_region_check_np(uint64_t* start_address
)
2775 if ( gLinkContext
.sharedRegionMode
== ImageLoader::kUseSharedRegion
)
2776 return syscall(294, start_address
);
2781 static int __attribute__((noinline
)) _shared_region_map_and_slide_np(int fd
, uint32_t count
, const shared_file_mapping_np mappings
[],
2782 int codeSignatureMappingIndex
, int slide
, void* slideInfo
, uint32_t slideInfoSize
)
2784 #if __IPHONE_OS_VERSION_MIN_REQUIRED
2785 // register code signature blob for whole dyld cache
2786 if ( codeSignatureMappingIndex
!= -1 ) {
2787 fsignatures_t siginfo
;
2788 siginfo
.fs_file_start
= 0; // cache always starts at beginning of file
2789 siginfo
.fs_blob_start
= (void*)mappings
[codeSignatureMappingIndex
].sfm_file_offset
;
2790 siginfo
.fs_blob_size
= mappings
[codeSignatureMappingIndex
].sfm_size
;
2791 int result
= fcntl(fd
, F_ADDFILESIGS
, &siginfo
);
2793 dyld::log("dyld: code signature for shared cache failed with errno=%d\n", errno
);
2796 if ( gLinkContext
.sharedRegionMode
== ImageLoader::kUseSharedRegion
) {
2797 return syscall(438, fd
, count
, mappings
, slide
, slideInfo
, slideInfoSize
);
2800 // remove the shared region sub-map
2801 vm_deallocate(mach_task_self(), (vm_address_t
)SHARED_REGION_BASE
, SHARED_REGION_SIZE
);
2803 // notify gdb or other lurkers that this process is no longer using the shared region
2804 dyld_all_image_infos
.processDetachedFromSharedRegion
= true;
2806 // map cache just for this process with mmap()
2807 const shared_file_mapping_np
* const start
= mappings
;
2808 const shared_file_mapping_np
* const end
= &mappings
[count
];
2809 for (const shared_file_mapping_np
* p
= start
; p
< end
; ++p
) {
2810 void* mmapAddress
= (void*)(uintptr_t)(p
->sfm_address
);
2811 size_t size
= p
->sfm_size
;
2812 //dyld::log("dyld: mapping address %p with size 0x%08lX\n", mmapAddress, size);
2814 if ( p
->sfm_init_prot
& VM_PROT_EXECUTE
)
2815 protection
|= PROT_EXEC
;
2816 if ( p
->sfm_init_prot
& VM_PROT_READ
)
2817 protection
|= PROT_READ
;
2818 if ( p
->sfm_init_prot
& VM_PROT_WRITE
)
2819 protection
|= PROT_WRITE
;
2820 off_t offset
= p
->sfm_file_offset
;
2821 if ( mmap(mmapAddress
, size
, protection
, MAP_FIXED
| MAP_PRIVATE
, fd
, offset
) != mmapAddress
) {
2822 // failed to map some chunk of this shared cache file
2823 // clear shared region
2824 vm_deallocate(mach_task_self(), (vm_address_t
)SHARED_REGION_BASE
, SHARED_REGION_SIZE
);
2825 // go back to not using shared region at all
2826 gLinkContext
.sharedRegionMode
= ImageLoader::kDontUseSharedRegion
;
2827 if ( gLinkContext
.verboseMapping
) {
2828 dyld::log("dyld: shared cached region cannot be mapped at address %p with size 0x%08lX\n",
2836 #if SLIDEABLE_CACHE_SUPPORT
2837 // update all __DATA pages with slide info
2839 const uintptr_t dataPagesStart
= mappings
[1].sfm_address
;
2840 const dyld_cache_slide_info
* slideInfoHeader
= (dyld_cache_slide_info
*)slideInfo
;
2841 const uint16_t* toc
= (uint16_t*)((long)(slideInfoHeader
) + slideInfoHeader
->toc_offset
);
2842 const uint8_t* entries
= (uint8_t*)((long)(slideInfoHeader
) + slideInfoHeader
->entries_offset
);
2843 for(uint32_t i
=0; i
< slideInfoHeader
->toc_count
; ++i
) {
2844 const uint8_t* entry
= &entries
[toc
[i
]*slideInfoHeader
->entries_size
];
2845 const uint8_t* page
= (uint8_t*)(long)(dataPagesStart
+ (4096*i
));
2846 //dyld::log("page=%p toc[%d]=%d entries=%p\n", page, i, toc[i], entry);
2847 for(int j
=0; j
< 128; ++j
) {
2848 uint8_t b
= entry
[j
];
2849 //dyld::log(" entry[%d] = 0x%02X\n", j, b);
2851 for(int k
=0; k
< 8; ++k
) {
2853 uintptr_t* p
= (uintptr_t*)(page
+ j
*8*4 + k
*4);
2854 uintptr_t value
= *p
;
2855 //dyld::log(" *%p was 0x%lX will be 0x%lX\n", p, value, value+sSharedCacheSlide);
2863 #endif // SLIDEABLE_CACHE_SUPPORT
2865 // succesfully mapped shared cache for just this process
2866 gLinkContext
.sharedRegionMode
= ImageLoader::kUsePrivateSharedRegion
;
2872 const void* imMemorySharedCacheHeader()
2874 return sSharedCache
;
2877 int openSharedCacheFile()
2880 strcpy(path
, sSharedCacheDir
);
2882 strcat(path
, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
);
2883 return ::open(path
, O_RDONLY
);
2886 #if SLIDEABLE_CACHE_SUPPORT
2887 static long pickCacheSlide(uint32_t mappingsCount
, shared_file_mapping_np mappings
[])
2889 // get bounds of cache
2890 uint64_t readOnlyLowAddress
= 0;
2891 uint64_t readOnlyHighAddress
= 0;
2892 uint64_t writableLowAddress
= 0;
2893 uint64_t writableHighAddress
= 0;
2894 for(uint32_t i
=0; i
< mappingsCount
; ++i
) {
2895 if ( mappings
[i
].sfm_init_prot
& VM_PROT_WRITE
) {
2896 writableLowAddress
= mappings
[i
].sfm_address
;
2897 writableHighAddress
= mappings
[i
].sfm_address
+ mappings
[i
].sfm_size
;
2900 if ( readOnlyLowAddress
== 0 ) {
2901 readOnlyLowAddress
= mappings
[i
].sfm_address
;
2902 readOnlyHighAddress
= mappings
[i
].sfm_address
+ mappings
[i
].sfm_size
;
2905 if ( readOnlyLowAddress
< mappings
[i
].sfm_address
) {
2906 readOnlyHighAddress
= mappings
[i
].sfm_address
+ mappings
[i
].sfm_size
;
2909 readOnlyLowAddress
= mappings
[i
].sfm_address
;
2915 // find read-only slop space
2916 uint64_t roSpace
= SHARED_REGION_READ_ONLY_END
- readOnlyHighAddress
;
2918 // find writable slop space
2919 uint64_t rwSpace
= SHARED_REGION_WRITABLE_END
- writableHighAddress
;
2921 // choose new random slide
2922 long slideSpace
= (roSpace
> rwSpace
) ? rwSpace
: roSpace
;
2923 long slide
= (arc4random() % slideSpace
) & (-4096);
2924 //dyld::log("roSpace=0x%0llX\n", roSpace);
2925 //dyld::log("rwSpace=0x%0llX\n", rwSpace);
2926 //dyld::log("slideSpace=0x%0lX\n", slideSpace);
2927 //dyld::log("slide=0x%0lX\n", slide);
2930 for(uint32_t i
=0; i
< mappingsCount
; ++i
) {
2931 mappings
[i
].sfm_address
+= slide
;
2936 #endif // SLIDEABLE_CACHE_SUPPORT
2938 static void mapSharedCache()
2940 uint64_t cacheBaseAddress
;
2941 // quick check if a cache is alreay mapped into shared region
2942 if ( _shared_region_check_np(&cacheBaseAddress
) == 0 ) {
2943 sSharedCache
= (dyld_cache_header
*)cacheBaseAddress
;
2944 // if we don't understand the currently mapped shared cache, then ignore
2945 if ( strcmp(sSharedCache
->magic
, ARCH_CACHE_MAGIC
) != 0 ) {
2946 sSharedCache
= NULL
;
2947 if ( gLinkContext
.verboseMapping
)
2948 dyld::log("dyld: existing shared cached in memory is not compatible\n");
2950 // check if cache file is slidable
2951 dyld_cache_header
* header
= (dyld_cache_header
*)sSharedCache
;
2952 if ( (header
->mappingOffset
>= 0x48) && (header
->slideInfoSize
!= 0) ) {
2953 // solve for slide by comparing loaded address to address of first region
2954 const uint8_t* loadedAddress
= (uint8_t*)sSharedCache
;
2955 const dyld_cache_mapping_info
* const mappings
= (dyld_cache_mapping_info
*)(loadedAddress
+header
->mappingOffset
);
2956 const uint8_t* preferedLoadAddress
= (uint8_t*)(long)(mappings
[0].address
);
2957 sSharedCacheSlide
= loadedAddress
- preferedLoadAddress
;
2958 dyld_all_image_infos
.sharedCacheSlide
= sSharedCacheSlide
;
2959 //dyld::log("sSharedCacheSlide=0x%08lX, loadedAddress=%p, preferedLoadAddress=%p\n", sSharedCacheSlide, loadedAddress, preferedLoadAddress);
2963 #if __i386__ || __x86_64__
2964 // <rdar://problem/5925940> Safe Boot should disable dyld shared cache
2965 // if we are in safe-boot mode and the cache was not made during this boot cycle,
2966 // delete the cache file
2967 uint32_t safeBootValue
= 0;
2968 size_t safeBootValueSize
= sizeof(safeBootValue
);
2969 if ( (sysctlbyname("kern.safeboot", &safeBootValue
, &safeBootValueSize
, NULL
, 0) == 0) && (safeBootValue
!= 0) ) {
2970 // user booted machine in safe-boot mode
2971 struct stat dyldCacheStatInfo
;
2972 // Don't use custom DYLD_SHARED_CACHE_DIR if provided, use standard path
2973 if ( ::stat(MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
, &dyldCacheStatInfo
) == 0 ) {
2974 struct timeval bootTimeValue
;
2975 size_t bootTimeValueSize
= sizeof(bootTimeValue
);
2976 if ( (sysctlbyname("kern.boottime", &bootTimeValue
, &bootTimeValueSize
, NULL
, 0) == 0) && (bootTimeValue
.tv_sec
!= 0) ) {
2977 // if the cache file was created before this boot, then throw it away and let it rebuild itself
2978 if ( dyldCacheStatInfo
.st_mtime
< bootTimeValue
.tv_sec
) {
2979 ::unlink(MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
);
2980 gLinkContext
.sharedRegionMode
= ImageLoader::kDontUseSharedRegion
;
2987 // map in shared cache to shared region
2988 int fd
= openSharedCacheFile();
2990 uint8_t firstPages
[8192];
2991 if ( ::read(fd
, firstPages
, 8192) == 8192 ) {
2992 dyld_cache_header
* header
= (dyld_cache_header
*)firstPages
;
2993 if ( strcmp(header
->magic
, ARCH_CACHE_MAGIC
) == 0 ) {
2994 const dyld_cache_mapping_info
* const fileMappingsStart
= (dyld_cache_mapping_info
*)&firstPages
[header
->mappingOffset
];
2995 const dyld_cache_mapping_info
* const fileMappingsEnd
= &fileMappingsStart
[header
->mappingCount
];
2996 shared_file_mapping_np mappings
[header
->mappingCount
+1]; // add room for code-sig
2997 unsigned int mappingCount
= header
->mappingCount
;
2998 int codeSignatureMappingIndex
= -1;
2999 // validate that the cache file has not been truncated
3000 bool goodCache
= false;
3001 struct stat stat_buf
;
3002 if ( fstat(fd
, &stat_buf
) == 0 ) {
3005 for (const dyld_cache_mapping_info
* p
= fileMappingsStart
; p
< fileMappingsEnd
; ++p
, ++i
) {
3006 mappings
[i
].sfm_address
= p
->address
;
3007 mappings
[i
].sfm_size
= p
->size
;
3008 mappings
[i
].sfm_file_offset
= p
->fileOffset
;
3009 mappings
[i
].sfm_max_prot
= p
->maxProt
;
3010 mappings
[i
].sfm_init_prot
= p
->initProt
;
3011 // rdar://problem/5694507 old update_dyld_shared_cache tool could make a cache file
3012 // that is not page aligned, but otherwise ok.
3013 if ( p
->fileOffset
+p
->size
> (uint64_t)(stat_buf
.st_size
+4095 & (-4096)) ) {
3014 dyld::log("dyld: shared cached file is corrupt: %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
"\n", sSharedCacheDir
);
3018 #if __IPHONE_OS_VERSION_MIN_REQUIRED
3019 // if shared cache is code signed, add a mapping for the code signature
3020 uint32_t signatureSize
= header
->codeSignatureSize
;
3021 // zero size in header means signature runs to end-of-file
3022 if ( signatureSize
== 0 )
3023 signatureSize
= stat_buf
.st_size
- header
->codeSignatureOffset
;
3024 if ( signatureSize
!= 0 ) {
3025 int linkeditMapping
= mappingCount
-1;
3026 codeSignatureMappingIndex
= mappingCount
++;
3027 mappings
[codeSignatureMappingIndex
].sfm_address
= mappings
[linkeditMapping
].sfm_address
+ mappings
[linkeditMapping
].sfm_size
;
3028 mappings
[codeSignatureMappingIndex
].sfm_size
= (signatureSize
+4095) & (-4096);
3029 mappings
[codeSignatureMappingIndex
].sfm_file_offset
= header
->codeSignatureOffset
;
3030 mappings
[codeSignatureMappingIndex
].sfm_max_prot
= VM_PROT_READ
;
3031 mappings
[codeSignatureMappingIndex
].sfm_init_prot
= VM_PROT_READ
;
3035 #if __MAC_OS_X_VERSION_MIN_REQUIRED
3036 // sanity check that /usr/lib/libSystem.B.dylib stat() info matches cache
3037 if ( header
->imagesCount
* sizeof(dyld_cache_image_info
) + header
->imagesOffset
< 8192 ) {
3038 bool foundLibSystem
= false;
3039 if ( stat("/usr/lib/libSystem.B.dylib", &stat_buf
) == 0 ) {
3040 const dyld_cache_image_info
* images
= (dyld_cache_image_info
*)&firstPages
[header
->imagesOffset
];
3041 const dyld_cache_image_info
* const imagesEnd
= &images
[header
->imagesCount
];
3042 for (const dyld_cache_image_info
* p
= images
; p
< imagesEnd
; ++p
) {
3043 if ( ((time_t)p
->modTime
== stat_buf
.st_mtime
) && ((ino_t
)p
->inode
== stat_buf
.st_ino
) ) {
3044 foundLibSystem
= true;
3049 if ( !sSharedCacheIgnoreInodeAndTimeStamp
&& !foundLibSystem
) {
3050 dyld::log("dyld: shared cached file was built against a different libSystem.dylib, ignoring cache.\n"
3051 "to update dyld shared cache run: 'sudo update_dyld_shared_cache' then reboot.\n");
3057 long cacheSlide
= 0;
3058 void* slideInfo
= NULL
;
3059 uint32_t slideInfoSize
= 0;
3060 #if SLIDEABLE_CACHE_SUPPORT
3061 // check if shared cache contains slid info
3062 if ( header
->slideInfoSize
!= 0 ) {
3063 // <rdar://problem/8611968> don't slide shared cache if ASLR disabled (main executable didn't slide)
3064 if ( sMainExecutable
->isPositionIndependentExecutable() && (sMainExecutable
->getSlide() == 0) )
3067 // generate random slide amount
3068 cacheSlide
= pickCacheSlide(mappingCount
, mappings
);
3069 slideInfo
= (void*)(long)(mappings
[2].sfm_address
+ (header
->slideInfoOffset
- mappings
[2].sfm_file_offset
));
3070 slideInfoSize
= header
->slideInfoSize
;
3071 // add VM_PROT_SLIDE bit to __DATA area of cache
3072 mappings
[1].sfm_max_prot
|= VM_PROT_SLIDE
;
3073 mappings
[1].sfm_init_prot
|= VM_PROT_SLIDE
;
3077 if (_shared_region_map_and_slide_np(fd
, mappingCount
, mappings
, codeSignatureMappingIndex
, cacheSlide
, slideInfo
, slideInfoSize
) == 0) {
3078 // successfully mapped cache into shared region
3079 sSharedCache
= (dyld_cache_header
*)mappings
[0].sfm_address
;
3080 sSharedCacheSlide
= cacheSlide
;
3081 dyld_all_image_infos
.sharedCacheSlide
= cacheSlide
;
3082 //dyld::log("sSharedCache=%p sSharedCacheSlide=0x%08lX\n", sSharedCache, sSharedCacheSlide);
3085 if ( gLinkContext
.verboseMapping
)
3086 dyld::log("dyld: shared cached file could not be mapped\n");
3091 if ( gLinkContext
.verboseMapping
)
3092 dyld::log("dyld: shared cached file is invalid\n");
3096 if ( gLinkContext
.verboseMapping
)
3097 dyld::log("dyld: shared cached file cannot be read\n");
3102 if ( gLinkContext
.verboseMapping
)
3103 dyld::log("dyld: shared cached file cannot be opened\n");
3107 // remember if dyld loaded at same address as when cache built
3108 if ( sSharedCache
!= NULL
) {
3109 gLinkContext
.dyldLoadedAtSameAddressNeededBySharedCache
= ((uintptr_t)(sSharedCache
->dyldBaseAddress
) == (uintptr_t)&_mh_dylinker_header
);
3112 // tell gdb where the shared cache is
3113 if ( sSharedCache
!= NULL
) {
3114 const dyld_cache_mapping_info
* const start
= (dyld_cache_mapping_info
*)((uint8_t*)sSharedCache
+ sSharedCache
->mappingOffset
);
3115 dyld_shared_cache_ranges
.sharedRegionsCount
= sSharedCache
->mappingCount
;
3116 // only room to tell gdb about first four regions
3117 if ( dyld_shared_cache_ranges
.sharedRegionsCount
> 4 )
3118 dyld_shared_cache_ranges
.sharedRegionsCount
= 4;
3119 if ( gLinkContext
.verboseMapping
) {
3120 if ( gLinkContext
.sharedRegionMode
== ImageLoader::kUseSharedRegion
)
3121 dyld::log("dyld: Mapping shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
"\n", sSharedCacheDir
);
3122 else if ( gLinkContext
.sharedRegionMode
== ImageLoader::kUsePrivateSharedRegion
)
3123 dyld::log("dyld: Mapping private shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
"\n", sSharedCacheDir
);
3125 const dyld_cache_mapping_info
* const end
= &start
[dyld_shared_cache_ranges
.sharedRegionsCount
];
3127 for (const dyld_cache_mapping_info
* p
= start
; p
< end
; ++p
, ++index
) {
3128 dyld_shared_cache_ranges
.ranges
[index
].start
= p
->address
+sSharedCacheSlide
;
3129 dyld_shared_cache_ranges
.ranges
[index
].length
= p
->size
;
3130 if ( gLinkContext
.verboseMapping
) {
3131 dyld::log(" 0x%08llX->0x%08llX %s%s%s init=%x, max=%x\n",
3132 p
->address
+sSharedCacheSlide
, p
->address
+sSharedCacheSlide
+p
->size
-1,
3133 ((p
->initProt
& VM_PROT_READ
) ? "read " : ""),
3134 ((p
->initProt
& VM_PROT_WRITE
) ? "write " : ""),
3135 ((p
->initProt
& VM_PROT_EXECUTE
) ? "execute " : ""), p
->initProt
, p
->maxProt
);
3138 // If a non-writable and executable region is found in the R/W shared region, then this is __IMPORT segments
3139 // This is an old cache. Make writable. dyld no longer supports turn W on and off as it binds
3140 if ( (p
->initProt
== (VM_PROT_READ
|VM_PROT_EXECUTE
)) && ((p
->address
& 0xF0000000) == 0xA0000000) ) {
3141 if ( p
->size
!= 0 ) {
3142 vm_prot_t prot
= VM_PROT_EXECUTE
| PROT_READ
| VM_PROT_WRITE
;
3143 vm_protect(mach_task_self(), p
->address
, p
->size
, false, prot
);
3144 if ( gLinkContext
.verboseMapping
) {
3145 dyld::log("%18s at 0x%08llX->0x%08llX altered permissions to %c%c%c\n", "", p
->address
,
3146 p
->address
+p
->size
-1,
3147 (prot
& PROT_READ
) ? 'r' : '.', (prot
& PROT_WRITE
) ? 'w' : '.', (prot
& PROT_EXEC
) ? 'x' : '.' );
3153 #if __IPHONE_OS_VERSION_MIN_REQUIRED
3154 if ( gLinkContext
.verboseMapping
) {
3155 // list the code blob
3156 dyld_cache_header
* header
= (dyld_cache_header
*)sSharedCache
;
3157 uint32_t signatureSize
= header
->codeSignatureSize
;
3158 // zero size in header means signature runs to end-of-file
3159 if ( signatureSize
== 0 ) {
3160 struct stat stat_buf
;
3161 if ( ::stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME
, &stat_buf
) == 0 )
3162 signatureSize
= stat_buf
.st_size
- header
->codeSignatureOffset
;
3164 if ( signatureSize
!= 0 ) {
3165 const dyld_cache_mapping_info
* const last
= &start
[dyld_shared_cache_ranges
.sharedRegionsCount
-1];
3166 uint64_t codeBlobStart
= last
->address
+ last
->size
;
3167 dyld::log(" 0x%08llX->0x%08llX (code signature)\n", codeBlobStart
, codeBlobStart
+signatureSize
);
3170 // check for file that enables dyld shared cache dylibs to be overridden
3171 struct stat enableStatBuf
;
3172 sDylibsOverrideCache
= ( ::stat(IPHONE_DYLD_SHARED_CACHE_DIR
"enable-dylibs-to-override-cache", &enableStatBuf
) == 0 );
3176 #endif // #if DYLD_SHARED_CACHE_SUPPORT
3180 // create when NSLinkModule is called for a second time on a bundle
3181 ImageLoader
* cloneImage(ImageLoader
* image
)
3183 // open file (automagically closed when this function exits)
3184 FileOpener
file(image
->getPath());
3186 struct stat stat_buf
;
3187 if ( fstat(file
.getFileDescriptor(), &stat_buf
) == -1)
3190 dyld::LoadContext context
;
3191 context
.useSearchPaths
= false;
3192 context
.useFallbackPaths
= false;
3193 context
.useLdLibraryPath
= false;
3194 context
.implicitRPath
= false;
3195 context
.matchByInstallName
= false;
3196 context
.dontLoad
= false;
3197 context
.mustBeBundle
= true;
3198 context
.mustBeDylib
= false;
3199 context
.canBePIE
= false;
3200 context
.origin
= NULL
;
3201 context
.rpath
= NULL
;
3202 return loadPhase6(file
.getFileDescriptor(), stat_buf
, image
->getPath(), context
);
3206 ImageLoader
* loadFromMemory(const uint8_t* mem
, uint64_t len
, const char* moduleName
)
3208 // if fat wrapper, find usable sub-file
3209 const fat_header
* memStartAsFat
= (fat_header
*)mem
;
3210 uint64_t fileOffset
= 0;
3211 uint64_t fileLength
= len
;
3212 if ( memStartAsFat
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
3213 if ( fatFindBest(memStartAsFat
, &fileOffset
, &fileLength
) ) {
3214 mem
= &mem
[fileOffset
];
3218 throw "no matching architecture in universal wrapper";
3223 if ( isCompatibleMachO(mem
, moduleName
) ) {
3224 ImageLoader
* image
= ImageLoaderMachO::instantiateFromMemory(moduleName
, (macho_header
*)mem
, len
, gLinkContext
);
3225 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
3226 if ( ! image
->isBundle() )
3231 // try other file formats here...
3233 // throw error about what was found
3234 switch (*(uint32_t*)mem
) {
3239 throw "mach-o, but wrong architecture";
3241 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
3242 mem
[0], mem
[1], mem
[2], mem
[3], mem
[4], mem
[5], mem
[6],mem
[7]);
3247 void registerAddCallback(ImageCallback func
)
3249 // now add to list to get notified when any more images are added
3250 sAddImageCallbacks
.push_back(func
);
3252 // call callback with all existing images
3253 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
3254 ImageLoader
* image
= *it
;
3255 if ( image
->getState() >= dyld_image_state_bound
&& image
->getState() < dyld_image_state_terminated
)
3256 (*func
)(image
->machHeader(), image
->getSlide());
3260 void registerRemoveCallback(ImageCallback func
)
3262 sRemoveImageCallbacks
.push_back(func
);
3265 void clearErrorMessage()
3267 error_string
[0] = '\0';
3270 void setErrorMessage(const char* message
)
3272 // save off error message in global buffer for CrashReporter to find
3273 strlcpy(error_string
, message
, sizeof(error_string
));
3276 const char* getErrorMessage()
3278 return error_string
;
3282 void halt(const char* message
)
3284 dyld::log("dyld: %s\n", message
);
3285 setErrorMessage(message
);
3286 uintptr_t terminationFlags
= 0;
3287 if ( !gLinkContext
.startedInitializingMainExecutable
)
3288 terminationFlags
= 1;
3289 setAlImageInfosHalt(error_string
, terminationFlags
);
3290 dyld_fatal_error(error_string
);
3293 static void setErrorStrings(unsigned errorCode
, const char* errorClientOfDylibPath
,
3294 const char* errorTargetDylibPath
, const char* errorSymbol
)
3296 dyld_all_image_infos
.errorKind
= errorCode
;
3297 dyld_all_image_infos
.errorClientOfDylibPath
= errorClientOfDylibPath
;
3298 dyld_all_image_infos
.errorTargetDylibPath
= errorTargetDylibPath
;
3299 dyld_all_image_infos
.errorSymbol
= errorSymbol
;
3303 uintptr_t bindLazySymbol(const mach_header
* mh
, uintptr_t* lazyPointer
)
3305 uintptr_t result
= 0;
3306 // acquire read-lock on dyld's data structures
3307 #if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved
3308 if ( gLibSystemHelpers
!= NULL
)
3309 (*gLibSystemHelpers
->lockForReading
)();
3311 // lookup and bind lazy pointer and get target address
3313 ImageLoader
* target
;
3315 // fast stubs pass NULL for mh and image is instead found via the location of stub (aka lazyPointer)
3317 target
= dyld::findImageContainingAddress(lazyPointer
);
3319 target
= dyld::findImageByMachHeader(mh
);
3321 // note, target should always be mach-o, because only mach-o lazy handler wired up to this
3322 target
= dyld::findImageByMachHeader(mh
);
3324 if ( target
== NULL
)
3325 throwf("image not found for lazy pointer at %p", lazyPointer
);
3326 result
= target
->doBindLazySymbol(lazyPointer
, gLinkContext
);
3328 catch (const char* message
) {
3329 dyld::log("dyld: lazy symbol binding failed: %s\n", message
);
3332 // release read-lock on dyld's data structures
3334 if ( gLibSystemHelpers
!= NULL
)
3335 (*gLibSystemHelpers
->unlockForReading
)();
3337 // return target address to glue which jumps to it with real parameters restored
3342 uintptr_t fastBindLazySymbol(ImageLoader
** imageLoaderCache
, uintptr_t lazyBindingInfoOffset
)
3344 uintptr_t result
= 0;
3346 if ( *imageLoaderCache
== NULL
) {
3348 *imageLoaderCache
= dyld::findMappedRange((uintptr_t)imageLoaderCache
);
3349 if ( *imageLoaderCache
== NULL
) {
3350 const char* message
= "fast lazy binding from unknown image";
3351 dyld::log("dyld: %s\n", message
);
3356 // bind lazy pointer and return it
3358 result
= (*imageLoaderCache
)->doBindFastLazySymbol(lazyBindingInfoOffset
, gLinkContext
,
3359 (dyld::gLibSystemHelpers
!= NULL
) ? dyld::gLibSystemHelpers
->acquireGlobalDyldLock
: NULL
,
3360 (dyld::gLibSystemHelpers
!= NULL
) ? dyld::gLibSystemHelpers
->releaseGlobalDyldLock
: NULL
);
3362 catch (const char* message
) {
3363 dyld::log("dyld: lazy symbol binding failed: %s\n", message
);
3367 // return target address to glue which jumps to it with real parameters restored
3373 void registerUndefinedHandler(UndefinedHandler handler
)
3375 sUndefinedHandler
= handler
;
3378 static void undefinedHandler(const char* symboName
)
3380 if ( sUndefinedHandler
!= NULL
) {
3381 (*sUndefinedHandler
)(symboName
);
3385 static bool findExportedSymbol(const char* name
, bool onlyInCoalesced
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
)
3387 // search all images in order
3388 const ImageLoader
* firstWeakImage
= NULL
;
3389 const ImageLoader::Symbol
* firstWeakSym
= NULL
;
3390 const unsigned int imageCount
= sAllImages
.size();
3391 for(unsigned int i
=0; i
< imageCount
; ++i
) {
3392 ImageLoader
* anImage
= sAllImages
[i
];
3393 // the use of inserted libraries alters search order
3394 // so that inserted libraries are found before the main executable
3395 if ( sInsertedDylibCount
> 0 ) {
3396 if ( i
< sInsertedDylibCount
)
3397 anImage
= sAllImages
[i
+1];
3398 else if ( i
== sInsertedDylibCount
)
3399 anImage
= sAllImages
[0];
3401 if ( ! anImage
->hasHiddenExports() && (!onlyInCoalesced
|| anImage
->hasCoalescedExports()) ) {
3402 *sym
= anImage
->findExportedSymbol(name
, false, image
);
3403 if ( *sym
!= NULL
) {
3404 // if weak definition found, record first one found
3405 if ( ((*image
)->getExportedSymbolInfo(*sym
) & ImageLoader::kWeakDefinition
) != 0 ) {
3406 if ( firstWeakImage
== NULL
) {
3407 firstWeakImage
= *image
;
3408 firstWeakSym
= *sym
;
3412 // found non-weak, so immediately return with it
3418 if ( firstWeakSym
!= NULL
) {
3419 // found a weak definition, but no non-weak, so return first weak found
3420 *sym
= firstWeakSym
;
3421 *image
= firstWeakImage
;
3428 bool flatFindExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
)
3430 return findExportedSymbol(name
, false, sym
, image
);
3433 bool findCoalescedExportedSymbol(const char* name
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
)
3435 return findExportedSymbol(name
, true, sym
, image
);
3439 bool flatFindExportedSymbolWithHint(const char* name
, const char* librarySubstring
, const ImageLoader::Symbol
** sym
, const ImageLoader
** image
)
3441 // search all images in order
3442 const unsigned int imageCount
= sAllImages
.size();
3443 for(unsigned int i
=0; i
< imageCount
; ++i
){
3444 ImageLoader
* anImage
= sAllImages
[i
];
3445 // only look at images whose paths contain the hint string (NULL hint string is wildcard)
3446 if ( ! anImage
->isBundle() && ((librarySubstring
==NULL
) || (strstr(anImage
->getPath(), librarySubstring
) != NULL
)) ) {
3447 *sym
= anImage
->findExportedSymbol(name
, false, image
);
3448 if ( *sym
!= NULL
) {
3456 unsigned int getCoalescedImages(ImageLoader
* images
[])
3458 unsigned int count
= 0;
3459 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
3460 ImageLoader
* image
= *it
;
3461 if ( image
->participatesInCoalescing() ) {
3470 static ImageLoader::MappedRegion
* getMappedRegions(ImageLoader::MappedRegion
* regions
)
3472 ImageLoader::MappedRegion
* end
= regions
;
3473 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
3474 (*it
)->getMappedRegions(end
);
3479 void registerImageStateSingleChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
)
3481 // mark the image that the handler is in as never-unload because dyld has a reference into it
3482 ImageLoader
* handlerImage
= findImageContainingAddress((void*)handler
);
3483 if ( handlerImage
!= NULL
)
3484 handlerImage
->setNeverUnload();
3486 // add to list of handlers
3487 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(state
, sSingleHandlers
);
3488 if ( handlers
!= NULL
) {
3489 // <rdar://problem/10332417> need updateAllImages() to be last in dyld_image_state_mapped list
3490 // so that if ObjC adds a handler that prevents a load, it happens before the gdb list is updated
3491 if ( state
== dyld_image_state_mapped
)
3492 handlers
->insert(handlers
->begin(), handler
);
3494 handlers
->push_back(handler
);
3496 // call callback with all existing images
3497 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
3498 ImageLoader
* image
= *it
;
3499 dyld_image_info info
;
3500 info
.imageLoadAddress
= image
->machHeader();
3501 info
.imageFilePath
= image
->getRealPath();
3502 info
.imageFileModDate
= image
->lastModified();
3503 // should only call handler if state == image->state
3504 if ( image
->getState() == state
)
3505 (*handler
)(state
, 1, &info
);
3506 // ignore returned string, too late to do anything
3511 void registerImageStateBatchChangeHandler(dyld_image_states state
, dyld_image_state_change_handler handler
)
3513 // mark the image that the handler is in as never-unload because dyld has a reference into it
3514 ImageLoader
* handlerImage
= findImageContainingAddress((void*)handler
);
3515 if ( handlerImage
!= NULL
)
3516 handlerImage
->setNeverUnload();
3518 // add to list of handlers
3519 std::vector
<dyld_image_state_change_handler
>* handlers
= stateToHandlers(state
, sBatchHandlers
);
3520 if ( handlers
!= NULL
) {
3521 // insert at front, so that gdb handler is always last
3522 handlers
->insert(handlers
->begin(), handler
);
3524 // call callback with all existing images
3526 notifyBatchPartial(state
, true, handler
);
3528 catch (const char* msg
) {
3529 // ignore request to abort during registration
3534 static ImageLoader
* libraryLocator(const char* libraryName
, bool search
, const char* origin
, const ImageLoader::RPathChain
* rpaths
)
3536 dyld::LoadContext context
;
3537 context
.useSearchPaths
= search
;
3538 context
.useFallbackPaths
= search
;
3539 context
.useLdLibraryPath
= false;
3540 context
.implicitRPath
= false;
3541 context
.matchByInstallName
= false;
3542 context
.dontLoad
= false;
3543 context
.mustBeBundle
= false;
3544 context
.mustBeDylib
= true;
3545 context
.canBePIE
= false;
3546 context
.origin
= origin
;
3547 context
.rpath
= rpaths
;
3548 return load(libraryName
, context
);
3551 static const char* basename(const char* path
)
3553 const char* last
= path
;
3554 for (const char* s
= path
; *s
!= '\0'; s
++) {
3561 static void setContext(const macho_header
* mainExecutableMH
, int argc
, const char* argv
[], const char* envp
[], const char* apple
[])
3563 gLinkContext
.loadLibrary
= &libraryLocator
;
3564 gLinkContext
.terminationRecorder
= &terminationRecorder
;
3565 gLinkContext
.flatExportFinder
= &flatFindExportedSymbol
;
3566 gLinkContext
.coalescedExportFinder
= &findCoalescedExportedSymbol
;
3567 gLinkContext
.getCoalescedImages
= &getCoalescedImages
;
3568 gLinkContext
.undefinedHandler
= &undefinedHandler
;
3569 gLinkContext
.getAllMappedRegions
= &getMappedRegions
;
3570 gLinkContext
.bindingHandler
= NULL
;
3571 gLinkContext
.notifySingle
= ¬ifySingle
;
3572 gLinkContext
.notifyBatch
= ¬ifyBatch
;
3573 gLinkContext
.removeImage
= &removeImage
;
3574 gLinkContext
.registerDOFs
= ®isterDOFs
;
3575 gLinkContext
.clearAllDepths
= &clearAllDepths
;
3576 gLinkContext
.printAllDepths
= &printAllDepths
;
3577 gLinkContext
.imageCount
= &imageCount
;
3578 gLinkContext
.setNewProgramVars
= &setNewProgramVars
;
3579 #if DYLD_SHARED_CACHE_SUPPORT
3580 gLinkContext
.inSharedCache
= &inSharedCache
;
3582 gLinkContext
.setErrorStrings
= &setErrorStrings
;
3583 #if SUPPORT_OLD_CRT_INITIALIZATION
3584 gLinkContext
.setRunInitialzersOldWay
= &setRunInitialzersOldWay
;
3586 gLinkContext
.bindingOptions
= ImageLoader::kBindingNone
;
3587 gLinkContext
.argc
= argc
;
3588 gLinkContext
.argv
= argv
;
3589 gLinkContext
.envp
= envp
;
3590 gLinkContext
.apple
= apple
;
3591 gLinkContext
.progname
= (argv
[0] != NULL
) ? basename(argv
[0]) : "";
3592 gLinkContext
.programVars
.mh
= mainExecutableMH
;
3593 gLinkContext
.programVars
.NXArgcPtr
= &gLinkContext
.argc
;
3594 gLinkContext
.programVars
.NXArgvPtr
= &gLinkContext
.argv
;
3595 gLinkContext
.programVars
.environPtr
= &gLinkContext
.envp
;
3596 gLinkContext
.programVars
.__prognamePtr
=&gLinkContext
.progname
;
3597 gLinkContext
.mainExecutable
= NULL
;
3598 gLinkContext
.imageSuffix
= NULL
;
3599 gLinkContext
.prebindUsage
= ImageLoader::kUseAllPrebinding
;
3600 gLinkContext
.sharedRegionMode
= ImageLoader::kUseSharedRegion
;
3605 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
3606 #define macho_segment_command segment_command_64
3607 #define macho_section section_64
3609 #define LC_SEGMENT_COMMAND LC_SEGMENT
3610 #define macho_segment_command segment_command
3611 #define macho_section section
3616 // Look for a special segment in the mach header.
3617 // Its presences means that the binary wants to have DYLD ignore
3618 // DYLD_ environment variables.
3620 static bool hasRestrictedSegment(const macho_header
* mh
)
3622 const uint32_t cmd_count
= mh
->ncmds
;
3623 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
3624 const struct load_command
* cmd
= cmds
;
3625 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
3627 case LC_SEGMENT_COMMAND
:
3629 const struct macho_segment_command
* seg
= (struct macho_segment_command
*)cmd
;
3631 //dyld::log("seg name: %s\n", seg->segname);
3632 if (strcmp(seg
->segname
, "__RESTRICT") == 0) {
3633 const struct macho_section
* const sectionsStart
= (struct macho_section
*)((char*)seg
+ sizeof(struct macho_segment_command
));
3634 const struct macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
3635 for (const struct macho_section
* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
3636 if (strcmp(sect
->sectname
, "__restrict") == 0)
3643 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
3649 #if SUPPORT_VERSIONED_PATHS
3651 // Peeks at a dylib file and returns its current_version and install_name.
3652 // Returns false on error.
3654 static bool getDylibVersionAndInstallname(const char* dylibPath
, uint32_t* version
, char* installName
)
3656 // open file (automagically closed when this function exits)
3657 FileOpener
file(dylibPath
);
3659 if ( file
.getFileDescriptor() == -1 )
3662 uint8_t firstPage
[4096];
3663 if ( pread(file
.getFileDescriptor(), firstPage
, 4096, 0) != 4096 )
3666 // if fat wrapper, find usable sub-file
3667 const fat_header
* fileStartAsFat
= (fat_header
*)firstPage
;
3668 if ( fileStartAsFat
->magic
== OSSwapBigToHostInt32(FAT_MAGIC
) ) {
3669 uint64_t fileOffset
;
3670 uint64_t fileLength
;
3671 if ( fatFindBest(fileStartAsFat
, &fileOffset
, &fileLength
) ) {
3672 if ( pread(file
.getFileDescriptor(), firstPage
, 4096, fileOffset
) != 4096 )
3680 // check mach-o header
3681 const mach_header
* mh
= (mach_header
*)firstPage
;
3682 if ( mh
->magic
!= sMainExecutableMachHeader
->magic
)
3684 if ( mh
->cputype
!= sMainExecutableMachHeader
->cputype
)
3687 // scan load commands for LC_ID_DYLIB
3688 const uint32_t cmd_count
= mh
->ncmds
;
3689 const struct load_command
* const cmds
= (struct load_command
*)(((char*)mh
)+sizeof(macho_header
));
3690 const struct load_command
* const cmdsReadEnd
= (struct load_command
*)(((char*)mh
)+4096);
3691 const struct load_command
* cmd
= cmds
;
3692 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
3696 const struct dylib_command
* id
= (struct dylib_command
*)cmd
;
3697 *version
= id
->dylib
.current_version
;
3698 if ( installName
!= NULL
)
3699 strlcpy(installName
, (char *)id
+ id
->dylib
.name
.offset
, PATH_MAX
);
3704 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
3705 if ( cmd
> cmdsReadEnd
)
3711 #endif // SUPPORT_VERSIONED_PATHS
3714 static void printAllImages()
3716 dyld::log("printAllImages()\n");
3717 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
3718 ImageLoader
* image
= *it
;
3719 dyld_image_states imageState
= image
->getState();
3720 dyld::log(" state=%d, refcount=%d, name=%s\n", imageState
, image
->referenceCount(), image
->getShortName());
3721 image
->printReferenceCounts();
3726 void link(ImageLoader
* image
, bool forceLazysBound
, const ImageLoader::RPathChain
& loaderRPaths
)
3728 // add to list of known images. This did not happen at creation time for bundles
3729 if ( image
->isBundle() && !image
->isLinked() )
3732 // we detect root images as those not linked in yet
3733 if ( !image
->isLinked() )
3734 addRootImage(image
);
3738 image
->link(gLinkContext
, forceLazysBound
, false, loaderRPaths
);
3740 catch (const char* msg
) {
3741 garbageCollectImages();
3747 void runInitializers(ImageLoader
* image
)
3749 // do bottom up initialization
3750 ImageLoader::InitializerTimingList initializerTimes
[sAllImages
.size()];
3751 initializerTimes
[0].count
= 0;
3752 image
->runInitializers(gLinkContext
, initializerTimes
[0]);
3755 void garbageCollectImages()
3757 // keep scanning list of images until entire list is scanned with no unreferenced images
3758 bool mightBeUnreferencedImages
= true;
3759 while ( mightBeUnreferencedImages
) {
3760 mightBeUnreferencedImages
= false;
3761 for (std::vector
<ImageLoader
*>::iterator it
=sAllImages
.begin(); it
!= sAllImages
.end(); it
++) {
3762 ImageLoader
* image
= *it
;
3763 if ( (image
->referenceCount() == 0) && !image
->neverUnload() && !image
->isBeingRemoved() ) {
3764 if ( image
->isReferencedUpward() ) {
3765 // temp hack for rdar://problem/10973109
3766 // if an image is upwardly referenced, we really need to scan all images
3767 // to see if any are still using it.
3771 //dyld::log("garbageCollectImages: deleting %p %s\n", image, image->getPath());
3772 image
->setBeingRemoved();
3774 ImageLoader::deleteImage(image
);
3776 catch (const char* msg
) {
3777 dyld::warn("problem deleting image: %s\n", msg
);
3779 mightBeUnreferencedImages
= true;
3788 static void preflight_finally(ImageLoader
* image
)
3790 if ( image
->isBundle() ) {
3791 removeImageFromAllImages(image
->machHeader());
3792 ImageLoader::deleteImage(image
);
3794 sBundleBeingLoaded
= NULL
;
3795 dyld::garbageCollectImages();
3799 void preflight(ImageLoader
* image
, const ImageLoader::RPathChain
& loaderRPaths
)
3802 if ( image
->isBundle() )
3803 sBundleBeingLoaded
= image
; // hack
3804 image
->link(gLinkContext
, false, true, loaderRPaths
);
3806 catch (const char* msg
) {
3807 preflight_finally(image
);
3810 preflight_finally(image
);
3813 static void loadInsertedDylib(const char* path
)
3815 ImageLoader
* image
= NULL
;
3817 LoadContext context
;
3818 context
.useSearchPaths
= false;
3819 context
.useFallbackPaths
= false;
3820 context
.useLdLibraryPath
= false;
3821 context
.implicitRPath
= false;
3822 context
.matchByInstallName
= false;
3823 context
.dontLoad
= false;
3824 context
.mustBeBundle
= false;
3825 context
.mustBeDylib
= true;
3826 context
.canBePIE
= false;
3827 context
.origin
= NULL
; // can't use @loader_path with DYLD_INSERT_LIBRARIES
3828 context
.rpath
= NULL
;
3829 image
= load(path
, context
);
3830 image
->setNeverUnload();
3833 halt(dyld::mkstringf("could not load inserted library: %s\n", path
));
3837 static bool processRestricted(const macho_header
* mainExecutableMH
)
3839 // all processes with setuid or setgid bit set are restricted
3840 if ( issetugid() ) {
3841 sRestrictedReason
= restrictedBySetGUid
;
3845 const uid_t euid
= geteuid();
3846 if ( (euid
!= 0) && hasRestrictedSegment(mainExecutableMH
) ) {
3847 // existence of __RESTRICT/__restrict section make process restricted
3848 sRestrictedReason
= restrictedBySegment
;
3852 #if __MAC_OS_X_VERSION_MIN_REQUIRED
3853 // ask kernel if code signature of program makes it restricted
3855 if ( syscall(SYS_csops
/* 169 */,
3856 0 /* asking about myself */,
3859 sizeof(flags
)) != -1) {
3860 if (flags
& CS_RESTRICT
) {
3861 sRestrictedReason
= restrictedByEntitlements
;
3872 // <rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots
3873 static void addDyldImageToUUIDList()
3875 const struct macho_header
* mh
= (macho_header
*)&__dso_handle
;
3876 const uint32_t cmd_count
= mh
->ncmds
;
3877 const struct load_command
* const cmds
= (struct load_command
*)((char*)mh
+ sizeof(macho_header
));
3878 const struct load_command
* cmd
= cmds
;
3879 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
3882 uuid_command
* uc
= (uuid_command
*)cmd
;
3883 dyld_uuid_info info
;
3884 info
.imageLoadAddress
= (mach_header
*)mh
;
3885 memcpy(info
.imageUUID
, uc
->uuid
, 16);
3886 addNonSharedCacheImageUUID(info
);
3890 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
3897 // Entry point for dyld. The kernel loads dyld and jumps to __dyld_start which
3898 // sets up some registers and call this function.
3900 // Returns address of main() in target program which __dyld_start jumps to
3903 _main(const macho_header
* mainExecutableMH
, uintptr_t mainExecutableSlide
,
3904 int argc
, const char* argv
[], const char* envp
[], const char* apple
[],
3905 uintptr_t* startGlue
)
3907 uintptr_t result
= 0;
3908 CRSetCrashLogMessage("dyld: launch started");
3909 #ifdef ALTERNATIVE_LOGFILE
3910 sLogfile
= open(ALTERNATIVE_LOGFILE
, O_WRONLY
| O_CREAT
| O_APPEND
);
3911 if ( sLogfile
== -1 ) {
3912 sLogfile
= STDERR_FILENO
;
3913 dyld::log("error opening alternate log file %s, errno = %d\n", ALTERNATIVE_LOGFILE
, errno
);
3918 char bindingsLogPath
[256];
3920 const char* shortProgName
= "unknown";
3922 shortProgName
= strrchr(argv
[0], '/');
3923 if ( shortProgName
== NULL
)
3924 shortProgName
= argv
[0];
3928 mysprintf(bindingsLogPath
, "/tmp/bindings/%d-%s", getpid(), shortProgName
);
3929 sBindingsLogfile
= open(bindingsLogPath
, O_WRONLY
| O_CREAT
, 0666);
3930 if ( sBindingsLogfile
== -1 ) {
3931 ::mkdir("/tmp/bindings", 0777);
3932 sBindingsLogfile
= open(bindingsLogPath
, O_WRONLY
| O_CREAT
, 0666);
3934 //dyld::log("open(%s) => %d, errno = %d\n", bindingsLogPath, sBindingsLogfile, errno);
3936 setContext(mainExecutableMH
, argc
, argv
, envp
, apple
);
3938 // Pickup the pointer to the exec path.
3939 sExecPath
= apple
[0];
3940 bool ignoreEnvironmentVariables
= false;
3941 if ( sExecPath
[0] != '/' ) {
3942 // have relative path, use cwd to make absolute
3943 char cwdbuff
[MAXPATHLEN
];
3944 if ( getcwd(cwdbuff
, MAXPATHLEN
) != NULL
) {
3945 // maybe use static buffer to avoid calling malloc so early...
3946 char* s
= new char[strlen(cwdbuff
) + strlen(sExecPath
) + 2];
3949 strcat(s
, sExecPath
);
3953 sMainExecutableMachHeader
= mainExecutableMH
;
3954 sProcessIsRestricted
= processRestricted(mainExecutableMH
);
3955 if ( sProcessIsRestricted
) {
3956 #if SUPPORT_LC_DYLD_ENVIRONMENT
3957 checkLoadCommandEnvironmentVariables();
3958 #if SUPPORT_VERSIONED_PATHS
3959 checkVersionedPaths();
3962 pruneEnvironmentVariables(envp
, &apple
);
3963 // set again because envp and apple may have changed or moved
3964 setContext(mainExecutableMH
, argc
, argv
, envp
, apple
);
3967 checkEnvironmentVariables(envp
, ignoreEnvironmentVariables
);
3968 if ( sEnv
.DYLD_PRINT_OPTS
)
3970 if ( sEnv
.DYLD_PRINT_ENV
)
3971 printEnvironmentVariables(envp
);
3973 // install gdb notifier
3974 stateToHandlers(dyld_image_state_dependents_mapped
, sBatchHandlers
)->push_back(notifyGDB
);
3975 stateToHandlers(dyld_image_state_mapped
, sSingleHandlers
)->push_back(updateAllImages
);
3976 // make initial allocations large enough that it is unlikely to need to be re-alloced
3977 sAllImages
.reserve(INITIAL_IMAGE_COUNT
);
3978 sImageRoots
.reserve(16);
3979 sAddImageCallbacks
.reserve(4);
3980 sRemoveImageCallbacks
.reserve(4);
3981 sImageFilesNeedingTermination
.reserve(16);
3982 sImageFilesNeedingDOFUnregistration
.reserve(8);
3984 #ifdef WAIT_FOR_SYSTEM_ORDER_HANDSHAKE
3985 // <rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process
3986 WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld_all_image_infos
.systemOrderFlag
);
3990 // add dyld itself to UUID list
3991 addDyldImageToUUIDList();
3992 CRSetCrashLogMessage("dyld: launch, loading dependent libraries");
3993 // instantiate ImageLoader for main executable
3994 sMainExecutable
= instantiateFromLoadedImage(mainExecutableMH
, mainExecutableSlide
, sExecPath
);
3995 sMainExecutable
->setNeverUnload();
3996 gLinkContext
.mainExecutable
= sMainExecutable
;
3997 gLinkContext
.processIsRestricted
= sProcessIsRestricted
;
3998 // load shared cache
3999 checkSharedRegionDisable();
4000 #if DYLD_SHARED_CACHE_SUPPORT
4001 if ( gLinkContext
.sharedRegionMode
!= ImageLoader::kDontUseSharedRegion
)
4004 // load any inserted libraries
4005 if ( sEnv
.DYLD_INSERT_LIBRARIES
!= NULL
) {
4006 for (const char* const* lib
= sEnv
.DYLD_INSERT_LIBRARIES
; *lib
!= NULL
; ++lib
)
4007 loadInsertedDylib(*lib
);
4009 // record count of inserted libraries so that a flat search will look at
4010 // inserted libraries, then main, then others.
4011 sInsertedDylibCount
= sAllImages
.size()-1;
4013 // link main executable
4014 gLinkContext
.linkingMainExecutable
= true;
4015 link(sMainExecutable
, sEnv
.DYLD_BIND_AT_LAUNCH
, ImageLoader::RPathChain(NULL
, NULL
));
4016 gLinkContext
.linkingMainExecutable
= false;
4017 if ( sMainExecutable
->forceFlat() ) {
4018 gLinkContext
.bindFlat
= true;
4019 gLinkContext
.prebindUsage
= ImageLoader::kUseNoPrebinding
;
4022 // link any inserted libraries
4023 // do this after linking main executable so that any dylibs pulled in by inserted
4024 // dylibs (e.g. libSystem) will not be in front of dylibs the program uses
4025 if ( sInsertedDylibCount
> 0 ) {
4026 for(unsigned int i
=0; i
< sInsertedDylibCount
; ++i
) {
4027 ImageLoader
* image
= sAllImages
[i
+1];
4028 link(image
, sEnv
.DYLD_BIND_AT_LAUNCH
, ImageLoader::RPathChain(NULL
, NULL
));
4029 // only INSERTED libraries can interpose
4030 image
->registerInterposing();
4034 CRSetCrashLogMessage("dyld: launch, running initializers");
4035 #if SUPPORT_OLD_CRT_INITIALIZATION
4036 // Old way is to run initializers via a callback from crt1.o
4037 if ( ! gRunInitializersOldWay
)
4038 initializeMainExecutable();
4040 // run all initializers
4041 initializeMainExecutable();
4043 // find entry point for main executable
4044 result
= (uintptr_t)sMainExecutable
->getThreadPC();
4045 if ( result
!= 0 ) {
4046 // main executable uses LC_MAIN, needs to return to glue in libdyld.dylib
4047 if ( (gLibSystemHelpers
!= NULL
) && (gLibSystemHelpers
->version
>= 9) )
4048 *startGlue
= (uintptr_t)gLibSystemHelpers
->startGlueToCallExit
;
4050 halt("libdyld.dylib support not present for LC_MAIN");
4053 // main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main()
4054 result
= (uintptr_t)sMainExecutable
->getMain();
4058 catch(const char* message
) {
4063 dyld::log("dyld: launch failed\n");
4066 #ifdef ALTERNATIVE_LOGFILE
4067 // only use alternate log during launch, otherwise file is open forever
4068 if ( sLogfile
!= STDERR_FILENO
) {
4070 sLogfile
= STDERR_FILENO
;
4073 CRSetCrashLogMessage(NULL
);