]> git.saurik.com Git - apple/dyld.git/blob - src/dyld.cpp
d143bc9238e869fee7f48a55089d3c4e84e045f6
[apple/dyld.git] / src / dyld.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <stdint.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <sys/param.h>
32 #include <mach/mach_time.h> // mach_absolute_time()
33 #include <mach/mach_init.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/syscall.h>
37 #include <sys/socket.h>
38 #include <sys/un.h>
39 #include <sys/syslog.h>
40 #include <sys/uio.h>
41 #include <mach-o/fat.h>
42 #include <mach-o/loader.h>
43 #include <mach-o/ldsyms.h>
44 #include <libkern/OSByteOrder.h>
45 #include <libkern/OSAtomic.h>
46 #include <mach/mach.h>
47 #include <sys/sysctl.h>
48 #include <sys/mman.h>
49 #include <sys/dtrace.h>
50 #include <libkern/OSAtomic.h>
51 #include <Availability.h>
52 #include <System/sys/codesign.h>
53 #include <_simple.h>
54
55
56 #ifndef CPU_SUBTYPE_ARM_V5TEJ
57 #define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7)
58 #endif
59 #ifndef CPU_SUBTYPE_ARM_XSCALE
60 #define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8)
61 #endif
62 #ifndef CPU_SUBTYPE_ARM_V7
63 #define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9)
64 #endif
65 #ifndef CPU_SUBTYPE_ARM_V7F
66 #define CPU_SUBTYPE_ARM_V7F ((cpu_subtype_t) 10)
67 #endif
68 #ifndef CPU_SUBTYPE_ARM_V7S
69 #define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t) 11)
70 #endif
71 #ifndef CPU_SUBTYPE_ARM_V7K
72 #define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12)
73 #endif
74 #ifndef LC_DYLD_ENVIRONMENT
75 #define LC_DYLD_ENVIRONMENT 0x27
76 #endif
77
78 #ifndef VM_PROT_SLIDE
79 #define VM_PROT_SLIDE 0x20
80 #endif
81
82 #include <vector>
83 #include <algorithm>
84
85 #include "mach-o/dyld_gdb.h"
86
87 #include "dyld.h"
88 #include "ImageLoader.h"
89 #include "ImageLoaderMachO.h"
90 #include "dyldLibSystemInterface.h"
91 #include "dyldSyscallInterface.h"
92 #if DYLD_SHARED_CACHE_SUPPORT
93 #include "dyld_cache_format.h"
94 #endif
95 #if CORESYMBOLICATION_SUPPORT
96 #include "coreSymbolicationDyldSupport.hpp"
97 #endif
98
99 // not libc header for send() syscall interface
100 extern "C" ssize_t __sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
101
102
103 // ARM is the only architecture that use cpu-sub-types
104 #define CPU_SUBTYPES_SUPPORTED __arm__
105
106
107
108 #define CPU_TYPE_MASK 0x00FFFFFF /* complement of CPU_ARCH_MASK */
109
110
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[]);
117
118 // magic so CrashReporter logs message
119 extern "C" {
120 char error_string[1024];
121 }
122 // implemented in dyldStartup.s for CrashReporter
123 extern "C" void dyld_fatal_error(const char* errString) __attribute__((noreturn));
124
125 // magic linker symbol for start of dyld binary
126 extern "C" void* __dso_handle;
127
128
129 //
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.
132 //
133 //
134 //
135 //
136 //
137 namespace dyld {
138 struct RegisteredDOF { const mach_header* mh; int registrationID; };
139 struct DylibOverride { const char* installName; const char* override; };
140 }
141
142
143 VECTOR_NEVER_DESTRUCTED(ImageLoader*);
144 VECTOR_NEVER_DESTRUCTED(dyld::RegisteredDOF);
145 VECTOR_NEVER_DESTRUCTED(dyld::ImageCallback);
146 VECTOR_NEVER_DESTRUCTED(dyld::DylibOverride);
147 VECTOR_NEVER_DESTRUCTED(ImageLoader::DynamicReference);
148
149 VECTOR_NEVER_DESTRUCTED(dyld_image_state_change_handler);
150
151 namespace dyld {
152
153
154 //
155 // state of all environment variables dyld uses
156 //
157 struct EnvironmentVariables {
158 const char* const * DYLD_FRAMEWORK_PATH;
159 const char* const * DYLD_FALLBACK_FRAMEWORK_PATH;
160 const char* const * DYLD_LIBRARY_PATH;
161 const char* const * DYLD_FALLBACK_LIBRARY_PATH;
162 const char* const * DYLD_INSERT_LIBRARIES;
163 const char* const * LD_LIBRARY_PATH; // for unix conformance
164 const char* const * DYLD_VERSIONED_LIBRARY_PATH;
165 const char* const * DYLD_VERSIONED_FRAMEWORK_PATH;
166 bool DYLD_PRINT_LIBRARIES;
167 bool DYLD_PRINT_LIBRARIES_POST_LAUNCH;
168 bool DYLD_BIND_AT_LAUNCH;
169 bool DYLD_PRINT_STATISTICS;
170 bool DYLD_PRINT_OPTS;
171 bool DYLD_PRINT_ENV;
172 bool DYLD_DISABLE_DOFS;
173 bool DYLD_PRINT_CS_NOTIFICATIONS;
174 // DYLD_SHARED_CACHE_DONT_VALIDATE ==> sSharedCacheIgnoreInodeAndTimeStamp
175 // DYLD_SHARED_CACHE_DIR ==> sSharedCacheDir
176 // DYLD_ROOT_PATH ==> gLinkContext.rootPaths
177 // DYLD_IMAGE_SUFFIX ==> gLinkContext.imageSuffix
178 // DYLD_PRINT_OPTS ==> gLinkContext.verboseOpts
179 // DYLD_PRINT_ENV ==> gLinkContext.verboseEnv
180 // DYLD_FORCE_FLAT_NAMESPACE ==> gLinkContext.bindFlat
181 // DYLD_PRINT_INITIALIZERS ==> gLinkContext.verboseInit
182 // DYLD_PRINT_SEGMENTS ==> gLinkContext.verboseMapping
183 // DYLD_PRINT_BINDINGS ==> gLinkContext.verboseBind
184 // DYLD_PRINT_WEAK_BINDINGS ==> gLinkContext.verboseWeakBind
185 // DYLD_PRINT_REBASINGS ==> gLinkContext.verboseRebase
186 // DYLD_PRINT_DOFS ==> gLinkContext.verboseDOF
187 // DYLD_PRINT_APIS ==> gLogAPIs
188 // DYLD_IGNORE_PREBINDING ==> gLinkContext.prebindUsage
189 // DYLD_PREBIND_DEBUG ==> gLinkContext.verbosePrebinding
190 // DYLD_NEW_LOCAL_SHARED_REGIONS ==> gLinkContext.sharedRegionMode
191 // DYLD_SHARED_REGION ==> gLinkContext.sharedRegionMode
192 // DYLD_PRINT_WARNINGS ==> gLinkContext.verboseWarnings
193 // DYLD_PRINT_RPATHS ==> gLinkContext.verboseRPaths
194 // DYLD_PRINT_INTERPOSING ==> gLinkContext.verboseInterposing
195 };
196
197
198
199 typedef std::vector<dyld_image_state_change_handler> StateHandlers;
200
201
202 enum RestrictedReason { restrictedNot, restrictedBySetGUid, restrictedBySegment, restrictedByEntitlements };
203
204 // all global state
205 static const char* sExecPath = NULL;
206 static const char* sExecShortName = NULL;
207 static const macho_header* sMainExecutableMachHeader = NULL;
208 #if CPU_SUBTYPES_SUPPORTED
209 static cpu_type_t sHostCPU;
210 static cpu_subtype_t sHostCPUsubtype;
211 #endif
212 static ImageLoader* sMainExecutable = NULL;
213 static bool sProcessIsRestricted = false;
214 static RestrictedReason sRestrictedReason = restrictedNot;
215 static unsigned int sInsertedDylibCount = 0;
216 static std::vector<ImageLoader*> sAllImages;
217 static std::vector<ImageLoader*> sImageRoots;
218 static std::vector<ImageLoader*> sImageFilesNeedingTermination;
219 static std::vector<RegisteredDOF> sImageFilesNeedingDOFUnregistration;
220 static std::vector<ImageCallback> sAddImageCallbacks;
221 static std::vector<ImageCallback> sRemoveImageCallbacks;
222 static void* sSingleHandlers[7][3];
223 static void* sBatchHandlers[7][3];
224 static ImageLoader* sLastImageByAddressCache;
225 static EnvironmentVariables sEnv;
226 static const char* sFrameworkFallbackPaths[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL };
227 static const char* sLibraryFallbackPaths[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL };
228 static UndefinedHandler sUndefinedHandler = NULL;
229 static ImageLoader* sBundleBeingLoaded = NULL; // hack until OFI is reworked
230 #if DYLD_SHARED_CACHE_SUPPORT
231 static const dyld_cache_header* sSharedCache = NULL;
232 static long sSharedCacheSlide = 0;
233 static bool sSharedCacheIgnoreInodeAndTimeStamp = false;
234 #if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT
235 bool gSharedCacheOverridden = false;
236 static const char* sSharedCacheDir = IPHONE_DYLD_SHARED_CACHE_DIR;
237 static bool sDylibsOverrideCache = false;
238 #else
239 static const char* sSharedCacheDir = MACOSX_DYLD_SHARED_CACHE_DIR;
240 #endif
241 #endif
242 ImageLoader::LinkContext gLinkContext;
243 bool gLogAPIs = false;
244 const struct LibSystemHelpers* gLibSystemHelpers = NULL;
245 #if SUPPORT_OLD_CRT_INITIALIZATION
246 bool gRunInitializersOldWay = false;
247 #endif
248 static std::vector<DylibOverride> sDylibOverrides;
249 #if !TARGET_IPHONE_SIMULATOR
250 static int sLogSocket = -1;
251 #endif
252 static bool sFrameworksFoundAsDylibs = false;
253
254 static std::vector<ImageLoader::DynamicReference> sDynamicReferences;
255
256
257 //
258 // The MappedRanges structure is used for fast address->image lookups.
259 // The table is only updated when the dyld lock is held, so we don't
260 // need to worry about multiple writers. But readers may look at this
261 // data without holding the lock. Therefore, all updates must be done
262 // in an order that will never cause readers to see inconsistent data.
263 // The general rule is that if the image field is non-NULL then
264 // the other fields are valid.
265 //
266 struct MappedRanges
267 {
268 enum { count=400 };
269 struct {
270 ImageLoader* image;
271 uintptr_t start;
272 uintptr_t end;
273 } array[count];
274 MappedRanges* next;
275 };
276
277 static MappedRanges sMappedRangesStart;
278
279 void addMappedRange(ImageLoader* image, uintptr_t start, uintptr_t end)
280 {
281 //dyld::log("addMappedRange(0x%lX->0x%lX) for %s\n", start, end, image->getShortName());
282 for (MappedRanges* p = &sMappedRangesStart; p != NULL; p = p->next) {
283 for (int i=0; i < MappedRanges::count; ++i) {
284 if ( p->array[i].image == NULL ) {
285 p->array[i].start = start;
286 p->array[i].end = end;
287 // add image field last with a barrier so that any reader will see consistent records
288 OSMemoryBarrier();
289 p->array[i].image = image;
290 return;
291 }
292 }
293 }
294 // table must be full, chain another
295 MappedRanges* newRanges = (MappedRanges*)malloc(sizeof(MappedRanges));
296 bzero(newRanges, sizeof(MappedRanges));
297 newRanges->array[0].start = start;
298 newRanges->array[0].end = end;
299 newRanges->array[0].image = image;
300 for (MappedRanges* p = &sMappedRangesStart; p != NULL; p = p->next) {
301 if ( p->next == NULL ) {
302 OSMemoryBarrier();
303 p->next = newRanges;
304 break;
305 }
306 }
307 }
308
309 void removedMappedRanges(ImageLoader* image)
310 {
311 for (MappedRanges* p = &sMappedRangesStart; p != NULL; p = p->next) {
312 for (int i=0; i < MappedRanges::count; ++i) {
313 if ( p->array[i].image == image ) {
314 // clear with a barrier so that any reader will see consistent records
315 OSMemoryBarrier();
316 p->array[i].image = NULL;
317 }
318 }
319 }
320 }
321
322 ImageLoader* findMappedRange(uintptr_t target)
323 {
324 for (MappedRanges* p = &sMappedRangesStart; p != NULL; p = p->next) {
325 for (int i=0; i < MappedRanges::count; ++i) {
326 if ( p->array[i].image != NULL ) {
327 if ( (p->array[i].start <= target) && (target < p->array[i].end) )
328 return p->array[i].image;
329 }
330 }
331 }
332 return NULL;
333 }
334
335
336
337 const char* mkstringf(const char* format, ...)
338 {
339 _SIMPLE_STRING buf = _simple_salloc();
340 if ( buf != NULL ) {
341 va_list list;
342 va_start(list, format);
343 _simple_vsprintf(buf, format, list);
344 va_end(list);
345 const char* t = strdup(_simple_string(buf));
346 _simple_sfree(buf);
347 if ( t != NULL )
348 return t;
349 }
350 return "mkstringf, out of memory error";
351 }
352
353
354 void throwf(const char* format, ...)
355 {
356 _SIMPLE_STRING buf = _simple_salloc();
357 if ( buf != NULL ) {
358 va_list list;
359 va_start(list, format);
360 _simple_vsprintf(buf, format, list);
361 va_end(list);
362 const char* t = strdup(_simple_string(buf));
363 _simple_sfree(buf);
364 if ( t != NULL )
365 throw t;
366 }
367 throw "throwf, out of memory error";
368 }
369
370
371 //#define ALTERNATIVE_LOGFILE "/dev/console"
372 #if !TARGET_IPHONE_SIMULATOR
373 static int sLogfile = STDERR_FILENO;
374 #endif
375
376 #if LOG_BINDINGS
377 static int sBindingsLogfile = -1;
378 static void mysprintf(char* dst, const char* format, ...)
379 {
380 _SIMPLE_STRING buf = _simple_salloc();
381 if ( buf != NULL ) {
382 va_list list;
383 va_start(list, format);
384 _simple_vsprintf(buf, format, list);
385 va_end(list);
386 strcpy(dst, _simple_string(buf));
387 _simple_sfree(buf);
388 }
389 else {
390 strcpy(dst, "out of memory");
391 }
392 }
393 void logBindings(const char* format, ...)
394 {
395 if ( sBindingsLogfile != -1 ) {
396 va_list list;
397 va_start(list, format);
398 _simple_vdprintf(sBindingsLogfile, format, list);
399 va_end(list);
400 }
401 }
402 #endif
403
404 #if !TARGET_IPHONE_SIMULATOR
405 // based on CFUtilities.c: also_do_stderr()
406 static bool useSyslog()
407 {
408 // Use syslog() for processes managed by launchd
409 if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 11) ) {
410 if ( (*gLibSystemHelpers->isLaunchdOwned)() ) {
411 return true;
412 }
413 }
414
415 // If stderr is not available, use syslog()
416 struct stat sb;
417 int result = fstat(STDERR_FILENO, &sb);
418 if ( result < 0 )
419 return true; // file descriptor 2 is closed
420
421 return false;
422 }
423
424
425 static void socket_syslogv(int priority, const char* format, va_list list)
426 {
427 // lazily create socket and connection to syslogd
428 if ( sLogSocket == -1 ) {
429 sLogSocket = ::socket(AF_UNIX, SOCK_DGRAM, 0);
430 if (sLogSocket == -1)
431 return; // cannot log
432 ::fcntl(sLogSocket, F_SETFD, 1);
433
434 struct sockaddr_un addr;
435 addr.sun_family = AF_UNIX;
436 strncpy(addr.sun_path, _PATH_LOG, sizeof(addr.sun_path));
437 if ( ::connect(sLogSocket, (struct sockaddr *)&addr, sizeof(addr)) == -1 ) {
438 ::close(sLogSocket);
439 sLogSocket = -1;
440 return;
441 }
442 }
443
444 // format message to syslogd like: "<priority>Process[pid]: message"
445 _SIMPLE_STRING buf = _simple_salloc();
446 if ( buf == NULL )
447 return;
448 if ( _simple_sprintf(buf, "<%d>%s[%d]: ", LOG_USER|LOG_NOTICE, sExecShortName, getpid()) == 0 ) {
449 if ( _simple_vsprintf(buf, format, list) == 0 ) {
450 const char* p = _simple_string(buf);
451 ::__sendto(sLogSocket, p, strlen(p), 0, NULL, 0);
452 }
453 }
454 _simple_sfree(buf);
455 }
456
457 void vlog(const char* format, va_list list)
458 {
459 if ( useSyslog() )
460 socket_syslogv(LOG_ERR, format, list);
461 else
462 _simple_vdprintf(sLogfile, format, list);
463 }
464
465 void log(const char* format, ...)
466 {
467 va_list list;
468 va_start(list, format);
469 vlog(format, list);
470 va_end(list);
471 }
472
473
474 void vwarn(const char* format, va_list list)
475 {
476 _simple_dprintf(sLogfile, "dyld: warning, ");
477 _simple_vdprintf(sLogfile, format, list);
478 }
479
480 void warn(const char* format, ...)
481 {
482 va_list list;
483 va_start(list, format);
484 vwarn(format, list);
485 va_end(list);
486 }
487
488
489 #endif // !TARGET_IPHONE_SIMULATOR
490
491
492 // <rdar://problem/8867781> control access to sAllImages through a lock
493 // because global dyld lock is not held during initialization phase of dlopen()
494 static long sAllImagesLock = 0;
495
496 static void allImagesLock()
497 {
498 //dyld::log("allImagesLock()\n");
499 while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)0, (void*)1, (void**)&sAllImagesLock) ) {
500 // spin
501 }
502 }
503
504 static void allImagesUnlock()
505 {
506 //dyld::log("allImagesUnlock()\n");
507 while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)1, (void*)0, (void**)&sAllImagesLock) ) {
508 // spin
509 }
510 }
511
512
513
514
515 // utility class to assure files are closed when an exception is thrown
516 class FileOpener {
517 public:
518 FileOpener(const char* path);
519 ~FileOpener();
520 int getFileDescriptor() { return fd; }
521 private:
522 int fd;
523 };
524
525 FileOpener::FileOpener(const char* path)
526 : fd(-1)
527 {
528 fd = my_open(path, O_RDONLY, 0);
529 }
530
531 FileOpener::~FileOpener()
532 {
533 if ( fd != -1 )
534 close(fd);
535 }
536
537
538 static void registerDOFs(const std::vector<ImageLoader::DOFInfo>& dofs)
539 {
540 const unsigned int dofSectionCount = dofs.size();
541 if ( !sEnv.DYLD_DISABLE_DOFS && (dofSectionCount != 0) ) {
542 int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
543 if ( fd < 0 ) {
544 //dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n");
545 }
546 else {
547 // allocate a buffer on the stack for the variable length dof_ioctl_data_t type
548 uint8_t buffer[sizeof(dof_ioctl_data_t) + dofSectionCount*sizeof(dof_helper_t)];
549 dof_ioctl_data_t* ioctlData = (dof_ioctl_data_t*)buffer;
550
551 // fill in buffer with one dof_helper_t per DOF section
552 ioctlData->dofiod_count = dofSectionCount;
553 for (unsigned int i=0; i < dofSectionCount; ++i) {
554 strlcpy(ioctlData->dofiod_helpers[i].dofhp_mod, dofs[i].imageShortName, DTRACE_MODNAMELEN);
555 ioctlData->dofiod_helpers[i].dofhp_dof = (uintptr_t)(dofs[i].dof);
556 ioctlData->dofiod_helpers[i].dofhp_addr = (uintptr_t)(dofs[i].dof);
557 }
558
559 // tell kernel about all DOF sections en mas
560 // pass pointer to ioctlData because ioctl() only copies a fixed size amount of data into kernel
561 user_addr_t val = (user_addr_t)(unsigned long)ioctlData;
562 if ( ioctl(fd, DTRACEHIOC_ADDDOF, &val) != -1 ) {
563 // kernel returns a unique identifier for each section in the dofiod_helpers[].dofhp_dof field.
564 for (unsigned int i=0; i < dofSectionCount; ++i) {
565 RegisteredDOF info;
566 info.mh = dofs[i].imageHeader;
567 info.registrationID = (int)(ioctlData->dofiod_helpers[i].dofhp_dof);
568 sImageFilesNeedingDOFUnregistration.push_back(info);
569 if ( gLinkContext.verboseDOF ) {
570 dyld::log("dyld: registering DOF section %p in %s with dtrace, ID=0x%08X\n",
571 dofs[i].dof, dofs[i].imageShortName, info.registrationID);
572 }
573 }
574 }
575 else {
576 dyld::log( "dyld: ioctl to register dtrace DOF section failed\n");
577 }
578 close(fd);
579 }
580 }
581 }
582
583 static void unregisterDOF(int registrationID)
584 {
585 int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
586 if ( fd < 0 ) {
587 dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to unregister dtrace DOF section\n");
588 }
589 else {
590 ioctl(fd, DTRACEHIOC_REMOVE, registrationID);
591 close(fd);
592 if ( gLinkContext.verboseInit )
593 dyld::warn("unregistering DOF section ID=0x%08X with dtrace\n", registrationID);
594 }
595 }
596
597
598 //
599 // _dyld_register_func_for_add_image() is implemented as part of the general image state change notification
600 //
601 static void notifyAddImageCallbacks(ImageLoader* image)
602 {
603 // use guard so that we cannot notify about the same image twice
604 if ( ! image->addFuncNotified() ) {
605 for (std::vector<ImageCallback>::iterator it=sAddImageCallbacks.begin(); it != sAddImageCallbacks.end(); it++)
606 (*it)(image->machHeader(), image->getSlide());
607 image->setAddFuncNotified();
608 }
609 }
610
611
612
613 // notify gdb about these new images
614 static const char* updateAllImages(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
615 {
616 // <rdar://problem/8812589> don't add images without paths to all-image-info-list
617 if ( info[0].imageFilePath != NULL )
618 addImagesToAllImages(infoCount, info);
619 return NULL;
620 }
621
622
623 static StateHandlers* stateToHandlers(dyld_image_states state, void* handlersArray[7][3])
624 {
625 switch ( state ) {
626 case dyld_image_state_mapped:
627 return reinterpret_cast<StateHandlers*>(&handlersArray[0]);
628
629 case dyld_image_state_dependents_mapped:
630 return reinterpret_cast<StateHandlers*>(&handlersArray[1]);
631
632 case dyld_image_state_rebased:
633 return reinterpret_cast<StateHandlers*>(&handlersArray[2]);
634
635 case dyld_image_state_bound:
636 return reinterpret_cast<StateHandlers*>(&handlersArray[3]);
637
638 case dyld_image_state_dependents_initialized:
639 return reinterpret_cast<StateHandlers*>(&handlersArray[4]);
640
641 case dyld_image_state_initialized:
642 return reinterpret_cast<StateHandlers*>(&handlersArray[5]);
643
644 case dyld_image_state_terminated:
645 return reinterpret_cast<StateHandlers*>(&handlersArray[6]);
646 }
647 return NULL;
648 }
649
650 static void notifySingle(dyld_image_states state, const ImageLoader* image)
651 {
652 //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath());
653 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
654 if ( handlers != NULL ) {
655 dyld_image_info info;
656 info.imageLoadAddress = image->machHeader();
657 info.imageFilePath = image->getRealPath();
658 info.imageFileModDate = image->lastModified();
659 for (std::vector<dyld_image_state_change_handler>::iterator it = handlers->begin(); it != handlers->end(); ++it) {
660 const char* result = (*it)(state, 1, &info);
661 if ( (result != NULL) && (state == dyld_image_state_mapped) ) {
662 //fprintf(stderr, " image rejected by handler=%p\n", *it);
663 // make copy of thrown string so that later catch clauses can free it
664 const char* str = strdup(result);
665 throw str;
666 }
667 }
668 }
669 if ( state == dyld_image_state_mapped ) {
670 // <rdar://problem/7008875> Save load addr + UUID for images from outside the shared cache
671 if ( !image->inSharedCache() ) {
672 dyld_uuid_info info;
673 if ( image->getUUID(info.imageUUID) ) {
674 info.imageLoadAddress = image->machHeader();
675 addNonSharedCacheImageUUID(info);
676 }
677 }
678 }
679 #if CORESYMBOLICATION_SUPPORT
680 // mach message csdlc about dynamically loaded images
681 if ( image->addFuncNotified() && (state == dyld_image_state_terminated) ) {
682 if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
683 dyld::log("dyld core symbolication unload notification: %p %s\n", image->machHeader(), image->getPath());
684 }
685 if ( dyld::gProcessInfo->coreSymbolicationShmPage != NULL) {
686 CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld::gProcessInfo->coreSymbolicationShmPage;
687 if ( connection->is_valid_version() ) {
688 coresymbolication_unload_image(connection, image);
689 }
690 }
691 }
692 #endif
693 }
694
695
696
697
698 //
699 // Normally, dyld_all_image_infos is only updated in batches after an entire
700 // graph is loaded. But if there is an error loading the initial set of
701 // dylibs needed by the main executable, dyld_all_image_infos is not yet set
702 // up, leading to usually brief crash logs.
703 //
704 // This function manually adds the images loaded so far to dyld::gProcessInfo.
705 // It should only be called before terminating.
706 //
707 void syncAllImages()
708 {
709 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
710 dyld_image_info info;
711 ImageLoader* image = *it;
712 info.imageLoadAddress = image->machHeader();
713 info.imageFilePath = image->getRealPath();
714 info.imageFileModDate = image->lastModified();
715 // add to all_image_infos if not already there
716 bool found = false;
717 int existingCount = dyld::gProcessInfo->infoArrayCount;
718 const dyld_image_info* existing = dyld::gProcessInfo->infoArray;
719 if ( existing != NULL ) {
720 for (int i=0; i < existingCount; ++i) {
721 if ( existing[i].imageLoadAddress == info.imageLoadAddress ) {
722 //dyld::log("not adding %s\n", info.imageFilePath);
723 found = true;
724 break;
725 }
726 }
727 }
728 if ( ! found ) {
729 //dyld::log("adding %s\n", info.imageFilePath);
730 addImagesToAllImages(1, &info);
731 }
732 }
733 }
734
735
736 static int imageSorter(const void* l, const void* r)
737 {
738 const ImageLoader* left = *((ImageLoader**)l);
739 const ImageLoader* right= *((ImageLoader**)r);
740 return left->compare(right);
741 }
742
743 static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image_state_change_handler onlyHandler)
744 {
745 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sBatchHandlers);
746 if ( handlers != NULL ) {
747 // don't use a vector because it will use malloc/free and we want notifcation to be low cost
748 allImagesLock();
749 ImageLoader* images[sAllImages.size()+1];
750 ImageLoader** end = images;
751 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
752 dyld_image_states imageState = (*it)->getState();
753 if ( (imageState == state) || (orLater && (imageState > state)) )
754 *end++ = *it;
755 }
756 if ( sBundleBeingLoaded != NULL ) {
757 dyld_image_states imageState = sBundleBeingLoaded->getState();
758 if ( (imageState == state) || (orLater && (imageState > state)) )
759 *end++ = sBundleBeingLoaded;
760 }
761 const char* dontLoadReason = NULL;
762 unsigned int count = end-images;
763 if ( end != images ) {
764 // sort bottom up
765 qsort(images, count, sizeof(ImageLoader*), &imageSorter);
766 // build info array
767 dyld_image_info infos[count];
768 for (unsigned int i=0; i < count; ++i) {
769 dyld_image_info* p = &infos[i];
770 ImageLoader* image = images[i];
771 //dyld::log(" state=%d, name=%s\n", state, image->getPath());
772 p->imageLoadAddress = image->machHeader();
773 p->imageFilePath = image->getRealPath();
774 p->imageFileModDate = image->lastModified();
775 // special case for add_image hook
776 if ( state == dyld_image_state_bound )
777 notifyAddImageCallbacks(image);
778 }
779
780 if ( onlyHandler != NULL ) {
781 const char* result = (*onlyHandler)(state, count, infos);
782 if ( (result != NULL) && (state == dyld_image_state_dependents_mapped) ) {
783 //fprintf(stderr, " images rejected by handler=%p\n", onlyHandler);
784 // make copy of thrown string so that later catch clauses can free it
785 dontLoadReason = strdup(result);
786 }
787 }
788 else {
789 // call each handler with whole array
790 for (std::vector<dyld_image_state_change_handler>::iterator it = handlers->begin(); it != handlers->end(); ++it) {
791 const char* result = (*it)(state, count, infos);
792 if ( (result != NULL) && (state == dyld_image_state_dependents_mapped) ) {
793 //fprintf(stderr, " images rejected by handler=%p\n", *it);
794 // make copy of thrown string so that later catch clauses can free it
795 dontLoadReason = strdup(result);
796 break;
797 }
798 }
799 }
800 }
801 allImagesUnlock();
802 if ( dontLoadReason != NULL )
803 throw dontLoadReason;
804 }
805 #if CORESYMBOLICATION_SUPPORT
806 if ( state == dyld_image_state_rebased ) {
807 if ( sEnv.DYLD_PRINT_CS_NOTIFICATIONS ) {
808 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
809 dyld_image_states imageState = (*it)->getState();
810 if ( (imageState == dyld_image_state_rebased) || (orLater && (imageState > dyld_image_state_rebased)) )
811 dyld::log("dyld core symbolication load notification: %p %s\n", (*it)->machHeader(), (*it)->getPath());
812 }
813 }
814 if ( dyld::gProcessInfo->coreSymbolicationShmPage != NULL) {
815 CSCppDyldSharedMemoryPage* connection = (CSCppDyldSharedMemoryPage*)dyld::gProcessInfo->coreSymbolicationShmPage;
816 if ( connection->is_valid_version() ) {
817 // This needs to be captured now
818 uint64_t load_timestamp = mach_absolute_time();
819 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
820 dyld_image_states imageState = (*it)->getState();
821 if ( (imageState == state) || (orLater && (imageState > state)) )
822 coresymbolication_load_image(connection, *it, load_timestamp);
823 }
824 }
825 }
826 }
827 #endif
828 }
829
830
831
832 static void notifyBatch(dyld_image_states state)
833 {
834 notifyBatchPartial(state, false, NULL);
835 }
836
837 // In order for register_func_for_add_image() callbacks to to be called bottom up,
838 // we need to maintain a list of root images. The main executable is usally the
839 // first root. Any images dynamically added are also roots (unless already loaded).
840 // If DYLD_INSERT_LIBRARIES is used, those libraries are first.
841 static void addRootImage(ImageLoader* image)
842 {
843 //dyld::log("addRootImage(%p, %s)\n", image, image->getPath());
844 // add to list of roots
845 sImageRoots.push_back(image);
846 }
847
848
849 static void clearAllDepths()
850 {
851 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++)
852 (*it)->clearDepth();
853 }
854
855 static void printAllDepths()
856 {
857 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++)
858 dyld::log("%03d %s\n", (*it)->getDepth(), (*it)->getShortName());
859 }
860
861
862 static unsigned int imageCount()
863 {
864 return sAllImages.size();
865 }
866
867
868 static void setNewProgramVars(const ProgramVars& newVars)
869 {
870 // make a copy of the pointers to program variables
871 gLinkContext.programVars = newVars;
872
873 // now set each program global to their initial value
874 *gLinkContext.programVars.NXArgcPtr = gLinkContext.argc;
875 *gLinkContext.programVars.NXArgvPtr = gLinkContext.argv;
876 *gLinkContext.programVars.environPtr = gLinkContext.envp;
877 *gLinkContext.programVars.__prognamePtr = gLinkContext.progname;
878 }
879
880 #if SUPPORT_OLD_CRT_INITIALIZATION
881 static void setRunInitialzersOldWay()
882 {
883 gRunInitializersOldWay = true;
884 }
885 #endif
886
887 static void addDynamicReference(ImageLoader* from, ImageLoader* to) {
888 // don't add dynamic reference if either are in the shared cache
889 if( from->inSharedCache() )
890 return;
891 if( to->inSharedCache() )
892 return;
893
894 // don't add dynamic reference if there already is a static one
895 if ( from->dependsOn(to) )
896 return;
897
898 // don't add if this combination already exists
899 for (std::vector<ImageLoader::DynamicReference>::iterator it=sDynamicReferences.begin(); it != sDynamicReferences.end(); ++it) {
900 if ( (it->from == from) && (it->to == to) )
901 return;
902 }
903 //dyld::log("addDynamicReference(%s, %s\n", from->getShortName(), to->getShortName());
904 ImageLoader::DynamicReference t;
905 t.from = from;
906 t.to = to;
907 sDynamicReferences.push_back(t);
908 }
909
910 static void addImage(ImageLoader* image)
911 {
912 // add to master list
913 allImagesLock();
914 sAllImages.push_back(image);
915 allImagesUnlock();
916
917 // update mapped ranges
918 uintptr_t lastSegStart = 0;
919 uintptr_t lastSegEnd = 0;
920 for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
921 if ( image->segUnaccessible(i) )
922 continue;
923 uintptr_t start = image->segActualLoadAddress(i);
924 uintptr_t end = image->segActualEndAddress(i);
925 if ( start == lastSegEnd ) {
926 // two segments are contiguous, just record combined segments
927 lastSegEnd = end;
928 }
929 else {
930 // non-contiguous segments, record last (if any)
931 if ( lastSegEnd != 0 )
932 addMappedRange(image, lastSegStart, lastSegEnd);
933 lastSegStart = start;
934 lastSegEnd = end;
935 }
936 }
937 if ( lastSegEnd != 0 )
938 addMappedRange(image, lastSegStart, lastSegEnd);
939
940
941 if ( sEnv.DYLD_PRINT_LIBRARIES || (sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH && (sMainExecutable!=NULL) && sMainExecutable->isLinked()) ) {
942 dyld::log("dyld: loaded: %s\n", image->getPath());
943 }
944
945 }
946
947 //
948 // Helper for std::remove_if
949 //
950 class RefUsesImage {
951 public:
952 RefUsesImage(ImageLoader* image) : _image(image) {}
953 bool operator()(const ImageLoader::DynamicReference& ref) const {
954 return ( (ref.from == _image) || (ref.to == _image) );
955 }
956 private:
957 ImageLoader* _image;
958 };
959
960
961
962 void removeImage(ImageLoader* image)
963 {
964 // if has dtrace DOF section, tell dtrace it is going away, then remove from sImageFilesNeedingDOFUnregistration
965 for (std::vector<RegisteredDOF>::iterator it=sImageFilesNeedingDOFUnregistration.begin(); it != sImageFilesNeedingDOFUnregistration.end(); ) {
966 if ( it->mh == image->machHeader() ) {
967 unregisterDOF(it->registrationID);
968 sImageFilesNeedingDOFUnregistration.erase(it);
969 // don't increment iterator, the erase caused next element to be copied to where this iterator points
970 }
971 else {
972 ++it;
973 }
974 }
975
976 // tell all registered remove image handlers about this
977 // do this before removing image from internal data structures so that the callback can query dyld about the image
978 if ( image->getState() >= dyld_image_state_bound ) {
979 for (std::vector<ImageCallback>::iterator it=sRemoveImageCallbacks.begin(); it != sRemoveImageCallbacks.end(); it++) {
980 (*it)(image->machHeader(), image->getSlide());
981 }
982 }
983
984 // notify
985 notifySingle(dyld_image_state_terminated, image);
986
987 // remove from mapped images table
988 removedMappedRanges(image);
989
990 // remove from master list
991 allImagesLock();
992 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
993 if ( *it == image ) {
994 sAllImages.erase(it);
995 break;
996 }
997 }
998 allImagesUnlock();
999
1000 // remove from sDynamicReferences
1001 sDynamicReferences.erase(std::remove_if(sDynamicReferences.begin(), sDynamicReferences.end(), RefUsesImage(image)), sDynamicReferences.end());
1002
1003 // flush find-by-address cache (do this after removed from master list, so there is no chance it can come back)
1004 if ( sLastImageByAddressCache == image )
1005 sLastImageByAddressCache = NULL;
1006
1007 // if in root list, pull it out
1008 for (std::vector<ImageLoader*>::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) {
1009 if ( *it == image ) {
1010 sImageRoots.erase(it);
1011 break;
1012 }
1013 }
1014
1015 // log if requested
1016 if ( sEnv.DYLD_PRINT_LIBRARIES || (sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH && (sMainExecutable!=NULL) && sMainExecutable->isLinked()) ) {
1017 dyld::log("dyld: unloaded: %s\n", image->getPath());
1018 }
1019
1020 // tell gdb, new way
1021 removeImageFromAllImages(image->machHeader());
1022 }
1023
1024
1025 void runImageTerminators(ImageLoader* image)
1026 {
1027 // if in termination list, pull it out and run terminator
1028 bool mightBeMore;
1029 do {
1030 mightBeMore = false;
1031 for (std::vector<ImageLoader*>::iterator it=sImageFilesNeedingTermination.begin(); it != sImageFilesNeedingTermination.end(); it++) {
1032 if ( *it == image ) {
1033 sImageFilesNeedingTermination.erase(it);
1034 image->doTermination(gLinkContext);
1035 mightBeMore = true;
1036 break;
1037 }
1038 }
1039 } while ( mightBeMore );
1040
1041 // <rdar://problem/7740779> dyld should directly call __cxa_finalize()
1042 if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 8) )
1043 (*gLibSystemHelpers->cxa_finalize)(image->machHeader());
1044
1045 }
1046
1047 static void terminationRecorder(ImageLoader* image)
1048 {
1049 sImageFilesNeedingTermination.push_back(image);
1050 }
1051
1052 const char* getExecutablePath()
1053 {
1054 return sExecPath;
1055 }
1056
1057
1058 void initializeMainExecutable()
1059 {
1060 // record that we've reached this step
1061 gLinkContext.startedInitializingMainExecutable = true;
1062
1063 // run initialzers for any inserted dylibs
1064 ImageLoader::InitializerTimingList initializerTimes[sAllImages.size()];
1065 const int rootCount = sImageRoots.size();
1066 if ( rootCount > 1 ) {
1067 for(int i=1; i < rootCount; ++i) {
1068 initializerTimes[0].count = 0;
1069 sImageRoots[i]->runInitializers(gLinkContext, initializerTimes[0]);
1070 }
1071 }
1072
1073 // run initializers for main executable and everything it brings up
1074 initializerTimes[0].count = 0;
1075 sMainExecutable->runInitializers(gLinkContext, initializerTimes[0]);
1076
1077 // register atexit() handler to run terminators in all loaded images when this process exits
1078 if ( gLibSystemHelpers != NULL )
1079 (*gLibSystemHelpers->cxa_atexit)(&runTerminators, NULL, NULL);
1080
1081 // dump info if requested
1082 if ( sEnv.DYLD_PRINT_STATISTICS )
1083 ImageLoaderMachO::printStatistics(sAllImages.size(), initializerTimes[0]);
1084 }
1085
1086 bool mainExecutablePrebound()
1087 {
1088 return sMainExecutable->usablePrebinding(gLinkContext);
1089 }
1090
1091 ImageLoader* mainExecutable()
1092 {
1093 return sMainExecutable;
1094 }
1095
1096
1097 void runTerminators(void* extra)
1098 {
1099 try {
1100 const unsigned int imageCount = sImageFilesNeedingTermination.size();
1101 for(unsigned int i=imageCount; i > 0; --i){
1102 ImageLoader* image = sImageFilesNeedingTermination[i-1];
1103 image->doTermination(gLinkContext);
1104 }
1105 sImageFilesNeedingTermination.clear();
1106 notifyBatch(dyld_image_state_terminated);
1107 }
1108 catch (const char* msg) {
1109 halt(msg);
1110 }
1111 }
1112
1113
1114 #if SUPPORT_VERSIONED_PATHS
1115
1116 // forward reference
1117 static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName);
1118
1119
1120 //
1121 // Examines a dylib file and if its current_version is newer than the installed
1122 // dylib at its install_name, then add the dylib file to sDylibOverrides.
1123 //
1124 static void checkDylibOverride(const char* dylibFile)
1125 {
1126 //dyld::log("checkDylibOverride('%s')\n", dylibFile);
1127 uint32_t altVersion;
1128 char sysInstallName[PATH_MAX];
1129 if ( getDylibVersionAndInstallname(dylibFile, &altVersion, sysInstallName) ) {
1130 //dyld::log("%s has version 0x%08X and install name %s\n", dylibFile, altVersion, sysInstallName);
1131 uint32_t sysVersion;
1132 if ( getDylibVersionAndInstallname(sysInstallName, &sysVersion, NULL) ) {
1133 //dyld::log("%s has version 0x%08X\n", sysInstallName, sysVersion);
1134 if ( altVersion > sysVersion ) {
1135 //dyld::log("override found: %s -> %s\n", sysInstallName, dylibFile);
1136 // see if there already is an override for this dylib
1137 bool entryExists = false;
1138 for (std::vector<DylibOverride>::iterator it = sDylibOverrides.begin(); it != sDylibOverrides.end(); ++it) {
1139 if ( strcmp(it->installName, sysInstallName) == 0 ) {
1140 entryExists = true;
1141 uint32_t prevVersion;
1142 if ( getDylibVersionAndInstallname(it->override, &prevVersion, NULL) ) {
1143 if ( altVersion > prevVersion ) {
1144 // found an even newer override
1145 free((void*)(it->override));
1146 char resolvedPath[PATH_MAX];
1147 if ( realpath(dylibFile, resolvedPath) != NULL )
1148 it->override = strdup(resolvedPath);
1149 else
1150 it->override = strdup(dylibFile);
1151 break;
1152 }
1153 }
1154 }
1155 }
1156 if ( ! entryExists ) {
1157 DylibOverride entry;
1158 entry.installName = strdup(sysInstallName);
1159 char resolvedPath[PATH_MAX];
1160 if ( realpath(dylibFile, resolvedPath) != NULL )
1161 entry.override = strdup(resolvedPath);
1162 else
1163 entry.override = strdup(dylibFile);
1164 sDylibOverrides.push_back(entry);
1165 //dyld::log("added override: %s -> %s\n", entry.installName, entry.override);
1166 }
1167 }
1168 }
1169 }
1170
1171 }
1172
1173 static void checkDylibOverridesInDir(const char* dirPath)
1174 {
1175 //dyld::log("checkDylibOverridesInDir('%s')\n", dirPath);
1176 char dylibPath[PATH_MAX];
1177 int dirPathLen = strlen(dirPath);
1178 strlcpy(dylibPath, dirPath, PATH_MAX);
1179 DIR* dirp = opendir(dirPath);
1180 if ( dirp != NULL) {
1181 dirent entry;
1182 dirent* entp = NULL;
1183 while ( readdir_r(dirp, &entry, &entp) == 0 ) {
1184 if ( entp == NULL )
1185 break;
1186 if ( entp->d_type != DT_REG )
1187 continue;
1188 dylibPath[dirPathLen] = '/';
1189 dylibPath[dirPathLen+1] = '\0';
1190 if ( strlcat(dylibPath, entp->d_name, PATH_MAX) > PATH_MAX )
1191 continue;
1192 checkDylibOverride(dylibPath);
1193 }
1194 closedir(dirp);
1195 }
1196 }
1197
1198
1199 static void checkFrameworkOverridesInDir(const char* dirPath)
1200 {
1201 //dyld::log("checkFrameworkOverridesInDir('%s')\n", dirPath);
1202 char frameworkPath[PATH_MAX];
1203 int dirPathLen = strlen(dirPath);
1204 strlcpy(frameworkPath, dirPath, PATH_MAX);
1205 DIR* dirp = opendir(dirPath);
1206 if ( dirp != NULL) {
1207 dirent entry;
1208 dirent* entp = NULL;
1209 while ( readdir_r(dirp, &entry, &entp) == 0 ) {
1210 if ( entp == NULL )
1211 break;
1212 if ( entp->d_type != DT_DIR )
1213 continue;
1214 frameworkPath[dirPathLen] = '/';
1215 frameworkPath[dirPathLen+1] = '\0';
1216 int dirNameLen = strlen(entp->d_name);
1217 if ( dirNameLen < 11 )
1218 continue;
1219 if ( strcmp(&entp->d_name[dirNameLen-10], ".framework") != 0 )
1220 continue;
1221 if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) > PATH_MAX )
1222 continue;
1223 if ( strlcat(frameworkPath, "/", PATH_MAX) > PATH_MAX )
1224 continue;
1225 if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) > PATH_MAX )
1226 continue;
1227 frameworkPath[strlen(frameworkPath)-10] = '\0';
1228 checkDylibOverride(frameworkPath);
1229 }
1230 closedir(dirp);
1231 }
1232 }
1233 #endif // SUPPORT_VERSIONED_PATHS
1234
1235
1236 //
1237 // Turns a colon separated list of strings into a NULL terminated array
1238 // of string pointers. If mainExecutableDir param is not NULL,
1239 // substitutes @loader_path with main executable's dir.
1240 //
1241 static const char** parseColonList(const char* list, const char* mainExecutableDir)
1242 {
1243 static const char* sEmptyList[] = { NULL };
1244
1245 if ( list[0] == '\0' )
1246 return sEmptyList;
1247
1248 int colonCount = 0;
1249 for(const char* s=list; *s != '\0'; ++s) {
1250 if (*s == ':')
1251 ++colonCount;
1252 }
1253
1254 int index = 0;
1255 const char* start = list;
1256 char** result = new char*[colonCount+2];
1257 for(const char* s=list; *s != '\0'; ++s) {
1258 if (*s == ':') {
1259 int len = s-start;
1260 if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
1261 int mainExecDirLen = strlen(mainExecutableDir);
1262 char* str = new char[mainExecDirLen+len+1];
1263 strcpy(str, mainExecutableDir);
1264 strlcat(str, &start[13], mainExecDirLen+len+1);
1265 str[mainExecDirLen+len-13] = '\0';
1266 start = &s[1];
1267 result[index++] = str;
1268 }
1269 else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
1270 int mainExecDirLen = strlen(mainExecutableDir);
1271 char* str = new char[mainExecDirLen+len+1];
1272 strcpy(str, mainExecutableDir);
1273 strlcat(str, &start[17], mainExecDirLen+len+1);
1274 str[mainExecDirLen+len-17] = '\0';
1275 start = &s[1];
1276 result[index++] = str;
1277 }
1278 else {
1279 char* str = new char[len+1];
1280 strncpy(str, start, len);
1281 str[len] = '\0';
1282 start = &s[1];
1283 result[index++] = str;
1284 }
1285 }
1286 }
1287 int len = strlen(start);
1288 if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
1289 int mainExecDirLen = strlen(mainExecutableDir);
1290 char* str = new char[mainExecDirLen+len+1];
1291 strcpy(str, mainExecutableDir);
1292 strlcat(str, &start[13], mainExecDirLen+len+1);
1293 str[mainExecDirLen+len-13] = '\0';
1294 result[index++] = str;
1295 }
1296 else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
1297 int mainExecDirLen = strlen(mainExecutableDir);
1298 char* str = new char[mainExecDirLen+len+1];
1299 strcpy(str, mainExecutableDir);
1300 strlcat(str, &start[17], mainExecDirLen+len+1);
1301 str[mainExecDirLen+len-17] = '\0';
1302 result[index++] = str;
1303 }
1304 else {
1305 char* str = new char[len+1];
1306 strcpy(str, start);
1307 result[index++] = str;
1308 }
1309 result[index] = NULL;
1310
1311 //dyld::log("parseColonList(%s)\n", list);
1312 //for(int i=0; result[i] != NULL; ++i)
1313 // dyld::log(" %s\n", result[i]);
1314 return (const char**)result;
1315 }
1316
1317 static void appendParsedColonList(const char* list, const char* mainExecutableDir, const char* const ** storage)
1318 {
1319 const char** newlist = parseColonList(list, mainExecutableDir);
1320 if ( *storage == NULL ) {
1321 // first time, just set
1322 *storage = newlist;
1323 }
1324 else {
1325 // need to append to existing list
1326 const char* const* existing = *storage;
1327 int count = 0;
1328 for(int i=0; existing[i] != NULL; ++i)
1329 ++count;
1330 for(int i=0; newlist[i] != NULL; ++i)
1331 ++count;
1332 const char** combinedList = new const char*[count+2];
1333 int index = 0;
1334 for(int i=0; existing[i] != NULL; ++i)
1335 combinedList[index++] = existing[i];
1336 for(int i=0; newlist[i] != NULL; ++i)
1337 combinedList[index++] = newlist[i];
1338 combinedList[index] = NULL;
1339 // leak old arrays
1340 *storage = combinedList;
1341 }
1342 }
1343
1344
1345 static void paths_expand_roots(const char **paths, const char *key, const char *val)
1346 {
1347 // assert(val != NULL);
1348 // assert(paths != NULL);
1349 if(NULL != key) {
1350 size_t keyLen = strlen(key);
1351 for(int i=0; paths[i] != NULL; ++i) {
1352 if ( strncmp(paths[i], key, keyLen) == 0 ) {
1353 char* newPath = new char[strlen(val) + (strlen(paths[i]) - keyLen) + 1];
1354 strcpy(newPath, val);
1355 strcat(newPath, &paths[i][keyLen]);
1356 paths[i] = newPath;
1357 }
1358 }
1359 }
1360 return;
1361 }
1362
1363 static void removePathWithPrefix(const char* paths[], const char* prefix)
1364 {
1365 size_t prefixLen = strlen(prefix);
1366 int skip = 0;
1367 int i;
1368 for(i = 0; paths[i] != NULL; ++i) {
1369 if ( strncmp(paths[i], prefix, prefixLen) == 0 )
1370 ++skip;
1371 else
1372 paths[i-skip] = paths[i];
1373 }
1374 paths[i-skip] = NULL;
1375 }
1376
1377
1378 #if 0
1379 static void paths_dump(const char **paths)
1380 {
1381 // assert(paths != NULL);
1382 const char **strs = paths;
1383 while(*strs != NULL)
1384 {
1385 dyld::log("\"%s\"\n", *strs);
1386 strs++;
1387 }
1388 return;
1389 }
1390 #endif
1391
1392 static void printOptions(const char* argv[])
1393 {
1394 uint32_t i = 0;
1395 while ( NULL != argv[i] ) {
1396 dyld::log("opt[%i] = \"%s\"\n", i, argv[i]);
1397 i++;
1398 }
1399 }
1400
1401 static void printEnvironmentVariables(const char* envp[])
1402 {
1403 while ( NULL != *envp ) {
1404 dyld::log("%s\n", *envp);
1405 envp++;
1406 }
1407 }
1408
1409 void processDyldEnvironmentVariable(const char* key, const char* value, const char* mainExecutableDir)
1410 {
1411 if ( strcmp(key, "DYLD_FRAMEWORK_PATH") == 0 ) {
1412 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FRAMEWORK_PATH);
1413 }
1414 else if ( strcmp(key, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) {
1415 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FALLBACK_FRAMEWORK_PATH);
1416 }
1417 else if ( strcmp(key, "DYLD_LIBRARY_PATH") == 0 ) {
1418 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_LIBRARY_PATH);
1419 }
1420 else if ( strcmp(key, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) {
1421 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FALLBACK_LIBRARY_PATH);
1422 }
1423 else if ( (strcmp(key, "DYLD_ROOT_PATH") == 0) || (strcmp(key, "DYLD_PATHS_ROOT") == 0) ) {
1424 if ( strcmp(value, "/") != 0 ) {
1425 gLinkContext.rootPaths = parseColonList(value, mainExecutableDir);
1426 for (int i=0; gLinkContext.rootPaths[i] != NULL; ++i) {
1427 if ( gLinkContext.rootPaths[i][0] != '/' ) {
1428 dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n");
1429 gLinkContext.rootPaths = NULL;
1430 break;
1431 }
1432 }
1433 }
1434 }
1435 else if ( strcmp(key, "DYLD_IMAGE_SUFFIX") == 0 ) {
1436 gLinkContext.imageSuffix = value;
1437 }
1438 else if ( strcmp(key, "DYLD_INSERT_LIBRARIES") == 0 ) {
1439 sEnv.DYLD_INSERT_LIBRARIES = parseColonList(value, NULL);
1440 }
1441 else if ( strcmp(key, "DYLD_PRINT_OPTS") == 0 ) {
1442 sEnv.DYLD_PRINT_OPTS = true;
1443 }
1444 else if ( strcmp(key, "DYLD_PRINT_ENV") == 0 ) {
1445 sEnv.DYLD_PRINT_ENV = true;
1446 }
1447 else if ( strcmp(key, "DYLD_DISABLE_DOFS") == 0 ) {
1448 sEnv.DYLD_DISABLE_DOFS = true;
1449 }
1450 else if ( strcmp(key, "DYLD_DISABLE_PREFETCH") == 0 ) {
1451 gLinkContext.preFetchDisabled = true;
1452 }
1453 else if ( strcmp(key, "DYLD_PRINT_LIBRARIES") == 0 ) {
1454 sEnv.DYLD_PRINT_LIBRARIES = true;
1455 }
1456 else if ( strcmp(key, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) {
1457 sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH = true;
1458 }
1459 else if ( strcmp(key, "DYLD_BIND_AT_LAUNCH") == 0 ) {
1460 sEnv.DYLD_BIND_AT_LAUNCH = true;
1461 }
1462 else if ( strcmp(key, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) {
1463 gLinkContext.bindFlat = true;
1464 }
1465 else if ( strcmp(key, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) {
1466 // ignore, no longer relevant but some scripts still set it
1467 }
1468 else if ( strcmp(key, "DYLD_NO_FIX_PREBINDING") == 0 ) {
1469 }
1470 else if ( strcmp(key, "DYLD_PREBIND_DEBUG") == 0 ) {
1471 gLinkContext.verbosePrebinding = true;
1472 }
1473 else if ( strcmp(key, "DYLD_PRINT_INITIALIZERS") == 0 ) {
1474 gLinkContext.verboseInit = true;
1475 }
1476 else if ( strcmp(key, "DYLD_PRINT_DOFS") == 0 ) {
1477 gLinkContext.verboseDOF = true;
1478 }
1479 else if ( strcmp(key, "DYLD_PRINT_STATISTICS") == 0 ) {
1480 sEnv.DYLD_PRINT_STATISTICS = true;
1481 }
1482 else if ( strcmp(key, "DYLD_PRINT_SEGMENTS") == 0 ) {
1483 gLinkContext.verboseMapping = true;
1484 }
1485 else if ( strcmp(key, "DYLD_PRINT_BINDINGS") == 0 ) {
1486 gLinkContext.verboseBind = true;
1487 }
1488 else if ( strcmp(key, "DYLD_PRINT_WEAK_BINDINGS") == 0 ) {
1489 gLinkContext.verboseWeakBind = true;
1490 }
1491 else if ( strcmp(key, "DYLD_PRINT_REBASINGS") == 0 ) {
1492 gLinkContext.verboseRebase = true;
1493 }
1494 else if ( strcmp(key, "DYLD_PRINT_APIS") == 0 ) {
1495 gLogAPIs = true;
1496 }
1497 else if ( strcmp(key, "DYLD_PRINT_WARNINGS") == 0 ) {
1498 gLinkContext.verboseWarnings = true;
1499 }
1500 else if ( strcmp(key, "DYLD_PRINT_RPATHS") == 0 ) {
1501 gLinkContext.verboseRPaths = true;
1502 }
1503 else if ( strcmp(key, "DYLD_PRINT_CS_NOTIFICATIONS") == 0 ) {
1504 sEnv.DYLD_PRINT_CS_NOTIFICATIONS = true;
1505 }
1506 else if ( strcmp(key, "DYLD_PRINT_INTERPOSING") == 0 ) {
1507 gLinkContext.verboseInterposing = true;
1508 }
1509 else if ( strcmp(key, "DYLD_PRINT_CODE_SIGNATURES") == 0 ) {
1510 gLinkContext.verboseCodeSignatures = true;
1511 }
1512 else if ( strcmp(key, "DYLD_SHARED_REGION") == 0 ) {
1513 if ( strcmp(value, "private") == 0 ) {
1514 gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
1515 }
1516 else if ( strcmp(value, "avoid") == 0 ) {
1517 gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
1518 }
1519 else if ( strcmp(value, "use") == 0 ) {
1520 gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion;
1521 }
1522 else if ( value[0] == '\0' ) {
1523 gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion;
1524 }
1525 else {
1526 dyld::warn("unknown option to DYLD_SHARED_REGION. Valid options are: use, private, avoid\n");
1527 }
1528 }
1529 #if DYLD_SHARED_CACHE_SUPPORT
1530 else if ( strcmp(key, "DYLD_SHARED_CACHE_DIR") == 0 ) {
1531 sSharedCacheDir = value;
1532 }
1533 else if ( strcmp(key, "DYLD_SHARED_CACHE_DONT_VALIDATE") == 0 ) {
1534 sSharedCacheIgnoreInodeAndTimeStamp = true;
1535 }
1536 #endif
1537 else if ( strcmp(key, "DYLD_IGNORE_PREBINDING") == 0 ) {
1538 if ( strcmp(value, "all") == 0 ) {
1539 gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
1540 }
1541 else if ( strcmp(value, "app") == 0 ) {
1542 gLinkContext.prebindUsage = ImageLoader::kUseAllButAppPredbinding;
1543 }
1544 else if ( strcmp(value, "nonsplit") == 0 ) {
1545 gLinkContext.prebindUsage = ImageLoader::kUseSplitSegPrebinding;
1546 }
1547 else if ( value[0] == '\0' ) {
1548 gLinkContext.prebindUsage = ImageLoader::kUseSplitSegPrebinding;
1549 }
1550 else {
1551 dyld::warn("unknown option to DYLD_IGNORE_PREBINDING. Valid options are: all, app, nonsplit\n");
1552 }
1553 }
1554 #if SUPPORT_VERSIONED_PATHS
1555 else if ( strcmp(key, "DYLD_VERSIONED_LIBRARY_PATH") == 0 ) {
1556 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_VERSIONED_LIBRARY_PATH);
1557 }
1558 else if ( strcmp(key, "DYLD_VERSIONED_FRAMEWORK_PATH") == 0 ) {
1559 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_VERSIONED_FRAMEWORK_PATH);
1560 }
1561 #endif
1562 else {
1563 dyld::warn("unknown environment variable: %s\n", key);
1564 }
1565 }
1566
1567
1568 #if SUPPORT_LC_DYLD_ENVIRONMENT
1569 static void checkLoadCommandEnvironmentVariables()
1570 {
1571 // <rdar://problem/8440934> Support augmenting dyld environment variables in load commands
1572 const uint32_t cmd_count = sMainExecutableMachHeader->ncmds;
1573 const struct load_command* const cmds = (struct load_command*)(((char*)sMainExecutableMachHeader)+sizeof(macho_header));
1574 const struct load_command* cmd = cmds;
1575 for (uint32_t i = 0; i < cmd_count; ++i) {
1576 switch (cmd->cmd) {
1577 case LC_DYLD_ENVIRONMENT:
1578 {
1579 const struct dylinker_command* envcmd = (struct dylinker_command*)cmd;
1580 const char* keyEqualsValue = (char*)envcmd + envcmd->name.offset;
1581 char mainExecutableDir[strlen(sExecPath)];
1582 strcpy(mainExecutableDir, sExecPath);
1583 char* lastSlash = strrchr(mainExecutableDir, '/');
1584 if ( lastSlash != NULL)
1585 lastSlash[1] = '\0';
1586 // only process variables that start with DYLD_ and end in _PATH
1587 if ( (strncmp(keyEqualsValue, "DYLD_", 5) == 0) ) {
1588 const char* equals = strchr(keyEqualsValue, '=');
1589 if ( equals != NULL ) {
1590 if ( strncmp(&equals[-5], "_PATH", 5) == 0 ) {
1591 const char* value = &equals[1];
1592 const int keyLen = equals-keyEqualsValue;
1593 char key[keyLen+1];
1594 strncpy(key, keyEqualsValue, keyLen);
1595 key[keyLen] = '\0';
1596 //dyld::log("processing: %s\n", keyEqualsValue);
1597 //dyld::log("mainExecutableDir: %s\n", mainExecutableDir);
1598 processDyldEnvironmentVariable(key, value, mainExecutableDir);
1599 }
1600 }
1601 }
1602 }
1603 break;
1604 }
1605 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1606 }
1607 }
1608 #endif // SUPPORT_LC_DYLD_ENVIRONMENT
1609
1610
1611 static bool hasCodeSignatureLoadCommand(const macho_header* mh)
1612 {
1613 const uint32_t cmd_count = mh->ncmds;
1614 const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
1615 const struct load_command* cmd = cmds;
1616 for (uint32_t i = 0; i < cmd_count; ++i) {
1617 if (cmd->cmd == LC_CODE_SIGNATURE)
1618 return true;
1619 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1620 }
1621 return false;
1622 }
1623
1624
1625 #if SUPPORT_VERSIONED_PATHS
1626 static void checkVersionedPaths()
1627 {
1628 // search DYLD_VERSIONED_LIBRARY_PATH directories for dylibs and check if they are newer
1629 if ( sEnv.DYLD_VERSIONED_LIBRARY_PATH != NULL ) {
1630 for(const char* const* lp = sEnv.DYLD_VERSIONED_LIBRARY_PATH; *lp != NULL; ++lp) {
1631 checkDylibOverridesInDir(*lp);
1632 }
1633 }
1634
1635 // search DYLD_VERSIONED_FRAMEWORK_PATH directories for dylibs and check if they are newer
1636 if ( sEnv.DYLD_VERSIONED_FRAMEWORK_PATH != NULL ) {
1637 for(const char* const* fp = sEnv.DYLD_VERSIONED_FRAMEWORK_PATH; *fp != NULL; ++fp) {
1638 checkFrameworkOverridesInDir(*fp);
1639 }
1640 }
1641 }
1642 #endif
1643
1644
1645 //
1646 // For security, setuid programs ignore DYLD_* environment variables.
1647 // Additionally, the DYLD_* enviroment variables are removed
1648 // from the environment, so that any child processes don't see them.
1649 //
1650 static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
1651 {
1652 // delete all DYLD_* and LD_LIBRARY_PATH environment variables
1653 int removedCount = 0;
1654 const char** d = envp;
1655 for(const char** s = envp; *s != NULL; s++) {
1656 if ( (strncmp(*s, "DYLD_", 5) != 0) && (strncmp(*s, "LD_LIBRARY_PATH=", 16) != 0) ) {
1657 *d++ = *s;
1658 }
1659 else {
1660 ++removedCount;
1661 }
1662 }
1663 *d++ = NULL;
1664 // <rdar://11894054> Disable warnings about DYLD_ env vars being ignored. The warnings are causing too much confusion.
1665 #if 0
1666 if ( removedCount != 0 ) {
1667 dyld::log("dyld: DYLD_ environment variables being ignored because ");
1668 switch (sRestrictedReason) {
1669 case restrictedNot:
1670 break;
1671 case restrictedBySetGUid:
1672 dyld::log("main executable (%s) is setuid or setgid\n", sExecPath);
1673 break;
1674 case restrictedBySegment:
1675 dyld::log("main executable (%s) has __RESTRICT/__restrict section\n", sExecPath);
1676 break;
1677 case restrictedByEntitlements:
1678 dyld::log("main executable (%s) is code signed with entitlements\n", sExecPath);
1679 break;
1680 }
1681 }
1682 #endif
1683 // slide apple parameters
1684 if ( removedCount > 0 ) {
1685 *applep = d;
1686 do {
1687 *d = d[removedCount];
1688 } while ( *d++ != NULL );
1689 for(int i=0; i < removedCount; ++i)
1690 *d++ = NULL;
1691 }
1692
1693 // disable framework and library fallback paths for setuid binaries rdar://problem/4589305
1694 sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = NULL;
1695 sEnv.DYLD_FALLBACK_LIBRARY_PATH = NULL;
1696 }
1697
1698
1699 static void checkEnvironmentVariables(const char* envp[], bool ignoreEnviron)
1700 {
1701 const char* home = NULL;
1702 const char** p;
1703 for(p = envp; *p != NULL; p++) {
1704 const char* keyEqualsValue = *p;
1705 if ( strncmp(keyEqualsValue, "DYLD_", 5) == 0 ) {
1706 const char* equals = strchr(keyEqualsValue, '=');
1707 if ( (equals != NULL) && !ignoreEnviron ) {
1708 const char* value = &equals[1];
1709 const int keyLen = equals-keyEqualsValue;
1710 char key[keyLen+1];
1711 strncpy(key, keyEqualsValue, keyLen);
1712 key[keyLen] = '\0';
1713 processDyldEnvironmentVariable(key, value, NULL);
1714 }
1715 }
1716 else if ( strncmp(keyEqualsValue, "HOME=", 5) == 0 ) {
1717 home = &keyEqualsValue[5];
1718 }
1719 else if ( strncmp(keyEqualsValue, "LD_LIBRARY_PATH=", 16) == 0 ) {
1720 const char* path = &keyEqualsValue[16];
1721 sEnv.LD_LIBRARY_PATH = parseColonList(path, NULL);
1722 }
1723 }
1724
1725 #if SUPPORT_LC_DYLD_ENVIRONMENT
1726 checkLoadCommandEnvironmentVariables();
1727 #endif // SUPPORT_LC_DYLD_ENVIRONMENT
1728
1729 // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
1730 if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
1731 const char** paths = sFrameworkFallbackPaths;
1732 if ( home == NULL )
1733 removePathWithPrefix(paths, "$HOME");
1734 else
1735 paths_expand_roots(paths, "$HOME", home);
1736 sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = paths;
1737 }
1738
1739 // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment
1740 if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL ) {
1741 const char** paths = sLibraryFallbackPaths;
1742 if ( home == NULL )
1743 removePathWithPrefix(paths, "$HOME");
1744 else
1745 paths_expand_roots(paths, "$HOME", home);
1746 sEnv.DYLD_FALLBACK_LIBRARY_PATH = paths;
1747 }
1748
1749 // <rdar://problem/11281064> DYLD_IMAGE_SUFFIX and DYLD_ROOT_PATH cannot be used together
1750 if ( (gLinkContext.imageSuffix != NULL) && (gLinkContext.rootPaths != NULL) ) {
1751 dyld::warn("Ignoring DYLD_IMAGE_SUFFIX because DYLD_ROOT_PATH is used.\n");
1752 gLinkContext.imageSuffix = NULL;
1753 }
1754
1755 #if SUPPORT_VERSIONED_PATHS
1756 checkVersionedPaths();
1757 #endif
1758 }
1759
1760
1761 static void getHostInfo()
1762 {
1763 #if CPU_SUBTYPES_SUPPORTED
1764 #if __ARM_ARCH_7A__
1765 sHostCPU = CPU_TYPE_ARM;
1766 sHostCPUsubtype = CPU_SUBTYPE_ARM_V7;
1767 #elif __ARM_ARCH_6K__
1768 sHostCPU = CPU_TYPE_ARM;
1769 sHostCPUsubtype = CPU_SUBTYPE_ARM_V6;
1770 #elif __ARM_ARCH_7F__
1771 sHostCPU = CPU_TYPE_ARM;
1772 sHostCPUsubtype = CPU_SUBTYPE_ARM_V7F;
1773 #elif __ARM_ARCH_7S__
1774 sHostCPU = CPU_TYPE_ARM;
1775 sHostCPUsubtype = CPU_SUBTYPE_ARM_V7S;
1776 #elif __ARM_ARCH_7K__
1777 sHostCPU = CPU_TYPE_ARM;
1778 sHostCPUsubtype = CPU_SUBTYPE_ARM_V7K;
1779 #else
1780 struct host_basic_info info;
1781 mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
1782 mach_port_t hostPort = mach_host_self();
1783 kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
1784 if ( result != KERN_SUCCESS )
1785 throw "host_info() failed";
1786 sHostCPU = info.cpu_type;
1787 sHostCPUsubtype = info.cpu_subtype;
1788 #endif
1789 #endif
1790 }
1791
1792 static void checkSharedRegionDisable()
1793 {
1794 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1795 // if main executable has segments that overlap the shared region,
1796 // then disable using the shared region
1797 if ( sMainExecutable->overlapsWithAddressRange((void*)(uintptr_t)SHARED_REGION_BASE, (void*)(uintptr_t)(SHARED_REGION_BASE + SHARED_REGION_SIZE)) ) {
1798 gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
1799 if ( gLinkContext.verboseMapping )
1800 dyld::warn("disabling shared region because main executable overlaps\n");
1801 }
1802 #endif
1803 // iPhoneOS cannot run without shared region
1804 }
1805
1806 bool validImage(const ImageLoader* possibleImage)
1807 {
1808 const unsigned int imageCount = sAllImages.size();
1809 for(unsigned int i=0; i < imageCount; ++i) {
1810 if ( possibleImage == sAllImages[i] ) {
1811 return true;
1812 }
1813 }
1814 return false;
1815 }
1816
1817 uint32_t getImageCount()
1818 {
1819 return sAllImages.size();
1820 }
1821
1822 ImageLoader* getIndexedImage(unsigned int index)
1823 {
1824 if ( index < sAllImages.size() )
1825 return sAllImages[index];
1826 return NULL;
1827 }
1828
1829 ImageLoader* findImageByMachHeader(const struct mach_header* target)
1830 {
1831 return findMappedRange((uintptr_t)target);
1832 }
1833
1834
1835 ImageLoader* findImageContainingAddress(const void* addr)
1836 {
1837 return findMappedRange((uintptr_t)addr);
1838 }
1839
1840
1841 ImageLoader* findImageContainingSymbol(const void* symbol)
1842 {
1843 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
1844 ImageLoader* anImage = *it;
1845 if ( anImage->containsSymbol(symbol) )
1846 return anImage;
1847 }
1848 return NULL;
1849 }
1850
1851
1852
1853 void forEachImageDo( void (*callback)(ImageLoader*, void* userData), void* userData)
1854 {
1855 const unsigned int imageCount = sAllImages.size();
1856 for(unsigned int i=0; i < imageCount; ++i) {
1857 ImageLoader* anImage = sAllImages[i];
1858 (*callback)(anImage, userData);
1859 }
1860 }
1861
1862 ImageLoader* findLoadedImage(const struct stat& stat_buf)
1863 {
1864 const unsigned int imageCount = sAllImages.size();
1865 for(unsigned int i=0; i < imageCount; ++i){
1866 ImageLoader* anImage = sAllImages[i];
1867 if ( anImage->statMatch(stat_buf) )
1868 return anImage;
1869 }
1870 return NULL;
1871 }
1872
1873 // based on ANSI-C strstr()
1874 static const char* strrstr(const char* str, const char* sub)
1875 {
1876 const int sublen = strlen(sub);
1877 for(const char* p = &str[strlen(str)]; p != str; --p) {
1878 if ( strncmp(p, sub, sublen) == 0 )
1879 return p;
1880 }
1881 return NULL;
1882 }
1883
1884
1885 //
1886 // Find framework path
1887 //
1888 // /path/foo.framework/foo => foo.framework/foo
1889 // /path/foo.framework/Versions/A/foo => foo.framework/Versions/A/foo
1890 // /path/foo.framework/Frameworks/bar.framework/bar => bar.framework/bar
1891 // /path/foo.framework/Libraries/bar.dylb => NULL
1892 // /path/foo.framework/bar => NULL
1893 //
1894 // Returns NULL if not a framework path
1895 //
1896 static const char* getFrameworkPartialPath(const char* path)
1897 {
1898 const char* dirDot = strrstr(path, ".framework/");
1899 if ( dirDot != NULL ) {
1900 const char* dirStart = dirDot;
1901 for ( ; dirStart >= path; --dirStart) {
1902 if ( (*dirStart == '/') || (dirStart == path) ) {
1903 const char* frameworkStart = &dirStart[1];
1904 if ( dirStart == path )
1905 --frameworkStart;
1906 int len = dirDot - frameworkStart;
1907 char framework[len+1];
1908 strncpy(framework, frameworkStart, len);
1909 framework[len] = '\0';
1910 const char* leaf = strrchr(path, '/');
1911 if ( leaf != NULL ) {
1912 if ( strcmp(framework, &leaf[1]) == 0 ) {
1913 return frameworkStart;
1914 }
1915 if ( gLinkContext.imageSuffix != NULL ) {
1916 // some debug frameworks have install names that end in _debug
1917 if ( strncmp(framework, &leaf[1], len) == 0 ) {
1918 if ( strcmp( gLinkContext.imageSuffix, &leaf[len+1]) == 0 )
1919 return frameworkStart;
1920 }
1921 }
1922 }
1923 }
1924 }
1925 }
1926 return NULL;
1927 }
1928
1929
1930 static const char* getLibraryLeafName(const char* path)
1931 {
1932 const char* start = strrchr(path, '/');
1933 if ( start != NULL )
1934 return &start[1];
1935 else
1936 return path;
1937 }
1938
1939
1940 // only for architectures that use cpu-sub-types
1941 #if CPU_SUBTYPES_SUPPORTED
1942
1943 const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST = -1;
1944
1945
1946 //
1947 // A fat file may contain multiple sub-images for the same CPU type.
1948 // In that case, dyld picks which sub-image to use by scanning a table
1949 // of preferred cpu-sub-types for the running cpu.
1950 //
1951 // There is one row in the table for each cpu-sub-type on which dyld might run.
1952 // The first entry in a row is that cpu-sub-type. It is followed by all
1953 // cpu-sub-types that can run on that cpu, if preferred order. Each row ends with
1954 // a "SUBTYPE_ALL" (to denote that images written to run on any cpu-sub-type are usable),
1955 // followed by one or more CPU_SUBTYPE_END_OF_LIST to pad out this row.
1956 //
1957
1958
1959 #if __arm__
1960 //
1961 // ARM sub-type lists
1962 //
1963 const int kARM_RowCount = 8;
1964 static const cpu_subtype_t kARM[kARM_RowCount][9] = {
1965
1966 // armv7f can run: v7f, v7, v6, v5, and v4
1967 { 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 },
1968
1969 // armv7k can run: v7k, v6, v5, and v4
1970 { 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 },
1971
1972 // armv7s can run: v7s, v7, v7f, v7k, v6, v5, and v4
1973 { CPU_SUBTYPE_ARM_V7S, CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V7F, 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 },
1974
1975 // armv7 can run: v7, v6, v5, and v4
1976 { 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 },
1977
1978 // armv6 can run: v6, v5, and v4
1979 { 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 },
1980
1981 // xscale can run: xscale, v5, and v4
1982 { 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 },
1983
1984 // armv5 can run: v5 and v4
1985 { 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 },
1986
1987 // armv4 can run: v4
1988 { 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 },
1989 };
1990 #endif
1991
1992
1993 // scan the tables above to find the cpu-sub-type-list for this machine
1994 static const cpu_subtype_t* findCPUSubtypeList(cpu_type_t cpu, cpu_subtype_t subtype)
1995 {
1996 switch (cpu) {
1997 #if __arm__
1998 case CPU_TYPE_ARM:
1999 for (int i=0; i < kARM_RowCount ; ++i) {
2000 if ( kARM[i][0] == subtype )
2001 return kARM[i];
2002 }
2003 break;
2004 #endif
2005 }
2006 return NULL;
2007 }
2008
2009
2010
2011
2012 // scan fat table-of-contents for best most preferred subtype
2013 static bool fatFindBestFromOrderedList(cpu_type_t cpu, const cpu_subtype_t list[], const fat_header* fh, uint64_t* offset, uint64_t* len)
2014 {
2015 const fat_arch* const archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
2016 for (uint32_t subTypeIndex=0; list[subTypeIndex] != CPU_SUBTYPE_END_OF_LIST; ++subTypeIndex) {
2017 for(uint32_t fatIndex=0; fatIndex < OSSwapBigToHostInt32(fh->nfat_arch); ++fatIndex) {
2018 if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[fatIndex].cputype) == cpu)
2019 && (list[subTypeIndex] == (cpu_subtype_t)OSSwapBigToHostInt32(archs[fatIndex].cpusubtype)) ) {
2020 *offset = OSSwapBigToHostInt32(archs[fatIndex].offset);
2021 *len = OSSwapBigToHostInt32(archs[fatIndex].size);
2022 return true;
2023 }
2024 }
2025 }
2026 return false;
2027 }
2028
2029 // scan fat table-of-contents for exact match of cpu and cpu-sub-type
2030 static bool fatFindExactMatch(cpu_type_t cpu, cpu_subtype_t subtype, const fat_header* fh, uint64_t* offset, uint64_t* len)
2031 {
2032 const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
2033 for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
2034 if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu)
2035 && ((cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == subtype) ) {
2036 *offset = OSSwapBigToHostInt32(archs[i].offset);
2037 *len = OSSwapBigToHostInt32(archs[i].size);
2038 return true;
2039 }
2040 }
2041 return false;
2042 }
2043
2044 // scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types
2045 static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t* offset, uint64_t* len)
2046 {
2047 const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
2048 for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
2049 if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu) {
2050 switch (cpu) {
2051 #if __arm__
2052 case CPU_TYPE_ARM:
2053 if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_ARM_ALL ) {
2054 *offset = OSSwapBigToHostInt32(archs[i].offset);
2055 *len = OSSwapBigToHostInt32(archs[i].size);
2056 return true;
2057 }
2058 break;
2059 #endif
2060 }
2061 }
2062 }
2063 return false;
2064 }
2065
2066 #endif // CPU_SUBTYPES_SUPPORTED
2067
2068 //
2069 // A fat file may contain multiple sub-images for the same cpu-type,
2070 // each optimized for a different cpu-sub-type (e.g G3 or G5).
2071 // This routine picks the optimal sub-image.
2072 //
2073 static bool fatFindBest(const fat_header* fh, uint64_t* offset, uint64_t* len)
2074 {
2075 #if CPU_SUBTYPES_SUPPORTED
2076 // assume all dylibs loaded must have same cpu type as main executable
2077 const cpu_type_t cpu = sMainExecutableMachHeader->cputype;
2078
2079 // We only know the subtype to use if the main executable cpu type matches the host
2080 if ( (cpu & CPU_TYPE_MASK) == sHostCPU ) {
2081 // get preference ordered list of subtypes
2082 const cpu_subtype_t* subTypePreferenceList = findCPUSubtypeList(cpu, sHostCPUsubtype);
2083
2084 // use ordered list to find best sub-image in fat file
2085 if ( subTypePreferenceList != NULL )
2086 return fatFindBestFromOrderedList(cpu, subTypePreferenceList, fh, offset, len);
2087
2088 // if running cpu is not in list, try for an exact match
2089 if ( fatFindExactMatch(cpu, sHostCPUsubtype, fh, offset, len) )
2090 return true;
2091 }
2092
2093 // running on an uknown cpu, can only load generic code
2094 return fatFindRunsOnAllCPUs(cpu, fh, offset, len);
2095 #else
2096 // just find first slice with matching architecture
2097 const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
2098 for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
2099 if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == sMainExecutableMachHeader->cputype) {
2100 *offset = OSSwapBigToHostInt32(archs[i].offset);
2101 *len = OSSwapBigToHostInt32(archs[i].size);
2102 return true;
2103 }
2104 }
2105 return false;
2106 #endif
2107 }
2108
2109
2110
2111 //
2112 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used
2113 // on the current processor. //
2114 bool isCompatibleMachO(const uint8_t* firstPage, const char* path)
2115 {
2116 #if CPU_SUBTYPES_SUPPORTED
2117 // It is deemed compatible if any of the following are true:
2118 // 1) mach_header subtype is in list of compatible subtypes for running processor
2119 // 2) mach_header subtype is same as running processor subtype
2120 // 3) mach_header subtype runs on all processor variants
2121 const mach_header* mh = (mach_header*)firstPage;
2122 if ( mh->magic == sMainExecutableMachHeader->magic ) {
2123 if ( mh->cputype == sMainExecutableMachHeader->cputype ) {
2124 if ( (mh->cputype & CPU_TYPE_MASK) == sHostCPU ) {
2125 // get preference ordered list of subtypes that this machine can use
2126 const cpu_subtype_t* subTypePreferenceList = findCPUSubtypeList(mh->cputype, sHostCPUsubtype);
2127 if ( subTypePreferenceList != NULL ) {
2128 // if image's subtype is in the list, it is compatible
2129 for (const cpu_subtype_t* p = subTypePreferenceList; *p != CPU_SUBTYPE_END_OF_LIST; ++p) {
2130 if ( *p == mh->cpusubtype )
2131 return true;
2132 }
2133 // have list and not in list, so not compatible
2134 throwf("incompatible cpu-subtype: 0x%08X in %s", mh->cpusubtype, path);
2135 }
2136 // unknown cpu sub-type, but if exact match for current subtype then ok to use
2137 if ( mh->cpusubtype == sHostCPUsubtype )
2138 return true;
2139 }
2140
2141 // cpu type has no ordered list of subtypes
2142 switch (mh->cputype) {
2143 case CPU_TYPE_I386:
2144 case CPU_TYPE_X86_64:
2145 // subtypes are not used or these architectures
2146 return true;
2147 }
2148 }
2149 }
2150 #else
2151 // For architectures that don't support cpu-sub-types
2152 // this just check the cpu type.
2153 const mach_header* mh = (mach_header*)firstPage;
2154 if ( mh->magic == sMainExecutableMachHeader->magic ) {
2155 if ( mh->cputype == sMainExecutableMachHeader->cputype ) {
2156 return true;
2157 }
2158 }
2159 #endif
2160 return false;
2161 }
2162
2163
2164
2165
2166 // The kernel maps in main executable before dyld gets control. We need to
2167 // make an ImageLoader* for the already mapped in main executable.
2168 static ImageLoader* instantiateFromLoadedImage(const macho_header* mh, uintptr_t slide, const char* path)
2169 {
2170 // try mach-o loader
2171 if ( isCompatibleMachO((const uint8_t*)mh, path) ) {
2172 ImageLoader* image = ImageLoaderMachO::instantiateMainExecutable(mh, slide, path, gLinkContext);
2173 addImage(image);
2174 return image;
2175 }
2176
2177 throw "main executable not a known format";
2178 }
2179
2180
2181 #if DYLD_SHARED_CACHE_SUPPORT
2182 static bool findInSharedCacheImage(const char* path, const struct stat* stat_buf, const macho_header** mh, const char** pathInCache, long* slide)
2183 {
2184 if ( sSharedCache != NULL ) {
2185 #if __MAC_OS_X_VERSION_MIN_REQUIRED
2186 // Mac OS X always requires inode/mtime to valid cache
2187 // if stat() not done yet, do it now
2188 struct stat statb;
2189 if ( stat_buf == NULL ) {
2190 if ( my_stat(path, &statb) == -1 )
2191 return false;
2192 stat_buf = &statb;
2193 }
2194 #endif
2195 // walk shared cache to see if there is a cached image that matches the inode/mtime/path desired
2196 const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)sSharedCache + sSharedCache->imagesOffset);
2197 const dyld_cache_image_info* const end = &start[sSharedCache->imagesCount];
2198 for( const dyld_cache_image_info* p = start; p != end; ++p) {
2199 #if __IPHONE_OS_VERSION_MIN_REQUIRED
2200 // just check path
2201 const char* aPath = (char*)sSharedCache + p->pathFileOffset;
2202 if ( strcmp(path, aPath) == 0 ) {
2203 // found image in cache
2204 *mh = (macho_header*)(p->address+sSharedCacheSlide);
2205 *pathInCache = aPath;
2206 *slide = sSharedCacheSlide;
2207 return true;
2208 }
2209 #elif __MAC_OS_X_VERSION_MIN_REQUIRED
2210 // check mtime and inode first because it is fast
2211 if ( sSharedCacheIgnoreInodeAndTimeStamp
2212 || ( ((time_t)p->modTime == stat_buf->st_mtime) && ((ino_t)p->inode == stat_buf->st_ino) ) ) {
2213 // mod-time and inode match an image in the shared cache, now check path
2214 const char* aPath = (char*)sSharedCache + p->pathFileOffset;
2215 bool cacheHit = (strcmp(path, aPath) == 0);
2216 if ( ! cacheHit ) {
2217 // path does not match install name of dylib in cache, but inode and mtime does match
2218 // perhaps path is a symlink to the cached dylib
2219 struct stat pathInCacheStatBuf;
2220 if ( my_stat(aPath, &pathInCacheStatBuf) != -1 )
2221 cacheHit = ( (pathInCacheStatBuf.st_dev == stat_buf->st_dev) && (pathInCacheStatBuf.st_ino == stat_buf->st_ino) );
2222 }
2223 if ( cacheHit ) {
2224 // found image in cache, return info
2225 *mh = (macho_header*)(p->address+sSharedCacheSlide);
2226 //dyld::log("findInSharedCacheImage(), mh=%p, p->address=0x%0llX, slid=0x%0lX, path=%p\n",
2227 // *mh, p->address, sSharedCacheSlide, aPath);
2228 *pathInCache = aPath;
2229 *slide = sSharedCacheSlide;
2230 return true;
2231 }
2232 }
2233 #endif
2234 }
2235 }
2236 return false;
2237 }
2238
2239 bool inSharedCache(const char* path)
2240 {
2241 const macho_header* mhInCache;
2242 const char* pathInCache;
2243 long slide;
2244 return findInSharedCacheImage(path, NULL, &mhInCache, &pathInCache, &slide);
2245 }
2246
2247 #endif
2248
2249 static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& context)
2250 {
2251 // now sanity check that this loaded image does not have the same install path as any existing image
2252 const char* loadedImageInstallPath = image->getInstallPath();
2253 if ( image->isDylib() && (loadedImageInstallPath != NULL) && (loadedImageInstallPath[0] == '/') ) {
2254 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
2255 ImageLoader* anImage = *it;
2256 const char* installPath = anImage->getInstallPath();
2257 if ( installPath != NULL) {
2258 if ( strcmp(loadedImageInstallPath, installPath) == 0 ) {
2259 //dyld::log("duplicate(%s) => %p\n", installPath, anImage);
2260 removeImage(image);
2261 ImageLoader::deleteImage(image);
2262 return anImage;
2263 }
2264 }
2265 }
2266 }
2267
2268 // some API's restrict what they can load
2269 if ( context.mustBeBundle && !image->isBundle() )
2270 throw "not a bundle";
2271 if ( context.mustBeDylib && !image->isDylib() )
2272 throw "not a dylib";
2273
2274 // regular main executables cannot be loaded
2275 if ( image->isExecutable() ) {
2276 if ( !context.canBePIE || !image->isPositionIndependentExecutable() )
2277 throw "can't load a main executable";
2278 }
2279
2280 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
2281 if ( ! image->isBundle() )
2282 addImage(image);
2283
2284 return image;
2285 }
2286
2287 // map in file and instantiate an ImageLoader
2288 static ImageLoader* loadPhase6(int fd, const struct stat& stat_buf, const char* path, const LoadContext& context)
2289 {
2290 //dyld::log("%s(%s)\n", __func__ , path);
2291 uint64_t fileOffset = 0;
2292 uint64_t fileLength = stat_buf.st_size;
2293
2294 // validate it is a file (not directory)
2295 if ( (stat_buf.st_mode & S_IFMT) != S_IFREG )
2296 throw "not a file";
2297
2298 uint8_t firstPage[4096];
2299 bool shortPage = false;
2300
2301 // min mach-o file is 4K
2302 if ( fileLength < 4096 ) {
2303 if ( pread(fd, firstPage, fileLength, 0) != (ssize_t)fileLength )
2304 throwf("pread of short file failed: %d", errno);
2305 shortPage = true;
2306 }
2307 else {
2308 if ( pread(fd, firstPage, 4096,0) != 4096 )
2309 throwf("pread of first 4K failed: %d", errno);
2310 }
2311
2312 // if fat wrapper, find usable sub-file
2313 const fat_header* fileStartAsFat = (fat_header*)firstPage;
2314 if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
2315 if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) {
2316 if ( (fileOffset+fileLength) > (uint64_t)(stat_buf.st_size) )
2317 throwf("truncated fat file. file length=%llu, but needed slice goes to %llu", stat_buf.st_size, fileOffset+fileLength);
2318 if (pread(fd, firstPage, 4096, fileOffset) != 4096)
2319 throwf("pread of fat file failed: %d", errno);
2320 }
2321 else {
2322 throw "no matching architecture in universal wrapper";
2323 }
2324 }
2325
2326 // try mach-o loader
2327 if ( shortPage )
2328 throw "file too short";
2329 if ( isCompatibleMachO(firstPage, path) ) {
2330
2331 // only MH_BUNDLE, MH_DYLIB, and some MH_EXECUTE can be dynamically loaded
2332 switch ( ((mach_header*)firstPage)->filetype ) {
2333 case MH_EXECUTE:
2334 case MH_DYLIB:
2335 case MH_BUNDLE:
2336 break;
2337 default:
2338 throw "mach-o, but wrong filetype";
2339 }
2340
2341 // instantiate an image
2342 ImageLoader* image = ImageLoaderMachO::instantiateFromFile(path, fd, firstPage, fileOffset, fileLength, stat_buf, gLinkContext);
2343
2344 // validate
2345 return checkandAddImage(image, context);
2346 }
2347
2348 // try other file formats here...
2349
2350
2351 // throw error about what was found
2352 switch (*(uint32_t*)firstPage) {
2353 case MH_MAGIC:
2354 case MH_CIGAM:
2355 case MH_MAGIC_64:
2356 case MH_CIGAM_64:
2357 throw "mach-o, but wrong architecture";
2358 default:
2359 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
2360 firstPage[0], firstPage[1], firstPage[2], firstPage[3], firstPage[4], firstPage[5], firstPage[6],firstPage[7]);
2361 }
2362 }
2363
2364
2365 static ImageLoader* loadPhase5open(const char* path, const LoadContext& context, const struct stat& stat_buf, std::vector<const char*>* exceptions)
2366 {
2367 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2368
2369 // open file (automagically closed when this function exits)
2370 FileOpener file(path);
2371
2372 // just return NULL if file not found, but record any other errors
2373 if ( file.getFileDescriptor() == -1 ) {
2374 int err = errno;
2375 if ( err != ENOENT ) {
2376 const char* newMsg = dyld::mkstringf("%s: open() failed with errno=%d", path, err);
2377 exceptions->push_back(newMsg);
2378 }
2379 return NULL;
2380 }
2381
2382 try {
2383 return loadPhase6(file.getFileDescriptor(), stat_buf, path, context);
2384 }
2385 catch (const char* msg) {
2386 const char* newMsg = dyld::mkstringf("%s: %s", path, msg);
2387 exceptions->push_back(newMsg);
2388 free((void*)msg);
2389 return NULL;
2390 }
2391 }
2392
2393
2394 #if __MAC_OS_X_VERSION_MIN_REQUIRED
2395 static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
2396 {
2397 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2398 ImageLoader* image = NULL;
2399
2400 // just return NULL if file not found, but record any other errors
2401 struct stat stat_buf;
2402 if ( my_stat(path, &stat_buf) == -1 ) {
2403 int err = errno;
2404 if ( err != ENOENT ) {
2405 exceptions->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path, err));
2406 }
2407 return NULL;
2408 }
2409
2410 // in case image was renamed or found via symlinks, check for inode match
2411 image = findLoadedImage(stat_buf);
2412 if ( image != NULL )
2413 return image;
2414
2415 // do nothing if not already loaded and if RTLD_NOLOAD or NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
2416 if ( context.dontLoad )
2417 return NULL;
2418
2419 #if DYLD_SHARED_CACHE_SUPPORT
2420 // see if this image is in shared cache
2421 const macho_header* mhInCache;
2422 const char* pathInCache;
2423 long slideInCache;
2424 if ( findInSharedCacheImage(path, &stat_buf, &mhInCache, &pathInCache, &slideInCache) ) {
2425 image = ImageLoaderMachO::instantiateFromCache(mhInCache, pathInCache, slideInCache, stat_buf, gLinkContext);
2426 return checkandAddImage(image, context);
2427 }
2428 #endif
2429 // file exists and is not in dyld shared cache, so open it
2430 return loadPhase5open(path, context, stat_buf, exceptions);
2431 }
2432 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED
2433
2434
2435
2436 #if __IPHONE_OS_VERSION_MIN_REQUIRED
2437 static ImageLoader* loadPhase5stat(const char* path, const LoadContext& context, struct stat* stat_buf,
2438 int* statErrNo, bool* imageFound, std::vector<const char*>* exceptions)
2439 {
2440 ImageLoader* image = NULL;
2441 *imageFound = false;
2442 *statErrNo = 0;
2443 if ( my_stat(path, stat_buf) == 0 ) {
2444 // in case image was renamed or found via symlinks, check for inode match
2445 image = findLoadedImage(*stat_buf);
2446 if ( image != NULL ) {
2447 *imageFound = true;
2448 return image;
2449 }
2450 // do nothing if not already loaded and if RTLD_NOLOAD
2451 if ( context.dontLoad ) {
2452 *imageFound = true;
2453 return NULL;
2454 }
2455 image = loadPhase5open(path, context, *stat_buf, exceptions);
2456 if ( image != NULL ) {
2457 *imageFound = true;
2458 return image;
2459 }
2460 }
2461 else {
2462 *statErrNo = errno;
2463 }
2464 return NULL;
2465 }
2466
2467 // try to open file
2468 static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
2469 {
2470 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2471 struct stat stat_buf;
2472 bool imageFound;
2473 int statErrNo;
2474 ImageLoader* image;
2475 #if DYLD_SHARED_CACHE_SUPPORT
2476 if ( sDylibsOverrideCache ) {
2477 // flag is set that allows installed framework roots to override dyld shared cache
2478 image = loadPhase5stat(path, context, &stat_buf, &statErrNo, &imageFound, exceptions);
2479 if ( imageFound )
2480 return image;
2481 }
2482 // see if this image is in shared cache
2483 const macho_header* mhInCache;
2484 const char* pathInCache;
2485 long slideInCache;
2486 if ( findInSharedCacheImage(path, NULL, &mhInCache, &pathInCache, &slideInCache) ) {
2487 // see if this image in the cache was already loaded via a different path
2488 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
2489 ImageLoader* anImage = *it;
2490 if ( (const macho_header*)anImage->machHeader() == mhInCache )
2491 return anImage;
2492 }
2493 // do nothing if not already loaded and if RTLD_NOLOAD
2494 if ( context.dontLoad )
2495 return NULL;
2496 // nope, so instantiate a new image from dyld shared cache
2497 // <rdar://problem/7014995> zero out stat buffer so mtime, etc are zero for items from the shared cache
2498 bzero(&stat_buf, sizeof(stat_buf));
2499 image = ImageLoaderMachO::instantiateFromCache(mhInCache, pathInCache, slideInCache, stat_buf, gLinkContext);
2500 return checkandAddImage(image, context);
2501 }
2502
2503 if ( !sDylibsOverrideCache ) {
2504 // flag is not set, and not in cache to try opening it
2505 image = loadPhase5stat(path, context, &stat_buf, &statErrNo, &imageFound, exceptions);
2506 if ( imageFound )
2507 return image;
2508 }
2509 #else
2510 image = loadPhase5stat(path, context, &stat_buf, &statErrNo, &imageFound, exceptions);
2511 if ( imageFound )
2512 return image;
2513 #endif
2514 // just return NULL if file not found, but record any other errors
2515 if ( (statErrNo != ENOENT) && (statErrNo != 0) ) {
2516 exceptions->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path, statErrNo));
2517 }
2518 return NULL;
2519 }
2520 #endif // __IPHONE_OS_VERSION_MIN_REQUIRED
2521
2522
2523 // look for path match with existing loaded images
2524 static ImageLoader* loadPhase5check(const char* path, const char* orgPath, const LoadContext& context)
2525 {
2526 //dyld::log("%s(%s, %s)\n", __func__ , path, orgPath);
2527 // search path against load-path and install-path of all already loaded images
2528 uint32_t hash = ImageLoader::hash(path);
2529 //dyld::log("check() hash=%d, path=%s\n", hash, path);
2530 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
2531 ImageLoader* anImage = *it;
2532 // check hash first to cut down on strcmp calls
2533 //dyld::log(" check() hash=%d, path=%s\n", anImage->getPathHash(), anImage->getPath());
2534 if ( anImage->getPathHash() == hash ) {
2535 if ( strcmp(path, anImage->getPath()) == 0 ) {
2536 // if we are looking for a dylib don't return something else
2537 if ( !context.mustBeDylib || anImage->isDylib() )
2538 return anImage;
2539 }
2540 }
2541 if ( context.matchByInstallName || anImage->matchInstallPath() ) {
2542 const char* installPath = anImage->getInstallPath();
2543 if ( installPath != NULL) {
2544 if ( strcmp(path, installPath) == 0 ) {
2545 // if we are looking for a dylib don't return something else
2546 if ( !context.mustBeDylib || anImage->isDylib() )
2547 return anImage;
2548 }
2549 }
2550 }
2551 // an install name starting with @rpath should match by install name, not just real path
2552 if ( (orgPath[0] == '@') && (strncmp(orgPath, "@rpath/", 7) == 0) ) {
2553 const char* installPath = anImage->getInstallPath();
2554 if ( installPath != NULL) {
2555 if ( !context.mustBeDylib || anImage->isDylib() ) {
2556 if ( strcmp(orgPath, installPath) == 0 )
2557 return anImage;
2558 }
2559 }
2560 }
2561 }
2562
2563 //dyld::log("%s(%s) => NULL\n", __func__, path);
2564 return NULL;
2565 }
2566
2567
2568 // open or check existing
2569 static ImageLoader* loadPhase5(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
2570 {
2571 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2572
2573 // check for specific dylib overrides
2574 for (std::vector<DylibOverride>::iterator it = sDylibOverrides.begin(); it != sDylibOverrides.end(); ++it) {
2575 if ( strcmp(it->installName, path) == 0 ) {
2576 path = it->override;
2577 break;
2578 }
2579 }
2580
2581 if ( exceptions != NULL )
2582 return loadPhase5load(path, orgPath, context, exceptions);
2583 else
2584 return loadPhase5check(path, orgPath, context);
2585 }
2586
2587 // try with and without image suffix
2588 static ImageLoader* loadPhase4(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
2589 {
2590 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2591 ImageLoader* image = NULL;
2592 if ( gLinkContext.imageSuffix != NULL ) {
2593 char pathWithSuffix[strlen(path)+strlen( gLinkContext.imageSuffix)+2];
2594 ImageLoader::addSuffix(path, gLinkContext.imageSuffix, pathWithSuffix);
2595 image = loadPhase5(pathWithSuffix, orgPath, context, exceptions);
2596 }
2597 if ( image == NULL )
2598 image = loadPhase5(path, orgPath, context, exceptions);
2599 return image;
2600 }
2601
2602 static ImageLoader* loadPhase2(const char* path, const char* orgPath, const LoadContext& context,
2603 const char* const frameworkPaths[], const char* const libraryPaths[],
2604 std::vector<const char*>* exceptions); // forward reference
2605
2606
2607 // expand @ variables
2608 static ImageLoader* loadPhase3(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
2609 {
2610 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2611 ImageLoader* image = NULL;
2612 if ( strncmp(path, "@executable_path/", 17) == 0 ) {
2613 // executable_path cannot be in used in any binary in a setuid process rdar://problem/4589305
2614 if ( sProcessIsRestricted )
2615 throwf("unsafe use of @executable_path in %s with restricted binary", context.origin);
2616 // handle @executable_path path prefix
2617 const char* executablePath = sExecPath;
2618 char newPath[strlen(executablePath) + strlen(path)];
2619 strcpy(newPath, executablePath);
2620 char* addPoint = strrchr(newPath,'/');
2621 if ( addPoint != NULL )
2622 strcpy(&addPoint[1], &path[17]);
2623 else
2624 strcpy(newPath, &path[17]);
2625 image = loadPhase4(newPath, orgPath, context, exceptions);
2626 if ( image != NULL )
2627 return image;
2628
2629 // perhaps main executable path is a sym link, find realpath and retry
2630 char resolvedPath[PATH_MAX];
2631 if ( realpath(sExecPath, resolvedPath) != NULL ) {
2632 char newRealPath[strlen(resolvedPath) + strlen(path)];
2633 strcpy(newRealPath, resolvedPath);
2634 char* addPoint = strrchr(newRealPath,'/');
2635 if ( addPoint != NULL )
2636 strcpy(&addPoint[1], &path[17]);
2637 else
2638 strcpy(newRealPath, &path[17]);
2639 image = loadPhase4(newRealPath, orgPath, context, exceptions);
2640 if ( image != NULL )
2641 return image;
2642 }
2643 }
2644 else if ( (strncmp(path, "@loader_path/", 13) == 0) && (context.origin != NULL) ) {
2645 // @loader_path cannot be used from the main executable of a setuid process rdar://problem/4589305
2646 if ( sProcessIsRestricted && (strcmp(context.origin, sExecPath) == 0) )
2647 throwf("unsafe use of @loader_path in %s with restricted binary", context.origin);
2648 // handle @loader_path path prefix
2649 char newPath[strlen(context.origin) + strlen(path)];
2650 strcpy(newPath, context.origin);
2651 char* addPoint = strrchr(newPath,'/');
2652 if ( addPoint != NULL )
2653 strcpy(&addPoint[1], &path[13]);
2654 else
2655 strcpy(newPath, &path[13]);
2656 image = loadPhase4(newPath, orgPath, context, exceptions);
2657 if ( image != NULL )
2658 return image;
2659
2660 // perhaps loader path is a sym link, find realpath and retry
2661 char resolvedPath[PATH_MAX];
2662 if ( realpath(context.origin, resolvedPath) != NULL ) {
2663 char newRealPath[strlen(resolvedPath) + strlen(path)];
2664 strcpy(newRealPath, resolvedPath);
2665 char* addPoint = strrchr(newRealPath,'/');
2666 if ( addPoint != NULL )
2667 strcpy(&addPoint[1], &path[13]);
2668 else
2669 strcpy(newRealPath, &path[13]);
2670 image = loadPhase4(newRealPath, orgPath, context, exceptions);
2671 if ( image != NULL )
2672 return image;
2673 }
2674 }
2675 else if ( context.implicitRPath || (strncmp(path, "@rpath/", 7) == 0) ) {
2676 const char* trailingPath = (strncmp(path, "@rpath/", 7) == 0) ? &path[7] : path;
2677 // substitute @rpath with all -rpath paths up the load chain
2678 for(const ImageLoader::RPathChain* rp=context.rpath; rp != NULL; rp=rp->next) {
2679 if (rp->paths != NULL ) {
2680 for(std::vector<const char*>::iterator it=rp->paths->begin(); it != rp->paths->end(); ++it) {
2681 const char* anRPath = *it;
2682 char newPath[strlen(anRPath) + strlen(trailingPath)+2];
2683 strcpy(newPath, anRPath);
2684 strcat(newPath, "/");
2685 strcat(newPath, trailingPath);
2686 image = loadPhase4(newPath, orgPath, context, exceptions);
2687 if ( gLinkContext.verboseRPaths && (exceptions != NULL) ) {
2688 if ( image != NULL )
2689 dyld::log("RPATH successful expansion of %s to: %s\n", orgPath, newPath);
2690 else
2691 dyld::log("RPATH failed to expanding %s to: %s\n", orgPath, newPath);
2692 }
2693 if ( image != NULL )
2694 return image;
2695 }
2696 }
2697 }
2698
2699 // substitute @rpath with LD_LIBRARY_PATH
2700 if ( sEnv.LD_LIBRARY_PATH != NULL ) {
2701 image = loadPhase2(trailingPath, orgPath, context, NULL, sEnv.LD_LIBRARY_PATH, exceptions);
2702 if ( image != NULL )
2703 return image;
2704 }
2705
2706 // if this is the "open" pass, don't try to open @rpath/... as a relative path
2707 if ( (exceptions != NULL) && (trailingPath != path) )
2708 return NULL;
2709 }
2710 else if (sProcessIsRestricted && (path[0] != '/' )) {
2711 throwf("unsafe use of relative rpath %s in %s with restricted binary", path, context.origin);
2712 }
2713
2714 return loadPhase4(path, orgPath, context, exceptions);
2715 }
2716
2717
2718 // try search paths
2719 static ImageLoader* loadPhase2(const char* path, const char* orgPath, const LoadContext& context,
2720 const char* const frameworkPaths[], const char* const libraryPaths[],
2721 std::vector<const char*>* exceptions)
2722 {
2723 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2724 ImageLoader* image = NULL;
2725 const char* frameworkPartialPath = getFrameworkPartialPath(path);
2726 if ( frameworkPaths != NULL ) {
2727 if ( frameworkPartialPath != NULL ) {
2728 const int frameworkPartialPathLen = strlen(frameworkPartialPath);
2729 for(const char* const* fp = frameworkPaths; *fp != NULL; ++fp) {
2730 char npath[strlen(*fp)+frameworkPartialPathLen+8];
2731 strcpy(npath, *fp);
2732 strcat(npath, "/");
2733 strcat(npath, frameworkPartialPath);
2734 //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
2735 image = loadPhase4(npath, orgPath, context, exceptions);
2736 if ( image != NULL )
2737 return image;
2738 }
2739 }
2740 }
2741 // <rdar://problem/12649639> An executable with the same name as a framework & DYLD_LIBRARY_PATH pointing to it gets loaded twice
2742 // <rdar://problem/14160846> Some apps depend on frameworks being found via library paths
2743 if ( (libraryPaths != NULL) && ((frameworkPartialPath == NULL) || sFrameworksFoundAsDylibs) ) {
2744 const char* libraryLeafName = getLibraryLeafName(path);
2745 const int libraryLeafNameLen = strlen(libraryLeafName);
2746 for(const char* const* lp = libraryPaths; *lp != NULL; ++lp) {
2747 char libpath[strlen(*lp)+libraryLeafNameLen+8];
2748 strcpy(libpath, *lp);
2749 strcat(libpath, "/");
2750 strcat(libpath, libraryLeafName);
2751 //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
2752 image = loadPhase4(libpath, orgPath, context, exceptions);
2753 if ( image != NULL )
2754 return image;
2755 }
2756 }
2757 return NULL;
2758 }
2759
2760 // try search overrides and fallbacks
2761 static ImageLoader* loadPhase1(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
2762 {
2763 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2764 ImageLoader* image = NULL;
2765
2766 // handle LD_LIBRARY_PATH environment variables that force searching
2767 if ( context.useLdLibraryPath && (sEnv.LD_LIBRARY_PATH != NULL) ) {
2768 image = loadPhase2(path, orgPath, context, NULL, sEnv.LD_LIBRARY_PATH, exceptions);
2769 if ( image != NULL )
2770 return image;
2771 }
2772
2773 // handle DYLD_ environment variables that force searching
2774 if ( context.useSearchPaths && ((sEnv.DYLD_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_LIBRARY_PATH != NULL)) ) {
2775 image = loadPhase2(path, orgPath, context, sEnv.DYLD_FRAMEWORK_PATH, sEnv.DYLD_LIBRARY_PATH, exceptions);
2776 if ( image != NULL )
2777 return image;
2778 }
2779
2780 // try raw path
2781 image = loadPhase3(path, orgPath, context, exceptions);
2782 if ( image != NULL )
2783 return image;
2784
2785 // try fallback paths during second time (will open file)
2786 const char* const* fallbackLibraryPaths = sEnv.DYLD_FALLBACK_LIBRARY_PATH;
2787 if ( (fallbackLibraryPaths != NULL) && !context.useFallbackPaths )
2788 fallbackLibraryPaths = NULL;
2789 if ( !context.dontLoad && (exceptions != NULL) && ((sEnv.DYLD_FALLBACK_FRAMEWORK_PATH != NULL) || (fallbackLibraryPaths != NULL)) ) {
2790 image = loadPhase2(path, orgPath, context, sEnv.DYLD_FALLBACK_FRAMEWORK_PATH, fallbackLibraryPaths, exceptions);
2791 if ( image != NULL )
2792 return image;
2793 }
2794
2795 return NULL;
2796 }
2797
2798 // try root substitutions
2799 static ImageLoader* loadPhase0(const char* path, const char* orgPath, const LoadContext& context, std::vector<const char*>* exceptions)
2800 {
2801 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
2802
2803 // handle DYLD_ROOT_PATH which forces absolute paths to use a new root
2804 if ( (gLinkContext.rootPaths != NULL) && (path[0] == '/') ) {
2805 for(const char* const* rootPath = gLinkContext.rootPaths ; *rootPath != NULL; ++rootPath) {
2806 char newPath[strlen(*rootPath) + strlen(path)+2];
2807 strcpy(newPath, *rootPath);
2808 strcat(newPath, path);
2809 ImageLoader* image = loadPhase1(newPath, orgPath, context, exceptions);
2810 if ( image != NULL )
2811 return image;
2812 }
2813 }
2814
2815 // try raw path
2816 return loadPhase1(path, orgPath, context, exceptions);
2817 }
2818
2819 //
2820 // Given all the DYLD_ environment variables, the general case for loading libraries
2821 // is that any given path expands into a list of possible locations to load. We
2822 // also must take care to ensure two copies of the "same" library are never loaded.
2823 //
2824 // The algorithm used here is that there is a separate function for each "phase" of the
2825 // path expansion. Each phase function calls the next phase with each possible expansion
2826 // of that phase. The result is the last phase is called with all possible paths.
2827 //
2828 // To catch duplicates the algorithm is run twice. The first time, the last phase checks
2829 // the path against all loaded images. The second time, the last phase calls open() on
2830 // the path. Either time, if an image is found, the phases all unwind without checking
2831 // for other paths.
2832 //
2833 ImageLoader* load(const char* path, const LoadContext& context)
2834 {
2835 CRSetCrashLogMessage2(path);
2836 const char* orgPath = path;
2837
2838 //dyld::log("%s(%s)\n", __func__ , path);
2839 char realPath[PATH_MAX];
2840 // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match
2841 if ( context.useSearchPaths && ( gLinkContext.imageSuffix != NULL) ) {
2842 if ( realpath(path, realPath) != NULL )
2843 path = realPath;
2844 }
2845
2846 // try all path permutations and check against existing loaded images
2847 ImageLoader* image = loadPhase0(path, orgPath, context, NULL);
2848 if ( image != NULL ) {
2849 CRSetCrashLogMessage2(NULL);
2850 return image;
2851 }
2852
2853 // try all path permutations and try open() until first success
2854 std::vector<const char*> exceptions;
2855 image = loadPhase0(path, orgPath, context, &exceptions);
2856 CRSetCrashLogMessage2(NULL);
2857 if ( image != NULL ) {
2858 // <rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables
2859 for (std::vector<const char*>::iterator it = exceptions.begin(); it != exceptions.end(); ++it) {
2860 free((void*)(*it));
2861 }
2862 #if __IPHONE_OS_VERSION_MIN_REQUIRED && DYLD_SHARED_CACHE_SUPPORT
2863 // if loaded image is not from cache, but original path is in cache
2864 // set gSharedCacheOverridden flag to disable some ObjC optimizations
2865 if ( !gSharedCacheOverridden ) {
2866 if ( !image->inSharedCache() && inSharedCache(path) ) {
2867 gSharedCacheOverridden = true;
2868 }
2869 }
2870 #endif
2871 return image;
2872 }
2873 else if ( exceptions.size() == 0 ) {
2874 if ( context.dontLoad ) {
2875 return NULL;
2876 }
2877 else
2878 throw "image not found";
2879 }
2880 else {
2881 const char* msgStart = "no suitable image found. Did find:";
2882 const char* delim = "\n\t";
2883 size_t allsizes = strlen(msgStart)+8;
2884 for (unsigned int i=0; i < exceptions.size(); ++i)
2885 allsizes += (strlen(exceptions[i]) + strlen(delim));
2886 char* fullMsg = new char[allsizes];
2887 strcpy(fullMsg, msgStart);
2888 for (unsigned int i=0; i < exceptions.size(); ++i) {
2889 strcat(fullMsg, delim);
2890 strcat(fullMsg, exceptions[i]);
2891 free((void*)exceptions[i]);
2892 }
2893 throw (const char*)fullMsg;
2894 }
2895 }
2896
2897
2898
2899 #if DYLD_SHARED_CACHE_SUPPORT
2900
2901
2902
2903 #if __i386__
2904 #define ARCH_NAME "i386"
2905 #define ARCH_CACHE_MAGIC "dyld_v1 i386"
2906 #elif __x86_64__
2907 #define ARCH_NAME "x86_64"
2908 #define ARCH_CACHE_MAGIC "dyld_v1 x86_64"
2909 #elif __ARM_ARCH_5TEJ__
2910 #define ARCH_NAME "armv5"
2911 #define ARCH_CACHE_MAGIC "dyld_v1 armv5"
2912 #elif __ARM_ARCH_6K__
2913 #define ARCH_NAME "armv6"
2914 #define ARCH_CACHE_MAGIC "dyld_v1 armv6"
2915 #elif __ARM_ARCH_7F__
2916 #define ARCH_NAME "armv7f"
2917 #define ARCH_CACHE_MAGIC "dyld_v1 armv7f"
2918 #elif __ARM_ARCH_7A__
2919 #define ARCH_NAME "armv7"
2920 #define ARCH_CACHE_MAGIC "dyld_v1 armv7"
2921 #elif __ARM_ARCH_7S__
2922 #define ARCH_NAME "armv7s"
2923 #define ARCH_CACHE_MAGIC "dyld_v1 armv7s"
2924 #elif __ARM_ARCH_7K__
2925 #define ARCH_NAME "armv7k"
2926 #define ARCH_CACHE_MAGIC "dyld_v1 armv7k"
2927 #endif
2928
2929
2930 static int __attribute__((noinline)) _shared_region_check_np(uint64_t* start_address)
2931 {
2932 if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion )
2933 return syscall(294, start_address);
2934 return -1;
2935 }
2936
2937
2938 static int __attribute__((noinline)) _shared_region_map_and_slide_np(int fd, uint32_t count, const shared_file_mapping_np mappings[],
2939 int codeSignatureMappingIndex, int slide, void* slideInfo, uint32_t slideInfoSize)
2940 {
2941 // register code signature blob for whole dyld cache
2942 if ( codeSignatureMappingIndex != -1 ) {
2943 fsignatures_t siginfo;
2944 siginfo.fs_file_start = 0; // cache always starts at beginning of file
2945 siginfo.fs_blob_start = (void*)mappings[codeSignatureMappingIndex].sfm_file_offset;
2946 siginfo.fs_blob_size = mappings[codeSignatureMappingIndex].sfm_size;
2947 int result = fcntl(fd, F_ADDFILESIGS, &siginfo);
2948 // <rdar://problem/12891874> don't warn in chrooted case because mapping syscall is about to fail too
2949 if ( (result == -1) && gLinkContext.verboseMapping )
2950 dyld::log("dyld: code signature registration for shared cache failed with errno=%d\n", errno);
2951 }
2952
2953 if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion ) {
2954 return syscall(438, fd, count, mappings, slide, slideInfo, slideInfoSize);
2955 }
2956
2957 // remove the shared region sub-map
2958 vm_deallocate(mach_task_self(), (vm_address_t)SHARED_REGION_BASE, SHARED_REGION_SIZE);
2959
2960 // notify gdb or other lurkers that this process is no longer using the shared region
2961 dyld::gProcessInfo->processDetachedFromSharedRegion = true;
2962
2963 // map cache just for this process with mmap()
2964 const shared_file_mapping_np* const start = mappings;
2965 const shared_file_mapping_np* const end = &mappings[count];
2966 for (const shared_file_mapping_np* p = start; p < end; ++p ) {
2967 void* mmapAddress = (void*)(uintptr_t)(p->sfm_address);
2968 size_t size = p->sfm_size;
2969 //dyld::log("dyld: mapping address %p with size 0x%08lX\n", mmapAddress, size);
2970 int protection = 0;
2971 if ( p->sfm_init_prot & VM_PROT_EXECUTE )
2972 protection |= PROT_EXEC;
2973 if ( p->sfm_init_prot & VM_PROT_READ )
2974 protection |= PROT_READ;
2975 if ( p->sfm_init_prot & VM_PROT_WRITE )
2976 protection |= PROT_WRITE;
2977 off_t offset = p->sfm_file_offset;
2978 if ( mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, fd, offset) != mmapAddress ) {
2979 // failed to map some chunk of this shared cache file
2980 // clear shared region
2981 vm_deallocate(mach_task_self(), (vm_address_t)SHARED_REGION_BASE, SHARED_REGION_SIZE);
2982 // go back to not using shared region at all
2983 gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
2984 if ( gLinkContext.verboseMapping ) {
2985 dyld::log("dyld: shared cached region cannot be mapped at address %p with size 0x%08lX\n",
2986 mmapAddress, size);
2987 }
2988 // return failure
2989 return -1;
2990 }
2991 }
2992
2993 // update all __DATA pages with slide info
2994 if ( slide != 0 ) {
2995 const uintptr_t dataPagesStart = mappings[1].sfm_address;
2996 const dyld_cache_slide_info* slideInfoHeader = (dyld_cache_slide_info*)slideInfo;
2997 const uint16_t* toc = (uint16_t*)((long)(slideInfoHeader) + slideInfoHeader->toc_offset);
2998 const uint8_t* entries = (uint8_t*)((long)(slideInfoHeader) + slideInfoHeader->entries_offset);
2999 for(uint32_t i=0; i < slideInfoHeader->toc_count; ++i) {
3000 const uint8_t* entry = &entries[toc[i]*slideInfoHeader->entries_size];
3001 const uint8_t* page = (uint8_t*)(long)(dataPagesStart + (4096*i));
3002 //dyld::log("page=%p toc[%d]=%d entries=%p\n", page, i, toc[i], entry);
3003 for(int j=0; j < 128; ++j) {
3004 uint8_t b = entry[j];
3005 //dyld::log(" entry[%d] = 0x%02X\n", j, b);
3006 if ( b != 0 ) {
3007 for(int k=0; k < 8; ++k) {
3008 if ( b & (1<<k) ) {
3009 uintptr_t* p = (uintptr_t*)(page + j*8*4 + k*4);
3010 uintptr_t value = *p;
3011 //dyld::log(" *%p was 0x%lX will be 0x%lX\n", p, value, value+sSharedCacheSlide);
3012 *p = value + slide;
3013 }
3014 }
3015 }
3016 }
3017 }
3018 }
3019
3020 // succesfully mapped shared cache for just this process
3021 gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
3022
3023 return 0;
3024 }
3025
3026
3027 const void* imMemorySharedCacheHeader()
3028 {
3029 return sSharedCache;
3030 }
3031
3032 int openSharedCacheFile()
3033 {
3034 char path[MAXPATHLEN];
3035 strlcpy(path, sSharedCacheDir, MAXPATHLEN);
3036 strlcat(path, "/", MAXPATHLEN);
3037 strlcat(path, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, MAXPATHLEN);
3038 return my_open(path, O_RDONLY, 0);
3039 }
3040
3041 static long pickCacheSlide(uint32_t mappingsCount, shared_file_mapping_np mappings[])
3042 {
3043 #if __x86_64__
3044 // x86_64 has a two memory regions:
3045 // 256MB at 0x00007FFF70000000
3046 // 1024MB at 0x00007FFF80000000
3047 // Some old shared caches have r/w region after rx region, so all regions slide within 1GB range
3048 // Newer shared caches have r/w region based at 0x7FFF70000000 and r/o regions at 0x7FFF80000000, so each part has max slide
3049 if ( (mappingsCount >= 3) && (mappings[1].sfm_init_prot == (VM_PROT_READ|VM_PROT_WRITE)) && (mappings[1].sfm_address == 0x00007FFF70000000) ) {
3050 const uint64_t rwSize = mappings[1].sfm_size;
3051 const uint64_t rwSlop = 0x10000000ULL - rwSize;
3052 const uint64_t roSize = (mappings[2].sfm_address + mappings[2].sfm_size) - mappings[0].sfm_address;
3053 const uint64_t roSlop = 0x40000000ULL - roSize;
3054 const uint64_t space = (rwSlop < roSlop) ? rwSlop : roSlop;
3055
3056 // choose new random slide
3057 long slide = (arc4random() % space) & (-4096);
3058 //dyld::log("rwSlop=0x%0llX, roSlop=0x%0llX\n", rwSlop, roSlop);
3059 //dyld::log("space=0x%0llX, slide=0x%0lX\n", space, slide);
3060
3061 // update mappings
3062 for(uint32_t i=0; i < mappingsCount; ++i) {
3063 mappings[i].sfm_address += slide;
3064 }
3065
3066 return slide;
3067 }
3068 // else fall through to handle old style cache
3069 #endif
3070 // get bounds of cache
3071 uint64_t lowAddress = 0;
3072 uint64_t highAddress = 0;
3073 for(uint32_t i=0; i < mappingsCount; ++i) {
3074 if ( lowAddress == 0 ) {
3075 lowAddress = mappings[i].sfm_address;
3076 highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
3077 }
3078 else {
3079 if ( mappings[i].sfm_address < lowAddress )
3080 lowAddress = mappings[i].sfm_address;
3081 if ( (mappings[i].sfm_address + mappings[i].sfm_size) > highAddress )
3082 highAddress = mappings[i].sfm_address + mappings[i].sfm_size;
3083 }
3084 }
3085
3086 // find slop space
3087 const uint64_t space = (SHARED_REGION_BASE + SHARED_REGION_SIZE) - highAddress;
3088
3089 // choose new random slide
3090 long slide = (arc4random() % space) & (-4096);
3091 //dyld::log("slideSpace=0x%0llX\n", space);
3092 //dyld::log("slide=0x%0lX\n", slide);
3093
3094 // update mappings
3095 for(uint32_t i=0; i < mappingsCount; ++i) {
3096 mappings[i].sfm_address += slide;
3097 }
3098
3099 return slide;
3100 }
3101
3102 static void mapSharedCache()
3103 {
3104 uint64_t cacheBaseAddress = 0;
3105 // quick check if a cache is alreay mapped into shared region
3106 if ( _shared_region_check_np(&cacheBaseAddress) == 0 ) {
3107 sSharedCache = (dyld_cache_header*)cacheBaseAddress;
3108 // if we don't understand the currently mapped shared cache, then ignore
3109 if ( strcmp(sSharedCache->magic, ARCH_CACHE_MAGIC) != 0 ) {
3110 sSharedCache = NULL;
3111 if ( gLinkContext.verboseMapping ) {
3112 dyld::log("dyld: existing shared cached in memory is not compatible\n");
3113 return;
3114 }
3115 }
3116 // check if cache file is slidable
3117 const dyld_cache_header* header = sSharedCache;
3118 if ( (header->mappingOffset >= 0x48) && (header->slideInfoSize != 0) ) {
3119 // solve for slide by comparing loaded address to address of first region
3120 const uint8_t* loadedAddress = (uint8_t*)sSharedCache;
3121 const dyld_cache_mapping_info* const mappings = (dyld_cache_mapping_info*)(loadedAddress+header->mappingOffset);
3122 const uint8_t* preferedLoadAddress = (uint8_t*)(long)(mappings[0].address);
3123 sSharedCacheSlide = loadedAddress - preferedLoadAddress;
3124 dyld::gProcessInfo->sharedCacheSlide = sSharedCacheSlide;
3125 //dyld::log("sSharedCacheSlide=0x%08lX, loadedAddress=%p, preferedLoadAddress=%p\n", sSharedCacheSlide, loadedAddress, preferedLoadAddress);
3126 }
3127 // if cache has a uuid, copy it
3128 if ( header->mappingOffset >= 0x68 ) {
3129 memcpy(dyld::gProcessInfo->sharedCacheUUID, header->uuid, 16);
3130 }
3131 }
3132 else {
3133 #if __i386__ || __x86_64__
3134 // <rdar://problem/5925940> Safe Boot should disable dyld shared cache
3135 // if we are in safe-boot mode and the cache was not made during this boot cycle,
3136 // delete the cache file
3137 uint32_t safeBootValue = 0;
3138 size_t safeBootValueSize = sizeof(safeBootValue);
3139 if ( (sysctlbyname("kern.safeboot", &safeBootValue, &safeBootValueSize, NULL, 0) == 0) && (safeBootValue != 0) ) {
3140 // user booted machine in safe-boot mode
3141 struct stat dyldCacheStatInfo;
3142 // Don't use custom DYLD_SHARED_CACHE_DIR if provided, use standard path
3143 if ( my_stat(MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &dyldCacheStatInfo) == 0 ) {
3144 struct timeval bootTimeValue;
3145 size_t bootTimeValueSize = sizeof(bootTimeValue);
3146 if ( (sysctlbyname("kern.boottime", &bootTimeValue, &bootTimeValueSize, NULL, 0) == 0) && (bootTimeValue.tv_sec != 0) ) {
3147 // if the cache file was created before this boot, then throw it away and let it rebuild itself
3148 if ( dyldCacheStatInfo.st_mtime < bootTimeValue.tv_sec ) {
3149 ::unlink(MACOSX_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME);
3150 gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
3151 return;
3152 }
3153 }
3154 }
3155 }
3156 #endif
3157 // map in shared cache to shared region
3158 int fd = openSharedCacheFile();
3159 if ( fd != -1 ) {
3160 uint8_t firstPages[8192];
3161 if ( ::read(fd, firstPages, 8192) == 8192 ) {
3162 dyld_cache_header* header = (dyld_cache_header*)firstPages;
3163 if ( strcmp(header->magic, ARCH_CACHE_MAGIC) == 0 ) {
3164 const dyld_cache_mapping_info* const fileMappingsStart = (dyld_cache_mapping_info*)&firstPages[header->mappingOffset];
3165 const dyld_cache_mapping_info* const fileMappingsEnd = &fileMappingsStart[header->mappingCount];
3166 shared_file_mapping_np mappings[header->mappingCount+1]; // add room for code-sig
3167 unsigned int mappingCount = header->mappingCount;
3168 int codeSignatureMappingIndex = -1;
3169 int readWriteMappingIndex = -1;
3170 int readOnlyMappingIndex = -1;
3171 // validate that the cache file has not been truncated
3172 bool goodCache = false;
3173 struct stat stat_buf;
3174 if ( fstat(fd, &stat_buf) == 0 ) {
3175 goodCache = true;
3176 int i=0;
3177 for (const dyld_cache_mapping_info* p = fileMappingsStart; p < fileMappingsEnd; ++p, ++i) {
3178 mappings[i].sfm_address = p->address;
3179 mappings[i].sfm_size = p->size;
3180 mappings[i].sfm_file_offset = p->fileOffset;
3181 mappings[i].sfm_max_prot = p->maxProt;
3182 mappings[i].sfm_init_prot = p->initProt;
3183 // rdar://problem/5694507 old update_dyld_shared_cache tool could make a cache file
3184 // that is not page aligned, but otherwise ok.
3185 if ( p->fileOffset+p->size > (uint64_t)(stat_buf.st_size+4095 & (-4096)) ) {
3186 dyld::log("dyld: shared cached file is corrupt: %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
3187 goodCache = false;
3188 }
3189 if ( (mappings[i].sfm_init_prot & (VM_PROT_READ|VM_PROT_WRITE)) == (VM_PROT_READ|VM_PROT_WRITE) ) {
3190 readWriteMappingIndex = i;
3191 }
3192 if ( mappings[i].sfm_init_prot == VM_PROT_READ ) {
3193 readOnlyMappingIndex = i;
3194 }
3195 }
3196 // if shared cache is code signed, add a mapping for the code signature
3197 uint32_t signatureSize = header->codeSignatureSize;
3198 // zero size in header means signature runs to end-of-file
3199 if ( signatureSize == 0 )
3200 signatureSize = stat_buf.st_size - header->codeSignatureOffset;
3201 if ( signatureSize != 0 ) {
3202 int linkeditMapping = mappingCount-1;
3203 codeSignatureMappingIndex = mappingCount++;
3204 mappings[codeSignatureMappingIndex].sfm_address = mappings[linkeditMapping].sfm_address + mappings[linkeditMapping].sfm_size;
3205 mappings[codeSignatureMappingIndex].sfm_size = (signatureSize+4095) & (-4096);
3206 mappings[codeSignatureMappingIndex].sfm_file_offset = header->codeSignatureOffset;
3207 mappings[codeSignatureMappingIndex].sfm_max_prot = VM_PROT_READ;
3208 mappings[codeSignatureMappingIndex].sfm_init_prot = VM_PROT_READ;
3209 }
3210 }
3211 #if __MAC_OS_X_VERSION_MIN_REQUIRED
3212 // sanity check that /usr/lib/libSystem.B.dylib stat() info matches cache
3213 if ( header->imagesCount * sizeof(dyld_cache_image_info) + header->imagesOffset < 8192 ) {
3214 bool foundLibSystem = false;
3215 if ( my_stat("/usr/lib/libSystem.B.dylib", &stat_buf) == 0 ) {
3216 const dyld_cache_image_info* images = (dyld_cache_image_info*)&firstPages[header->imagesOffset];
3217 const dyld_cache_image_info* const imagesEnd = &images[header->imagesCount];
3218 for (const dyld_cache_image_info* p = images; p < imagesEnd; ++p) {
3219 if ( ((time_t)p->modTime == stat_buf.st_mtime) && ((ino_t)p->inode == stat_buf.st_ino) ) {
3220 foundLibSystem = true;
3221 break;
3222 }
3223 }
3224 }
3225 if ( !sSharedCacheIgnoreInodeAndTimeStamp && !foundLibSystem ) {
3226 dyld::log("dyld: shared cached file was built against a different libSystem.dylib, ignoring cache.\n"
3227 "to update dyld shared cache run: 'sudo update_dyld_shared_cache' then reboot.\n");
3228 goodCache = false;
3229 }
3230 }
3231 #endif
3232 if ( goodCache && (readWriteMappingIndex == -1) ) {
3233 dyld::log("dyld: shared cached file is missing read/write mapping: %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
3234 goodCache = false;
3235 }
3236 if ( goodCache && (readOnlyMappingIndex == -1) ) {
3237 dyld::log("dyld: shared cached file is missing read-only mapping: %s" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
3238 goodCache = false;
3239 }
3240 if ( goodCache ) {
3241 long cacheSlide = 0;
3242 void* slideInfo = NULL;
3243 uint32_t slideInfoSize = 0;
3244 // check if shared cache contains slid info
3245 if ( header->slideInfoSize != 0 ) {
3246 // <rdar://problem/8611968> don't slide shared cache if ASLR disabled (main executable didn't slide)
3247 if ( sMainExecutable->isPositionIndependentExecutable() && (sMainExecutable->getSlide() == 0) )
3248 cacheSlide = 0;
3249 else {
3250 // generate random slide amount
3251 cacheSlide = pickCacheSlide(mappingCount, mappings);
3252 slideInfo = (void*)(long)(mappings[readOnlyMappingIndex].sfm_address + (header->slideInfoOffset - mappings[readOnlyMappingIndex].sfm_file_offset));
3253 slideInfoSize = header->slideInfoSize;
3254 // add VM_PROT_SLIDE bit to __DATA area of cache
3255 mappings[readWriteMappingIndex].sfm_max_prot |= VM_PROT_SLIDE;
3256 mappings[readWriteMappingIndex].sfm_init_prot |= VM_PROT_SLIDE;
3257 }
3258 }
3259 if (_shared_region_map_and_slide_np(fd, mappingCount, mappings, codeSignatureMappingIndex, cacheSlide, slideInfo, slideInfoSize) == 0) {
3260 // successfully mapped cache into shared region
3261 sSharedCache = (dyld_cache_header*)mappings[0].sfm_address;
3262 sSharedCacheSlide = cacheSlide;
3263 dyld::gProcessInfo->sharedCacheSlide = cacheSlide;
3264 //dyld::log("sSharedCache=%p sSharedCacheSlide=0x%08lX\n", sSharedCache, sSharedCacheSlide);
3265 // if cache has a uuid, copy it
3266 if ( header->mappingOffset >= 0x68 ) {
3267 memcpy(dyld::gProcessInfo->sharedCacheUUID, header->uuid, 16);
3268 }
3269 }
3270 else {
3271 if ( gLinkContext.verboseMapping )
3272 dyld::log("dyld: shared cached file could not be mapped\n");
3273 }
3274 }
3275 }
3276 else {
3277 if ( gLinkContext.verboseMapping )
3278 dyld::log("dyld: shared cached file is invalid\n");
3279 }
3280 }
3281 else {
3282 if ( gLinkContext.verboseMapping )
3283 dyld::log("dyld: shared cached file cannot be read\n");
3284 }
3285 close(fd);
3286 }
3287 else {
3288 if ( gLinkContext.verboseMapping )
3289 dyld::log("dyld: shared cached file cannot be opened\n");
3290 }
3291 }
3292
3293 // remember if dyld loaded at same address as when cache built
3294 if ( sSharedCache != NULL ) {
3295 gLinkContext.dyldLoadedAtSameAddressNeededBySharedCache = ((uintptr_t)(sSharedCache->dyldBaseAddress) == (uintptr_t)&_mh_dylinker_header);
3296 }
3297
3298 // tell gdb where the shared cache is
3299 if ( sSharedCache != NULL ) {
3300 const dyld_cache_mapping_info* const start = (dyld_cache_mapping_info*)((uint8_t*)sSharedCache + sSharedCache->mappingOffset);
3301 dyld_shared_cache_ranges.sharedRegionsCount = sSharedCache->mappingCount;
3302 // only room to tell gdb about first four regions
3303 if ( dyld_shared_cache_ranges.sharedRegionsCount > 4 )
3304 dyld_shared_cache_ranges.sharedRegionsCount = 4;
3305 if ( gLinkContext.verboseMapping ) {
3306 if ( gLinkContext.sharedRegionMode == ImageLoader::kUseSharedRegion )
3307 dyld::log("dyld: Mapping shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
3308 else if ( gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion )
3309 dyld::log("dyld: Mapping private shared cache from %s/" DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME "\n", sSharedCacheDir);
3310 }
3311 const dyld_cache_mapping_info* const end = &start[dyld_shared_cache_ranges.sharedRegionsCount];
3312 int index = 0;
3313 for (const dyld_cache_mapping_info* p = start; p < end; ++p, ++index ) {
3314 dyld_shared_cache_ranges.ranges[index].start = p->address+sSharedCacheSlide;
3315 dyld_shared_cache_ranges.ranges[index].length = p->size;
3316 if ( gLinkContext.verboseMapping ) {
3317 dyld::log(" 0x%08llX->0x%08llX %s%s%s init=%x, max=%x\n",
3318 p->address+sSharedCacheSlide, p->address+sSharedCacheSlide+p->size-1,
3319 ((p->initProt & VM_PROT_READ) ? "read " : ""),
3320 ((p->initProt & VM_PROT_WRITE) ? "write " : ""),
3321 ((p->initProt & VM_PROT_EXECUTE) ? "execute " : ""), p->initProt, p->maxProt);
3322 }
3323 #if __i386__
3324 // If a non-writable and executable region is found in the R/W shared region, then this is __IMPORT segments
3325 // This is an old cache. Make writable. dyld no longer supports turn W on and off as it binds
3326 if ( (p->initProt == (VM_PROT_READ|VM_PROT_EXECUTE)) && ((p->address & 0xF0000000) == 0xA0000000) ) {
3327 if ( p->size != 0 ) {
3328 vm_prot_t prot = VM_PROT_EXECUTE | PROT_READ | VM_PROT_WRITE;
3329 vm_protect(mach_task_self(), p->address, p->size, false, prot);
3330 if ( gLinkContext.verboseMapping ) {
3331 dyld::log("%18s at 0x%08llX->0x%08llX altered permissions to %c%c%c\n", "", p->address,
3332 p->address+p->size-1,
3333 (prot & PROT_READ) ? 'r' : '.', (prot & PROT_WRITE) ? 'w' : '.', (prot & PROT_EXEC) ? 'x' : '.' );
3334 }
3335 }
3336 }
3337 #endif
3338 }
3339 if ( gLinkContext.verboseMapping ) {
3340 // list the code blob
3341 dyld_cache_header* header = (dyld_cache_header*)sSharedCache;
3342 uint32_t signatureSize = header->codeSignatureSize;
3343 // zero size in header means signature runs to end-of-file
3344 if ( signatureSize == 0 ) {
3345 struct stat stat_buf;
3346 if ( my_stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &stat_buf) == 0 )
3347 signatureSize = stat_buf.st_size - header->codeSignatureOffset;
3348 }
3349 if ( signatureSize != 0 ) {
3350 const dyld_cache_mapping_info* const last = &start[dyld_shared_cache_ranges.sharedRegionsCount-1];
3351 uint64_t codeBlobStart = last->address + last->size;
3352 dyld::log(" 0x%08llX->0x%08llX (code signature)\n", codeBlobStart, codeBlobStart+signatureSize);
3353 }
3354 }
3355 #if __IPHONE_OS_VERSION_MIN_REQUIRED
3356 // check for file that enables dyld shared cache dylibs to be overridden
3357 struct stat enableStatBuf;
3358 sDylibsOverrideCache = ( my_stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0 );
3359 #endif
3360 }
3361 }
3362 #endif // #if DYLD_SHARED_CACHE_SUPPORT
3363
3364
3365
3366 // create when NSLinkModule is called for a second time on a bundle
3367 ImageLoader* cloneImage(ImageLoader* image)
3368 {
3369 // open file (automagically closed when this function exits)
3370 FileOpener file(image->getPath());
3371
3372 struct stat stat_buf;
3373 if ( fstat(file.getFileDescriptor(), &stat_buf) == -1)
3374 throw "stat error";
3375
3376 dyld::LoadContext context;
3377 context.useSearchPaths = false;
3378 context.useFallbackPaths = false;
3379 context.useLdLibraryPath = false;
3380 context.implicitRPath = false;
3381 context.matchByInstallName = false;
3382 context.dontLoad = false;
3383 context.mustBeBundle = true;
3384 context.mustBeDylib = false;
3385 context.canBePIE = false;
3386 context.origin = NULL;
3387 context.rpath = NULL;
3388 return loadPhase6(file.getFileDescriptor(), stat_buf, image->getPath(), context);
3389 }
3390
3391
3392 ImageLoader* loadFromMemory(const uint8_t* mem, uint64_t len, const char* moduleName)
3393 {
3394 // if fat wrapper, find usable sub-file
3395 const fat_header* memStartAsFat = (fat_header*)mem;
3396 uint64_t fileOffset = 0;
3397 uint64_t fileLength = len;
3398 if ( memStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
3399 if ( fatFindBest(memStartAsFat, &fileOffset, &fileLength) ) {
3400 mem = &mem[fileOffset];
3401 len = fileLength;
3402 }
3403 else {
3404 throw "no matching architecture in universal wrapper";
3405 }
3406 }
3407
3408 // try each loader
3409 if ( isCompatibleMachO(mem, moduleName) ) {
3410 ImageLoader* image = ImageLoaderMachO::instantiateFromMemory(moduleName, (macho_header*)mem, len, gLinkContext);
3411 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
3412 if ( ! image->isBundle() )
3413 addImage(image);
3414 return image;
3415 }
3416
3417 // try other file formats here...
3418
3419 // throw error about what was found
3420 switch (*(uint32_t*)mem) {
3421 case MH_MAGIC:
3422 case MH_CIGAM:
3423 case MH_MAGIC_64:
3424 case MH_CIGAM_64:
3425 throw "mach-o, but wrong architecture";
3426 default:
3427 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
3428 mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6],mem[7]);
3429 }
3430 }
3431
3432
3433 void registerAddCallback(ImageCallback func)
3434 {
3435 // now add to list to get notified when any more images are added
3436 sAddImageCallbacks.push_back(func);
3437
3438 // call callback with all existing images
3439 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3440 ImageLoader* image = *it;
3441 if ( image->getState() >= dyld_image_state_bound && image->getState() < dyld_image_state_terminated )
3442 (*func)(image->machHeader(), image->getSlide());
3443 }
3444 }
3445
3446 void registerRemoveCallback(ImageCallback func)
3447 {
3448 sRemoveImageCallbacks.push_back(func);
3449 }
3450
3451 void clearErrorMessage()
3452 {
3453 error_string[0] = '\0';
3454 }
3455
3456 void setErrorMessage(const char* message)
3457 {
3458 // save off error message in global buffer for CrashReporter to find
3459 strlcpy(error_string, message, sizeof(error_string));
3460 }
3461
3462 const char* getErrorMessage()
3463 {
3464 return error_string;
3465 }
3466
3467
3468 void halt(const char* message)
3469 {
3470 dyld::log("dyld: %s\n", message);
3471 setErrorMessage(message);
3472 uintptr_t terminationFlags = 0;
3473 if ( !gLinkContext.startedInitializingMainExecutable )
3474 terminationFlags = 1;
3475 setAlImageInfosHalt(error_string, terminationFlags);
3476 dyld_fatal_error(error_string);
3477 }
3478
3479 static void setErrorStrings(unsigned errorCode, const char* errorClientOfDylibPath,
3480 const char* errorTargetDylibPath, const char* errorSymbol)
3481 {
3482 dyld::gProcessInfo->errorKind = errorCode;
3483 dyld::gProcessInfo->errorClientOfDylibPath = errorClientOfDylibPath;
3484 dyld::gProcessInfo->errorTargetDylibPath = errorTargetDylibPath;
3485 dyld::gProcessInfo->errorSymbol = errorSymbol;
3486 }
3487
3488
3489 uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
3490 {
3491 uintptr_t result = 0;
3492 // acquire read-lock on dyld's data structures
3493 #if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved
3494 if ( gLibSystemHelpers != NULL )
3495 (*gLibSystemHelpers->lockForReading)();
3496 #endif
3497 // lookup and bind lazy pointer and get target address
3498 try {
3499 ImageLoader* target;
3500 #if __i386__
3501 // fast stubs pass NULL for mh and image is instead found via the location of stub (aka lazyPointer)
3502 if ( mh == NULL )
3503 target = dyld::findImageContainingAddress(lazyPointer);
3504 else
3505 target = dyld::findImageByMachHeader(mh);
3506 #else
3507 // note, target should always be mach-o, because only mach-o lazy handler wired up to this
3508 target = dyld::findImageByMachHeader(mh);
3509 #endif
3510 if ( target == NULL )
3511 throwf("image not found for lazy pointer at %p", lazyPointer);
3512 result = target->doBindLazySymbol(lazyPointer, gLinkContext);
3513 }
3514 catch (const char* message) {
3515 dyld::log("dyld: lazy symbol binding failed: %s\n", message);
3516 halt(message);
3517 }
3518 // release read-lock on dyld's data structures
3519 #if 0
3520 if ( gLibSystemHelpers != NULL )
3521 (*gLibSystemHelpers->unlockForReading)();
3522 #endif
3523 // return target address to glue which jumps to it with real parameters restored
3524 return result;
3525 }
3526
3527
3528 uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindingInfoOffset)
3529 {
3530 uintptr_t result = 0;
3531 // get image
3532 if ( *imageLoaderCache == NULL ) {
3533 // save in cache
3534 *imageLoaderCache = dyld::findMappedRange((uintptr_t)imageLoaderCache);
3535 if ( *imageLoaderCache == NULL ) {
3536 const char* message = "fast lazy binding from unknown image";
3537 dyld::log("dyld: %s\n", message);
3538 halt(message);
3539 }
3540 }
3541
3542 // bind lazy pointer and return it
3543 try {
3544 result = (*imageLoaderCache)->doBindFastLazySymbol(lazyBindingInfoOffset, gLinkContext,
3545 (dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->acquireGlobalDyldLock : NULL,
3546 (dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->releaseGlobalDyldLock : NULL);
3547 }
3548 catch (const char* message) {
3549 dyld::log("dyld: lazy symbol binding failed: %s\n", message);
3550 halt(message);
3551 }
3552
3553 // return target address to glue which jumps to it with real parameters restored
3554 return result;
3555 }
3556
3557
3558
3559 void registerUndefinedHandler(UndefinedHandler handler)
3560 {
3561 sUndefinedHandler = handler;
3562 }
3563
3564 static void undefinedHandler(const char* symboName)
3565 {
3566 if ( sUndefinedHandler != NULL ) {
3567 (*sUndefinedHandler)(symboName);
3568 }
3569 }
3570
3571 static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const ImageLoader::Symbol** sym, const ImageLoader** image)
3572 {
3573 // search all images in order
3574 const ImageLoader* firstWeakImage = NULL;
3575 const ImageLoader::Symbol* firstWeakSym = NULL;
3576 const unsigned int imageCount = sAllImages.size();
3577 for(unsigned int i=0; i < imageCount; ++i) {
3578 ImageLoader* anImage = sAllImages[i];
3579 // the use of inserted libraries alters search order
3580 // so that inserted libraries are found before the main executable
3581 if ( sInsertedDylibCount > 0 ) {
3582 if ( i < sInsertedDylibCount )
3583 anImage = sAllImages[i+1];
3584 else if ( i == sInsertedDylibCount )
3585 anImage = sAllImages[0];
3586 }
3587 if ( ! anImage->hasHiddenExports() && (!onlyInCoalesced || anImage->hasCoalescedExports()) ) {
3588 *sym = anImage->findExportedSymbol(name, false, image);
3589 if ( *sym != NULL ) {
3590 // if weak definition found, record first one found
3591 if ( ((*image)->getExportedSymbolInfo(*sym) & ImageLoader::kWeakDefinition) != 0 ) {
3592 if ( firstWeakImage == NULL ) {
3593 firstWeakImage = *image;
3594 firstWeakSym = *sym;
3595 }
3596 }
3597 else {
3598 // found non-weak, so immediately return with it
3599 return true;
3600 }
3601 }
3602 }
3603 }
3604 if ( firstWeakSym != NULL ) {
3605 // found a weak definition, but no non-weak, so return first weak found
3606 *sym = firstWeakSym;
3607 *image = firstWeakImage;
3608 return true;
3609 }
3610
3611 return false;
3612 }
3613
3614 bool flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, const ImageLoader** image)
3615 {
3616 return findExportedSymbol(name, false, sym, image);
3617 }
3618
3619 bool findCoalescedExportedSymbol(const char* name, const ImageLoader::Symbol** sym, const ImageLoader** image)
3620 {
3621 return findExportedSymbol(name, true, sym, image);
3622 }
3623
3624
3625 bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, const ImageLoader** image)
3626 {
3627 // search all images in order
3628 const unsigned int imageCount = sAllImages.size();
3629 for(unsigned int i=0; i < imageCount; ++i){
3630 ImageLoader* anImage = sAllImages[i];
3631 // only look at images whose paths contain the hint string (NULL hint string is wildcard)
3632 if ( ! anImage->isBundle() && ((librarySubstring==NULL) || (strstr(anImage->getPath(), librarySubstring) != NULL)) ) {
3633 *sym = anImage->findExportedSymbol(name, false, image);
3634 if ( *sym != NULL ) {
3635 return true;
3636 }
3637 }
3638 }
3639 return false;
3640 }
3641
3642 unsigned int getCoalescedImages(ImageLoader* images[])
3643 {
3644 unsigned int count = 0;
3645 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3646 ImageLoader* image = *it;
3647 if ( image->participatesInCoalescing() ) {
3648 *images++ = *it;
3649 ++count;
3650 }
3651 }
3652 return count;
3653 }
3654
3655
3656 static ImageLoader::MappedRegion* getMappedRegions(ImageLoader::MappedRegion* regions)
3657 {
3658 ImageLoader::MappedRegion* end = regions;
3659 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3660 (*it)->getMappedRegions(end);
3661 }
3662 return end;
3663 }
3664
3665 void registerImageStateSingleChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler)
3666 {
3667 // mark the image that the handler is in as never-unload because dyld has a reference into it
3668 ImageLoader* handlerImage = findImageContainingAddress((void*)handler);
3669 if ( handlerImage != NULL )
3670 handlerImage->setNeverUnload();
3671
3672 // add to list of handlers
3673 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
3674 if ( handlers != NULL ) {
3675 // <rdar://problem/10332417> need updateAllImages() to be last in dyld_image_state_mapped list
3676 // so that if ObjC adds a handler that prevents a load, it happens before the gdb list is updated
3677 if ( state == dyld_image_state_mapped )
3678 handlers->insert(handlers->begin(), handler);
3679 else
3680 handlers->push_back(handler);
3681
3682 // call callback with all existing images
3683 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3684 ImageLoader* image = *it;
3685 dyld_image_info info;
3686 info.imageLoadAddress = image->machHeader();
3687 info.imageFilePath = image->getRealPath();
3688 info.imageFileModDate = image->lastModified();
3689 // should only call handler if state == image->state
3690 if ( image->getState() == state )
3691 (*handler)(state, 1, &info);
3692 // ignore returned string, too late to do anything
3693 }
3694 }
3695 }
3696
3697 void registerImageStateBatchChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler)
3698 {
3699 // mark the image that the handler is in as never-unload because dyld has a reference into it
3700 ImageLoader* handlerImage = findImageContainingAddress((void*)handler);
3701 if ( handlerImage != NULL )
3702 handlerImage->setNeverUnload();
3703
3704 // add to list of handlers
3705 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sBatchHandlers);
3706 if ( handlers != NULL ) {
3707 // insert at front, so that gdb handler is always last
3708 handlers->insert(handlers->begin(), handler);
3709
3710 // call callback with all existing images
3711 try {
3712 notifyBatchPartial(state, true, handler);
3713 }
3714 catch (const char* msg) {
3715 // ignore request to abort during registration
3716 }
3717 }
3718 }
3719
3720 static ImageLoader* libraryLocator(const char* libraryName, bool search, const char* origin, const ImageLoader::RPathChain* rpaths)
3721 {
3722 dyld::LoadContext context;
3723 context.useSearchPaths = search;
3724 context.useFallbackPaths = search;
3725 context.useLdLibraryPath = false;
3726 context.implicitRPath = false;
3727 context.matchByInstallName = false;
3728 context.dontLoad = false;
3729 context.mustBeBundle = false;
3730 context.mustBeDylib = true;
3731 context.canBePIE = false;
3732 context.origin = origin;
3733 context.rpath = rpaths;
3734 return load(libraryName, context);
3735 }
3736
3737 static const char* basename(const char* path)
3738 {
3739 const char* last = path;
3740 for (const char* s = path; *s != '\0'; s++) {
3741 if (*s == '/')
3742 last = s+1;
3743 }
3744 return last;
3745 }
3746
3747 static void setContext(const macho_header* mainExecutableMH, int argc, const char* argv[], const char* envp[], const char* apple[])
3748 {
3749 gLinkContext.loadLibrary = &libraryLocator;
3750 gLinkContext.terminationRecorder = &terminationRecorder;
3751 gLinkContext.flatExportFinder = &flatFindExportedSymbol;
3752 gLinkContext.coalescedExportFinder = &findCoalescedExportedSymbol;
3753 gLinkContext.getCoalescedImages = &getCoalescedImages;
3754 gLinkContext.undefinedHandler = &undefinedHandler;
3755 gLinkContext.getAllMappedRegions = &getMappedRegions;
3756 gLinkContext.bindingHandler = NULL;
3757 gLinkContext.notifySingle = &notifySingle;
3758 gLinkContext.notifyBatch = &notifyBatch;
3759 gLinkContext.removeImage = &removeImage;
3760 gLinkContext.registerDOFs = &registerDOFs;
3761 gLinkContext.clearAllDepths = &clearAllDepths;
3762 gLinkContext.printAllDepths = &printAllDepths;
3763 gLinkContext.imageCount = &imageCount;
3764 gLinkContext.setNewProgramVars = &setNewProgramVars;
3765 #if DYLD_SHARED_CACHE_SUPPORT
3766 gLinkContext.inSharedCache = &inSharedCache;
3767 #endif
3768 gLinkContext.setErrorStrings = &setErrorStrings;
3769 #if SUPPORT_OLD_CRT_INITIALIZATION
3770 gLinkContext.setRunInitialzersOldWay= &setRunInitialzersOldWay;
3771 #endif
3772 gLinkContext.findImageContainingAddress = &findImageContainingAddress;
3773 gLinkContext.addDynamicReference = &addDynamicReference;
3774 gLinkContext.bindingOptions = ImageLoader::kBindingNone;
3775 gLinkContext.argc = argc;
3776 gLinkContext.argv = argv;
3777 gLinkContext.envp = envp;
3778 gLinkContext.apple = apple;
3779 gLinkContext.progname = (argv[0] != NULL) ? basename(argv[0]) : "";
3780 gLinkContext.programVars.mh = mainExecutableMH;
3781 gLinkContext.programVars.NXArgcPtr = &gLinkContext.argc;
3782 gLinkContext.programVars.NXArgvPtr = &gLinkContext.argv;
3783 gLinkContext.programVars.environPtr = &gLinkContext.envp;
3784 gLinkContext.programVars.__prognamePtr=&gLinkContext.progname;
3785 gLinkContext.mainExecutable = NULL;
3786 gLinkContext.imageSuffix = NULL;
3787 gLinkContext.prebindUsage = ImageLoader::kUseAllPrebinding;
3788 gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion;
3789 }
3790
3791
3792 #if __LP64__
3793 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
3794 #define macho_segment_command segment_command_64
3795 #define macho_section section_64
3796 #else
3797 #define LC_SEGMENT_COMMAND LC_SEGMENT
3798 #define macho_segment_command segment_command
3799 #define macho_section section
3800 #endif
3801
3802
3803 //
3804 // Look for a special segment in the mach header.
3805 // Its presences means that the binary wants to have DYLD ignore
3806 // DYLD_ environment variables.
3807 //
3808 static bool hasRestrictedSegment(const macho_header* mh)
3809 {
3810 const uint32_t cmd_count = mh->ncmds;
3811 const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
3812 const struct load_command* cmd = cmds;
3813 for (uint32_t i = 0; i < cmd_count; ++i) {
3814 switch (cmd->cmd) {
3815 case LC_SEGMENT_COMMAND:
3816 {
3817 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
3818
3819 //dyld::log("seg name: %s\n", seg->segname);
3820 if (strcmp(seg->segname, "__RESTRICT") == 0) {
3821 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
3822 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
3823 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
3824 if (strcmp(sect->sectname, "__restrict") == 0)
3825 return true;
3826 }
3827 }
3828 }
3829 break;
3830 }
3831 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
3832 }
3833
3834 return false;
3835 }
3836
3837 #if SUPPORT_VERSIONED_PATHS
3838 //
3839 // Peeks at a dylib file and returns its current_version and install_name.
3840 // Returns false on error.
3841 //
3842 static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName)
3843 {
3844 // open file (automagically closed when this function exits)
3845 FileOpener file(dylibPath);
3846
3847 if ( file.getFileDescriptor() == -1 )
3848 return false;
3849
3850 uint8_t firstPage[4096];
3851 if ( pread(file.getFileDescriptor(), firstPage, 4096, 0) != 4096 )
3852 return false;
3853
3854 // if fat wrapper, find usable sub-file
3855 const fat_header* fileStartAsFat = (fat_header*)firstPage;
3856 if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
3857 uint64_t fileOffset;
3858 uint64_t fileLength;
3859 if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) {
3860 if ( pread(file.getFileDescriptor(), firstPage, 4096, fileOffset) != 4096 )
3861 return false;
3862 }
3863 else {
3864 return false;
3865 }
3866 }
3867
3868 // check mach-o header
3869 const mach_header* mh = (mach_header*)firstPage;
3870 if ( mh->magic != sMainExecutableMachHeader->magic )
3871 return false;
3872 if ( mh->cputype != sMainExecutableMachHeader->cputype )
3873 return false;
3874
3875 // scan load commands for LC_ID_DYLIB
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* const cmdsReadEnd = (struct load_command*)(((char*)mh)+4096);
3879 const struct load_command* cmd = cmds;
3880 for (uint32_t i = 0; i < cmd_count; ++i) {
3881 switch (cmd->cmd) {
3882 case LC_ID_DYLIB:
3883 {
3884 const struct dylib_command* id = (struct dylib_command*)cmd;
3885 *version = id->dylib.current_version;
3886 if ( installName != NULL )
3887 strlcpy(installName, (char *)id + id->dylib.name.offset, PATH_MAX);
3888 return true;
3889 }
3890 break;
3891 }
3892 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
3893 if ( cmd > cmdsReadEnd )
3894 return false;
3895 }
3896
3897 return false;
3898 }
3899 #endif // SUPPORT_VERSIONED_PATHS
3900
3901 #if 0
3902 static void printAllImages()
3903 {
3904 dyld::log("printAllImages()\n");
3905 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3906 ImageLoader* image = *it;
3907 dyld_image_states imageState = image->getState();
3908 dyld::log(" state=%d, dlopen-count=%d, never-unload=%d, in-use=%d, name=%s\n",
3909 imageState, image->dlopenCount(), image->neverUnload(), image->isMarkedInUse(), image->getShortName());
3910 }
3911 }
3912 #endif
3913
3914 void link(ImageLoader* image, bool forceLazysBound, bool neverUnload, const ImageLoader::RPathChain& loaderRPaths)
3915 {
3916 // add to list of known images. This did not happen at creation time for bundles
3917 if ( image->isBundle() && !image->isLinked() )
3918 addImage(image);
3919
3920 // we detect root images as those not linked in yet
3921 if ( !image->isLinked() )
3922 addRootImage(image);
3923
3924 // process images
3925 try {
3926 image->link(gLinkContext, forceLazysBound, false, neverUnload, loaderRPaths);
3927 }
3928 catch (const char* msg) {
3929 garbageCollectImages();
3930 throw;
3931 }
3932 }
3933
3934
3935 void runInitializers(ImageLoader* image)
3936 {
3937 // do bottom up initialization
3938 ImageLoader::InitializerTimingList initializerTimes[sAllImages.size()];
3939 initializerTimes[0].count = 0;
3940 image->runInitializers(gLinkContext, initializerTimes[0]);
3941 }
3942
3943 // This function is called at the end of dlclose() when the reference count goes to zero.
3944 // The dylib being unloaded may have brought in other dependent dylibs when it was loaded.
3945 // Those dependent dylibs need to be unloaded, but only if they are not referenced by
3946 // something else. We use a standard mark and sweep garbage collection.
3947 //
3948 // The tricky part is that when a dylib is unloaded it may have a termination function that
3949 // can run and itself call dlclose() on yet another dylib. The problem is that this
3950 // sort of gabage collection is not re-entrant. Instead a terminator's call to dlclose()
3951 // which calls garbageCollectImages() will just set a flag to re-do the garbage collection
3952 // when the current pass is done.
3953 //
3954 // Also note that this is done within the dyld global lock, so it is always single threaded.
3955 //
3956 void garbageCollectImages()
3957 {
3958 static bool sDoingGC = false;
3959 static bool sRedo = false;
3960
3961 if ( sDoingGC ) {
3962 // GC is currently being run, just set a flag to have it run again.
3963 sRedo = true;
3964 return;
3965 }
3966
3967 sDoingGC = true;
3968 do {
3969 sRedo = false;
3970
3971 // mark phase: mark all images not-in-use
3972 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3973 ImageLoader* image = *it;
3974 //dyld::log("gc: neverUnload=%d name=%s\n", image->neverUnload(), image->getShortName());
3975 image->markNotUsed();
3976 }
3977
3978 // sweep phase: mark as in-use, images reachable from never-unload or in-use image
3979 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3980 ImageLoader* image = *it;
3981 if ( (image->dlopenCount() != 0) || image->neverUnload() ) {
3982 image->markedUsedRecursive(sDynamicReferences);
3983 }
3984 }
3985
3986 // collect phase: build array of images not marked in-use
3987 ImageLoader* deadImages[sAllImages.size()];
3988 unsigned deadCount = 0;
3989 unsigned i = 0;
3990 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3991 ImageLoader* image = *it;
3992 if ( ! image->isMarkedInUse() ) {
3993 deadImages[i++] = image;
3994 if (gLogAPIs) dyld::log("dlclose(), found unused image %p %s\n", image, image->getShortName());
3995 ++deadCount;
3996 }
3997 }
3998
3999 // collect phase: run termination routines for images not marked in-use
4000 // TO DO: When libc has cxa_finalize() that takes array of images, pass deadImages[] instead of the for loop here
4001 for (unsigned i=0; i < deadCount; ++i) {
4002 ImageLoader* image = deadImages[i];
4003 try {
4004 if (gLogAPIs) dyld::log("dlclose(), running terminators for %p %s\n", image, image->getShortName());
4005 runImageTerminators(image);
4006 }
4007 catch (const char* msg) {
4008 dyld::warn("problem running terminators for image: %s\n", msg);
4009 }
4010 }
4011
4012 // collect phase: delete all images which are not marked in-use
4013 bool mightBeMore;
4014 do {
4015 mightBeMore = false;
4016 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4017 ImageLoader* image = *it;
4018 if ( ! image->isMarkedInUse() ) {
4019 try {
4020 if (gLogAPIs) dyld::log("dlclose(), deleting %p %s\n", image, image->getShortName());
4021 removeImage(image);
4022 ImageLoader::deleteImage(image);
4023 mightBeMore = true;
4024 break; // interator in invalidated by this removal
4025 }
4026 catch (const char* msg) {
4027 dyld::warn("problem deleting image: %s\n", msg);
4028 }
4029 }
4030 }
4031 } while ( mightBeMore );
4032 } while (sRedo);
4033 sDoingGC = false;
4034
4035 //printAllImages();
4036
4037 }
4038
4039
4040 static void preflight_finally(ImageLoader* image)
4041 {
4042 if ( image->isBundle() ) {
4043 removeImageFromAllImages(image->machHeader());
4044 ImageLoader::deleteImage(image);
4045 }
4046 sBundleBeingLoaded = NULL;
4047 dyld::garbageCollectImages();
4048 }
4049
4050
4051 void preflight(ImageLoader* image, const ImageLoader::RPathChain& loaderRPaths)
4052 {
4053 try {
4054 if ( image->isBundle() )
4055 sBundleBeingLoaded = image; // hack
4056 image->link(gLinkContext, false, true, false, loaderRPaths);
4057 }
4058 catch (const char* msg) {
4059 preflight_finally(image);
4060 throw;
4061 }
4062 preflight_finally(image);
4063 }
4064
4065 static void loadInsertedDylib(const char* path)
4066 {
4067 ImageLoader* image = NULL;
4068 try {
4069 LoadContext context;
4070 context.useSearchPaths = false;
4071 context.useFallbackPaths = false;
4072 context.useLdLibraryPath = false;
4073 context.implicitRPath = false;
4074 context.matchByInstallName = false;
4075 context.dontLoad = false;
4076 context.mustBeBundle = false;
4077 context.mustBeDylib = true;
4078 context.canBePIE = false;
4079 context.origin = NULL; // can't use @loader_path with DYLD_INSERT_LIBRARIES
4080 context.rpath = NULL;
4081 image = load(path, context);
4082 }
4083 catch (const char* msg) {
4084 halt(dyld::mkstringf("could not load inserted library '%s' because %s\n", path, msg));
4085 }
4086 catch (...) {
4087 halt(dyld::mkstringf("could not load inserted library '%s'\n", path));
4088 }
4089 }
4090
4091 static bool processRestricted(const macho_header* mainExecutableMH)
4092 {
4093 #if __MAC_OS_X_VERSION_MIN_REQUIRED
4094 // ask kernel if code signature of program makes it restricted
4095 uint32_t flags;
4096 if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
4097 if ( flags & CS_ENFORCEMENT ) {
4098 gLinkContext.codeSigningEnforced = true;
4099 }
4100 }
4101 if (flags & CS_RESTRICT) {
4102 sRestrictedReason = restrictedByEntitlements;
4103 return true;
4104 }
4105 #else
4106 gLinkContext.codeSigningEnforced = true;
4107 #endif
4108
4109 // all processes with setuid or setgid bit set are restricted
4110 if ( issetugid() ) {
4111 sRestrictedReason = restrictedBySetGUid;
4112 return true;
4113 }
4114
4115 // <rdar://problem/13158444&13245742> Respect __RESTRICT,__restrict section for root processes
4116 if ( hasRestrictedSegment(mainExecutableMH) ) {
4117 // existence of __RESTRICT/__restrict section make process restricted
4118 sRestrictedReason = restrictedBySegment;
4119 return true;
4120 }
4121 return false;
4122 }
4123
4124
4125 bool processIsRestricted()
4126 {
4127 return sProcessIsRestricted;
4128 }
4129
4130
4131 // <rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots
4132 static void addDyldImageToUUIDList()
4133 {
4134 const struct macho_header* mh = (macho_header*)&__dso_handle;
4135 const uint32_t cmd_count = mh->ncmds;
4136 const struct load_command* const cmds = (struct load_command*)((char*)mh + sizeof(macho_header));
4137 const struct load_command* cmd = cmds;
4138 for (uint32_t i = 0; i < cmd_count; ++i) {
4139 switch (cmd->cmd) {
4140 case LC_UUID: {
4141 uuid_command* uc = (uuid_command*)cmd;
4142 dyld_uuid_info info;
4143 info.imageLoadAddress = (mach_header*)mh;
4144 memcpy(info.imageUUID, uc->uuid, 16);
4145 addNonSharedCacheImageUUID(info);
4146 return;
4147 }
4148 }
4149 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
4150 }
4151 }
4152
4153 #if __MAC_OS_X_VERSION_MIN_REQUIRED
4154 typedef int (*open_proc_t)(const char*, int, int);
4155 typedef int (*fcntl_proc_t)(int, int, void*);
4156 typedef int (*ioctl_proc_t)(int, unsigned long, void*);
4157 static void* getProcessInfo() { return dyld::gProcessInfo; }
4158 static SyscallHelpers sSysCalls = {
4159 1,
4160 (open_proc_t)&open,
4161 &close,
4162 &pread,
4163 &write,
4164 &mmap,
4165 &munmap,
4166 &madvise,
4167 &stat,
4168 (fcntl_proc_t)&fcntl,
4169 (ioctl_proc_t)&ioctl,
4170 &issetugid,
4171 &getcwd,
4172 &realpath,
4173 &vm_allocate,
4174 &vm_deallocate,
4175 &vm_protect,
4176 &vlog,
4177 &vwarn,
4178 &pthread_mutex_lock,
4179 &pthread_mutex_unlock,
4180 &mach_thread_self,
4181 &mach_port_deallocate,
4182 &task_self_trap,
4183 &mach_timebase_info,
4184 &OSAtomicCompareAndSwapPtrBarrier,
4185 &OSMemoryBarrier,
4186 &getProcessInfo,
4187 &__error,
4188 &mach_absolute_time
4189 };
4190
4191 __attribute__((noinline))
4192 static uintptr_t useSimulatorDyld(int fd, const macho_header* mainExecutableMH, const char* dyldPath,
4193 int argc, const char* argv[], const char* envp[], const char* apple[], uintptr_t* startGlue)
4194 {
4195 *startGlue = 0;
4196
4197 // verify simulator dyld file is owned by root
4198 struct stat sb;
4199 if ( fstat(fd, &sb) == -1 )
4200 return 0;
4201 if ( sb.st_uid != 0 )
4202 return 0;
4203
4204 // read first page of dyld file
4205 uint8_t firstPage[4096];
4206 if ( pread(fd, firstPage, 4096, 0) != 4096 )
4207 return 0;
4208
4209 // if fat file, pick matching slice
4210 uint64_t fileOffset = 0;
4211 uint64_t fileLength = sb.st_size;
4212 const fat_header* fileStartAsFat = (fat_header*)firstPage;
4213 if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
4214 if ( !fatFindBest(fileStartAsFat, &fileOffset, &fileLength) )
4215 return 0;
4216 // re-read buffer from start of mach-o slice in fat file
4217 if ( pread(fd, firstPage, 4096, fileOffset) != 4096 )
4218 return 0;
4219 }
4220 else if ( !isCompatibleMachO(firstPage, dyldPath) ) {
4221 return 0;
4222 }
4223
4224 // calculate total size of dyld segments
4225 const macho_header* mh = (const macho_header*)firstPage;
4226 uintptr_t mappingSize = 0;
4227 uintptr_t preferredLoadAddress = 0;
4228 const uint32_t cmd_count = mh->ncmds;
4229 const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
4230 const struct load_command* cmd = cmds;
4231 for (uint32_t i = 0; i < cmd_count; ++i) {
4232 switch (cmd->cmd) {
4233 case LC_SEGMENT_COMMAND:
4234 {
4235 struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
4236 mappingSize += seg->vmsize;
4237 if ( seg->fileoff == 0 )
4238 preferredLoadAddress = seg->vmaddr;
4239 }
4240 break;
4241 }
4242 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
4243 }
4244
4245 // reserve space, then mmap each segment
4246 vm_address_t loadAddress = 0;
4247 uintptr_t entry = 0;
4248 if ( ::vm_allocate(mach_task_self(), &loadAddress, mappingSize, VM_FLAGS_ANYWHERE) != 0 )
4249 return 0;
4250 cmd = cmds;
4251 struct linkedit_data_command* codeSigCmd = NULL;
4252 for (uint32_t i = 0; i < cmd_count; ++i) {
4253 switch (cmd->cmd) {
4254 case LC_SEGMENT_COMMAND:
4255 {
4256 struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
4257 uintptr_t requestedLoadAddress = seg->vmaddr - preferredLoadAddress + loadAddress;
4258 void* segAddress = ::mmap((void*)requestedLoadAddress, seg->filesize, seg->initprot, MAP_FIXED | MAP_PRIVATE, fd, fileOffset + seg->fileoff);
4259 //dyld::log("dyld_sim %s mapped at %p\n", seg->segname, segAddress);
4260 if ( segAddress == (void*)(-1) )
4261 return 0;
4262 }
4263 break;
4264 case LC_UNIXTHREAD:
4265 {
4266 #if __i386__
4267 const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
4268 entry = (registers->__eip + loadAddress - preferredLoadAddress);
4269 #elif __x86_64__
4270 const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
4271 entry = (registers->__rip + loadAddress - preferredLoadAddress);
4272 #endif
4273 }
4274 break;
4275 case LC_CODE_SIGNATURE:
4276 codeSigCmd = (struct linkedit_data_command*)cmd;
4277 break;
4278 }
4279 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
4280 }
4281
4282 if ( codeSigCmd != NULL ) {
4283 fsignatures_t siginfo;
4284 siginfo.fs_file_start=fileOffset; // start of mach-o slice in fat file
4285 siginfo.fs_blob_start=(void*)(long)(codeSigCmd->dataoff); // start of code-signature in mach-o file
4286 siginfo.fs_blob_size=codeSigCmd->datasize; // size of code-signature
4287 int result = fcntl(fd, F_ADDFILESIGS, &siginfo);
4288 if ( result == -1 ) {
4289 if ( (errno == EPERM) || (errno == EBADEXEC) )
4290 return 0;
4291 }
4292 }
4293 close(fd);
4294
4295 // notify debugger that dyld_sim is loaded
4296 dyld_image_info info;
4297 info.imageLoadAddress = (mach_header*)loadAddress;
4298 info.imageFilePath = strdup(dyldPath);
4299 info.imageFileModDate = sb.st_mtime;
4300 addImagesToAllImages(1, &info);
4301 dyld::gProcessInfo->notification(dyld_image_adding, 1, &info);
4302
4303 // jump into new simulator dyld
4304 typedef uintptr_t (*sim_entry_proc_t)(int argc, const char* argv[], const char* envp[], const char* apple[],
4305 const macho_header* mainExecutableMH, const macho_header* dyldMH, uintptr_t dyldSlide,
4306 const dyld::SyscallHelpers* vtable, uintptr_t* startGlue);
4307 sim_entry_proc_t newDyld = (sim_entry_proc_t)entry;
4308 return (*newDyld)(argc, argv, envp, apple, mainExecutableMH, (macho_header*)loadAddress,
4309 loadAddress - preferredLoadAddress,
4310 &sSysCalls, startGlue);
4311 }
4312 #endif
4313
4314
4315 //
4316 // Entry point for dyld. The kernel loads dyld and jumps to __dyld_start which
4317 // sets up some registers and call this function.
4318 //
4319 // Returns address of main() in target program which __dyld_start jumps to
4320 //
4321 uintptr_t
4322 _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
4323 int argc, const char* argv[], const char* envp[], const char* apple[],
4324 uintptr_t* startGlue)
4325 {
4326 uintptr_t result = 0;
4327 sMainExecutableMachHeader = mainExecutableMH;
4328 #if __MAC_OS_X_VERSION_MIN_REQUIRED
4329 // if this is host dyld, check to see if iOS simulator is being run
4330 const char* rootPath = _simple_getenv(envp, "DYLD_ROOT_PATH");
4331 if ( rootPath != NULL ) {
4332 // look to see if simulator has its own dyld
4333 char simDyldPath[PATH_MAX];
4334 strlcpy(simDyldPath, rootPath, PATH_MAX);
4335 strlcat(simDyldPath, "/usr/lib/dyld_sim", PATH_MAX);
4336 int fd = my_open(simDyldPath, O_RDONLY, 0);
4337 if ( fd != -1 ) {
4338 result = useSimulatorDyld(fd, mainExecutableMH, simDyldPath, argc, argv, envp, apple, startGlue);
4339 if ( !result && (*startGlue == 0) )
4340 halt("problem loading iOS simulator dyld");
4341 return result;
4342 }
4343 }
4344 #endif
4345
4346 CRSetCrashLogMessage("dyld: launch started");
4347 #ifdef ALTERNATIVE_LOGFILE
4348 sLogfile = open(ALTERNATIVE_LOGFILE, O_WRONLY | O_CREAT | O_APPEND);
4349 if ( sLogfile == -1 ) {
4350 sLogfile = STDERR_FILENO;
4351 dyld::log("error opening alternate log file %s, errno = %d\n", ALTERNATIVE_LOGFILE, errno);
4352 }
4353 #endif
4354
4355 #if LOG_BINDINGS
4356 char bindingsLogPath[256];
4357
4358 const char* shortProgName = "unknown";
4359 if ( argc > 0 ) {
4360 shortProgName = strrchr(argv[0], '/');
4361 if ( shortProgName == NULL )
4362 shortProgName = argv[0];
4363 else
4364 ++shortProgName;
4365 }
4366 mysprintf(bindingsLogPath, "/tmp/bindings/%d-%s", getpid(), shortProgName);
4367 sBindingsLogfile = open(bindingsLogPath, O_WRONLY | O_CREAT, 0666);
4368 if ( sBindingsLogfile == -1 ) {
4369 ::mkdir("/tmp/bindings", 0777);
4370 sBindingsLogfile = open(bindingsLogPath, O_WRONLY | O_CREAT, 0666);
4371 }
4372 //dyld::log("open(%s) => %d, errno = %d\n", bindingsLogPath, sBindingsLogfile, errno);
4373 #endif
4374 setContext(mainExecutableMH, argc, argv, envp, apple);
4375
4376 // Pickup the pointer to the exec path.
4377 sExecPath = _simple_getenv(apple, "executable_path");
4378
4379 // <rdar://problem/13868260> Remove interim apple[0] transition code from dyld
4380 if (!sExecPath) sExecPath = apple[0];
4381
4382 sExecPath = apple[0];
4383 bool ignoreEnvironmentVariables = false;
4384 if ( sExecPath[0] != '/' ) {
4385 // have relative path, use cwd to make absolute
4386 char cwdbuff[MAXPATHLEN];
4387 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
4388 // maybe use static buffer to avoid calling malloc so early...
4389 char* s = new char[strlen(cwdbuff) + strlen(sExecPath) + 2];
4390 strcpy(s, cwdbuff);
4391 strcat(s, "/");
4392 strcat(s, sExecPath);
4393 sExecPath = s;
4394 }
4395 }
4396 // Remember short name of process for later logging
4397 sExecShortName = ::strrchr(sExecPath, '/');
4398 if ( sExecShortName != NULL )
4399 ++sExecShortName;
4400 else
4401 sExecShortName = sExecPath;
4402 sProcessIsRestricted = processRestricted(mainExecutableMH);
4403 if ( sProcessIsRestricted ) {
4404 #if SUPPORT_LC_DYLD_ENVIRONMENT
4405 checkLoadCommandEnvironmentVariables();
4406 #if SUPPORT_VERSIONED_PATHS
4407 checkVersionedPaths();
4408 #endif
4409 #endif
4410 pruneEnvironmentVariables(envp, &apple);
4411 // set again because envp and apple may have changed or moved
4412 setContext(mainExecutableMH, argc, argv, envp, apple);
4413 }
4414 else
4415 checkEnvironmentVariables(envp, ignoreEnvironmentVariables);
4416 if ( sEnv.DYLD_PRINT_OPTS )
4417 printOptions(argv);
4418 if ( sEnv.DYLD_PRINT_ENV )
4419 printEnvironmentVariables(envp);
4420 getHostInfo();
4421 // install gdb notifier
4422 stateToHandlers(dyld_image_state_dependents_mapped, sBatchHandlers)->push_back(notifyGDB);
4423 stateToHandlers(dyld_image_state_mapped, sSingleHandlers)->push_back(updateAllImages);
4424 // make initial allocations large enough that it is unlikely to need to be re-alloced
4425 sAllImages.reserve(INITIAL_IMAGE_COUNT);
4426 sImageRoots.reserve(16);
4427 sAddImageCallbacks.reserve(4);
4428 sRemoveImageCallbacks.reserve(4);
4429 sImageFilesNeedingTermination.reserve(16);
4430 sImageFilesNeedingDOFUnregistration.reserve(8);
4431
4432 #ifdef WAIT_FOR_SYSTEM_ORDER_HANDSHAKE
4433 // <rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process
4434 WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld::gProcessInfo->systemOrderFlag);
4435 #endif
4436
4437
4438 try {
4439 // add dyld itself to UUID list
4440 addDyldImageToUUIDList();
4441 if ( sProcessIsRestricted )
4442 CRSetCrashLogMessage("dyld: launch, loading dependent libraries, ignoring DYLD_* env vars");
4443 else
4444 CRSetCrashLogMessage("dyld: launch, loading dependent libraries");
4445 // instantiate ImageLoader for main executable
4446 sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
4447 gLinkContext.mainExecutable = sMainExecutable;
4448 gLinkContext.processIsRestricted = sProcessIsRestricted;
4449 gLinkContext.mainExecutableCodeSigned = hasCodeSignatureLoadCommand(mainExecutableMH);
4450 // load shared cache
4451 checkSharedRegionDisable();
4452 #if DYLD_SHARED_CACHE_SUPPORT
4453 if ( gLinkContext.sharedRegionMode != ImageLoader::kDontUseSharedRegion )
4454 mapSharedCache();
4455 #endif
4456 // load any inserted libraries
4457 if ( sEnv.DYLD_INSERT_LIBRARIES != NULL ) {
4458 for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib)
4459 loadInsertedDylib(*lib);
4460 }
4461 // record count of inserted libraries so that a flat search will look at
4462 // inserted libraries, then main, then others.
4463 sInsertedDylibCount = sAllImages.size()-1;
4464
4465 // link main executable
4466 gLinkContext.linkingMainExecutable = true;
4467 link(sMainExecutable, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL));
4468 sMainExecutable->setNeverUnloadRecursive();
4469 if ( sMainExecutable->forceFlat() ) {
4470 gLinkContext.bindFlat = true;
4471 gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
4472 }
4473
4474 // link any inserted libraries
4475 // do this after linking main executable so that any dylibs pulled in by inserted
4476 // dylibs (e.g. libSystem) will not be in front of dylibs the program uses
4477 if ( sInsertedDylibCount > 0 ) {
4478 for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
4479 ImageLoader* image = sAllImages[i+1];
4480 link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL));
4481 image->setNeverUnloadRecursive();
4482 // only INSERTED libraries can interpose
4483 image->registerInterposing();
4484 }
4485 }
4486 // apply interposing to initial set of images
4487 for(int i=0; i < sImageRoots.size(); ++i) {
4488 sImageRoots[i]->applyInterposing(gLinkContext);
4489 }
4490 gLinkContext.linkingMainExecutable = false;
4491
4492 // <rdar://problem/12186933> do weak binding only after all inserted images linked
4493 sMainExecutable->weakBind(gLinkContext);
4494
4495 CRSetCrashLogMessage("dyld: launch, running initializers");
4496 #if SUPPORT_OLD_CRT_INITIALIZATION
4497 // Old way is to run initializers via a callback from crt1.o
4498 if ( ! gRunInitializersOldWay )
4499 initializeMainExecutable();
4500 #else
4501 // run all initializers
4502 initializeMainExecutable();
4503 #endif
4504 // find entry point for main executable
4505 result = (uintptr_t)sMainExecutable->getThreadPC();
4506 if ( result != 0 ) {
4507 // main executable uses LC_MAIN, needs to return to glue in libdyld.dylib
4508 if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 9) )
4509 *startGlue = (uintptr_t)gLibSystemHelpers->startGlueToCallExit;
4510 else
4511 halt("libdyld.dylib support not present for LC_MAIN");
4512 }
4513 else {
4514 // main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main()
4515 result = (uintptr_t)sMainExecutable->getMain();
4516 *startGlue = 0;
4517 }
4518 }
4519 catch(const char* message) {
4520 syncAllImages();
4521 halt(message);
4522 }
4523 catch(...) {
4524 dyld::log("dyld: launch failed\n");
4525 }
4526
4527 #ifdef ALTERNATIVE_LOGFILE
4528 // only use alternate log during launch, otherwise file is open forever
4529 if ( sLogfile != STDERR_FILENO ) {
4530 close(sLogfile);
4531 sLogfile = STDERR_FILENO;
4532 }
4533 #endif
4534 CRSetCrashLogMessage(NULL);
4535
4536 return result;
4537 }
4538
4539
4540
4541 } // namespace
4542
4543
4544