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