dyld-655.1.1.tar.gz
[apple/dyld.git] / src / dyld.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2013 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 <pthread.h>
32 #include <libproc.h>
33 #include <sys/param.h>
34 #include <mach/mach_time.h> // mach_absolute_time()
35 #include <mach/mach_init.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/syscall.h>
39 #include <sys/socket.h>
40 #include <sys/un.h>
41 #include <sys/syslog.h>
42 #include <sys/uio.h>
43 #include <mach/mach.h>
44 #include <mach-o/fat.h>
45 #include <mach-o/loader.h>
46 #include <mach-o/ldsyms.h>
47 #include <libkern/OSByteOrder.h>
48 #include <libkern/OSAtomic.h>
49 #include <mach/mach.h>
50 #include <sys/sysctl.h>
51 #include <sys/mman.h>
52 #include <sys/dtrace.h>
53 #include <libkern/OSAtomic.h>
54 #include <Availability.h>
55 #include <System/sys/codesign.h>
56 #include <System/sys/csr.h>
57 #include <_simple.h>
58 #include <os/lock_private.h>
59 #include <System/machine/cpu_capabilities.h>
60 #include <System/sys/reason.h>
61 #include <kern/kcdata.h>
62 #if TARGET_IPHONE_SIMULATOR
63 enum {
64 AMFI_DYLD_INPUT_PROC_IN_SIMULATOR = (1 << 0),
65 };
66 enum amfi_dyld_policy_output_flag_set {
67 AMFI_DYLD_OUTPUT_ALLOW_AT_PATH = (1 << 0),
68 AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS = (1 << 1),
69 AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE = (1 << 2),
70 AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS = (1 << 3),
71 AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS = (1 << 4),
72 AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION = (1 << 5),
73 };
74 extern "C" int amfi_check_dyld_policy_self(uint64_t input_flags, uint64_t* output_flags);
75 #else
76 #include <libamfi.h>
77 #endif
78 extern "C" {
79 #include <corecrypto/ccdigest.h>
80 #include <corecrypto/ccsha2.h>
81 }
82 #include <sandbox.h>
83 #include <sandbox/private.h>
84 #if __has_feature(ptrauth_calls)
85 #include <ptrauth.h>
86 #endif
87
88 extern "C" int __fork();
89
90 #include <array>
91 #include <algorithm>
92 #include <vector>
93
94 #ifndef CPU_SUBTYPE_ARM_V5TEJ
95 #define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7)
96 #endif
97 #ifndef CPU_SUBTYPE_ARM_XSCALE
98 #define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8)
99 #endif
100 #ifndef CPU_SUBTYPE_ARM_V7
101 #define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9)
102 #endif
103 #ifndef CPU_SUBTYPE_ARM_V7F
104 #define CPU_SUBTYPE_ARM_V7F ((cpu_subtype_t) 10)
105 #endif
106 #ifndef CPU_SUBTYPE_ARM_V7S
107 #define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t) 11)
108 #endif
109 #ifndef CPU_SUBTYPE_ARM_V7K
110 #define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t) 12)
111 #endif
112 #ifndef LC_DYLD_ENVIRONMENT
113 #define LC_DYLD_ENVIRONMENT 0x27
114 #endif
115
116 #ifndef CPU_SUBTYPE_X86_64_H
117 #define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t) 8)
118 #endif
119
120 #ifndef CPU_SUBTYPE_ARM64_E
121 #define CPU_SUBTYPE_ARM64_E 2
122 #endif
123
124 #ifndef CPU_ARCH_ABI64_32
125 #define CPU_ARCH_ABI64_32 ((cpu_type_t) 0x02000000)
126 #endif
127 #ifndef CPU_TYPE_ARM64_32
128 #define CPU_TYPE_ARM64_32 ((cpu_type_t) (CPU_TYPE_ARM | CPU_ARCH_ABI64_32))
129 #endif
130 #ifndef CPU_SUBTYPE_ARM64_32_V8
131 #define CPU_SUBTYPE_ARM64_32_V8 ((cpu_subtype_t) 1)
132 #endif
133
134 #ifndef VM_PROT_SLIDE
135 #define VM_PROT_SLIDE 0x20
136 #endif
137
138 #include "mach-o/dyld_gdb.h"
139
140 #include "dyld.h"
141 #include "ImageLoader.h"
142 #include "ImageLoaderMachO.h"
143 #include "dyldLibSystemInterface.h"
144 #include "dyld_cache_format.h"
145 #include "dyld_process_info_internal.h"
146
147 #if SUPPORT_ACCELERATE_TABLES
148 #include "ImageLoaderMegaDylib.h"
149 #endif
150
151 #if TARGET_IPHONE_SIMULATOR
152 extern "C" void* gSyscallHelpers;
153 #else
154 #include "dyldSyscallInterface.h"
155 #endif
156
157 #include "Closure.h"
158 #include "libdyldEntryVector.h"
159 #include "MachOLoaded.h"
160 #include "Loading.h"
161 #include "DyldSharedCache.h"
162 #include "SharedCacheRuntime.h"
163 #include "StringUtils.h"
164 #include "Tracing.h"
165 #include "ClosureBuilder.h"
166 #include "ClosureFileSystemPhysical.h"
167 #include "FileUtils.h"
168
169
170 // not libc header for send() syscall interface
171 extern "C" ssize_t __sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
172
173
174 // ARM and x86_64 are the only architecture that use cpu-sub-types
175 #define CPU_SUBTYPES_SUPPORTED ((__arm__ || __arm64__ || __x86_64__) && !TARGET_IPHONE_SIMULATOR)
176
177 #if __LP64__
178 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
179 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
180 #define LC_ENCRYPT_COMMAND LC_ENCRYPTION_INFO
181 #define macho_segment_command segment_command_64
182 #define macho_section section_64
183 #else
184 #define LC_SEGMENT_COMMAND LC_SEGMENT
185 #define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
186 #define LC_ENCRYPT_COMMAND LC_ENCRYPTION_INFO_64
187 #define macho_segment_command segment_command
188 #define macho_section section
189 #endif
190
191
192
193 #define CPU_TYPE_MASK 0x00FFFFFF /* complement of CPU_ARCH_MASK */
194
195
196 /* implemented in dyld_gdb.cpp */
197 extern void resetAllImages();
198 extern void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]);
199 extern void removeImageFromAllImages(const mach_header* mh);
200 extern void addNonSharedCacheImageUUID(const dyld_uuid_info& info);
201 extern const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const dyld_image_info info[]);
202 extern size_t allImagesCount();
203
204 // magic so CrashReporter logs message
205 extern "C" {
206 char error_string[1024];
207 }
208
209 // magic linker symbol for start of dyld binary
210 extern "C" const macho_header __dso_handle;
211
212
213 //
214 // The file contains the core of dyld used to get a process to main().
215 // The API's that dyld supports are implemented in dyldAPIs.cpp.
216 //
217 //
218 //
219 //
220 //
221 namespace dyld {
222 struct RegisteredDOF { const mach_header* mh; int registrationID; };
223 struct DylibOverride { const char* installName; const char* override; };
224 }
225
226
227 VECTOR_NEVER_DESTRUCTED(ImageLoader*);
228 VECTOR_NEVER_DESTRUCTED(dyld::RegisteredDOF);
229 VECTOR_NEVER_DESTRUCTED(dyld::ImageCallback);
230 VECTOR_NEVER_DESTRUCTED(dyld::DylibOverride);
231 VECTOR_NEVER_DESTRUCTED(ImageLoader::DynamicReference);
232
233 VECTOR_NEVER_DESTRUCTED(dyld_image_state_change_handler);
234
235 namespace dyld {
236
237
238 //
239 // state of all environment variables dyld uses
240 //
241 struct EnvironmentVariables {
242 const char* const * DYLD_FRAMEWORK_PATH;
243 const char* const * DYLD_FALLBACK_FRAMEWORK_PATH;
244 const char* const * DYLD_LIBRARY_PATH;
245 const char* const * DYLD_FALLBACK_LIBRARY_PATH;
246 const char* const * DYLD_INSERT_LIBRARIES;
247 const char* const * LD_LIBRARY_PATH; // for unix conformance
248 const char* const * DYLD_VERSIONED_LIBRARY_PATH;
249 const char* const * DYLD_VERSIONED_FRAMEWORK_PATH;
250 bool DYLD_PRINT_LIBRARIES_POST_LAUNCH;
251 bool DYLD_BIND_AT_LAUNCH;
252 bool DYLD_PRINT_STATISTICS;
253 bool DYLD_PRINT_STATISTICS_DETAILS;
254 bool DYLD_PRINT_OPTS;
255 bool DYLD_PRINT_ENV;
256 bool DYLD_DISABLE_DOFS;
257 // DYLD_SHARED_CACHE_DIR ==> sSharedCacheOverrideDir
258 // DYLD_ROOT_PATH ==> gLinkContext.rootPaths
259 // DYLD_IMAGE_SUFFIX ==> gLinkContext.imageSuffix
260 // DYLD_PRINT_OPTS ==> gLinkContext.verboseOpts
261 // DYLD_PRINT_ENV ==> gLinkContext.verboseEnv
262 // DYLD_FORCE_FLAT_NAMESPACE ==> gLinkContext.bindFlat
263 // DYLD_PRINT_INITIALIZERS ==> gLinkContext.verboseInit
264 // DYLD_PRINT_SEGMENTS ==> gLinkContext.verboseMapping
265 // DYLD_PRINT_BINDINGS ==> gLinkContext.verboseBind
266 // DYLD_PRINT_WEAK_BINDINGS ==> gLinkContext.verboseWeakBind
267 // DYLD_PRINT_REBASINGS ==> gLinkContext.verboseRebase
268 // DYLD_PRINT_DOFS ==> gLinkContext.verboseDOF
269 // DYLD_PRINT_APIS ==> gLogAPIs
270 // DYLD_IGNORE_PREBINDING ==> gLinkContext.prebindUsage
271 // DYLD_PREBIND_DEBUG ==> gLinkContext.verbosePrebinding
272 // DYLD_NEW_LOCAL_SHARED_REGIONS ==> gLinkContext.sharedRegionMode
273 // DYLD_SHARED_REGION ==> gLinkContext.sharedRegionMode
274 // DYLD_PRINT_WARNINGS ==> gLinkContext.verboseWarnings
275 // DYLD_PRINT_RPATHS ==> gLinkContext.verboseRPaths
276 // DYLD_PRINT_INTERPOSING ==> gLinkContext.verboseInterposing
277 // DYLD_PRINT_LIBRARIES ==> gLinkContext.verboseLoading
278 };
279
280
281
282 typedef std::vector<dyld_image_state_change_handler> StateHandlers;
283
284
285 enum EnvVarMode { envNone, envPrintOnly, envAll };
286
287 // all global state
288 static const char* sExecPath = NULL;
289 static const char* sExecShortName = NULL;
290 static const macho_header* sMainExecutableMachHeader = NULL;
291 static uintptr_t sMainExecutableSlide = 0;
292 #if CPU_SUBTYPES_SUPPORTED
293 static cpu_type_t sHostCPU;
294 static cpu_subtype_t sHostCPUsubtype;
295 #endif
296 static ImageLoaderMachO* sMainExecutable = NULL;
297 static size_t sInsertedDylibCount = 0;
298 static std::vector<ImageLoader*> sAllImages;
299 static std::vector<ImageLoader*> sImageRoots;
300 static std::vector<ImageLoader*> sImageFilesNeedingTermination;
301 static std::vector<RegisteredDOF> sImageFilesNeedingDOFUnregistration;
302 static std::vector<ImageCallback> sAddImageCallbacks;
303 static std::vector<ImageCallback> sRemoveImageCallbacks;
304 static std::vector<LoadImageCallback> sAddLoadImageCallbacks;
305 static bool sRemoveImageCallbacksInUse = false;
306 static void* sSingleHandlers[7][3];
307 static void* sBatchHandlers[7][3];
308 static ImageLoader* sLastImageByAddressCache;
309 static EnvironmentVariables sEnv;
310 #if __MAC_OS_X_VERSION_MIN_REQUIRED
311 static const char* sFrameworkFallbackPaths[] = { "$HOME/Library/Frameworks", "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", NULL };
312 static const char* sLibraryFallbackPaths[] = { "$HOME/lib", "/usr/local/lib", "/usr/lib", NULL };
313 static const char* sRestrictedFrameworkFallbackPaths[] = { "/System/Library/Frameworks", NULL };
314 static const char* sRestrictedLibraryFallbackPaths[] = { "/usr/lib", NULL };
315 #else
316 static const char* sFrameworkFallbackPaths[] = { "/System/Library/Frameworks", NULL };
317 static const char* sLibraryFallbackPaths[] = { "/usr/local/lib", "/usr/lib", NULL };
318 #endif
319 static UndefinedHandler sUndefinedHandler = NULL;
320 static ImageLoader* sBundleBeingLoaded = NULL; // hack until OFI is reworked
321 static dyld3::SharedCacheLoadInfo sSharedCacheLoadInfo;
322 static const char* sSharedCacheOverrideDir;
323 bool gSharedCacheOverridden = false;
324 ImageLoader::LinkContext gLinkContext;
325 bool gLogAPIs = false;
326 #if SUPPORT_ACCELERATE_TABLES
327 bool gLogAppAPIs = false;
328 #endif
329 const struct LibSystemHelpers* gLibSystemHelpers = NULL;
330 #if SUPPORT_OLD_CRT_INITIALIZATION
331 bool gRunInitializersOldWay = false;
332 #endif
333 static std::vector<DylibOverride> sDylibOverrides;
334 #if !TARGET_IPHONE_SIMULATOR
335 static int sLogSocket = -1;
336 #endif
337 static bool sFrameworksFoundAsDylibs = false;
338 #if __x86_64__ && !TARGET_IPHONE_SIMULATOR
339 static bool sHaswell = false;
340 #endif
341 static std::vector<ImageLoader::DynamicReference> sDynamicReferences;
342 static OSSpinLock sDynamicReferencesLock = 0;
343 #if !TARGET_IPHONE_SIMULATOR
344 static bool sLogToFile = false;
345 #endif
346 static char sLoadingCrashMessage[1024] = "dyld: launch, loading dependent libraries";
347 static _dyld_objc_notify_mapped sNotifyObjCMapped;
348 static _dyld_objc_notify_init sNotifyObjCInit;
349 static _dyld_objc_notify_unmapped sNotifyObjCUnmapped;
350
351 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR
352 static bool sForceStderr = false;
353 #endif
354
355
356 #if SUPPORT_ACCELERATE_TABLES
357 static ImageLoaderMegaDylib* sAllCacheImagesProxy = NULL;
358 static bool sDisableAcceleratorTables = false;
359 #endif
360
361 bool gUseDyld3 = false;
362 static bool sSkipMain = false;
363 static bool sEnableClosures = false;
364 static uint64_t launchTraceID = 0;
365
366 //
367 // The MappedRanges structure is used for fast address->image lookups.
368 // The table is only updated when the dyld lock is held, so we don't
369 // need to worry about multiple writers. But readers may look at this
370 // data without holding the lock. Therefore, all updates must be done
371 // in an order that will never cause readers to see inconsistent data.
372 // The general rule is that if the image field is non-NULL then
373 // the other fields are valid.
374 //
375 struct MappedRanges
376 {
377 MappedRanges* next;
378 unsigned long count;
379 struct {
380 ImageLoader* image;
381 uintptr_t start;
382 uintptr_t end;
383 } array[1];
384 };
385
386 static MappedRanges* sMappedRangesStart;
387
388 void addMappedRange(ImageLoader* image, uintptr_t start, uintptr_t end)
389 {
390 //dyld::log("addMappedRange(0x%lX->0x%lX) for %s\n", start, end, image->getShortName());
391 for (MappedRanges* p = sMappedRangesStart; p != NULL; p = p->next) {
392 for (unsigned long i=0; i < p->count; ++i) {
393 if ( p->array[i].image == NULL ) {
394 p->array[i].start = start;
395 p->array[i].end = end;
396 // add image field last with a barrier so that any reader will see consistent records
397 OSMemoryBarrier();
398 p->array[i].image = image;
399 return;
400 }
401 }
402 }
403 // table must be full, chain another
404 #if SUPPORT_ACCELERATE_TABLES
405 unsigned count = (sAllCacheImagesProxy != NULL) ? 16 : 400;
406 #else
407 unsigned count = 400;
408 #endif
409 size_t allocationSize = sizeof(MappedRanges) + (count-1)*3*sizeof(void*);
410 MappedRanges* newRanges = (MappedRanges*)malloc(allocationSize);
411 bzero(newRanges, allocationSize);
412 newRanges->count = count;
413 newRanges->array[0].start = start;
414 newRanges->array[0].end = end;
415 newRanges->array[0].image = image;
416 OSMemoryBarrier();
417 if ( sMappedRangesStart == NULL ) {
418 sMappedRangesStart = newRanges;
419 }
420 else {
421 for (MappedRanges* p = sMappedRangesStart; p != NULL; p = p->next) {
422 if ( p->next == NULL ) {
423 OSMemoryBarrier();
424 p->next = newRanges;
425 break;
426 }
427 }
428 }
429 }
430
431 void removedMappedRanges(ImageLoader* image)
432 {
433 for (MappedRanges* p = sMappedRangesStart; p != NULL; p = p->next) {
434 for (unsigned long i=0; i < p->count; ++i) {
435 if ( p->array[i].image == image ) {
436 // clear with a barrier so that any reader will see consistent records
437 OSMemoryBarrier();
438 p->array[i].image = NULL;
439 }
440 }
441 }
442 }
443
444 ImageLoader* findMappedRange(uintptr_t target)
445 {
446 for (MappedRanges* p = sMappedRangesStart; p != NULL; p = p->next) {
447 for (unsigned long i=0; i < p->count; ++i) {
448 if ( p->array[i].image != NULL ) {
449 if ( (p->array[i].start <= target) && (target < p->array[i].end) )
450 return p->array[i].image;
451 }
452 }
453 }
454 return NULL;
455 }
456
457
458
459 const char* mkstringf(const char* format, ...)
460 {
461 _SIMPLE_STRING buf = _simple_salloc();
462 if ( buf != NULL ) {
463 va_list list;
464 va_start(list, format);
465 _simple_vsprintf(buf, format, list);
466 va_end(list);
467 const char* t = strdup(_simple_string(buf));
468 _simple_sfree(buf);
469 if ( t != NULL )
470 return t;
471 }
472 return "mkstringf, out of memory error";
473 }
474
475
476 void throwf(const char* format, ...)
477 {
478 _SIMPLE_STRING buf = _simple_salloc();
479 if ( buf != NULL ) {
480 va_list list;
481 va_start(list, format);
482 _simple_vsprintf(buf, format, list);
483 va_end(list);
484 const char* t = strdup(_simple_string(buf));
485 _simple_sfree(buf);
486 if ( t != NULL )
487 throw t;
488 }
489 throw "throwf, out of memory error";
490 }
491
492
493 #if !TARGET_IPHONE_SIMULATOR
494 static int sLogfile = STDERR_FILENO;
495 #endif
496
497 #if !TARGET_IPHONE_SIMULATOR
498 // based on CFUtilities.c: also_do_stderr()
499 static bool useSyslog()
500 {
501 // Use syslog() for processes managed by launchd
502 static bool launchdChecked = false;
503 static bool launchdOwned = false;
504 if ( !launchdChecked && gProcessInfo->libSystemInitialized ) {
505 if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 11) ) {
506 // <rdar://problem/23520449> only call isLaunchdOwned() after libSystem is initialized
507 launchdOwned = (*gLibSystemHelpers->isLaunchdOwned)();
508 launchdChecked = true;
509 }
510 }
511 if ( launchdChecked && launchdOwned )
512 return true;
513
514 // If stderr is not available, use syslog()
515 struct stat sb;
516 int result = fstat(STDERR_FILENO, &sb);
517 if ( result < 0 )
518 return true; // file descriptor 2 is closed
519
520 return false;
521 }
522
523
524 static void socket_syslogv(int priority, const char* format, va_list list)
525 {
526 // lazily create socket and connection to syslogd
527 if ( sLogSocket == -1 ) {
528 sLogSocket = ::socket(AF_UNIX, SOCK_DGRAM, 0);
529 if (sLogSocket == -1)
530 return; // cannot log
531 ::fcntl(sLogSocket, F_SETFD, 1);
532
533 struct sockaddr_un addr;
534 addr.sun_family = AF_UNIX;
535 strncpy(addr.sun_path, _PATH_LOG, sizeof(addr.sun_path));
536 if ( ::connect(sLogSocket, (struct sockaddr *)&addr, sizeof(addr)) == -1 ) {
537 ::close(sLogSocket);
538 sLogSocket = -1;
539 return;
540 }
541 }
542
543 // format message to syslogd like: "<priority>Process[pid]: message"
544 _SIMPLE_STRING buf = _simple_salloc();
545 if ( buf == NULL )
546 return;
547 if ( _simple_sprintf(buf, "<%d>%s[%d]: ", LOG_USER|LOG_NOTICE, sExecShortName, getpid()) == 0 ) {
548 if ( _simple_vsprintf(buf, format, list) == 0 ) {
549 const char* p = _simple_string(buf);
550 ::__sendto(sLogSocket, p, strlen(p), 0, NULL, 0);
551 }
552 }
553 _simple_sfree(buf);
554 }
555
556
557
558 void vlog(const char* format, va_list list)
559 {
560 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR
561 // <rdar://problem/25965832> log to console when running iOS app from Xcode
562 if ( !sLogToFile && !sForceStderr && useSyslog() )
563 #else
564 if ( !sLogToFile && useSyslog() )
565 #endif
566 socket_syslogv(LOG_ERR, format, list);
567 else {
568 _simple_vdprintf(sLogfile, format, list);
569 }
570 }
571
572 void log(const char* format, ...)
573 {
574 va_list list;
575 va_start(list, format);
576 vlog(format, list);
577 va_end(list);
578 }
579
580
581 void vwarn(const char* format, va_list list)
582 {
583 _simple_dprintf(sLogfile, "dyld: warning, ");
584 _simple_vdprintf(sLogfile, format, list);
585 }
586
587 void warn(const char* format, ...)
588 {
589 va_list list;
590 va_start(list, format);
591 vwarn(format, list);
592 va_end(list);
593 }
594
595 #else
596 extern void vlog(const char* format, va_list list);
597 #endif // !TARGET_IPHONE_SIMULATOR
598
599
600 // <rdar://problem/8867781> control access to sAllImages through a lock
601 // because global dyld lock is not held during initialization phase of dlopen()
602 // <rdar://problem/16145518> Use OSSpinLockLock to allow yielding
603 static OSSpinLock sAllImagesLock = 0;
604
605 static void allImagesLock()
606 {
607 OSSpinLockLock(&sAllImagesLock);
608 }
609
610 static void allImagesUnlock()
611 {
612 OSSpinLockUnlock(&sAllImagesLock);
613 }
614
615
616 // utility class to assure files are closed when an exception is thrown
617 class FileOpener {
618 public:
619 FileOpener(const char* path);
620 ~FileOpener();
621 int getFileDescriptor() { return fd; }
622 private:
623 int fd;
624 };
625
626 FileOpener::FileOpener(const char* path)
627 : fd(-1)
628 {
629 fd = my_open(path, O_RDONLY, 0);
630 }
631
632 FileOpener::~FileOpener()
633 {
634 if ( fd != -1 )
635 close(fd);
636 }
637
638
639 static void registerDOFs(const std::vector<ImageLoader::DOFInfo>& dofs)
640 {
641 const size_t dofSectionCount = dofs.size();
642 if ( !sEnv.DYLD_DISABLE_DOFS && (dofSectionCount != 0) ) {
643 int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
644 if ( fd < 0 ) {
645 //dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to register dtrace DOF sections\n");
646 }
647 else {
648 // allocate a buffer on the stack for the variable length dof_ioctl_data_t type
649 uint8_t buffer[sizeof(dof_ioctl_data_t) + dofSectionCount*sizeof(dof_helper_t)];
650 dof_ioctl_data_t* ioctlData = (dof_ioctl_data_t*)buffer;
651
652 // fill in buffer with one dof_helper_t per DOF section
653 ioctlData->dofiod_count = dofSectionCount;
654 for (unsigned int i=0; i < dofSectionCount; ++i) {
655 strlcpy(ioctlData->dofiod_helpers[i].dofhp_mod, dofs[i].imageShortName, DTRACE_MODNAMELEN);
656 ioctlData->dofiod_helpers[i].dofhp_dof = (uintptr_t)(dofs[i].dof);
657 ioctlData->dofiod_helpers[i].dofhp_addr = (uintptr_t)(dofs[i].dof);
658 }
659
660 // tell kernel about all DOF sections en mas
661 // pass pointer to ioctlData because ioctl() only copies a fixed size amount of data into kernel
662 user_addr_t val = (user_addr_t)(unsigned long)ioctlData;
663 if ( ioctl(fd, DTRACEHIOC_ADDDOF, &val) != -1 ) {
664 // kernel returns a unique identifier for each section in the dofiod_helpers[].dofhp_dof field.
665 for (unsigned int i=0; i < dofSectionCount; ++i) {
666 RegisteredDOF info;
667 info.mh = dofs[i].imageHeader;
668 info.registrationID = (int)(ioctlData->dofiod_helpers[i].dofhp_dof);
669 sImageFilesNeedingDOFUnregistration.push_back(info);
670 if ( gLinkContext.verboseDOF ) {
671 dyld::log("dyld: registering DOF section %p in %s with dtrace, ID=0x%08X\n",
672 dofs[i].dof, dofs[i].imageShortName, info.registrationID);
673 }
674 }
675 }
676 else {
677 //dyld::log( "dyld: ioctl to register dtrace DOF section failed\n");
678 }
679 close(fd);
680 }
681 }
682 }
683
684 static void unregisterDOF(int registrationID)
685 {
686 int fd = open("/dev/" DTRACEMNR_HELPER, O_RDWR);
687 if ( fd < 0 ) {
688 dyld::warn("can't open /dev/" DTRACEMNR_HELPER " to unregister dtrace DOF section\n");
689 }
690 else {
691 ioctl(fd, DTRACEHIOC_REMOVE, registrationID);
692 close(fd);
693 if ( gLinkContext.verboseInit )
694 dyld::warn("unregistering DOF section ID=0x%08X with dtrace\n", registrationID);
695 }
696 }
697
698
699 //
700 // _dyld_register_func_for_add_image() is implemented as part of the general image state change notification
701 //
702 static void notifyAddImageCallbacks(ImageLoader* image)
703 {
704 // use guard so that we cannot notify about the same image twice
705 if ( ! image->addFuncNotified() ) {
706 for (std::vector<ImageCallback>::iterator it=sAddImageCallbacks.begin(); it != sAddImageCallbacks.end(); it++) {
707 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE, (uint64_t)image->machHeader(), (uint64_t)(*it), 0);
708 (*it)(image->machHeader(), image->getSlide());
709 }
710 for (LoadImageCallback func : sAddLoadImageCallbacks) {
711 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE, (uint64_t)image->machHeader(), (uint64_t)(*func), 0);
712 (*func)(image->machHeader(), image->getPath(), !image->neverUnload());
713 }
714 image->setAddFuncNotified();
715 }
716 }
717
718
719
720 // notify gdb about these new images
721 static const char* updateAllImages(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
722 {
723 // <rdar://problem/8812589> don't add images without paths to all-image-info-list
724 if ( info[0].imageFilePath != NULL )
725 addImagesToAllImages(infoCount, info);
726 return NULL;
727 }
728
729
730 static StateHandlers* stateToHandlers(dyld_image_states state, void* handlersArray[7][3])
731 {
732 switch ( state ) {
733 case dyld_image_state_mapped:
734 return reinterpret_cast<StateHandlers*>(&handlersArray[0]);
735
736 case dyld_image_state_dependents_mapped:
737 return reinterpret_cast<StateHandlers*>(&handlersArray[1]);
738
739 case dyld_image_state_rebased:
740 return reinterpret_cast<StateHandlers*>(&handlersArray[2]);
741
742 case dyld_image_state_bound:
743 return reinterpret_cast<StateHandlers*>(&handlersArray[3]);
744
745 case dyld_image_state_dependents_initialized:
746 return reinterpret_cast<StateHandlers*>(&handlersArray[4]);
747
748 case dyld_image_state_initialized:
749 return reinterpret_cast<StateHandlers*>(&handlersArray[5]);
750
751 case dyld_image_state_terminated:
752 return reinterpret_cast<StateHandlers*>(&handlersArray[6]);
753 }
754 return NULL;
755 }
756
757 #if SUPPORT_ACCELERATE_TABLES
758 static dyld_image_state_change_handler getPreInitNotifyHandler(unsigned index)
759 {
760 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(dyld_image_state_dependents_initialized, sSingleHandlers);
761 if ( index >= handlers->size() )
762 return NULL;
763 return (*handlers)[index];
764 }
765
766 static dyld_image_state_change_handler getBoundBatchHandler(unsigned index)
767 {
768 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(dyld_image_state_bound, sBatchHandlers);
769 if ( index >= handlers->size() )
770 return NULL;
771 return (*handlers)[index];
772 }
773
774 static void notifySingleFromCache(dyld_image_states state, const mach_header* mh, const char* path)
775 {
776 //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath());
777 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
778 if ( handlers != NULL ) {
779 dyld_image_info info;
780 info.imageLoadAddress = mh;
781 info.imageFilePath = path;
782 info.imageFileModDate = 0;
783 for (dyld_image_state_change_handler handler : *handlers) {
784 const char* result = (*handler)(state, 1, &info);
785 if ( (result != NULL) && (state == dyld_image_state_mapped) ) {
786 //fprintf(stderr, " image rejected by handler=%p\n", *it);
787 // make copy of thrown string so that later catch clauses can free it
788 const char* str = strdup(result);
789 throw str;
790 }
791 }
792 }
793 if ( (state == dyld_image_state_dependents_initialized) && (sNotifyObjCInit != NULL) && (mh->flags & MH_HAS_OBJC) ) {
794 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)mh, 0, 0);
795 (*sNotifyObjCInit)(path, mh);
796 }
797 }
798 #endif
799
800 #if !TARGET_OS_SIMULATOR
801 static void sendMessage(unsigned portSlot, mach_msg_id_t msgId, mach_msg_size_t sendSize, mach_msg_header_t* buffer, mach_msg_size_t bufferSize) {
802 // Allocate a port to listen on in this monitoring task
803 mach_port_t sendPort = dyld::gProcessInfo->notifyPorts[portSlot];
804 if (sendPort == MACH_PORT_NULL) {
805 return;
806 }
807 mach_port_t replyPort = MACH_PORT_NULL;
808 mach_port_options_t options = { .flags = MPO_CONTEXT_AS_GUARD | MPO_STRICT,
809 .mpl = { 1 }};
810 kern_return_t kr = mach_port_construct(mach_task_self(), &options, (mach_port_context_t)&replyPort, &replyPort);
811 if (kr != KERN_SUCCESS) {
812 return;
813 }
814 // Assemble a message
815 mach_msg_header_t* h = buffer;
816 h->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
817 h->msgh_id = msgId;
818 h->msgh_local_port = replyPort;
819 h->msgh_remote_port = sendPort;
820 h->msgh_reserved = 0;
821 h->msgh_size = sendSize;
822 kr = mach_msg(h, MACH_SEND_MSG | MACH_RCV_MSG, h->msgh_size, bufferSize, replyPort, 0, MACH_PORT_NULL);
823 mach_msg_destroy(h);
824 if ( kr == MACH_SEND_INVALID_DEST ) {
825 if (OSAtomicCompareAndSwap32(sendPort, 0, (volatile int32_t*)&dyld::gProcessInfo->notifyPorts[portSlot])) {
826 mach_port_deallocate(mach_task_self(), sendPort);
827 }
828 }
829 mach_port_destruct(mach_task_self(), replyPort, 0, (mach_port_context_t)&replyPort);
830 }
831
832 static void notifyMonitoringDyld(bool unloading, unsigned imageCount, const struct mach_header* loadAddresses[],
833 const char* imagePaths[])
834 {
835 dyld3::ScopedTimer(DBG_DYLD_REMOTE_IMAGE_NOTIFIER, 0, 0, 0);
836 for (int slot=0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; ++slot) {
837 if ( dyld::gProcessInfo->notifyPorts[slot] == 0) continue;
838 unsigned entriesSize = imageCount*sizeof(dyld_process_info_image_entry);
839 unsigned pathsSize = 0;
840 for (unsigned j=0; j < imageCount; ++j) {
841 pathsSize += (strlen(imagePaths[j]) + 1);
842 }
843 unsigned totalSize = (sizeof(dyld_process_info_notify_header) + entriesSize + pathsSize + 127) & -128; // align
844 if ( totalSize > DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE ) {
845 // Putting all image paths into one message would make buffer too big.
846 // Instead split into two messages. Recurse as needed until paths fit in buffer.
847 unsigned imageHalfCount = imageCount/2;
848 notifyMonitoringDyld(unloading, imageHalfCount, loadAddresses, imagePaths);
849 notifyMonitoringDyld(unloading, imageCount - imageHalfCount, &loadAddresses[imageHalfCount], &imagePaths[imageHalfCount]);
850 return;
851 }
852 uint8_t buffer[totalSize + MAX_TRAILER_SIZE];
853 dyld_process_info_notify_header* header = (dyld_process_info_notify_header*)buffer;
854 header->version = 1;
855 header->imageCount = imageCount;
856 header->imagesOffset = sizeof(dyld_process_info_notify_header);
857 header->stringsOffset = sizeof(dyld_process_info_notify_header) + entriesSize;
858 header->timestamp = dyld::gProcessInfo->infoArrayChangeTimestamp;
859 dyld_process_info_image_entry* entries = (dyld_process_info_image_entry*)&buffer[header->imagesOffset];
860 char* const pathPoolStart = (char*)&buffer[header->stringsOffset];
861 char* pathPool = pathPoolStart;
862 for (unsigned j=0; j < imageCount; ++j) {
863 strcpy(pathPool, imagePaths[j]);
864 uint32_t len = (uint32_t)strlen(pathPool);
865 bzero(entries->uuid, 16);
866 dyld3::MachOFile* mf = (dyld3::MachOFile*)loadAddresses[j];
867 mf->getUuid(entries->uuid);
868 entries->loadAddress = (uint64_t)loadAddresses[j];
869 entries->pathStringOffset = (uint32_t)(pathPool - pathPoolStart);
870 entries->pathLength = len;
871 pathPool += (len +1);
872 ++entries;
873 }
874 if (unloading) {
875 sendMessage(slot, DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID, totalSize, (mach_msg_header_t*)buffer, totalSize+MAX_TRAILER_SIZE);
876 } else {
877 sendMessage(slot, DYLD_PROCESS_INFO_NOTIFY_LOAD_ID, totalSize, (mach_msg_header_t*)buffer, totalSize+MAX_TRAILER_SIZE);
878 }
879 }
880 }
881
882 static void notifyMonitoringDyldMain()
883 {
884 dyld3::ScopedTimer(DBG_DYLD_REMOTE_IMAGE_NOTIFIER, 0, 0, 0);
885 for (int slot=0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; ++slot) {
886 if ( dyld::gProcessInfo->notifyPorts[slot] == 0) continue;
887 uint8_t buffer[sizeof(mach_msg_header_t) + MAX_TRAILER_SIZE];
888 sendMessage(slot, DYLD_PROCESS_INFO_NOTIFY_MAIN_ID, sizeof(mach_msg_header_t), (mach_msg_header_t*)buffer, sizeof(mach_msg_header_t) + MAX_TRAILER_SIZE);
889 }
890 }
891 #else
892 extern void notifyMonitoringDyldMain() VIS_HIDDEN;
893 extern void notifyMonitoringDyld(bool unloading, unsigned imageCount, const struct mach_header* loadAddresses[],
894 const char* imagePaths[]) VIS_HIDDEN;
895 #endif
896
897 void notifyKernel(const ImageLoader& image, bool loading) {
898 if ( !image.inSharedCache() ) {
899 uint32_t baseCode = loading ? DBG_DYLD_UUID_MAP_A : DBG_DYLD_UUID_UNMAP_A;
900 uuid_t uuid;
901 ino_t inode = image.getInode();
902 image.getUUID(uuid);
903 dyld3::kdebug_trace_dyld_image(baseCode, (const uuid_t *)&uuid, *(fsobj_id_t*)&inode, {{ image.getDevice(), 0 }}, image.machHeader());
904 }
905 }
906
907 static void notifySingle(dyld_image_states state, const ImageLoader* image, ImageLoader::InitializerTimingList* timingInfo)
908 {
909 //dyld::log("notifySingle(state=%d, image=%s)\n", state, image->getPath());
910 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
911 if ( handlers != NULL ) {
912 dyld_image_info info;
913 info.imageLoadAddress = image->machHeader();
914 info.imageFilePath = image->getRealPath();
915 info.imageFileModDate = image->lastModified();
916 for (std::vector<dyld_image_state_change_handler>::iterator it = handlers->begin(); it != handlers->end(); ++it) {
917 const char* result = (*it)(state, 1, &info);
918 if ( (result != NULL) && (state == dyld_image_state_mapped) ) {
919 //fprintf(stderr, " image rejected by handler=%p\n", *it);
920 // make copy of thrown string so that later catch clauses can free it
921 const char* str = strdup(result);
922 throw str;
923 }
924 }
925 }
926 if ( state == dyld_image_state_mapped ) {
927 // <rdar://problem/7008875> Save load addr + UUID for images from outside the shared cache
928 if ( !image->inSharedCache() ) {
929 dyld_uuid_info info;
930 if ( image->getUUID(info.imageUUID) ) {
931 info.imageLoadAddress = image->machHeader();
932 addNonSharedCacheImageUUID(info);
933 }
934 }
935 }
936 if ( (state == dyld_image_state_dependents_initialized) && (sNotifyObjCInit != NULL) && image->notifyObjC() ) {
937 uint64_t t0 = mach_absolute_time();
938 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)image->machHeader(), 0, 0);
939 (*sNotifyObjCInit)(image->getRealPath(), image->machHeader());
940 uint64_t t1 = mach_absolute_time();
941 uint64_t t2 = mach_absolute_time();
942 uint64_t timeInObjC = t1-t0;
943 uint64_t emptyTime = (t2-t1)*100;
944 if ( (timeInObjC > emptyTime) && (timingInfo != NULL) ) {
945 timingInfo->addTime(image->getShortName(), timeInObjC);
946 }
947 }
948 // mach message csdlc about dynamically unloaded images
949 if ( image->addFuncNotified() && (state == dyld_image_state_terminated) ) {
950 notifyKernel(*image, false);
951 const struct mach_header* loadAddress[] = { image->machHeader() };
952 const char* loadPath[] = { image->getPath() };
953 notifyMonitoringDyld(true, 1, loadAddress, loadPath);
954 }
955 }
956
957
958 //
959 // Normally, dyld_all_image_infos is only updated in batches after an entire
960 // graph is loaded. But if there is an error loading the initial set of
961 // dylibs needed by the main executable, dyld_all_image_infos is not yet set
962 // up, leading to usually brief crash logs.
963 //
964 // This function manually adds the images loaded so far to dyld::gProcessInfo.
965 // It should only be called before terminating.
966 //
967 void syncAllImages()
968 {
969 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
970 dyld_image_info info;
971 ImageLoader* image = *it;
972 info.imageLoadAddress = image->machHeader();
973 info.imageFilePath = image->getRealPath();
974 info.imageFileModDate = image->lastModified();
975 // add to all_image_infos if not already there
976 bool found = false;
977 int existingCount = dyld::gProcessInfo->infoArrayCount;
978 const dyld_image_info* existing = dyld::gProcessInfo->infoArray;
979 if ( existing != NULL ) {
980 for (int i=0; i < existingCount; ++i) {
981 if ( existing[i].imageLoadAddress == info.imageLoadAddress ) {
982 //dyld::log("not adding %s\n", info.imageFilePath);
983 found = true;
984 break;
985 }
986 }
987 }
988 if ( ! found ) {
989 //dyld::log("adding %s\n", info.imageFilePath);
990 addImagesToAllImages(1, &info);
991 }
992 }
993 }
994
995
996 static int imageSorter(const void* l, const void* r)
997 {
998 const ImageLoader* left = *((ImageLoader**)l);
999 const ImageLoader* right= *((ImageLoader**)r);
1000 return left->compare(right);
1001 }
1002
1003 static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image_state_change_handler onlyHandler, bool preflightOnly, bool onlyObjCMappedNotification)
1004 {
1005 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sBatchHandlers);
1006 if ( (handlers != NULL) || ((state == dyld_image_state_bound) && (sNotifyObjCMapped != NULL)) ) {
1007 // don't use a vector because it will use malloc/free and we want notifcation to be low cost
1008 allImagesLock();
1009 dyld_image_info infos[allImagesCount()+1];
1010 ImageLoader* images[allImagesCount()+1];
1011 ImageLoader** end = images;
1012 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
1013 dyld_image_states imageState = (*it)->getState();
1014 if ( (imageState == state) || (orLater && (imageState > state)) )
1015 *end++ = *it;
1016 }
1017 if ( sBundleBeingLoaded != NULL ) {
1018 dyld_image_states imageState = sBundleBeingLoaded->getState();
1019 if ( (imageState == state) || (orLater && (imageState > state)) )
1020 *end++ = sBundleBeingLoaded;
1021 }
1022 const char* dontLoadReason = NULL;
1023 uint32_t imageCount = (uint32_t)(end-images);
1024 if ( imageCount != 0 ) {
1025 // sort bottom up
1026 qsort(images, imageCount, sizeof(ImageLoader*), &imageSorter);
1027 // build info array
1028 for (unsigned int i=0; i < imageCount; ++i) {
1029 dyld_image_info* p = &infos[i];
1030 ImageLoader* image = images[i];
1031 //dyld::log(" state=%d, name=%s\n", state, image->getPath());
1032 p->imageLoadAddress = image->machHeader();
1033 p->imageFilePath = image->getRealPath();
1034 p->imageFileModDate = image->lastModified();
1035 // get these registered with the kernel as early as possible
1036 if ( state == dyld_image_state_dependents_mapped)
1037 notifyKernel(*image, true);
1038 // special case for add_image hook
1039 if ( state == dyld_image_state_bound )
1040 notifyAddImageCallbacks(image);
1041 }
1042 }
1043 #if SUPPORT_ACCELERATE_TABLES
1044 if ( sAllCacheImagesProxy != NULL ) {
1045 unsigned cacheCount = sAllCacheImagesProxy->appendImagesToNotify(state, orLater, &infos[imageCount]);
1046 // support _dyld_register_func_for_add_image()
1047 if ( state == dyld_image_state_bound ) {
1048 for (ImageCallback callback : sAddImageCallbacks) {
1049 for (unsigned i=0; i < cacheCount; ++i) {
1050 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE, (uint64_t)infos[imageCount+i].imageLoadAddress, (uint64_t)(*callback), 0);
1051 (*callback)(infos[imageCount+i].imageLoadAddress, sSharedCacheLoadInfo.slide);
1052 }
1053 }
1054 for (LoadImageCallback func : sAddLoadImageCallbacks) {
1055 for (unsigned i=0; i < cacheCount; ++i) {
1056 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE, (uint64_t)infos[imageCount+i].imageLoadAddress, (uint64_t)(*func), 0);
1057 (*func)(infos[imageCount+i].imageLoadAddress, infos[imageCount+i].imageFilePath, false);
1058 }
1059 }
1060 }
1061 imageCount += cacheCount;
1062 }
1063 #endif
1064 if ( imageCount != 0 ) {
1065 if ( !onlyObjCMappedNotification ) {
1066 if ( onlyHandler != NULL ) {
1067 const char* result = NULL;
1068 if ( result == NULL ) {
1069 result = (*onlyHandler)(state, imageCount, infos);
1070 }
1071 if ( (result != NULL) && (state == dyld_image_state_dependents_mapped) ) {
1072 //fprintf(stderr, " images rejected by handler=%p\n", onlyHandler);
1073 // make copy of thrown string so that later catch clauses can free it
1074 dontLoadReason = strdup(result);
1075 }
1076 }
1077 else {
1078 // call each handler with whole array
1079 if ( handlers != NULL ) {
1080 for (std::vector<dyld_image_state_change_handler>::iterator it = handlers->begin(); it != handlers->end(); ++it) {
1081 const char* result = (*it)(state, imageCount, infos);
1082 if ( (result != NULL) && (state == dyld_image_state_dependents_mapped) ) {
1083 //fprintf(stderr, " images rejected by handler=%p\n", *it);
1084 // make copy of thrown string so that later catch clauses can free it
1085 dontLoadReason = strdup(result);
1086 break;
1087 }
1088 }
1089 }
1090 }
1091 }
1092 // tell objc about new images
1093 if ( (onlyHandler == NULL) && ((state == dyld_image_state_bound) || (orLater && (dyld_image_state_bound > state))) && (sNotifyObjCMapped != NULL) ) {
1094 const char* paths[imageCount];
1095 const mach_header* mhs[imageCount];
1096 unsigned objcImageCount = 0;
1097 for (int i=0; i < imageCount; ++i) {
1098 const ImageLoader* image = findImageByMachHeader(infos[i].imageLoadAddress);
1099 bool hasObjC = false;
1100 if ( image != NULL ) {
1101 hasObjC = image->notifyObjC();
1102 }
1103 #if SUPPORT_ACCELERATE_TABLES
1104 else if ( sAllCacheImagesProxy != NULL ) {
1105 const mach_header* mh;
1106 const char* path;
1107 unsigned index;
1108 if ( sAllCacheImagesProxy->addressInCache(infos[i].imageLoadAddress, &mh, &path, &index) ) {
1109 hasObjC = (mh->flags & MH_HAS_OBJC);
1110 }
1111 }
1112 #endif
1113 if ( hasObjC ) {
1114 paths[objcImageCount] = infos[i].imageFilePath;
1115 mhs[objcImageCount] = infos[i].imageLoadAddress;
1116 ++objcImageCount;
1117 }
1118 }
1119 if ( objcImageCount != 0 ) {
1120 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_MAP, 0, 0, 0);
1121 uint64_t t0 = mach_absolute_time();
1122 (*sNotifyObjCMapped)(objcImageCount, paths, mhs);
1123 uint64_t t1 = mach_absolute_time();
1124 ImageLoader::fgTotalObjCSetupTime += (t1-t0);
1125 }
1126 }
1127 }
1128 allImagesUnlock();
1129 if ( dontLoadReason != NULL )
1130 throw dontLoadReason;
1131 if ( !preflightOnly && (state == dyld_image_state_dependents_mapped) ) {
1132 const struct mach_header* loadAddresses[imageCount];
1133 const char* loadPaths[imageCount];
1134 for(uint32_t i = 0; i<imageCount; ++i) {
1135 loadAddresses[i] = infos[i].imageLoadAddress;
1136 loadPaths[i] = infos[i].imageFilePath;
1137 }
1138 notifyMonitoringDyld(false, imageCount, loadAddresses, loadPaths);
1139 }
1140 }
1141 }
1142
1143 static void notifyBatch(dyld_image_states state, bool preflightOnly)
1144 {
1145 notifyBatchPartial(state, false, NULL, preflightOnly, false);
1146 }
1147
1148 static
1149 void coresymbolication_load_notifier(void* connection, uint64_t timestamp, const char* path, const struct mach_header* mh)
1150 {
1151 const struct mach_header* loadAddress[] = { mh };
1152 const char* loadPath[] = { path };
1153 notifyMonitoringDyld(false, 1, loadAddress, loadPath);
1154 }
1155
1156 static
1157 void coresymbolication_unload_notifier(void* connection, uint64_t timestamp, const char* path, const struct mach_header* mh)
1158 {
1159 const struct mach_header* loadAddress = { mh };
1160 const char* loadPath = { path };
1161 notifyMonitoringDyld(true, 1, &loadAddress, &loadPath);
1162 }
1163
1164 // In order for register_func_for_add_image() callbacks to to be called bottom up,
1165 // we need to maintain a list of root images. The main executable is usally the
1166 // first root. Any images dynamically added are also roots (unless already loaded).
1167 // If DYLD_INSERT_LIBRARIES is used, those libraries are first.
1168 static void addRootImage(ImageLoader* image)
1169 {
1170 //dyld::log("addRootImage(%p, %s)\n", image, image->getPath());
1171 // add to list of roots
1172 sImageRoots.push_back(image);
1173 }
1174
1175
1176 static void clearAllDepths()
1177 {
1178 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++)
1179 (*it)->clearDepth();
1180 }
1181
1182 static void printAllDepths()
1183 {
1184 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++)
1185 dyld::log("%03d %s\n", (*it)->getDepth(), (*it)->getShortName());
1186 }
1187
1188
1189 static unsigned int imageCount()
1190 {
1191 allImagesLock();
1192 unsigned int result = (unsigned int)sAllImages.size();
1193 allImagesUnlock();
1194 return (result);
1195 }
1196
1197
1198 static void setNewProgramVars(const ProgramVars& newVars)
1199 {
1200 // make a copy of the pointers to program variables
1201 gLinkContext.programVars = newVars;
1202
1203 // now set each program global to their initial value
1204 *gLinkContext.programVars.NXArgcPtr = gLinkContext.argc;
1205 *gLinkContext.programVars.NXArgvPtr = gLinkContext.argv;
1206 *gLinkContext.programVars.environPtr = gLinkContext.envp;
1207 *gLinkContext.programVars.__prognamePtr = gLinkContext.progname;
1208 }
1209
1210 #if SUPPORT_OLD_CRT_INITIALIZATION
1211 static void setRunInitialzersOldWay()
1212 {
1213 gRunInitializersOldWay = true;
1214 }
1215 #endif
1216
1217 static bool sandboxBlocked(const char* path, const char* kind)
1218 {
1219 #if TARGET_IPHONE_SIMULATOR
1220 // sandbox calls not yet supported in simulator runtime
1221 return false;
1222 #else
1223 sandbox_filter_type filter = (sandbox_filter_type)(SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT);
1224 return ( sandbox_check(getpid(), kind, filter, path) > 0 );
1225 #endif
1226 }
1227
1228 bool sandboxBlockedMmap(const char* path)
1229 {
1230 return sandboxBlocked(path, "file-map-executable");
1231 }
1232
1233 bool sandboxBlockedOpen(const char* path)
1234 {
1235 return sandboxBlocked(path, "file-read-data");
1236 }
1237
1238 bool sandboxBlockedStat(const char* path)
1239 {
1240 return sandboxBlocked(path, "file-read-metadata");
1241 }
1242
1243
1244 static void addDynamicReference(ImageLoader* from, ImageLoader* to) {
1245 // don't add dynamic reference if target is in the shared cache (since it can't be unloaded)
1246 if ( to->inSharedCache() )
1247 return;
1248
1249 // don't add dynamic reference if there already is a static one
1250 if ( from->dependsOn(to) )
1251 return;
1252
1253 // don't add if this combination already exists
1254 OSSpinLockLock(&sDynamicReferencesLock);
1255 for (std::vector<ImageLoader::DynamicReference>::iterator it=sDynamicReferences.begin(); it != sDynamicReferences.end(); ++it) {
1256 if ( (it->from == from) && (it->to == to) ) {
1257 OSSpinLockUnlock(&sDynamicReferencesLock);
1258 return;
1259 }
1260 }
1261
1262 //dyld::log("addDynamicReference(%s, %s\n", from->getShortName(), to->getShortName());
1263 ImageLoader::DynamicReference t;
1264 t.from = from;
1265 t.to = to;
1266 sDynamicReferences.push_back(t);
1267 OSSpinLockUnlock(&sDynamicReferencesLock);
1268 }
1269
1270 static void addImage(ImageLoader* image)
1271 {
1272 // add to master list
1273 allImagesLock();
1274 sAllImages.push_back(image);
1275 allImagesUnlock();
1276
1277 // update mapped ranges
1278 uintptr_t lastSegStart = 0;
1279 uintptr_t lastSegEnd = 0;
1280 for(unsigned int i=0, e=image->segmentCount(); i < e; ++i) {
1281 if ( image->segUnaccessible(i) )
1282 continue;
1283 uintptr_t start = image->segActualLoadAddress(i);
1284 uintptr_t end = image->segActualEndAddress(i);
1285 if ( start == lastSegEnd ) {
1286 // two segments are contiguous, just record combined segments
1287 lastSegEnd = end;
1288 }
1289 else {
1290 // non-contiguous segments, record last (if any)
1291 if ( lastSegEnd != 0 )
1292 addMappedRange(image, lastSegStart, lastSegEnd);
1293 lastSegStart = start;
1294 lastSegEnd = end;
1295 }
1296 }
1297 if ( lastSegEnd != 0 )
1298 addMappedRange(image, lastSegStart, lastSegEnd);
1299
1300
1301 if ( gLinkContext.verboseLoading || (sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH && (sMainExecutable!=NULL) && sMainExecutable->isLinked()) ) {
1302 dyld::log("dyld: loaded: %s\n", image->getPath());
1303 }
1304
1305 }
1306
1307 //
1308 // Helper for std::remove_if
1309 //
1310 class RefUsesImage {
1311 public:
1312 RefUsesImage(ImageLoader* image) : _image(image) {}
1313 bool operator()(const ImageLoader::DynamicReference& ref) const {
1314 return ( (ref.from == _image) || (ref.to == _image) );
1315 }
1316 private:
1317 ImageLoader* _image;
1318 };
1319
1320
1321
1322 void removeImage(ImageLoader* image)
1323 {
1324 // if has dtrace DOF section, tell dtrace it is going away, then remove from sImageFilesNeedingDOFUnregistration
1325 for (std::vector<RegisteredDOF>::iterator it=sImageFilesNeedingDOFUnregistration.begin(); it != sImageFilesNeedingDOFUnregistration.end(); ) {
1326 if ( it->mh == image->machHeader() ) {
1327 unregisterDOF(it->registrationID);
1328 sImageFilesNeedingDOFUnregistration.erase(it);
1329 // don't increment iterator, the erase caused next element to be copied to where this iterator points
1330 }
1331 else {
1332 ++it;
1333 }
1334 }
1335
1336 // tell all registered remove image handlers about this
1337 // do this before removing image from internal data structures so that the callback can query dyld about the image
1338 if ( image->getState() >= dyld_image_state_bound ) {
1339 sRemoveImageCallbacksInUse = true; // This only runs inside dyld's global lock, so ok to use a global for the in-use flag.
1340 for (std::vector<ImageCallback>::iterator it=sRemoveImageCallbacks.begin(); it != sRemoveImageCallbacks.end(); it++) {
1341 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_REMOVE_IMAGE, (uint64_t)image->machHeader(), (uint64_t)(*it), 0);
1342 (*it)(image->machHeader(), image->getSlide());
1343 }
1344 sRemoveImageCallbacksInUse = false;
1345
1346 if ( sNotifyObjCUnmapped != NULL && image->notifyObjC() )
1347 (*sNotifyObjCUnmapped)(image->getRealPath(), image->machHeader());
1348 }
1349
1350 // notify
1351 notifySingle(dyld_image_state_terminated, image, NULL);
1352
1353 // remove from mapped images table
1354 removedMappedRanges(image);
1355
1356 // remove from master list
1357 allImagesLock();
1358 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
1359 if ( *it == image ) {
1360 sAllImages.erase(it);
1361 break;
1362 }
1363 }
1364 allImagesUnlock();
1365
1366 // remove from sDynamicReferences
1367 OSSpinLockLock(&sDynamicReferencesLock);
1368 sDynamicReferences.erase(std::remove_if(sDynamicReferences.begin(), sDynamicReferences.end(), RefUsesImage(image)), sDynamicReferences.end());
1369 OSSpinLockUnlock(&sDynamicReferencesLock);
1370
1371 // flush find-by-address cache (do this after removed from master list, so there is no chance it can come back)
1372 if ( sLastImageByAddressCache == image )
1373 sLastImageByAddressCache = NULL;
1374
1375 // if in root list, pull it out
1376 for (std::vector<ImageLoader*>::iterator it=sImageRoots.begin(); it != sImageRoots.end(); it++) {
1377 if ( *it == image ) {
1378 sImageRoots.erase(it);
1379 break;
1380 }
1381 }
1382
1383 // log if requested
1384 if ( gLinkContext.verboseLoading || (sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH && (sMainExecutable!=NULL) && sMainExecutable->isLinked()) ) {
1385 dyld::log("dyld: unloaded: %s\n", image->getPath());
1386 }
1387
1388 // tell gdb, new way
1389 removeImageFromAllImages(image->machHeader());
1390 }
1391
1392
1393 void runImageStaticTerminators(ImageLoader* image)
1394 {
1395 // if in termination list, pull it out and run terminator
1396 bool mightBeMore;
1397 do {
1398 mightBeMore = false;
1399 for (std::vector<ImageLoader*>::iterator it=sImageFilesNeedingTermination.begin(); it != sImageFilesNeedingTermination.end(); it++) {
1400 if ( *it == image ) {
1401 sImageFilesNeedingTermination.erase(it);
1402 if (gLogAPIs) dyld::log("dlclose(), running static terminators for %p %s\n", image, image->getShortName());
1403 image->doTermination(gLinkContext);
1404 mightBeMore = true;
1405 break;
1406 }
1407 }
1408 } while ( mightBeMore );
1409 }
1410
1411 static void terminationRecorder(ImageLoader* image)
1412 {
1413 sImageFilesNeedingTermination.push_back(image);
1414 }
1415
1416 const char* getExecutablePath()
1417 {
1418 return sExecPath;
1419 }
1420
1421 static void runAllStaticTerminators(void* extra)
1422 {
1423 try {
1424 const size_t imageCount = sImageFilesNeedingTermination.size();
1425 for(size_t i=imageCount; i > 0; --i){
1426 ImageLoader* image = sImageFilesNeedingTermination[i-1];
1427 image->doTermination(gLinkContext);
1428 }
1429 sImageFilesNeedingTermination.clear();
1430 notifyBatch(dyld_image_state_terminated, false);
1431 }
1432 catch (const char* msg) {
1433 halt(msg);
1434 }
1435 }
1436
1437 void initializeMainExecutable()
1438 {
1439 // record that we've reached this step
1440 gLinkContext.startedInitializingMainExecutable = true;
1441
1442 // run initialzers for any inserted dylibs
1443 ImageLoader::InitializerTimingList initializerTimes[allImagesCount()];
1444 initializerTimes[0].count = 0;
1445 const size_t rootCount = sImageRoots.size();
1446 if ( rootCount > 1 ) {
1447 for(size_t i=1; i < rootCount; ++i) {
1448 sImageRoots[i]->runInitializers(gLinkContext, initializerTimes[0]);
1449 }
1450 }
1451
1452 // run initializers for main executable and everything it brings up
1453 sMainExecutable->runInitializers(gLinkContext, initializerTimes[0]);
1454
1455 // register cxa_atexit() handler to run static terminators in all loaded images when this process exits
1456 if ( gLibSystemHelpers != NULL )
1457 (*gLibSystemHelpers->cxa_atexit)(&runAllStaticTerminators, NULL, NULL);
1458
1459 // dump info if requested
1460 if ( sEnv.DYLD_PRINT_STATISTICS )
1461 ImageLoader::printStatistics((unsigned int)allImagesCount(), initializerTimes[0]);
1462 if ( sEnv.DYLD_PRINT_STATISTICS_DETAILS )
1463 ImageLoaderMachO::printStatisticsDetails((unsigned int)allImagesCount(), initializerTimes[0]);
1464 }
1465
1466 bool mainExecutablePrebound()
1467 {
1468 return sMainExecutable->usablePrebinding(gLinkContext);
1469 }
1470
1471 ImageLoader* mainExecutable()
1472 {
1473 return sMainExecutable;
1474 }
1475
1476
1477
1478
1479 #if SUPPORT_VERSIONED_PATHS
1480
1481 // forward reference
1482 static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName);
1483
1484
1485 //
1486 // Examines a dylib file and if its current_version is newer than the installed
1487 // dylib at its install_name, then add the dylib file to sDylibOverrides.
1488 //
1489 static void checkDylibOverride(const char* dylibFile)
1490 {
1491 //dyld::log("checkDylibOverride('%s')\n", dylibFile);
1492 uint32_t altVersion;
1493 char sysInstallName[PATH_MAX];
1494 if ( getDylibVersionAndInstallname(dylibFile, &altVersion, sysInstallName) && (sysInstallName[0] =='/') ) {
1495 //dyld::log("%s has version 0x%08X and install name %s\n", dylibFile, altVersion, sysInstallName);
1496 uint32_t sysVersion;
1497 if ( getDylibVersionAndInstallname(sysInstallName, &sysVersion, NULL) ) {
1498 //dyld::log("%s has version 0x%08X\n", sysInstallName, sysVersion);
1499 if ( altVersion > sysVersion ) {
1500 //dyld::log("override found: %s -> %s\n", sysInstallName, dylibFile);
1501 // see if there already is an override for this dylib
1502 bool entryExists = false;
1503 for (std::vector<DylibOverride>::iterator it = sDylibOverrides.begin(); it != sDylibOverrides.end(); ++it) {
1504 if ( strcmp(it->installName, sysInstallName) == 0 ) {
1505 entryExists = true;
1506 uint32_t prevVersion;
1507 if ( getDylibVersionAndInstallname(it->override, &prevVersion, NULL) ) {
1508 if ( altVersion > prevVersion ) {
1509 // found an even newer override
1510 free((void*)(it->override));
1511 char resolvedPath[PATH_MAX];
1512 if ( realpath(dylibFile, resolvedPath) != NULL )
1513 it->override = strdup(resolvedPath);
1514 else
1515 it->override = strdup(dylibFile);
1516 break;
1517 }
1518 }
1519 }
1520 }
1521 if ( ! entryExists ) {
1522 DylibOverride entry;
1523 entry.installName = strdup(sysInstallName);
1524 char resolvedPath[PATH_MAX];
1525 if ( realpath(dylibFile, resolvedPath) != NULL )
1526 entry.override = strdup(resolvedPath);
1527 else
1528 entry.override = strdup(dylibFile);
1529 sDylibOverrides.push_back(entry);
1530 //dyld::log("added override: %s -> %s\n", entry.installName, entry.override);
1531 }
1532 }
1533 }
1534 }
1535
1536 }
1537
1538 static void checkDylibOverridesInDir(const char* dirPath)
1539 {
1540 //dyld::log("checkDylibOverridesInDir('%s')\n", dirPath);
1541 char dylibPath[PATH_MAX];
1542 long dirPathLen = strlcpy(dylibPath, dirPath, PATH_MAX-1);
1543 if ( dirPathLen >= PATH_MAX )
1544 return;
1545 DIR* dirp = opendir(dirPath);
1546 if ( dirp != NULL) {
1547 dirent entry;
1548 dirent* entp = NULL;
1549 while ( readdir_r(dirp, &entry, &entp) == 0 ) {
1550 if ( entp == NULL )
1551 break;
1552 if ( entp->d_type != DT_REG )
1553 continue;
1554 dylibPath[dirPathLen] = '/';
1555 dylibPath[dirPathLen+1] = '\0';
1556 if ( strlcat(dylibPath, entp->d_name, PATH_MAX) >= PATH_MAX )
1557 continue;
1558 checkDylibOverride(dylibPath);
1559 }
1560 closedir(dirp);
1561 }
1562 }
1563
1564
1565 static void checkFrameworkOverridesInDir(const char* dirPath)
1566 {
1567 //dyld::log("checkFrameworkOverridesInDir('%s')\n", dirPath);
1568 char frameworkPath[PATH_MAX];
1569 long dirPathLen = strlcpy(frameworkPath, dirPath, PATH_MAX-1);
1570 if ( dirPathLen >= PATH_MAX )
1571 return;
1572 DIR* dirp = opendir(dirPath);
1573 if ( dirp != NULL) {
1574 dirent entry;
1575 dirent* entp = NULL;
1576 while ( readdir_r(dirp, &entry, &entp) == 0 ) {
1577 if ( entp == NULL )
1578 break;
1579 if ( entp->d_type != DT_DIR )
1580 continue;
1581 frameworkPath[dirPathLen] = '/';
1582 frameworkPath[dirPathLen+1] = '\0';
1583 int dirNameLen = (int)strlen(entp->d_name);
1584 if ( dirNameLen < 11 )
1585 continue;
1586 if ( strcmp(&entp->d_name[dirNameLen-10], ".framework") != 0 )
1587 continue;
1588 if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) >= PATH_MAX )
1589 continue;
1590 if ( strlcat(frameworkPath, "/", PATH_MAX) >= PATH_MAX )
1591 continue;
1592 if ( strlcat(frameworkPath, entp->d_name, PATH_MAX) >= PATH_MAX )
1593 continue;
1594 frameworkPath[strlen(frameworkPath)-10] = '\0';
1595 checkDylibOverride(frameworkPath);
1596 }
1597 closedir(dirp);
1598 }
1599 }
1600 #endif // SUPPORT_VERSIONED_PATHS
1601
1602
1603 //
1604 // Turns a colon separated list of strings into a NULL terminated array
1605 // of string pointers. If mainExecutableDir param is not NULL,
1606 // substitutes @loader_path with main executable's dir.
1607 //
1608 static const char** parseColonList(const char* list, const char* mainExecutableDir)
1609 {
1610 static const char* sEmptyList[] = { NULL };
1611
1612 if ( list[0] == '\0' )
1613 return sEmptyList;
1614
1615 int colonCount = 0;
1616 for(const char* s=list; *s != '\0'; ++s) {
1617 if (*s == ':')
1618 ++colonCount;
1619 }
1620
1621 int index = 0;
1622 const char* start = list;
1623 char** result = new char*[colonCount+2];
1624 for(const char* s=list; *s != '\0'; ++s) {
1625 if (*s == ':') {
1626 size_t len = s-start;
1627 if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
1628 if ( !gLinkContext.allowAtPaths ) {
1629 dyld::log("dyld: warning: @loader_path/ ignored because of amfi policy\n");
1630 continue;
1631 }
1632 size_t mainExecDirLen = strlen(mainExecutableDir);
1633 char* str = new char[mainExecDirLen+len+1];
1634 strcpy(str, mainExecutableDir);
1635 strlcat(str, &start[13], mainExecDirLen+len+1);
1636 str[mainExecDirLen+len-13] = '\0';
1637 start = &s[1];
1638 result[index++] = str;
1639 }
1640 else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
1641 if ( !gLinkContext.allowAtPaths ) {
1642 dyld::log("dyld: warning: @executable_path/ ignored because of amfi policy\n");
1643 continue;
1644 }
1645 size_t mainExecDirLen = strlen(mainExecutableDir);
1646 char* str = new char[mainExecDirLen+len+1];
1647 strcpy(str, mainExecutableDir);
1648 strlcat(str, &start[17], mainExecDirLen+len+1);
1649 str[mainExecDirLen+len-17] = '\0';
1650 start = &s[1];
1651 result[index++] = str;
1652 }
1653 else {
1654 char* str = new char[len+1];
1655 strncpy(str, start, len);
1656 str[len] = '\0';
1657 start = &s[1];
1658 result[index++] = str;
1659 }
1660 }
1661 }
1662 size_t len = strlen(start);
1663 if ( (mainExecutableDir != NULL) && (strncmp(start, "@loader_path/", 13) == 0) ) {
1664 if ( !gLinkContext.allowAtPaths ) {
1665 dyld::log("dyld: warning: @loader_path/ ignored because of amfi policy\n");
1666 }
1667 else
1668 {
1669 size_t mainExecDirLen = strlen(mainExecutableDir);
1670 char* str = new char[mainExecDirLen+len+1];
1671 strcpy(str, mainExecutableDir);
1672 strlcat(str, &start[13], mainExecDirLen+len+1);
1673 str[mainExecDirLen+len-13] = '\0';
1674 result[index++] = str;
1675 }
1676 }
1677 else if ( (mainExecutableDir != NULL) && (strncmp(start, "@executable_path/", 17) == 0) ) {
1678 if ( !gLinkContext.allowAtPaths ) {
1679 dyld::log("dyld: warning: @executable_path/ ignored because of amfi policy\n");
1680 }
1681 else
1682 {
1683 size_t mainExecDirLen = strlen(mainExecutableDir);
1684 char* str = new char[mainExecDirLen+len+1];
1685 strcpy(str, mainExecutableDir);
1686 strlcat(str, &start[17], mainExecDirLen+len+1);
1687 str[mainExecDirLen+len-17] = '\0';
1688 result[index++] = str;
1689 }
1690 }
1691 else {
1692 char* str = new char[len+1];
1693 strcpy(str, start);
1694 result[index++] = str;
1695 }
1696 result[index] = NULL;
1697
1698 //dyld::log("parseColonList(%s)\n", list);
1699 //for(int i=0; result[i] != NULL; ++i)
1700 // dyld::log(" %s\n", result[i]);
1701 return (const char**)result;
1702 }
1703
1704 static void appendParsedColonList(const char* list, const char* mainExecutableDir, const char* const ** storage)
1705 {
1706 const char** newlist = parseColonList(list, mainExecutableDir);
1707 if ( *storage == NULL ) {
1708 // first time, just set
1709 *storage = newlist;
1710 }
1711 else {
1712 // need to append to existing list
1713 const char* const* existing = *storage;
1714 int count = 0;
1715 for(int i=0; existing[i] != NULL; ++i)
1716 ++count;
1717 for(int i=0; newlist[i] != NULL; ++i)
1718 ++count;
1719 const char** combinedList = new const char*[count+2];
1720 int index = 0;
1721 for(int i=0; existing[i] != NULL; ++i)
1722 combinedList[index++] = existing[i];
1723 for(int i=0; newlist[i] != NULL; ++i)
1724 combinedList[index++] = newlist[i];
1725 combinedList[index] = NULL;
1726 // leak old arrays
1727 *storage = combinedList;
1728 }
1729 }
1730
1731 #if __MAC_OS_X_VERSION_MIN_REQUIRED
1732 static void paths_expand_roots(const char **paths, const char *key, const char *val)
1733 {
1734 // assert(val != NULL);
1735 // assert(paths != NULL);
1736 if(NULL != key) {
1737 size_t keyLen = strlen(key);
1738 for(int i=0; paths[i] != NULL; ++i) {
1739 if ( strncmp(paths[i], key, keyLen) == 0 ) {
1740 char* newPath = new char[strlen(val) + (strlen(paths[i]) - keyLen) + 1];
1741 strcpy(newPath, val);
1742 strcat(newPath, &paths[i][keyLen]);
1743 paths[i] = newPath;
1744 }
1745 }
1746 }
1747 return;
1748 }
1749
1750 static void removePathWithPrefix(const char* paths[], const char* prefix)
1751 {
1752 size_t prefixLen = strlen(prefix);
1753 int skip = 0;
1754 int i;
1755 for(i = 0; paths[i] != NULL; ++i) {
1756 if ( strncmp(paths[i], prefix, prefixLen) == 0 )
1757 ++skip;
1758 else
1759 paths[i-skip] = paths[i];
1760 }
1761 paths[i-skip] = NULL;
1762 }
1763 #endif
1764
1765
1766 #if 0
1767 static void paths_dump(const char **paths)
1768 {
1769 // assert(paths != NULL);
1770 const char **strs = paths;
1771 while(*strs != NULL)
1772 {
1773 dyld::log("\"%s\"\n", *strs);
1774 strs++;
1775 }
1776 return;
1777 }
1778 #endif
1779
1780
1781
1782 static void printOptions(const char* argv[])
1783 {
1784 uint32_t i = 0;
1785 while ( NULL != argv[i] ) {
1786 dyld::log("opt[%i] = \"%s\"\n", i, argv[i]);
1787 i++;
1788 }
1789 }
1790
1791 static void printEnvironmentVariables(const char* envp[])
1792 {
1793 while ( NULL != *envp ) {
1794 dyld::log("%s\n", *envp);
1795 envp++;
1796 }
1797 }
1798
1799 void processDyldEnvironmentVariable(const char* key, const char* value, const char* mainExecutableDir)
1800 {
1801 if ( strcmp(key, "DYLD_FRAMEWORK_PATH") == 0 ) {
1802 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FRAMEWORK_PATH);
1803 }
1804 else if ( strcmp(key, "DYLD_FALLBACK_FRAMEWORK_PATH") == 0 ) {
1805 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FALLBACK_FRAMEWORK_PATH);
1806 }
1807 else if ( strcmp(key, "DYLD_LIBRARY_PATH") == 0 ) {
1808 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_LIBRARY_PATH);
1809 }
1810 else if ( strcmp(key, "DYLD_FALLBACK_LIBRARY_PATH") == 0 ) {
1811 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_FALLBACK_LIBRARY_PATH);
1812 }
1813 #if SUPPORT_ROOT_PATH
1814 else if ( (strcmp(key, "DYLD_ROOT_PATH") == 0) || (strcmp(key, "DYLD_PATHS_ROOT") == 0) ) {
1815 if ( strcmp(value, "/") != 0 ) {
1816 gLinkContext.rootPaths = parseColonList(value, mainExecutableDir);
1817 for (int i=0; gLinkContext.rootPaths[i] != NULL; ++i) {
1818 if ( gLinkContext.rootPaths[i][0] != '/' ) {
1819 dyld::warn("DYLD_ROOT_PATH not used because it contains a non-absolute path\n");
1820 gLinkContext.rootPaths = NULL;
1821 break;
1822 }
1823 }
1824 }
1825 }
1826 #endif
1827 else if ( strcmp(key, "DYLD_IMAGE_SUFFIX") == 0 ) {
1828 gLinkContext.imageSuffix = parseColonList(value, NULL);
1829 }
1830 else if ( strcmp(key, "DYLD_INSERT_LIBRARIES") == 0 ) {
1831 sEnv.DYLD_INSERT_LIBRARIES = parseColonList(value, NULL);
1832 #if SUPPORT_ACCELERATE_TABLES
1833 sDisableAcceleratorTables = true;
1834 #endif
1835 }
1836 else if ( strcmp(key, "DYLD_PRINT_OPTS") == 0 ) {
1837 sEnv.DYLD_PRINT_OPTS = true;
1838 }
1839 else if ( strcmp(key, "DYLD_PRINT_ENV") == 0 ) {
1840 sEnv.DYLD_PRINT_ENV = true;
1841 }
1842 else if ( strcmp(key, "DYLD_DISABLE_DOFS") == 0 ) {
1843 sEnv.DYLD_DISABLE_DOFS = true;
1844 }
1845 else if ( strcmp(key, "DYLD_DISABLE_PREFETCH") == 0 ) {
1846 gLinkContext.preFetchDisabled = true;
1847 }
1848 else if ( strcmp(key, "DYLD_PRINT_LIBRARIES") == 0 ) {
1849 gLinkContext.verboseLoading = true;
1850 }
1851 else if ( strcmp(key, "DYLD_PRINT_LIBRARIES_POST_LAUNCH") == 0 ) {
1852 sEnv.DYLD_PRINT_LIBRARIES_POST_LAUNCH = true;
1853 }
1854 else if ( strcmp(key, "DYLD_BIND_AT_LAUNCH") == 0 ) {
1855 sEnv.DYLD_BIND_AT_LAUNCH = true;
1856 }
1857 else if ( strcmp(key, "DYLD_FORCE_FLAT_NAMESPACE") == 0 ) {
1858 gLinkContext.bindFlat = true;
1859 }
1860 else if ( strcmp(key, "DYLD_NEW_LOCAL_SHARED_REGIONS") == 0 ) {
1861 // ignore, no longer relevant but some scripts still set it
1862 }
1863 else if ( strcmp(key, "DYLD_NO_FIX_PREBINDING") == 0 ) {
1864 }
1865 else if ( strcmp(key, "DYLD_PREBIND_DEBUG") == 0 ) {
1866 gLinkContext.verbosePrebinding = true;
1867 }
1868 else if ( strcmp(key, "DYLD_PRINT_INITIALIZERS") == 0 ) {
1869 gLinkContext.verboseInit = true;
1870 }
1871 else if ( strcmp(key, "DYLD_PRINT_DOFS") == 0 ) {
1872 gLinkContext.verboseDOF = true;
1873 }
1874 else if ( strcmp(key, "DYLD_PRINT_STATISTICS") == 0 ) {
1875 sEnv.DYLD_PRINT_STATISTICS = true;
1876 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR
1877 // <rdar://problem/26614838> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps
1878 sForceStderr = true;
1879 #endif
1880 }
1881 else if ( strcmp(key, "DYLD_PRINT_TO_STDERR") == 0 ) {
1882 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR
1883 // <rdar://problem/26633440> DYLD_PRINT_STATISTICS no longer logs to xcode console for device apps
1884 sForceStderr = true;
1885 #endif
1886 }
1887 else if ( strcmp(key, "DYLD_PRINT_STATISTICS_DETAILS") == 0 ) {
1888 sEnv.DYLD_PRINT_STATISTICS_DETAILS = true;
1889 }
1890 else if ( strcmp(key, "DYLD_PRINT_SEGMENTS") == 0 ) {
1891 gLinkContext.verboseMapping = true;
1892 }
1893 else if ( strcmp(key, "DYLD_PRINT_BINDINGS") == 0 ) {
1894 gLinkContext.verboseBind = true;
1895 }
1896 else if ( strcmp(key, "DYLD_PRINT_WEAK_BINDINGS") == 0 ) {
1897 gLinkContext.verboseWeakBind = true;
1898 }
1899 else if ( strcmp(key, "DYLD_PRINT_REBASINGS") == 0 ) {
1900 gLinkContext.verboseRebase = true;
1901 }
1902 else if ( strcmp(key, "DYLD_PRINT_APIS") == 0 ) {
1903 gLogAPIs = true;
1904 }
1905 #if SUPPORT_ACCELERATE_TABLES
1906 else if ( strcmp(key, "DYLD_PRINT_APIS_APP") == 0 ) {
1907 gLogAppAPIs = true;
1908 }
1909 #endif
1910 else if ( strcmp(key, "DYLD_PRINT_WARNINGS") == 0 ) {
1911 gLinkContext.verboseWarnings = true;
1912 }
1913 else if ( strcmp(key, "DYLD_PRINT_RPATHS") == 0 ) {
1914 gLinkContext.verboseRPaths = true;
1915 }
1916 else if ( strcmp(key, "DYLD_PRINT_INTERPOSING") == 0 ) {
1917 gLinkContext.verboseInterposing = true;
1918 }
1919 else if ( strcmp(key, "DYLD_PRINT_CODE_SIGNATURES") == 0 ) {
1920 gLinkContext.verboseCodeSignatures = true;
1921 }
1922 else if ( (strcmp(key, "DYLD_SHARED_REGION") == 0) && gLinkContext.allowEnvVarsSharedCache ) {
1923 if ( strcmp(value, "private") == 0 ) {
1924 gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
1925 }
1926 else if ( strcmp(value, "avoid") == 0 ) {
1927 gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
1928 }
1929 else if ( strcmp(value, "use") == 0 ) {
1930 gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion;
1931 }
1932 else if ( value[0] == '\0' ) {
1933 gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion;
1934 }
1935 else {
1936 dyld::warn("unknown option to DYLD_SHARED_REGION. Valid options are: use, private, avoid\n");
1937 }
1938 }
1939 else if ( (strcmp(key, "DYLD_SHARED_CACHE_DIR") == 0) && gLinkContext.allowEnvVarsSharedCache ) {
1940 sSharedCacheOverrideDir = value;
1941 }
1942 else if ( strcmp(key, "DYLD_USE_CLOSURES") == 0 ) {
1943 if ( dyld3::internalInstall() ) {
1944 #if __MAC_OS_X_VERSION_MIN_REQUIRED && __i386__
1945 // don't support dyld3 for 32-bit macOS
1946 #else
1947 sEnableClosures = true;
1948 #endif
1949 }
1950 }
1951 else if ( strcmp(key, "DYLD_IGNORE_PREBINDING") == 0 ) {
1952 if ( strcmp(value, "all") == 0 ) {
1953 gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
1954 }
1955 else if ( strcmp(value, "app") == 0 ) {
1956 gLinkContext.prebindUsage = ImageLoader::kUseAllButAppPredbinding;
1957 }
1958 else if ( strcmp(value, "nonsplit") == 0 ) {
1959 gLinkContext.prebindUsage = ImageLoader::kUseSplitSegPrebinding;
1960 }
1961 else if ( value[0] == '\0' ) {
1962 gLinkContext.prebindUsage = ImageLoader::kUseSplitSegPrebinding;
1963 }
1964 else {
1965 dyld::warn("unknown option to DYLD_IGNORE_PREBINDING. Valid options are: all, app, nonsplit\n");
1966 }
1967 }
1968 #if SUPPORT_VERSIONED_PATHS
1969 else if ( strcmp(key, "DYLD_VERSIONED_LIBRARY_PATH") == 0 ) {
1970 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_VERSIONED_LIBRARY_PATH);
1971 #if SUPPORT_ACCELERATE_TABLES
1972 sDisableAcceleratorTables = true;
1973 #endif
1974 }
1975 else if ( strcmp(key, "DYLD_VERSIONED_FRAMEWORK_PATH") == 0 ) {
1976 appendParsedColonList(value, mainExecutableDir, &sEnv.DYLD_VERSIONED_FRAMEWORK_PATH);
1977 #if SUPPORT_ACCELERATE_TABLES
1978 sDisableAcceleratorTables = true;
1979 #endif
1980 }
1981 #endif
1982 #if !TARGET_IPHONE_SIMULATOR
1983 else if ( (strcmp(key, "DYLD_PRINT_TO_FILE") == 0) && (mainExecutableDir == NULL) && gLinkContext.allowEnvVarsSharedCache ) {
1984 int fd = open(value, O_WRONLY | O_CREAT | O_APPEND, 0644);
1985 if ( fd != -1 ) {
1986 sLogfile = fd;
1987 sLogToFile = true;
1988 }
1989 else {
1990 dyld::log("dyld: could not open DYLD_PRINT_TO_FILE='%s', errno=%d\n", value, errno);
1991 }
1992 }
1993 else if ( (strcmp(key, "DYLD_SKIP_MAIN") == 0)) {
1994 if ( dyld3::internalInstall() )
1995 sSkipMain = true;
1996 }
1997 #endif
1998 else {
1999 dyld::warn("unknown environment variable: %s\n", key);
2000 }
2001 }
2002
2003
2004 #if SUPPORT_LC_DYLD_ENVIRONMENT
2005 static void checkLoadCommandEnvironmentVariables()
2006 {
2007 // <rdar://problem/8440934> Support augmenting dyld environment variables in load commands
2008 const uint32_t cmd_count = sMainExecutableMachHeader->ncmds;
2009 const struct load_command* const cmds = (struct load_command*)(((char*)sMainExecutableMachHeader)+sizeof(macho_header));
2010 const struct load_command* cmd = cmds;
2011 for (uint32_t i = 0; i < cmd_count; ++i) {
2012 switch (cmd->cmd) {
2013 case LC_DYLD_ENVIRONMENT:
2014 {
2015 const struct dylinker_command* envcmd = (struct dylinker_command*)cmd;
2016 const char* keyEqualsValue = (char*)envcmd + envcmd->name.offset;
2017 char mainExecutableDir[strlen(sExecPath)+2];
2018 strcpy(mainExecutableDir, sExecPath);
2019 char* lastSlash = strrchr(mainExecutableDir, '/');
2020 if ( lastSlash != NULL)
2021 lastSlash[1] = '\0';
2022 // only process variables that start with DYLD_ and end in _PATH
2023 if ( (strncmp(keyEqualsValue, "DYLD_", 5) == 0) ) {
2024 const char* equals = strchr(keyEqualsValue, '=');
2025 if ( equals != NULL ) {
2026 if ( strncmp(&equals[-5], "_PATH", 5) == 0 ) {
2027 const char* value = &equals[1];
2028 const size_t keyLen = equals-keyEqualsValue;
2029 // <rdar://problem/22799635> don't let malformed load command overflow stack
2030 if ( keyLen < 40 ) {
2031 char key[keyLen+1];
2032 strncpy(key, keyEqualsValue, keyLen);
2033 key[keyLen] = '\0';
2034 //dyld::log("processing: %s\n", keyEqualsValue);
2035 //dyld::log("mainExecutableDir: %s\n", mainExecutableDir);
2036 processDyldEnvironmentVariable(key, value, mainExecutableDir);
2037 }
2038 }
2039 }
2040 }
2041 }
2042 break;
2043 }
2044 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2045 }
2046 }
2047 #endif // SUPPORT_LC_DYLD_ENVIRONMENT
2048
2049
2050 static bool hasCodeSignatureLoadCommand(const macho_header* mh)
2051 {
2052 const uint32_t cmd_count = mh->ncmds;
2053 const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
2054 const struct load_command* cmd = cmds;
2055 for (uint32_t i = 0; i < cmd_count; ++i) {
2056 if (cmd->cmd == LC_CODE_SIGNATURE)
2057 return true;
2058 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2059 }
2060 return false;
2061 }
2062
2063
2064 #if SUPPORT_VERSIONED_PATHS
2065 static void checkVersionedPaths()
2066 {
2067 // search DYLD_VERSIONED_LIBRARY_PATH directories for dylibs and check if they are newer
2068 if ( sEnv.DYLD_VERSIONED_LIBRARY_PATH != NULL ) {
2069 for(const char* const* lp = sEnv.DYLD_VERSIONED_LIBRARY_PATH; *lp != NULL; ++lp) {
2070 checkDylibOverridesInDir(*lp);
2071 }
2072 }
2073
2074 // search DYLD_VERSIONED_FRAMEWORK_PATH directories for dylibs and check if they are newer
2075 if ( sEnv.DYLD_VERSIONED_FRAMEWORK_PATH != NULL ) {
2076 for(const char* const* fp = sEnv.DYLD_VERSIONED_FRAMEWORK_PATH; *fp != NULL; ++fp) {
2077 checkFrameworkOverridesInDir(*fp);
2078 }
2079 }
2080 }
2081 #endif
2082
2083
2084 #if __MAC_OS_X_VERSION_MIN_REQUIRED
2085 //
2086 // For security, setuid programs ignore DYLD_* environment variables.
2087 // Additionally, the DYLD_* enviroment variables are removed
2088 // from the environment, so that any child processes don't see them.
2089 //
2090 static void pruneEnvironmentVariables(const char* envp[], const char*** applep)
2091 {
2092 #if SUPPORT_LC_DYLD_ENVIRONMENT
2093 checkLoadCommandEnvironmentVariables();
2094 #endif
2095
2096 // Are we testing dyld on an internal config?
2097 if ( _simple_getenv(envp, "DYLD_SKIP_MAIN") != NULL ) {
2098 if ( dyld3::internalInstall() )
2099 sSkipMain = true;
2100 }
2101
2102 // delete all DYLD_* and LD_LIBRARY_PATH environment variables
2103 int removedCount = 0;
2104 const char** d = envp;
2105 for(const char** s = envp; *s != NULL; s++) {
2106
2107 if ( (strncmp(*s, "DYLD_", 5) != 0) && (strncmp(*s, "LD_LIBRARY_PATH=", 16) != 0) ) {
2108 *d++ = *s;
2109 }
2110 else {
2111 ++removedCount;
2112 }
2113 }
2114 *d++ = NULL;
2115 // slide apple parameters
2116 if ( removedCount > 0 ) {
2117 *applep = d;
2118 do {
2119 *d = d[removedCount];
2120 } while ( *d++ != NULL );
2121 for(int i=0; i < removedCount; ++i)
2122 *d++ = NULL;
2123 }
2124
2125 // disable framework and library fallback paths for setuid binaries rdar://problem/4589305
2126 sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = NULL;
2127 sEnv.DYLD_FALLBACK_LIBRARY_PATH = NULL;
2128
2129 if ( removedCount > 0 )
2130 strlcat(sLoadingCrashMessage, ", ignoring DYLD_* env vars", sizeof(sLoadingCrashMessage));
2131 }
2132 #endif
2133
2134 static void defaultUninitializedFallbackPaths(const char* envp[])
2135 {
2136 #if __MAC_OS_X_VERSION_MIN_REQUIRED
2137 if ( !gLinkContext.allowClassicFallbackPaths ) {
2138 sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = sRestrictedFrameworkFallbackPaths;
2139 sEnv.DYLD_FALLBACK_LIBRARY_PATH = sRestrictedLibraryFallbackPaths;
2140 return;
2141 }
2142
2143 // default value for DYLD_FALLBACK_FRAMEWORK_PATH, if not set in environment
2144 const char* home = _simple_getenv(envp, "HOME");;
2145 if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL ) {
2146 const char** fpaths = sFrameworkFallbackPaths;
2147 if ( home == NULL )
2148 removePathWithPrefix(fpaths, "$HOME");
2149 else
2150 paths_expand_roots(fpaths, "$HOME", home);
2151 sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = fpaths;
2152 }
2153
2154 // default value for DYLD_FALLBACK_LIBRARY_PATH, if not set in environment
2155 if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL ) {
2156 const char** lpaths = sLibraryFallbackPaths;
2157 if ( home == NULL )
2158 removePathWithPrefix(lpaths, "$HOME");
2159 else
2160 paths_expand_roots(lpaths, "$HOME", home);
2161 sEnv.DYLD_FALLBACK_LIBRARY_PATH = lpaths;
2162 }
2163 #else
2164 if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == NULL )
2165 sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = sFrameworkFallbackPaths;
2166
2167 if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == NULL )
2168 sEnv.DYLD_FALLBACK_LIBRARY_PATH = sLibraryFallbackPaths;
2169 #endif
2170 }
2171
2172
2173 static void checkEnvironmentVariables(const char* envp[])
2174 {
2175 if ( !gLinkContext.allowEnvVarsPath && !gLinkContext.allowEnvVarsPrint )
2176 return;
2177 const char** p;
2178 for(p = envp; *p != NULL; p++) {
2179 const char* keyEqualsValue = *p;
2180 if ( strncmp(keyEqualsValue, "DYLD_", 5) == 0 ) {
2181 const char* equals = strchr(keyEqualsValue, '=');
2182 if ( equals != NULL ) {
2183 strlcat(sLoadingCrashMessage, "\n", sizeof(sLoadingCrashMessage));
2184 strlcat(sLoadingCrashMessage, keyEqualsValue, sizeof(sLoadingCrashMessage));
2185 const char* value = &equals[1];
2186 const size_t keyLen = equals-keyEqualsValue;
2187 char key[keyLen+1];
2188 strncpy(key, keyEqualsValue, keyLen);
2189 key[keyLen] = '\0';
2190 if ( (strncmp(key, "DYLD_PRINT_", 11) == 0) && !gLinkContext.allowEnvVarsPrint )
2191 continue;
2192 processDyldEnvironmentVariable(key, value, NULL);
2193 }
2194 }
2195 else if ( strncmp(keyEqualsValue, "LD_LIBRARY_PATH=", 16) == 0 ) {
2196 const char* path = &keyEqualsValue[16];
2197 sEnv.LD_LIBRARY_PATH = parseColonList(path, NULL);
2198 }
2199 }
2200
2201 #if SUPPORT_LC_DYLD_ENVIRONMENT
2202 checkLoadCommandEnvironmentVariables();
2203 #endif // SUPPORT_LC_DYLD_ENVIRONMENT
2204
2205 #if SUPPORT_ROOT_PATH
2206 // <rdar://problem/11281064> DYLD_IMAGE_SUFFIX and DYLD_ROOT_PATH cannot be used together
2207 if ( (gLinkContext.imageSuffix != NULL && *gLinkContext.imageSuffix != NULL) && (gLinkContext.rootPaths != NULL) ) {
2208 dyld::warn("Ignoring DYLD_IMAGE_SUFFIX because DYLD_ROOT_PATH is used.\n");
2209 gLinkContext.imageSuffix = NULL; // this leaks allocations from parseColonList
2210 }
2211 #endif
2212 }
2213
2214 #if __x86_64__ && !TARGET_IPHONE_SIMULATOR
2215 static bool isGCProgram(const macho_header* mh, uintptr_t slide)
2216 {
2217 const uint32_t cmd_count = mh->ncmds;
2218 const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
2219 const struct load_command* cmd = cmds;
2220 for (uint32_t i = 0; i < cmd_count; ++i) {
2221 switch (cmd->cmd) {
2222 case LC_SEGMENT_COMMAND:
2223 {
2224 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
2225 if (strcmp(seg->segname, "__DATA") == 0) {
2226 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
2227 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
2228 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
2229 if (strncmp(sect->sectname, "__objc_imageinfo", 16) == 0) {
2230 const uint32_t* objcInfo = (uint32_t*)(sect->addr + slide);
2231 return (objcInfo[1] & 6); // 6 = (OBJC_IMAGE_SUPPORTS_GC | OBJC_IMAGE_REQUIRES_GC)
2232 }
2233 }
2234 }
2235 }
2236 break;
2237 }
2238 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2239 }
2240 return false;
2241 }
2242 #endif
2243
2244 static void getHostInfo(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide)
2245 {
2246 #if CPU_SUBTYPES_SUPPORTED
2247 #if __ARM_ARCH_7K__
2248 sHostCPU = CPU_TYPE_ARM;
2249 sHostCPUsubtype = CPU_SUBTYPE_ARM_V7K;
2250 #elif __ARM_ARCH_7A__
2251 sHostCPU = CPU_TYPE_ARM;
2252 sHostCPUsubtype = CPU_SUBTYPE_ARM_V7;
2253 #elif __ARM_ARCH_6K__
2254 sHostCPU = CPU_TYPE_ARM;
2255 sHostCPUsubtype = CPU_SUBTYPE_ARM_V6;
2256 #elif __ARM_ARCH_7F__
2257 sHostCPU = CPU_TYPE_ARM;
2258 sHostCPUsubtype = CPU_SUBTYPE_ARM_V7F;
2259 #elif __ARM_ARCH_7S__
2260 sHostCPU = CPU_TYPE_ARM;
2261 sHostCPUsubtype = CPU_SUBTYPE_ARM_V7S;
2262 #elif __ARM64_ARCH_8_32__
2263 sHostCPU = CPU_TYPE_ARM64_32;
2264 sHostCPUsubtype = CPU_SUBTYPE_ARM64_32_V8;
2265 #elif __arm64e__
2266 sHostCPU = CPU_TYPE_ARM64;
2267 sHostCPUsubtype = CPU_SUBTYPE_ARM64_E;
2268 #elif __arm64__
2269 sHostCPU = CPU_TYPE_ARM64;
2270 sHostCPUsubtype = CPU_SUBTYPE_ARM64_V8;
2271 #else
2272 struct host_basic_info info;
2273 mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
2274 mach_port_t hostPort = mach_host_self();
2275 kern_return_t result = host_info(hostPort, HOST_BASIC_INFO, (host_info_t)&info, &count);
2276 if ( result != KERN_SUCCESS )
2277 throw "host_info() failed";
2278 sHostCPU = info.cpu_type;
2279 sHostCPUsubtype = info.cpu_subtype;
2280 mach_port_deallocate(mach_task_self(), hostPort);
2281 #if __x86_64__
2282 // host_info returns CPU_TYPE_I386 even for x86_64. Override that here so that
2283 // we don't need to mask the cpu type later.
2284 sHostCPU = CPU_TYPE_X86_64;
2285 #if !TARGET_IPHONE_SIMULATOR
2286 sHaswell = (sHostCPUsubtype == CPU_SUBTYPE_X86_64_H);
2287 // <rdar://problem/18528074> x86_64h: Fall back to the x86_64 slice if an app requires GC.
2288 if ( sHaswell ) {
2289 if ( isGCProgram(mainExecutableMH, mainExecutableSlide) ) {
2290 // When running a GC program on a haswell machine, don't use and 'h slices
2291 sHostCPUsubtype = CPU_SUBTYPE_X86_64_ALL;
2292 sHaswell = false;
2293 gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
2294 }
2295 }
2296 #endif
2297 #endif
2298 #endif
2299 #endif
2300 }
2301
2302 static void checkSharedRegionDisable(const dyld3::MachOLoaded* mainExecutableMH, uintptr_t mainExecutableSlide)
2303 {
2304 #if __MAC_OS_X_VERSION_MIN_REQUIRED
2305 // if main executable has segments that overlap the shared region,
2306 // then disable using the shared region
2307 if ( mainExecutableMH->intersectsRange(SHARED_REGION_BASE, SHARED_REGION_SIZE) ) {
2308 gLinkContext.sharedRegionMode = ImageLoader::kDontUseSharedRegion;
2309 if ( gLinkContext.verboseMapping )
2310 dyld::warn("disabling shared region because main executable overlaps\n");
2311 }
2312 #if __i386__
2313 if ( !gLinkContext.allowEnvVarsPath ) {
2314 // <rdar://problem/15280847> use private or no shared region for suid processes
2315 gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
2316 }
2317 #endif
2318 #endif
2319 // iOS cannot run without shared region
2320 }
2321
2322 bool validImage(const ImageLoader* possibleImage)
2323 {
2324 const size_t imageCount = sAllImages.size();
2325 for(size_t i=0; i < imageCount; ++i) {
2326 if ( possibleImage == sAllImages[i] ) {
2327 return true;
2328 }
2329 }
2330 return false;
2331 }
2332
2333 uint32_t getImageCount()
2334 {
2335 return (uint32_t)sAllImages.size();
2336 }
2337
2338 ImageLoader* getIndexedImage(unsigned int index)
2339 {
2340 if ( index < sAllImages.size() )
2341 return sAllImages[index];
2342 return NULL;
2343 }
2344
2345 ImageLoader* findImageByMachHeader(const struct mach_header* target)
2346 {
2347 return findMappedRange((uintptr_t)target);
2348 }
2349
2350
2351 ImageLoader* findImageContainingAddress(const void* addr)
2352 {
2353 #if SUPPORT_ACCELERATE_TABLES
2354 if ( sAllCacheImagesProxy != NULL ) {
2355 const mach_header* mh;
2356 const char* path;
2357 unsigned index;
2358 if ( sAllCacheImagesProxy->addressInCache(addr, &mh, &path, &index) )
2359 return sAllCacheImagesProxy;
2360 }
2361 #endif
2362 return findMappedRange((uintptr_t)addr);
2363 }
2364
2365
2366 ImageLoader* findImageContainingSymbol(const void* symbol)
2367 {
2368 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
2369 ImageLoader* anImage = *it;
2370 if ( anImage->containsSymbol(symbol) )
2371 return anImage;
2372 }
2373 return NULL;
2374 }
2375
2376
2377
2378 void forEachImageDo( void (*callback)(ImageLoader*, void* userData), void* userData)
2379 {
2380 const size_t imageCount = sAllImages.size();
2381 for(size_t i=0; i < imageCount; ++i) {
2382 ImageLoader* anImage = sAllImages[i];
2383 (*callback)(anImage, userData);
2384 }
2385 }
2386
2387 ImageLoader* findLoadedImage(const struct stat& stat_buf)
2388 {
2389 const size_t imageCount = sAllImages.size();
2390 for(size_t i=0; i < imageCount; ++i){
2391 ImageLoader* anImage = sAllImages[i];
2392 if ( anImage->statMatch(stat_buf) )
2393 return anImage;
2394 }
2395 return NULL;
2396 }
2397
2398 // based on ANSI-C strstr()
2399 static const char* strrstr(const char* str, const char* sub)
2400 {
2401 const size_t sublen = strlen(sub);
2402 for(const char* p = &str[strlen(str)]; p != str; --p) {
2403 if ( strncmp(p, sub, sublen) == 0 )
2404 return p;
2405 }
2406 return NULL;
2407 }
2408
2409
2410 //
2411 // Find framework path
2412 //
2413 // /path/foo.framework/foo => foo.framework/foo
2414 // /path/foo.framework/Versions/A/foo => foo.framework/Versions/A/foo
2415 // /path/foo.framework/Frameworks/bar.framework/bar => bar.framework/bar
2416 // /path/foo.framework/Libraries/bar.dylb => NULL
2417 // /path/foo.framework/bar => NULL
2418 //
2419 // Returns NULL if not a framework path
2420 //
2421 static const char* getFrameworkPartialPath(const char* path)
2422 {
2423 const char* dirDot = strrstr(path, ".framework/");
2424 if ( dirDot != NULL ) {
2425 const char* dirStart = dirDot;
2426 for ( ; dirStart >= path; --dirStart) {
2427 if ( (*dirStart == '/') || (dirStart == path) ) {
2428 const char* frameworkStart = &dirStart[1];
2429 if ( dirStart == path )
2430 --frameworkStart;
2431 size_t len = dirDot - frameworkStart;
2432 char framework[len+1];
2433 strncpy(framework, frameworkStart, len);
2434 framework[len] = '\0';
2435 const char* leaf = strrchr(path, '/');
2436 if ( leaf != NULL ) {
2437 if ( strcmp(framework, &leaf[1]) == 0 ) {
2438 return frameworkStart;
2439 }
2440 if ( gLinkContext.imageSuffix != NULL ) {
2441 // some debug frameworks have install names that end in _debug
2442 if ( strncmp(framework, &leaf[1], len) == 0 ) {
2443 for (const char* const* suffix=gLinkContext.imageSuffix; *suffix != NULL; ++suffix) {
2444 if ( strcmp(*suffix, &leaf[len+1]) == 0 )
2445 return frameworkStart;
2446 }
2447 }
2448 }
2449 }
2450 }
2451 }
2452 }
2453 return NULL;
2454 }
2455
2456
2457 static const char* getLibraryLeafName(const char* path)
2458 {
2459 const char* start = strrchr(path, '/');
2460 if ( start != NULL )
2461 return &start[1];
2462 else
2463 return path;
2464 }
2465
2466
2467 // only for architectures that use cpu-sub-types
2468 #if CPU_SUBTYPES_SUPPORTED
2469
2470 const cpu_subtype_t CPU_SUBTYPE_END_OF_LIST = -1;
2471
2472
2473 //
2474 // A fat file may contain multiple sub-images for the same CPU type.
2475 // In that case, dyld picks which sub-image to use by scanning a table
2476 // of preferred cpu-sub-types for the running cpu.
2477 //
2478 // There is one row in the table for each cpu-sub-type on which dyld might run.
2479 // The first entry in a row is that cpu-sub-type. It is followed by all
2480 // cpu-sub-types that can run on that cpu, if preferred order. Each row ends with
2481 // a "SUBTYPE_ALL" (to denote that images written to run on any cpu-sub-type are usable),
2482 // followed by one or more CPU_SUBTYPE_END_OF_LIST to pad out this row.
2483 //
2484
2485
2486 #if __arm__
2487 //
2488 // ARM sub-type lists
2489 //
2490 const int kARM_RowCount = 8;
2491 static const cpu_subtype_t kARM[kARM_RowCount][9] = {
2492
2493 // armv7f can run: v7f, v7, v6, v5, and v4
2494 { 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 },
2495
2496 // armv7k can run: v7k
2497 { CPU_SUBTYPE_ARM_V7K, CPU_SUBTYPE_END_OF_LIST },
2498
2499 // armv7s can run: v7s, v7, v7f, v7k, v6, v5, and v4
2500 { CPU_SUBTYPE_ARM_V7S, CPU_SUBTYPE_ARM_V7, CPU_SUBTYPE_ARM_V7F, CPU_SUBTYPE_ARM_V6, CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_V4T, CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_END_OF_LIST },
2501
2502 // armv7 can run: v7, v6, v5, and v4
2503 { 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 },
2504
2505 // armv6 can run: v6, v5, and v4
2506 { 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 },
2507
2508 // xscale can run: xscale, v5, and v4
2509 { 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 },
2510
2511 // armv5 can run: v5 and v4
2512 { 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 },
2513
2514 // armv4 can run: v4
2515 { 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 },
2516 };
2517 #endif
2518
2519 #if __arm64__
2520 //
2521 // ARM64 sub-type lists
2522 //
2523 const int kARM64_RowCount = 2;
2524 static const cpu_subtype_t kARM64[kARM64_RowCount][4] = {
2525
2526 // armv64e can run: 64e, 64
2527 { CPU_SUBTYPE_ARM64_E, CPU_SUBTYPE_ARM64_V8, CPU_SUBTYPE_ARM64_ALL, CPU_SUBTYPE_END_OF_LIST },
2528
2529 // armv64 can run: 64
2530 { CPU_SUBTYPE_ARM64_V8, CPU_SUBTYPE_ARM64_ALL, CPU_SUBTYPE_END_OF_LIST },
2531 };
2532
2533 #if __ARM64_ARCH_8_32__
2534 const int kARM64_32_RowCount = 2;
2535 static const cpu_subtype_t kARM64_32[kARM64_32_RowCount][4] = {
2536
2537 // armv64_32 can run: v8
2538 { CPU_SUBTYPE_ARM64_32_V8, CPU_SUBTYPE_END_OF_LIST },
2539
2540 // armv64 can run: 64
2541 { CPU_SUBTYPE_ARM64_V8, CPU_SUBTYPE_ARM64_ALL, CPU_SUBTYPE_END_OF_LIST },
2542 };
2543 #endif
2544
2545 #endif
2546
2547 #if __x86_64__
2548 //
2549 // x86_64 sub-type lists
2550 //
2551 const int kX86_64_RowCount = 2;
2552 static const cpu_subtype_t kX86_64[kX86_64_RowCount][5] = {
2553
2554 // x86_64h can run: x86_64h, x86_64h(lib), x86_64(lib), and x86_64
2555 { CPU_SUBTYPE_X86_64_H, (cpu_subtype_t)(CPU_SUBTYPE_LIB64|CPU_SUBTYPE_X86_64_H), (cpu_subtype_t)(CPU_SUBTYPE_LIB64|CPU_SUBTYPE_X86_64_ALL), CPU_SUBTYPE_X86_64_ALL, CPU_SUBTYPE_END_OF_LIST },
2556
2557 // x86_64 can run: x86_64(lib) and x86_64
2558 { CPU_SUBTYPE_X86_64_ALL, (cpu_subtype_t)(CPU_SUBTYPE_LIB64|CPU_SUBTYPE_X86_64_ALL), CPU_SUBTYPE_END_OF_LIST },
2559
2560 };
2561 #endif
2562
2563
2564 // scan the tables above to find the cpu-sub-type-list for this machine
2565 static const cpu_subtype_t* findCPUSubtypeList(cpu_type_t cpu, cpu_subtype_t subtype)
2566 {
2567 switch (cpu) {
2568 #if __arm__
2569 case CPU_TYPE_ARM:
2570 for (int i=0; i < kARM_RowCount ; ++i) {
2571 if ( kARM[i][0] == subtype )
2572 return kARM[i];
2573 }
2574 break;
2575 #endif
2576 #if __arm64__
2577 case CPU_TYPE_ARM64:
2578 for (int i=0; i < kARM64_RowCount ; ++i) {
2579 if ( kARM64[i][0] == subtype )
2580 return kARM64[i];
2581 }
2582 break;
2583
2584 #if __ARM64_ARCH_8_32__
2585 case CPU_TYPE_ARM64_32:
2586 for (int i=0; i < kARM64_32_RowCount ; ++i) {
2587 if ( kARM64_32[i][0] == subtype )
2588 return kARM64_32[i];
2589 }
2590 break;
2591 #endif
2592
2593 #endif
2594 #if __x86_64__
2595 case CPU_TYPE_X86_64:
2596 for (int i=0; i < kX86_64_RowCount ; ++i) {
2597 if ( kX86_64[i][0] == subtype )
2598 return kX86_64[i];
2599 }
2600 break;
2601 #endif
2602 }
2603 return NULL;
2604 }
2605
2606
2607
2608
2609 // scan fat table-of-contents for best most preferred subtype
2610 static bool fatFindBestFromOrderedList(cpu_type_t cpu, const cpu_subtype_t list[], const fat_header* fh, uint64_t* offset, uint64_t* len)
2611 {
2612 const fat_arch* const archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
2613 for (uint32_t subTypeIndex=0; list[subTypeIndex] != CPU_SUBTYPE_END_OF_LIST; ++subTypeIndex) {
2614 for(uint32_t fatIndex=0; fatIndex < OSSwapBigToHostInt32(fh->nfat_arch); ++fatIndex) {
2615 if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[fatIndex].cputype) == cpu)
2616 && (list[subTypeIndex] == (cpu_subtype_t)OSSwapBigToHostInt32(archs[fatIndex].cpusubtype)) ) {
2617 *offset = OSSwapBigToHostInt32(archs[fatIndex].offset);
2618 *len = OSSwapBigToHostInt32(archs[fatIndex].size);
2619 return true;
2620 }
2621 }
2622 }
2623 return false;
2624 }
2625
2626 // scan fat table-of-contents for exact match of cpu and cpu-sub-type
2627 static bool fatFindExactMatch(cpu_type_t cpu, cpu_subtype_t subtype, const fat_header* fh, uint64_t* offset, uint64_t* len)
2628 {
2629 const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
2630 for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
2631 if ( ((cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu)
2632 && ((cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == subtype) ) {
2633 *offset = OSSwapBigToHostInt32(archs[i].offset);
2634 *len = OSSwapBigToHostInt32(archs[i].size);
2635 return true;
2636 }
2637 }
2638 return false;
2639 }
2640
2641 // scan fat table-of-contents for image with matching cpu-type and runs-on-all-sub-types
2642 static bool fatFindRunsOnAllCPUs(cpu_type_t cpu, const fat_header* fh, uint64_t* offset, uint64_t* len)
2643 {
2644 const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
2645 for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
2646 if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == cpu) {
2647 switch (cpu) {
2648 #if __arm__
2649 case CPU_TYPE_ARM:
2650 if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_ARM_ALL ) {
2651 *offset = OSSwapBigToHostInt32(archs[i].offset);
2652 *len = OSSwapBigToHostInt32(archs[i].size);
2653 return true;
2654 }
2655 break;
2656 #endif
2657 #if __arm64__
2658 case CPU_TYPE_ARM64:
2659 if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_ARM64_ALL ) {
2660 *offset = OSSwapBigToHostInt32(archs[i].offset);
2661 *len = OSSwapBigToHostInt32(archs[i].size);
2662 return true;
2663 }
2664 break;
2665 #endif
2666 #if __x86_64__
2667 case CPU_TYPE_X86_64:
2668 if ( (cpu_subtype_t)OSSwapBigToHostInt32(archs[i].cpusubtype) == CPU_SUBTYPE_X86_64_ALL ) {
2669 *offset = OSSwapBigToHostInt32(archs[i].offset);
2670 *len = OSSwapBigToHostInt32(archs[i].size);
2671 return true;
2672 }
2673 break;
2674 #endif
2675 }
2676 }
2677 }
2678 return false;
2679 }
2680
2681 #endif // CPU_SUBTYPES_SUPPORTED
2682
2683
2684 //
2685 // Validate the fat_header and fat_arch array:
2686 //
2687 // 1) arch count would not cause array to extend past 4096 byte read buffer
2688 // 2) no slice overlaps the fat_header and arch array
2689 // 3) arch list does not contain duplicate cputype/cpusubtype tuples
2690 // 4) arch list does not have two overlapping slices.
2691 //
2692 static bool fatValidate(const fat_header* fh)
2693 {
2694 if ( fh->magic != OSSwapBigToHostInt32(FAT_MAGIC) )
2695 return false;
2696
2697 // since only first 4096 bytes of file read, we can only handle up to 204 slices.
2698 const uint32_t sliceCount = OSSwapBigToHostInt32(fh->nfat_arch);
2699 if ( sliceCount > 204 )
2700 return false;
2701
2702 // compare all slices looking for conflicts
2703 const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
2704 for (uint32_t i=0; i < sliceCount; ++i) {
2705 uint32_t i_offset = OSSwapBigToHostInt32(archs[i].offset);
2706 uint32_t i_size = OSSwapBigToHostInt32(archs[i].size);
2707 uint32_t i_cputype = OSSwapBigToHostInt32(archs[i].cputype);
2708 uint32_t i_cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype);
2709 uint32_t i_end = i_offset + i_size;
2710 // slice cannot overlap with header
2711 if ( i_offset < 4096 )
2712 return false;
2713 // slice size cannot overflow
2714 if ( i_end < i_offset )
2715 return false;
2716 for (uint32_t j=i+1; j < sliceCount; ++j) {
2717 uint32_t j_offset = OSSwapBigToHostInt32(archs[j].offset);
2718 uint32_t j_size = OSSwapBigToHostInt32(archs[j].size);
2719 uint32_t j_cputype = OSSwapBigToHostInt32(archs[j].cputype);
2720 uint32_t j_cpusubtype = OSSwapBigToHostInt32(archs[j].cpusubtype);
2721 uint32_t j_end = j_offset + j_size;
2722 // duplicate slices types not allowed
2723 if ( (i_cputype == j_cputype) && (i_cpusubtype == j_cpusubtype) )
2724 return false;
2725 // slice size cannot overflow
2726 if ( j_end < j_offset )
2727 return false;
2728 // check for overlap of slices
2729 if ( i_offset <= j_offset ) {
2730 if ( j_offset < i_end )
2731 return false; // j overlaps end of i
2732 }
2733 else {
2734 // j overlaps end of i
2735 if ( i_offset < j_end )
2736 return false; // i overlaps end of j
2737 }
2738 }
2739 }
2740 return true;
2741 }
2742
2743 //
2744 // A fat file may contain multiple sub-images for the same cpu-type,
2745 // each optimized for a different cpu-sub-type (e.g G3 or G5).
2746 // This routine picks the optimal sub-image.
2747 //
2748 static bool fatFindBest(const fat_header* fh, uint64_t* offset, uint64_t* len)
2749 {
2750 if ( !fatValidate(fh) )
2751 return false;
2752
2753 #if CPU_SUBTYPES_SUPPORTED
2754 // assume all dylibs loaded must have same cpu type as main executable
2755 const cpu_type_t cpu = sMainExecutableMachHeader->cputype;
2756
2757 // We only know the subtype to use if the main executable cpu type matches the host
2758 if ( cpu == sHostCPU ) {
2759 // get preference ordered list of subtypes
2760 const cpu_subtype_t* subTypePreferenceList = findCPUSubtypeList(cpu, sHostCPUsubtype);
2761
2762 // use ordered list to find best sub-image in fat file
2763 if ( subTypePreferenceList != NULL ) {
2764 if ( fatFindBestFromOrderedList(cpu, subTypePreferenceList, fh, offset, len) )
2765 return true;
2766 }
2767
2768 // if running cpu is not in list, try for an exact match
2769 if ( fatFindExactMatch(cpu, sHostCPUsubtype, fh, offset, len) )
2770 return true;
2771 }
2772
2773 // running on an uknown cpu, can only load generic code
2774 return fatFindRunsOnAllCPUs(cpu, fh, offset, len);
2775 #else
2776 // just find first slice with matching architecture
2777 const fat_arch* archs = (fat_arch*)(((char*)fh)+sizeof(fat_header));
2778 for(uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
2779 if ( (cpu_type_t)OSSwapBigToHostInt32(archs[i].cputype) == sMainExecutableMachHeader->cputype) {
2780 *offset = OSSwapBigToHostInt32(archs[i].offset);
2781 *len = OSSwapBigToHostInt32(archs[i].size);
2782 return true;
2783 }
2784 }
2785 return false;
2786 #endif
2787 }
2788
2789
2790
2791 //
2792 // This is used to validate if a non-fat (aka thin or raw) mach-o file can be used
2793 // on the current processor. //
2794 bool isCompatibleMachO(const uint8_t* firstPage, const char* path)
2795 {
2796 #if CPU_SUBTYPES_SUPPORTED
2797 // It is deemed compatible if any of the following are true:
2798 // 1) mach_header subtype is in list of compatible subtypes for running processor
2799 // 2) mach_header subtype is same as running processor subtype
2800 // 3) mach_header subtype runs on all processor variants
2801 const mach_header* mh = (mach_header*)firstPage;
2802 if ( mh->magic == sMainExecutableMachHeader->magic ) {
2803 if ( mh->cputype == sMainExecutableMachHeader->cputype ) {
2804 if ( mh->cputype == sHostCPU ) {
2805 // get preference ordered list of subtypes that this machine can use
2806 const cpu_subtype_t* subTypePreferenceList = findCPUSubtypeList(mh->cputype, sHostCPUsubtype);
2807 if ( subTypePreferenceList != NULL ) {
2808 // if image's subtype is in the list, it is compatible
2809 for (const cpu_subtype_t* p = subTypePreferenceList; *p != CPU_SUBTYPE_END_OF_LIST; ++p) {
2810 if ( *p == mh->cpusubtype )
2811 return true;
2812 }
2813 // have list and not in list, so not compatible
2814 throwf("incompatible cpu-subtype: 0x%08X in %s", mh->cpusubtype, path);
2815 }
2816 // unknown cpu sub-type, but if exact match for current subtype then ok to use
2817 if ( mh->cpusubtype == sHostCPUsubtype )
2818 return true;
2819 }
2820
2821 // cpu type has no ordered list of subtypes
2822 switch (mh->cputype) {
2823 case CPU_TYPE_I386:
2824 case CPU_TYPE_X86_64:
2825 // subtypes are not used or these architectures
2826 return true;
2827 }
2828 }
2829 }
2830 #else
2831 // For architectures that don't support cpu-sub-types
2832 // this just check the cpu type.
2833 const mach_header* mh = (mach_header*)firstPage;
2834 if ( mh->magic == sMainExecutableMachHeader->magic ) {
2835 if ( mh->cputype == sMainExecutableMachHeader->cputype ) {
2836 return true;
2837 }
2838 }
2839 #endif
2840 return false;
2841 }
2842
2843
2844
2845
2846 // The kernel maps in main executable before dyld gets control. We need to
2847 // make an ImageLoader* for the already mapped in main executable.
2848 static ImageLoaderMachO* instantiateFromLoadedImage(const macho_header* mh, uintptr_t slide, const char* path)
2849 {
2850 // try mach-o loader
2851 if ( isCompatibleMachO((const uint8_t*)mh, path) ) {
2852 ImageLoader* image = ImageLoaderMachO::instantiateMainExecutable(mh, slide, path, gLinkContext);
2853 addImage(image);
2854 return (ImageLoaderMachO*)image;
2855 }
2856
2857 throw "main executable not a known format";
2858 }
2859
2860 #if SUPPORT_ACCELERATE_TABLES
2861 static bool dylibsCanOverrideCache()
2862 {
2863 if ( !dyld3::internalInstall() )
2864 return false;
2865 return ( (sSharedCacheLoadInfo.loadAddress != nullptr) && (sSharedCacheLoadInfo.loadAddress->header.cacheType == kDyldSharedCacheTypeDevelopment) );
2866 }
2867 #endif
2868
2869 const void* imMemorySharedCacheHeader()
2870 {
2871 return sSharedCacheLoadInfo.loadAddress;
2872 }
2873
2874
2875 const char* getStandardSharedCacheFilePath()
2876 {
2877 if ( sSharedCacheLoadInfo.loadAddress != nullptr )
2878 return sSharedCacheLoadInfo.path;
2879 else
2880 return nullptr;
2881 }
2882
2883
2884 static bool findInSharedCacheImage(const char* path, bool searchByPath, const struct stat* stat_buf, const macho_header** mh, const char** pathInCache, long* slide)
2885 {
2886 dyld3::SharedCacheFindDylibResults results;
2887 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &results) ) {
2888 *mh = (macho_header*)results.mhInCache;
2889 *pathInCache = results.pathInCache;
2890 *slide = results.slideInCache;
2891 return true;
2892 }
2893 return false;
2894 }
2895
2896 bool inSharedCache(const char* path)
2897 {
2898 return dyld3::pathIsInSharedCacheImage(sSharedCacheLoadInfo, path);
2899 }
2900
2901
2902 static ImageLoader* checkandAddImage(ImageLoader* image, const LoadContext& context)
2903 {
2904 // now sanity check that this loaded image does not have the same install path as any existing image
2905 const char* loadedImageInstallPath = image->getInstallPath();
2906 if ( image->isDylib() && (loadedImageInstallPath != NULL) && (loadedImageInstallPath[0] == '/') ) {
2907 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
2908 ImageLoader* anImage = *it;
2909 const char* installPath = anImage->getInstallPath();
2910 if ( installPath != NULL) {
2911 if ( strcmp(loadedImageInstallPath, installPath) == 0 ) {
2912 //dyld::log("duplicate(%s) => %p\n", installPath, anImage);
2913 removeImage(image);
2914 ImageLoader::deleteImage(image);
2915 return anImage;
2916 }
2917 }
2918 }
2919 }
2920
2921 // some API's restrict what they can load
2922 if ( context.mustBeBundle && !image->isBundle() )
2923 throw "not a bundle";
2924 if ( context.mustBeDylib && !image->isDylib() )
2925 throw "not a dylib";
2926
2927 // regular main executables cannot be loaded
2928 if ( image->isExecutable() ) {
2929 if ( !context.canBePIE || !image->isPositionIndependentExecutable() )
2930 throw "can't load a main executable";
2931 }
2932
2933 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
2934 if ( ! image->isBundle() )
2935 addImage(image);
2936
2937 return image;
2938 }
2939
2940 #if TARGET_IPHONE_SIMULATOR
2941 static bool isSimulatorBinary(const uint8_t* firstPages, const char* path)
2942 {
2943 const macho_header* mh = (macho_header*)firstPages;
2944 const uint32_t cmd_count = mh->ncmds;
2945 const load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
2946 const load_command* const cmdsEnd = (load_command*)((char*)cmds + mh->sizeofcmds);
2947 const struct load_command* cmd = cmds;
2948 for (uint32_t i = 0; i < cmd_count; ++i) {
2949 switch (cmd->cmd) {
2950 #if TARGET_OS_WATCH
2951 case LC_VERSION_MIN_WATCHOS:
2952 return true;
2953 #elif TARGET_OS_TV
2954 case LC_VERSION_MIN_TVOS:
2955 return true;
2956 #elif TARGET_OS_IOS
2957 case LC_VERSION_MIN_IPHONEOS:
2958 return true;
2959 #endif
2960 case LC_VERSION_MIN_MACOSX:
2961 // grandfather in a few libSystem dylibs
2962 if ((strcmp(path, "/usr/lib/system/libsystem_kernel.dylib") == 0) ||
2963 (strcmp(path, "/usr/lib/system/libsystem_platform.dylib") == 0) ||
2964 (strcmp(path, "/usr/lib/system/libsystem_pthread.dylib") == 0) ||
2965 (strcmp(path, "/usr/lib/system/libsystem_platform_debug.dylib") == 0) ||
2966 (strcmp(path, "/usr/lib/system/libsystem_pthread_debug.dylib") == 0))
2967 return true;
2968 return false;
2969 case LC_BUILD_VERSION:
2970 {
2971 // Same logic as above, but for LC_BUILD_VERSION instead of legacy load commands
2972 const struct build_version_command* buildVersionCmd = (build_version_command*)cmd;
2973 switch(buildVersionCmd->platform) {
2974 case PLATFORM_IOSSIMULATOR:
2975 case PLATFORM_TVOSSIMULATOR:
2976 case PLATFORM_WATCHOSSIMULATOR:
2977 case PLATFORM_WATCHOS:
2978 return true;
2979 #if TARGET_OS_IOSMAC
2980 case 6:
2981 return true;
2982 #endif
2983 case PLATFORM_MACOS:
2984 if ((strcmp(path, "/usr/lib/system/libsystem_kernel.dylib") == 0) ||
2985 (strcmp(path, "/usr/lib/system/libsystem_platform.dylib") == 0) ||
2986 (strcmp(path, "/usr/lib/system/libsystem_pthread.dylib") == 0) ||
2987 (strcmp(path, "/usr/lib/system/libsystem_platform_debug.dylib") == 0) ||
2988 (strcmp(path, "/usr/lib/system/libsystem_pthread_debug.dylib") == 0))
2989 return true;
2990 }
2991 }
2992 }
2993 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
2994 if ( cmd > cmdsEnd )
2995 return false;
2996 }
2997 return false;
2998 }
2999 #endif
3000
3001 #if __MAC_OS_X_VERSION_MIN_REQUIRED
3002 static bool iOSMacWhiteListed(const char* path)
3003 {
3004 static char* whiteListBuffer = nullptr;
3005 static size_t whiteListSize = 0;
3006 static bool tried = false;
3007 if ( !tried ) {
3008 // only try to map file once
3009 whiteListBuffer = (char*)mapFileReadOnly("/System/iOSSupport/dyld/macOS-whitelist.txt", whiteListSize);
3010 tried = true;
3011 }
3012 __block bool result = false;
3013 if ( whiteListBuffer != nullptr ) {
3014 dyld3::forEachLineInFile(whiteListBuffer, whiteListSize, ^(const char* line, bool& stop) {
3015 // lines in the file are prefixes. Any path that starts with one of these lines is allowed to be unzippered
3016 size_t lineLen = strlen(line);
3017 if ( (*line == '/') && strncmp(line, path, lineLen) == 0 ) {
3018 result = true;
3019 stop = true;
3020 }
3021 });
3022 }
3023 return result;
3024 }
3025
3026 static bool iOSMacBlackListed(const char* path)
3027 {
3028 static char* blackListBuffer = nullptr;
3029 static size_t blackListSize = 0;
3030 static bool tried = false;
3031 if ( !tried ) {
3032 // only try to map file once
3033 blackListBuffer = (char*)mapFileReadOnly("/System/iOSSupport/dyld/macOS-blacklist.txt", blackListSize);
3034 tried = true;
3035 }
3036 __block bool result = false;
3037 if ( blackListBuffer != nullptr ) {
3038 dyld3::forEachLineInFile(blackListBuffer, blackListSize, ^(const char* line, bool& stop) {
3039 // lines in the file are prefixes. Any path that starts with one of these lines is allowed to be unzippered
3040 size_t lineLen = strlen(line);
3041 if ( (*line == '/') && strncmp(line, path, lineLen) == 0 ) {
3042 result = true;
3043 stop = true;
3044 }
3045 });
3046 }
3047 return result;
3048 }
3049
3050
3051 #endif
3052
3053 // map in file and instantiate an ImageLoader
3054 static ImageLoader* loadPhase6(int fd, const struct stat& stat_buf, const char* path, const LoadContext& context)
3055 {
3056 //dyld::log("%s(%s)\n", __func__ , path);
3057 uint64_t fileOffset = 0;
3058 uint64_t fileLength = stat_buf.st_size;
3059
3060 // validate it is a file (not directory)
3061 if ( (stat_buf.st_mode & S_IFMT) != S_IFREG )
3062 throw "not a file";
3063
3064 uint8_t firstPages[MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE];
3065 uint8_t *firstPagesPtr = firstPages;
3066 bool shortPage = false;
3067
3068 // min mach-o file is 4K
3069 if ( fileLength < 4096 ) {
3070 if ( pread(fd, firstPages, (size_t)fileLength, 0) != (ssize_t)fileLength )
3071 throwf("pread of short file failed: %d", errno);
3072 shortPage = true;
3073 }
3074 else {
3075 // optimistically read only first 4KB
3076 if ( pread(fd, firstPages, 4096, 0) != 4096 )
3077 throwf("pread of first 4K failed: %d", errno);
3078 }
3079
3080 // if fat wrapper, find usable sub-file
3081 const fat_header* fileStartAsFat = (fat_header*)firstPages;
3082 if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
3083 if ( OSSwapBigToHostInt32(fileStartAsFat->nfat_arch) > ((4096 - sizeof(fat_header)) / sizeof(fat_arch)) )
3084 throwf("fat header too large: %u entries", OSSwapBigToHostInt32(fileStartAsFat->nfat_arch));
3085 if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) {
3086 if ( (fileOffset+fileLength) > (uint64_t)(stat_buf.st_size) )
3087 throwf("truncated fat file. file length=%llu, but needed slice goes to %llu", stat_buf.st_size, fileOffset+fileLength);
3088 if (pread(fd, firstPages, 4096, fileOffset) != 4096)
3089 throwf("pread of fat file failed: %d", errno);
3090 }
3091 else {
3092 throw "no matching architecture in universal wrapper";
3093 }
3094 }
3095
3096 // try mach-o loader
3097 if ( shortPage )
3098 throw "file too short";
3099
3100 if ( isCompatibleMachO(firstPages, path) ) {
3101
3102 // only MH_BUNDLE, MH_DYLIB, and some MH_EXECUTE can be dynamically loaded
3103 const mach_header* mh = (mach_header*)firstPages;
3104 switch ( mh->filetype ) {
3105 case MH_EXECUTE:
3106 case MH_DYLIB:
3107 case MH_BUNDLE:
3108 break;
3109 default:
3110 throw "mach-o, but wrong filetype";
3111 }
3112
3113 uint32_t headerAndLoadCommandsSize = sizeof(macho_header) + mh->sizeofcmds;
3114 if ( headerAndLoadCommandsSize > MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE )
3115 throwf("malformed mach-o: load commands size (%u) > %u", headerAndLoadCommandsSize, MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE);
3116
3117 if ( headerAndLoadCommandsSize > fileLength )
3118 dyld::throwf("malformed mach-o: load commands size (%u) > mach-o file size (%llu)", headerAndLoadCommandsSize, fileLength);
3119
3120 if ( headerAndLoadCommandsSize > 4096 ) {
3121 // read more pages
3122 unsigned readAmount = headerAndLoadCommandsSize - 4096;
3123 if ( pread(fd, &firstPages[4096], readAmount, fileOffset+4096) != readAmount )
3124 throwf("pread of extra load commands past 4KB failed: %d", errno);
3125 }
3126
3127 #if TARGET_IPHONE_SIMULATOR
3128 // <rdar://problem/14168872> dyld_sim should restrict loading osx binaries
3129 if ( !isSimulatorBinary(firstPages, path) ) {
3130 #if TARGET_OS_WATCH
3131 throw "mach-o, but not built for watchOS simulator";
3132 #elif TARGET_OS_TV
3133 throw "mach-o, but not built for tvOS simulator";
3134 #else
3135 throw "mach-o, but not built for iOS simulator";
3136 #endif
3137 }
3138 #endif
3139
3140 #if __MAC_OS_X_VERSION_MIN_REQUIRED
3141 if ( gLinkContext.marzipan ) {
3142 const dyld3::MachOFile* mf = (dyld3::MachOFile*)firstPages;
3143 bool isiOSMacBinary = mf->supportsPlatform(dyld3::Platform::iOSMac) || iOSMacWhiteListed(path);
3144 bool isProhibitedMacOSBinary = !isiOSMacBinary && iOSMacBlackListed(path);
3145 if ( (context.enforceIOSMac && !isiOSMacBinary) || isProhibitedMacOSBinary ) {
3146 throw "mach-o, but not built for iOSMac";
3147 }
3148 }
3149 #endif
3150
3151 #if __arm64e__
3152 if ( (sMainExecutableMachHeader->cpusubtype == CPU_SUBTYPE_ARM64_E) && (mh->cpusubtype != CPU_SUBTYPE_ARM64_E) )
3153 throw "arm64 dylibs cannot be loaded into arm64e processes";
3154 #endif
3155 ImageLoader* image = nullptr;
3156 {
3157 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_MAP_IMAGE, path, 0, 0);
3158 image = ImageLoaderMachO::instantiateFromFile(path, fd, firstPagesPtr, headerAndLoadCommandsSize, fileOffset, fileLength, stat_buf, gLinkContext);
3159 timer.setData4((uint64_t)image->machHeader());
3160 }
3161
3162 // validate
3163 return checkandAddImage(image, context);
3164 }
3165
3166 // try other file formats here...
3167
3168
3169 // throw error about what was found
3170 switch (*(uint32_t*)firstPages) {
3171 case MH_MAGIC:
3172 case MH_CIGAM:
3173 case MH_MAGIC_64:
3174 case MH_CIGAM_64:
3175 throw "mach-o, but wrong architecture";
3176 default:
3177 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
3178 firstPages[0], firstPages[1], firstPages[2], firstPages[3], firstPages[4], firstPages[5], firstPages[6],firstPages[7]);
3179 }
3180 }
3181
3182
3183 static ImageLoader* loadPhase5open(const char* path, const LoadContext& context, const struct stat& stat_buf, std::vector<const char*>* exceptions)
3184 {
3185 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3186
3187 // open file (automagically closed when this function exits)
3188 FileOpener file(path);
3189
3190 // just return NULL if file not found, but record any other errors
3191 if ( file.getFileDescriptor() == -1 ) {
3192 int err = errno;
3193 if ( err != ENOENT ) {
3194 const char* newMsg;
3195 if ( (err == EPERM) && sandboxBlockedOpen(path) )
3196 newMsg = dyld::mkstringf("file system sandbox blocked open() of '%s'", path);
3197 else
3198 newMsg = dyld::mkstringf("%s: open() failed with errno=%d", path, err);
3199 exceptions->push_back(newMsg);
3200 }
3201 return NULL;
3202 }
3203
3204 try {
3205 return loadPhase6(file.getFileDescriptor(), stat_buf, path, context);
3206 }
3207 catch (const char* msg) {
3208 const char* newMsg = dyld::mkstringf("%s: %s", path, msg);
3209 exceptions->push_back(newMsg);
3210 free((void*)msg);
3211 return NULL;
3212 }
3213 }
3214
3215
3216
3217 // try to open file
3218 static ImageLoader* loadPhase5load(const char* path, const char* orgPath, const LoadContext& context, unsigned& cacheIndex, std::vector<const char*>* exceptions)
3219 {
3220 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3221 #if SUPPORT_ACCELERATE_TABLES
3222 if ( sAllCacheImagesProxy != NULL ) {
3223 if ( sAllCacheImagesProxy->hasDylib(path, &cacheIndex) )
3224 return sAllCacheImagesProxy;
3225 }
3226 #endif
3227 #if TARGET_IPHONE_SIMULATOR
3228 // in simulators, 'path' has DYLD_ROOT_PATH prepended, but cache index does not have the prefix, so use orgPath
3229 const char* pathToFindInCache = orgPath;
3230 #else
3231 const char* pathToFindInCache = path;
3232 #endif
3233 uint statErrNo;
3234 struct stat statBuf;
3235 bool didStat = false;
3236 bool existsOnDisk;
3237 dyld3::SharedCacheFindDylibResults shareCacheResults;
3238 shareCacheResults.image = nullptr;
3239 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, pathToFindInCache, &shareCacheResults) ) {
3240 // see if this image in the cache was already loaded via a different path
3241 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); ++it) {
3242 ImageLoader* anImage = *it;
3243 if ( (const mach_header*)anImage->machHeader() == shareCacheResults.mhInCache )
3244 return anImage;
3245 }
3246 // if RTLD_NOLOAD, do nothing if not already loaded
3247 if ( context.dontLoad ) {
3248 // <rdar://33412890> possible that there is an override of cache
3249 if ( my_stat(path, &statBuf) == 0 ) {
3250 ImageLoader* imageLoader = findLoadedImage(statBuf);
3251 if ( imageLoader != NULL )
3252 return imageLoader;
3253 }
3254 return NULL;
3255 }
3256 bool useCache = false;
3257 if ( shareCacheResults.image == nullptr ) {
3258 // HACK to support old caches
3259 existsOnDisk = ( my_stat(path, &statBuf) == 0 );
3260 didStat = true;
3261 statErrNo = errno;
3262 useCache = !existsOnDisk;
3263 }
3264 else {
3265 // <rdar://problem/7014995> zero out stat buffer so mtime, etc are zero for items from the shared cache
3266 bzero(&statBuf, sizeof(statBuf));
3267 if ( shareCacheResults.image->overridableDylib() ) {
3268 existsOnDisk = ( my_stat(path, &statBuf) == 0 );
3269 didStat = true;
3270 statErrNo = errno;
3271 if ( sSharedCacheLoadInfo.loadAddress->header.dylibsExpectedOnDisk ) {
3272 uint64_t expectedINode;
3273 uint64_t expectedMtime;
3274 if ( shareCacheResults.image->hasFileModTimeAndInode(expectedINode, expectedMtime) ) {
3275 if ( (expectedMtime == statBuf.st_mtime) && (expectedINode == statBuf.st_ino) )
3276 useCache = true;
3277 }
3278 }
3279 else {
3280 if ( !existsOnDisk )
3281 useCache = true;
3282 }
3283 }
3284 else {
3285 useCache = true;
3286 }
3287 }
3288 if ( useCache ) {
3289 #if __MAC_OS_X_VERSION_MIN_REQUIRED
3290 if ( gLinkContext.marzipan ) {
3291 const dyld3::MachOFile* mf = (dyld3::MachOFile*)shareCacheResults.mhInCache;
3292 bool isiOSMacBinary = mf->supportsPlatform(dyld3::Platform::iOSMac) || iOSMacWhiteListed(path);
3293 bool isProhibitedMacOSBinary = !isiOSMacBinary && iOSMacBlackListed(path);
3294 if ( (context.enforceIOSMac && !isiOSMacBinary) || isProhibitedMacOSBinary ) {
3295 throw "mach-o, but not built for iOSMac";
3296 }
3297 }
3298 #endif
3299 ImageLoader* imageLoader = ImageLoaderMachO::instantiateFromCache((macho_header*)shareCacheResults.mhInCache, shareCacheResults.pathInCache, shareCacheResults.slideInCache, statBuf, gLinkContext);
3300 return checkandAddImage(imageLoader, context);
3301 }
3302 }
3303
3304 // not in cache or cache not usable
3305 if ( !didStat ) {
3306 existsOnDisk = ( my_stat(path, &statBuf) == 0 );
3307 statErrNo = errno;
3308 }
3309 if ( existsOnDisk ) {
3310 // in case image was renamed or found via symlinks, check for inode match
3311 ImageLoader* imageLoader = findLoadedImage(statBuf);
3312 if ( imageLoader != NULL )
3313 return imageLoader;
3314 // do nothing if not already loaded and if RTLD_NOLOAD
3315 if ( context.dontLoad )
3316 return NULL;
3317 // try opening file
3318 imageLoader = loadPhase5open(path, context, statBuf, exceptions);
3319 if ( imageLoader != NULL ) {
3320 if ( shareCacheResults.image != nullptr ) {
3321 // if image was found in cache, but is overridden by a newer file on disk, record what the image overrides
3322 imageLoader->setOverridesCachedDylib(shareCacheResults.image->imageNum());
3323 }
3324 return imageLoader;
3325 }
3326 }
3327
3328 // just return NULL if file not found, but record any other errors
3329 if ( (statErrNo != ENOENT) && (statErrNo != 0) ) {
3330 if ( (statErrNo == EPERM) && sandboxBlockedStat(path) )
3331 exceptions->push_back(dyld::mkstringf("%s: file system sandbox blocked stat()", path));
3332 else
3333 exceptions->push_back(dyld::mkstringf("%s: stat() failed with errno=%d", path, statErrNo));
3334 }
3335 return NULL;
3336 }
3337
3338 // look for path match with existing loaded images
3339 static ImageLoader* loadPhase5check(const char* path, const char* orgPath, const LoadContext& context)
3340 {
3341 //dyld::log("%s(%s, %s)\n", __func__ , path, orgPath);
3342 // search path against load-path and install-path of all already loaded images
3343 uint32_t hash = ImageLoader::hash(path);
3344 //dyld::log("check() hash=%d, path=%s\n", hash, path);
3345 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3346 ImageLoader* anImage = *it;
3347 // check hash first to cut down on strcmp calls
3348 //dyld::log(" check() hash=%d, path=%s\n", anImage->getPathHash(), anImage->getPath());
3349 if ( anImage->getPathHash() == hash ) {
3350 if ( strcmp(path, anImage->getPath()) == 0 ) {
3351 // if we are looking for a dylib don't return something else
3352 if ( !context.mustBeDylib || anImage->isDylib() )
3353 return anImage;
3354 }
3355 }
3356 if ( context.matchByInstallName || anImage->matchInstallPath() ) {
3357 const char* installPath = anImage->getInstallPath();
3358 if ( installPath != NULL) {
3359 if ( strcmp(path, installPath) == 0 ) {
3360 // if we are looking for a dylib don't return something else
3361 if ( !context.mustBeDylib || anImage->isDylib() )
3362 return anImage;
3363 }
3364 }
3365 }
3366 // an install name starting with @rpath should match by install name, not just real path
3367 if ( (orgPath[0] == '@') && (strncmp(orgPath, "@rpath/", 7) == 0) ) {
3368 const char* installPath = anImage->getInstallPath();
3369 if ( installPath != NULL) {
3370 if ( !context.mustBeDylib || anImage->isDylib() ) {
3371 if ( strcmp(orgPath, installPath) == 0 )
3372 return anImage;
3373 }
3374 }
3375 }
3376 }
3377
3378 //dyld::log("%s(%s) => NULL\n", __func__, path);
3379 return NULL;
3380 }
3381
3382
3383 // open or check existing
3384 static ImageLoader* loadPhase5(const char* path, const char* orgPath, const LoadContext& context, unsigned& cacheIndex, std::vector<const char*>* exceptions)
3385 {
3386 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3387
3388 // check for specific dylib overrides
3389 for (std::vector<DylibOverride>::iterator it = sDylibOverrides.begin(); it != sDylibOverrides.end(); ++it) {
3390 if ( strcmp(it->installName, path) == 0 ) {
3391 path = it->override;
3392 break;
3393 }
3394 }
3395
3396 if ( exceptions != NULL )
3397 return loadPhase5load(path, orgPath, context, cacheIndex, exceptions);
3398 else
3399 return loadPhase5check(path, orgPath, context);
3400 }
3401
3402 // try with and without image suffix
3403 static ImageLoader* loadPhase4(const char* path, const char* orgPath, const LoadContext& context, unsigned& cacheIndex, std::vector<const char*>* exceptions)
3404 {
3405 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3406 ImageLoader* image = NULL;
3407 if ( gLinkContext.imageSuffix != NULL ) {
3408 for (const char* const* suffix=gLinkContext.imageSuffix; *suffix != NULL; ++suffix) {
3409 char pathWithSuffix[strlen(path)+strlen(*suffix)+2];
3410 ImageLoader::addSuffix(path, *suffix, pathWithSuffix);
3411 image = loadPhase5(pathWithSuffix, orgPath, context, cacheIndex, exceptions);
3412 if ( image != NULL )
3413 break;
3414 }
3415 if ( image != NULL ) {
3416 // if original path is in the dyld cache, then mark this one found as an override
3417 dyld3::SharedCacheFindDylibResults shareCacheResults;
3418 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &shareCacheResults) && (shareCacheResults.image != nullptr) )
3419 image->setOverridesCachedDylib(shareCacheResults.image->imageNum());
3420 }
3421 }
3422 if ( image == NULL )
3423 image = loadPhase5(path, orgPath, context, cacheIndex, exceptions);
3424 return image;
3425 }
3426
3427 static ImageLoader* loadPhase2(const char* path, const char* orgPath, const LoadContext& context,
3428 const char* const frameworkPaths[], const char* const libraryPaths[],
3429 unsigned& cacheIndex, std::vector<const char*>* exceptions); // forward reference
3430
3431
3432 // expand @ variables
3433 static ImageLoader* loadPhase3(const char* path, const char* orgPath, const LoadContext& context, unsigned& cacheIndex, std::vector<const char*>* exceptions)
3434 {
3435 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3436 ImageLoader* image = NULL;
3437 if ( strncmp(path, "@executable_path/", 17) == 0 ) {
3438 // executable_path cannot be in used in any binary in a setuid process rdar://problem/4589305
3439 if ( !gLinkContext.allowAtPaths )
3440 throwf("unsafe use of @executable_path in %s with restricted binary", context.origin);
3441 // handle @executable_path path prefix
3442 const char* executablePath = sExecPath;
3443 char newPath[strlen(executablePath) + strlen(path)];
3444 strcpy(newPath, executablePath);
3445 char* addPoint = strrchr(newPath,'/');
3446 if ( addPoint != NULL )
3447 strcpy(&addPoint[1], &path[17]);
3448 else
3449 strcpy(newPath, &path[17]);
3450 image = loadPhase4(newPath, orgPath, context, cacheIndex, exceptions);
3451 if ( image != NULL )
3452 return image;
3453
3454 // perhaps main executable path is a sym link, find realpath and retry
3455 char resolvedPath[PATH_MAX];
3456 if ( realpath(sExecPath, resolvedPath) != NULL ) {
3457 char newRealPath[strlen(resolvedPath) + strlen(path)];
3458 strcpy(newRealPath, resolvedPath);
3459 addPoint = strrchr(newRealPath,'/');
3460 if ( addPoint != NULL )
3461 strcpy(&addPoint[1], &path[17]);
3462 else
3463 strcpy(newRealPath, &path[17]);
3464 image = loadPhase4(newRealPath, orgPath, context, cacheIndex, exceptions);
3465 if ( image != NULL )
3466 return image;
3467 }
3468 }
3469 else if ( (strncmp(path, "@loader_path/", 13) == 0) && (context.origin != NULL) ) {
3470 // @loader_path cannot be used from the main executable of a setuid process rdar://problem/4589305
3471 if ( !gLinkContext.allowAtPaths && (strcmp(context.origin, sExecPath) == 0) )
3472 throwf("unsafe use of @loader_path in %s with restricted binary", context.origin);
3473 // handle @loader_path path prefix
3474 char newPath[strlen(context.origin) + strlen(path)];
3475 strcpy(newPath, context.origin);
3476 char* addPoint = strrchr(newPath,'/');
3477 if ( addPoint != NULL )
3478 strcpy(&addPoint[1], &path[13]);
3479 else
3480 strcpy(newPath, &path[13]);
3481 image = loadPhase4(newPath, orgPath, context, cacheIndex, exceptions);
3482 if ( image != NULL )
3483 return image;
3484
3485 // perhaps loader path is a sym link, find realpath and retry
3486 char resolvedPath[PATH_MAX];
3487 if ( realpath(context.origin, resolvedPath) != NULL ) {
3488 char newRealPath[strlen(resolvedPath) + strlen(path)];
3489 strcpy(newRealPath, resolvedPath);
3490 addPoint = strrchr(newRealPath,'/');
3491 if ( addPoint != NULL )
3492 strcpy(&addPoint[1], &path[13]);
3493 else
3494 strcpy(newRealPath, &path[13]);
3495 image = loadPhase4(newRealPath, orgPath, context, cacheIndex, exceptions);
3496 if ( image != NULL )
3497 return image;
3498 }
3499 }
3500 else if ( context.implicitRPath || (strncmp(path, "@rpath/", 7) == 0) ) {
3501 const char* trailingPath = (strncmp(path, "@rpath/", 7) == 0) ? &path[7] : path;
3502 // substitute @rpath with all -rpath paths up the load chain
3503 for(const ImageLoader::RPathChain* rp=context.rpath; rp != NULL; rp=rp->next) {
3504 if (rp->paths != NULL ) {
3505 for(std::vector<const char*>::iterator it=rp->paths->begin(); it != rp->paths->end(); ++it) {
3506 const char* anRPath = *it;
3507 char newPath[strlen(anRPath) + strlen(trailingPath)+2];
3508 strcpy(newPath, anRPath);
3509 if ( newPath[strlen(newPath)-1] != '/' )
3510 strcat(newPath, "/");
3511 strcat(newPath, trailingPath);
3512 image = loadPhase4(newPath, orgPath, context, cacheIndex, exceptions);
3513 if ( gLinkContext.verboseRPaths && (exceptions != NULL) ) {
3514 if ( image != NULL )
3515 dyld::log("RPATH successful expansion of %s to: %s\n", orgPath, newPath);
3516 else
3517 dyld::log("RPATH failed to expanding %s to: %s\n", orgPath, newPath);
3518 }
3519 if ( image != NULL )
3520 return image;
3521 }
3522 }
3523 }
3524
3525 // substitute @rpath with LD_LIBRARY_PATH
3526 if ( sEnv.LD_LIBRARY_PATH != NULL ) {
3527 image = loadPhase2(trailingPath, orgPath, context, NULL, sEnv.LD_LIBRARY_PATH, cacheIndex, exceptions);
3528 if ( image != NULL )
3529 return image;
3530 }
3531
3532 // if this is the "open" pass, don't try to open @rpath/... as a relative path
3533 if ( (exceptions != NULL) && (trailingPath != path) )
3534 return NULL;
3535 }
3536 else if ( !gLinkContext.allowEnvVarsPath && (path[0] != '/' ) ) {
3537 throwf("unsafe use of relative rpath %s in %s with restricted binary", path, context.origin);
3538 }
3539
3540 return loadPhase4(path, orgPath, context, cacheIndex, exceptions);
3541 }
3542
3543 static ImageLoader* loadPhase2cache(const char* path, const char *orgPath, const LoadContext& context, unsigned& cacheIndex, std::vector<const char*>* exceptions) {
3544 ImageLoader* image = NULL;
3545 #if !TARGET_IPHONE_SIMULATOR
3546 if ( exceptions != NULL) {
3547 char resolvedPath[PATH_MAX];
3548 realpath(path, resolvedPath);
3549 int myerr = errno;
3550 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
3551 if ( (myerr == ENOENT) || (myerr == 0) )
3552 {
3553 image = loadPhase4(resolvedPath, orgPath, context, cacheIndex, exceptions);
3554 }
3555 }
3556 #endif
3557 return image;
3558 }
3559
3560
3561 // try search paths
3562 static ImageLoader* loadPhase2(const char* path, const char* orgPath, const LoadContext& context,
3563 const char* const frameworkPaths[], const char* const libraryPaths[],
3564 unsigned& cacheIndex, std::vector<const char*>* exceptions)
3565 {
3566 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3567 ImageLoader* image = NULL;
3568 const char* frameworkPartialPath = getFrameworkPartialPath(path);
3569 if ( frameworkPaths != NULL ) {
3570 if ( frameworkPartialPath != NULL ) {
3571 const size_t frameworkPartialPathLen = strlen(frameworkPartialPath);
3572 for(const char* const* fp = frameworkPaths; *fp != NULL; ++fp) {
3573 char npath[strlen(*fp)+frameworkPartialPathLen+8];
3574 strcpy(npath, *fp);
3575 strcat(npath, "/");
3576 strcat(npath, frameworkPartialPath);
3577 //dyld::log("dyld: fallback framework path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, npath);
3578 image = loadPhase4(npath, orgPath, context, cacheIndex, exceptions);
3579 // Look in the cache if appropriate
3580 if ( image == NULL)
3581 image = loadPhase2cache(npath, orgPath, context, cacheIndex, exceptions);
3582 if ( image != NULL ) {
3583 // if original path is in the dyld cache, then mark this one found as an override
3584 dyld3::SharedCacheFindDylibResults shareCacheResults;
3585 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &shareCacheResults) && (shareCacheResults.image != nullptr) )
3586 image->setOverridesCachedDylib(shareCacheResults.image->imageNum());
3587 return image;
3588 }
3589 }
3590 }
3591 }
3592 // <rdar://problem/12649639> An executable with the same name as a framework & DYLD_LIBRARY_PATH pointing to it gets loaded twice
3593 // <rdar://problem/14160846> Some apps depend on frameworks being found via library paths
3594 if ( (libraryPaths != NULL) && ((frameworkPartialPath == NULL) || sFrameworksFoundAsDylibs) ) {
3595 const char* libraryLeafName = getLibraryLeafName(path);
3596 const size_t libraryLeafNameLen = strlen(libraryLeafName);
3597 for(const char* const* lp = libraryPaths; *lp != NULL; ++lp) {
3598 char libpath[strlen(*lp)+libraryLeafNameLen+8];
3599 strcpy(libpath, *lp);
3600 strcat(libpath, "/");
3601 strcat(libpath, libraryLeafName);
3602 //dyld::log("dyld: fallback library path used: %s() -> loadPhase4(\"%s\", ...)\n", __func__, libpath);
3603 image = loadPhase4(libpath, orgPath, context, cacheIndex, exceptions);
3604 // Look in the cache if appropriate
3605 if ( image == NULL)
3606 image = loadPhase2cache(libpath, orgPath, context, cacheIndex, exceptions);
3607 if ( image != NULL ) {
3608 // if original path is in the dyld cache, then mark this one found as an override
3609 dyld3::SharedCacheFindDylibResults shareCacheResults;
3610 if ( dyld3::findInSharedCacheImage(sSharedCacheLoadInfo, path, &shareCacheResults) && (shareCacheResults.image != nullptr) )
3611 image->setOverridesCachedDylib(shareCacheResults.image->imageNum());
3612 return image;
3613 }
3614 }
3615 }
3616 return NULL;
3617 }
3618
3619 // try search overrides and fallbacks
3620 static ImageLoader* loadPhase1(const char* path, const char* orgPath, const LoadContext& context, unsigned& cacheIndex, std::vector<const char*>* exceptions)
3621 {
3622 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3623 ImageLoader* image = NULL;
3624
3625 // handle LD_LIBRARY_PATH environment variables that force searching
3626 if ( context.useLdLibraryPath && (sEnv.LD_LIBRARY_PATH != NULL) ) {
3627 image = loadPhase2(path, orgPath, context, NULL, sEnv.LD_LIBRARY_PATH, cacheIndex,exceptions);
3628 if ( image != NULL )
3629 return image;
3630 }
3631
3632 // handle DYLD_ environment variables that force searching
3633 if ( context.useSearchPaths && ((sEnv.DYLD_FRAMEWORK_PATH != NULL) || (sEnv.DYLD_LIBRARY_PATH != NULL)) ) {
3634 image = loadPhase2(path, orgPath, context, sEnv.DYLD_FRAMEWORK_PATH, sEnv.DYLD_LIBRARY_PATH, cacheIndex, exceptions);
3635 if ( image != NULL )
3636 return image;
3637 }
3638
3639 // try raw path
3640 image = loadPhase3(path, orgPath, context, cacheIndex, exceptions);
3641 if ( image != NULL )
3642 return image;
3643
3644 // try fallback paths during second time (will open file)
3645 const char* const* fallbackLibraryPaths = sEnv.DYLD_FALLBACK_LIBRARY_PATH;
3646 if ( (fallbackLibraryPaths != NULL) && !context.useFallbackPaths )
3647 fallbackLibraryPaths = NULL;
3648 if ( !context.dontLoad && (exceptions != NULL) && ((sEnv.DYLD_FALLBACK_FRAMEWORK_PATH != NULL) || (fallbackLibraryPaths != NULL)) ) {
3649 image = loadPhase2(path, orgPath, context, sEnv.DYLD_FALLBACK_FRAMEWORK_PATH, fallbackLibraryPaths, cacheIndex, exceptions);
3650 if ( image != NULL )
3651 return image;
3652 }
3653
3654 return NULL;
3655 }
3656
3657 // try root substitutions
3658 static ImageLoader* loadPhase0(const char* path, const char* orgPath, const LoadContext& context, unsigned& cacheIndex, std::vector<const char*>* exceptions)
3659 {
3660 //dyld::log("%s(%s, %p)\n", __func__ , path, exceptions);
3661
3662 #if __MAC_OS_X_VERSION_MIN_REQUIRED
3663 // handle macOS dylibs dlopen()ing versioned path which needs to map to flat path in mazipan simulator
3664 if ( gLinkContext.marzipan && strstr(path, ".framework/Versions/")) {
3665 uintptr_t sourceOffset = 0;
3666 uintptr_t destOffset = 0;
3667 size_t sourceLangth = strlen(path);
3668 char flatPath[sourceLangth];
3669 flatPath[0] = 0;
3670 const char* frameworkBase = NULL;
3671 while ((frameworkBase = strstr(&path[sourceOffset], ".framework/Versions/"))) {
3672 uintptr_t foundLength = (frameworkBase - &path[sourceOffset]) + strlen(".framework/") ;
3673 strlcat(&flatPath[destOffset], &path[sourceOffset], foundLength);
3674 sourceOffset += foundLength + strlen("Versions/") + 1;
3675 destOffset += foundLength - 1;
3676 }
3677 strlcat(&flatPath[destOffset], &path[sourceOffset], sourceLangth);
3678 ImageLoader* image = loadPhase0(flatPath, orgPath, context, cacheIndex, exceptions);
3679 if ( image != NULL )
3680 return image;
3681 }
3682 #endif
3683
3684 #if SUPPORT_ROOT_PATH
3685 // handle DYLD_ROOT_PATH which forces absolute paths to use a new root
3686 if ( (gLinkContext.rootPaths != NULL) && (path[0] == '/') ) {
3687 for(const char* const* rootPath = gLinkContext.rootPaths; *rootPath != NULL; ++rootPath) {
3688 size_t rootLen = strlen(*rootPath);
3689 if ( strncmp(path, *rootPath, rootLen) != 0 ) {
3690 char newPath[rootLen + strlen(path)+2];
3691 strcpy(newPath, *rootPath);
3692 strcat(newPath, path);
3693 ImageLoader* image = loadPhase1(newPath, orgPath, context, cacheIndex, exceptions);
3694 if ( image != NULL )
3695 return image;
3696 }
3697 }
3698 }
3699 #endif
3700
3701 // try raw path
3702 return loadPhase1(path, orgPath, context, cacheIndex, exceptions);
3703 }
3704
3705 static bool cacheablePath(const char* path) {
3706 if (strncmp(path, "/usr/lib/", 9) == 0)
3707 return true;
3708 if (strncmp(path, "/System/Library/", 16) == 0)
3709 return true;
3710 return false;
3711 }
3712
3713 //
3714 // Given all the DYLD_ environment variables, the general case for loading libraries
3715 // is that any given path expands into a list of possible locations to load. We
3716 // also must take care to ensure two copies of the "same" library are never loaded.
3717 //
3718 // The algorithm used here is that there is a separate function for each "phase" of the
3719 // path expansion. Each phase function calls the next phase with each possible expansion
3720 // of that phase. The result is the last phase is called with all possible paths.
3721 //
3722 // To catch duplicates the algorithm is run twice. The first time, the last phase checks
3723 // the path against all loaded images. The second time, the last phase calls open() on
3724 // the path. Either time, if an image is found, the phases all unwind without checking
3725 // for other paths.
3726 //
3727 ImageLoader* load(const char* path, const LoadContext& context, unsigned& cacheIndex)
3728 {
3729 CRSetCrashLogMessage2(path);
3730 const char* orgPath = path;
3731 cacheIndex = UINT32_MAX;
3732
3733 //dyld::log("%s(%s)\n", __func__ , path);
3734 char realPath[PATH_MAX];
3735 // when DYLD_IMAGE_SUFFIX is in used, do a realpath(), otherwise a load of "Foo.framework/Foo" will not match
3736 if ( context.useSearchPaths && ( gLinkContext.imageSuffix != NULL && *gLinkContext.imageSuffix != NULL) ) {
3737 if ( realpath(path, realPath) != NULL )
3738 path = realPath;
3739 }
3740
3741 // try all path permutations and check against existing loaded images
3742
3743 ImageLoader* image = loadPhase0(path, orgPath, context, cacheIndex, NULL);
3744 if ( image != NULL ) {
3745 CRSetCrashLogMessage2(NULL);
3746 return image;
3747 }
3748
3749 // try all path permutations and try open() until first success
3750 std::vector<const char*> exceptions;
3751 image = loadPhase0(path, orgPath, context, cacheIndex, &exceptions);
3752 #if !TARGET_IPHONE_SIMULATOR
3753 // <rdar://problem/16704628> support symlinks on disk to a path in dyld shared cache
3754 if ( image == NULL)
3755 image = loadPhase2cache(path, orgPath, context, cacheIndex, &exceptions);
3756 #endif
3757 CRSetCrashLogMessage2(NULL);
3758 if ( image != NULL ) {
3759 // <rdar://problem/6916014> leak in dyld during dlopen when using DYLD_ variables
3760 for (std::vector<const char*>::iterator it = exceptions.begin(); it != exceptions.end(); ++it) {
3761 free((void*)(*it));
3762 }
3763 // if loaded image is not from cache, but original path is in cache
3764 // set gSharedCacheOverridden flag to disable some ObjC optimizations
3765 if ( !gSharedCacheOverridden && !image->inSharedCache() && image->isDylib() && cacheablePath(path) && inSharedCache(path) ) {
3766 gSharedCacheOverridden = true;
3767 }
3768 return image;
3769 }
3770 else if ( exceptions.size() == 0 ) {
3771 if ( context.dontLoad ) {
3772 return NULL;
3773 }
3774 else
3775 throw "image not found";
3776 }
3777 else {
3778 const char* msgStart = "no suitable image found. Did find:";
3779 const char* delim = "\n\t";
3780 size_t allsizes = strlen(msgStart)+8;
3781 for (size_t i=0; i < exceptions.size(); ++i)
3782 allsizes += (strlen(exceptions[i]) + strlen(delim));
3783 char* fullMsg = new char[allsizes];
3784 strcpy(fullMsg, msgStart);
3785 for (size_t i=0; i < exceptions.size(); ++i) {
3786 strcat(fullMsg, delim);
3787 strcat(fullMsg, exceptions[i]);
3788 free((void*)exceptions[i]);
3789 }
3790 throw (const char*)fullMsg;
3791 }
3792 }
3793
3794
3795
3796
3797
3798 static void mapSharedCache()
3799 {
3800 dyld3::SharedCacheOptions opts;
3801 opts.cacheDirOverride = sSharedCacheOverrideDir;
3802 opts.forcePrivate = (gLinkContext.sharedRegionMode == ImageLoader::kUsePrivateSharedRegion);
3803
3804
3805 #if __x86_64__ && !TARGET_IPHONE_SIMULATOR
3806 opts.useHaswell = sHaswell;
3807 #else
3808 opts.useHaswell = false;
3809 #endif
3810 opts.verbose = gLinkContext.verboseMapping;
3811 loadDyldCache(opts, &sSharedCacheLoadInfo);
3812
3813 // update global state
3814 if ( sSharedCacheLoadInfo.loadAddress != nullptr ) {
3815 gLinkContext.dyldCache = sSharedCacheLoadInfo.loadAddress;
3816 dyld::gProcessInfo->processDetachedFromSharedRegion = opts.forcePrivate;
3817 dyld::gProcessInfo->sharedCacheSlide = sSharedCacheLoadInfo.slide;
3818 dyld::gProcessInfo->sharedCacheBaseAddress = (unsigned long)sSharedCacheLoadInfo.loadAddress;
3819 sSharedCacheLoadInfo.loadAddress->getUUID(dyld::gProcessInfo->sharedCacheUUID);
3820 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_SHARED_CACHE_A, (const uuid_t *)&dyld::gProcessInfo->sharedCacheUUID[0], {0,0}, {{ 0, 0 }}, (const mach_header *)sSharedCacheLoadInfo.loadAddress);
3821 }
3822
3823 //#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR
3824 // RAM disk booting does not have shared cache yet
3825 // Don't make lack of a shared cache fatal in that case
3826 // if ( sSharedCacheLoadInfo.loadAddress == nullptr ) {
3827 // if ( sSharedCacheLoadInfo.errorMessage != nullptr )
3828 // halt(sSharedCacheLoadInfo.errorMessage);
3829 // else
3830 // halt("error loading dyld shared cache");
3831 // }
3832 //#endif
3833 }
3834
3835
3836
3837 // create when NSLinkModule is called for a second time on a bundle
3838 ImageLoader* cloneImage(ImageLoader* image)
3839 {
3840 // open file (automagically closed when this function exits)
3841 FileOpener file(image->getPath());
3842
3843 struct stat stat_buf;
3844 if ( fstat(file.getFileDescriptor(), &stat_buf) == -1)
3845 throw "stat error";
3846
3847 dyld::LoadContext context;
3848 context.useSearchPaths = false;
3849 context.useFallbackPaths = false;
3850 context.useLdLibraryPath = false;
3851 context.implicitRPath = false;
3852 context.matchByInstallName = false;
3853 context.dontLoad = false;
3854 context.mustBeBundle = true;
3855 context.mustBeDylib = false;
3856 context.canBePIE = false;
3857 context.enforceIOSMac = false;
3858 context.origin = NULL;
3859 context.rpath = NULL;
3860 return loadPhase6(file.getFileDescriptor(), stat_buf, image->getPath(), context);
3861 }
3862
3863
3864 ImageLoader* loadFromMemory(const uint8_t* mem, uint64_t len, const char* moduleName)
3865 {
3866 // if fat wrapper, find usable sub-file
3867 const fat_header* memStartAsFat = (fat_header*)mem;
3868 uint64_t fileOffset = 0;
3869 uint64_t fileLength = len;
3870 if ( memStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
3871 if ( fatFindBest(memStartAsFat, &fileOffset, &fileLength) ) {
3872 mem = &mem[fileOffset];
3873 len = fileLength;
3874 }
3875 else {
3876 throw "no matching architecture in universal wrapper";
3877 }
3878 }
3879
3880 // try each loader
3881 if ( isCompatibleMachO(mem, moduleName) ) {
3882 ImageLoader* image = ImageLoaderMachO::instantiateFromMemory(moduleName, (macho_header*)mem, len, gLinkContext);
3883 // don't add bundles to global list, they can be loaded but not linked. When linked it will be added to list
3884 if ( ! image->isBundle() )
3885 addImage(image);
3886 return image;
3887 }
3888
3889 // try other file formats here...
3890
3891 // throw error about what was found
3892 switch (*(uint32_t*)mem) {
3893 case MH_MAGIC:
3894 case MH_CIGAM:
3895 case MH_MAGIC_64:
3896 case MH_CIGAM_64:
3897 throw "mach-o, but wrong architecture";
3898 default:
3899 throwf("unknown file type, first eight bytes: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
3900 mem[0], mem[1], mem[2], mem[3], mem[4], mem[5], mem[6],mem[7]);
3901 }
3902 }
3903
3904
3905 void registerAddCallback(ImageCallback func)
3906 {
3907 // now add to list to get notified when any more images are added
3908 sAddImageCallbacks.push_back(func);
3909
3910 // call callback with all existing images
3911 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
3912 ImageLoader* image = *it;
3913 if ( image->getState() >= dyld_image_state_bound && image->getState() < dyld_image_state_terminated ) {
3914 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE, (uint64_t)image->machHeader(), (uint64_t)(*func), 0);
3915 (*func)(image->machHeader(), image->getSlide());
3916 }
3917 }
3918 #if SUPPORT_ACCELERATE_TABLES
3919 if ( sAllCacheImagesProxy != NULL ) {
3920 dyld_image_info infos[allImagesCount()+1];
3921 unsigned cacheCount = sAllCacheImagesProxy->appendImagesToNotify(dyld_image_state_bound, true, infos);
3922 for (unsigned i=0; i < cacheCount; ++i) {
3923 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE, (uint64_t)infos[i].imageLoadAddress, (uint64_t)(*func), 0);
3924 (*func)(infos[i].imageLoadAddress, sSharedCacheLoadInfo.slide);
3925 }
3926 }
3927 #endif
3928 }
3929
3930 void registerLoadCallback(LoadImageCallback func)
3931 {
3932 // now add to list to get notified when any more images are added
3933 sAddLoadImageCallbacks.push_back(func);
3934
3935 // call callback with all existing images
3936 for (ImageLoader* image : sAllImages) {
3937 if ( image->getState() >= dyld_image_state_bound && image->getState() < dyld_image_state_terminated ) {
3938 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE, (uint64_t)image->machHeader(), (uint64_t)(*func), 0);
3939 (*func)(image->machHeader(), image->getPath(), !image->neverUnload());
3940 }
3941 }
3942 #if SUPPORT_ACCELERATE_TABLES
3943 if ( sAllCacheImagesProxy != NULL ) {
3944 dyld_image_info infos[allImagesCount()+1];
3945 unsigned cacheCount = sAllCacheImagesProxy->appendImagesToNotify(dyld_image_state_bound, true, infos);
3946 for (unsigned i=0; i < cacheCount; ++i) {
3947 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_FUNC_FOR_ADD_IMAGE, (uint64_t)infos[i].imageLoadAddress, (uint64_t)(*func), 0);
3948 (*func)(infos[i].imageLoadAddress, infos[i].imageFilePath, false);
3949 }
3950 }
3951 #endif
3952 }
3953
3954 void registerRemoveCallback(ImageCallback func)
3955 {
3956 // <rdar://problem/15025198> ignore calls to register a notification during a notification
3957 if ( sRemoveImageCallbacksInUse )
3958 return;
3959 sRemoveImageCallbacks.push_back(func);
3960 }
3961
3962 void clearErrorMessage()
3963 {
3964 error_string[0] = '\0';
3965 }
3966
3967 void setErrorMessage(const char* message)
3968 {
3969 // save off error message in global buffer for CrashReporter to find
3970 strlcpy(error_string, message, sizeof(error_string));
3971 }
3972
3973 const char* getErrorMessage()
3974 {
3975 return error_string;
3976 }
3977
3978 void halt(const char* message)
3979 {
3980 dyld::log("dyld: %s\n", message);
3981 setErrorMessage(message);
3982 dyld::gProcessInfo->errorMessage = error_string;
3983 if ( !gLinkContext.startedInitializingMainExecutable )
3984 dyld::gProcessInfo->terminationFlags = 1;
3985 else
3986 dyld::gProcessInfo->terminationFlags = 0;
3987
3988 char payloadBuffer[EXIT_REASON_PAYLOAD_MAX_LEN];
3989 dyld_abort_payload* payload = (dyld_abort_payload*)payloadBuffer;
3990 payload->version = 1;
3991 payload->flags = gLinkContext.startedInitializingMainExecutable ? 0 : 1;
3992 payload->targetDylibPathOffset = 0;
3993 payload->clientPathOffset = 0;
3994 payload->symbolOffset = 0;
3995 int payloadSize = sizeof(dyld_abort_payload);
3996
3997 if ( dyld::gProcessInfo->errorTargetDylibPath != NULL ) {
3998 payload->targetDylibPathOffset = payloadSize;
3999 payloadSize += strlcpy(&payloadBuffer[payloadSize], dyld::gProcessInfo->errorTargetDylibPath, sizeof(payloadBuffer)-payloadSize) + 1;
4000 }
4001 if ( dyld::gProcessInfo->errorClientOfDylibPath != NULL ) {
4002 payload->clientPathOffset = payloadSize;
4003 payloadSize += strlcpy(&payloadBuffer[payloadSize], dyld::gProcessInfo->errorClientOfDylibPath, sizeof(payloadBuffer)-payloadSize) + 1;
4004 }
4005 if ( dyld::gProcessInfo->errorSymbol != NULL ) {
4006 payload->symbolOffset = payloadSize;
4007 payloadSize += strlcpy(&payloadBuffer[payloadSize], dyld::gProcessInfo->errorSymbol, sizeof(payloadBuffer)-payloadSize) + 1;
4008 }
4009 char truncMessage[EXIT_REASON_USER_DESC_MAX_LEN];
4010 strlcpy(truncMessage, message, EXIT_REASON_USER_DESC_MAX_LEN);
4011 abort_with_payload(OS_REASON_DYLD, dyld::gProcessInfo->errorKind ? dyld::gProcessInfo->errorKind : DYLD_EXIT_REASON_OTHER, payloadBuffer, payloadSize, truncMessage, 0);
4012 }
4013
4014 static void setErrorStrings(unsigned errorCode, const char* errorClientOfDylibPath,
4015 const char* errorTargetDylibPath, const char* errorSymbol)
4016 {
4017 dyld::gProcessInfo->errorKind = errorCode;
4018 dyld::gProcessInfo->errorClientOfDylibPath = errorClientOfDylibPath;
4019 dyld::gProcessInfo->errorTargetDylibPath = errorTargetDylibPath;
4020 dyld::gProcessInfo->errorSymbol = errorSymbol;
4021 }
4022
4023
4024 uintptr_t bindLazySymbol(const mach_header* mh, uintptr_t* lazyPointer)
4025 {
4026 uintptr_t result = 0;
4027 // acquire read-lock on dyld's data structures
4028 #if 0 // rdar://problem/3811777 turn off locking until deadlock is resolved
4029 if ( gLibSystemHelpers != NULL )
4030 (*gLibSystemHelpers->lockForReading)();
4031 #endif
4032 // lookup and bind lazy pointer and get target address
4033 try {
4034 ImageLoader* target;
4035 #if __i386__
4036 // fast stubs pass NULL for mh and image is instead found via the location of stub (aka lazyPointer)
4037 if ( mh == NULL )
4038 target = dyld::findImageContainingAddress(lazyPointer);
4039 else
4040 target = dyld::findImageByMachHeader(mh);
4041 #else
4042 // note, target should always be mach-o, because only mach-o lazy handler wired up to this
4043 target = dyld::findImageByMachHeader(mh);
4044 #endif
4045 if ( target == NULL )
4046 throwf("image not found for lazy pointer at %p", lazyPointer);
4047 result = target->doBindLazySymbol(lazyPointer, gLinkContext);
4048 }
4049 catch (const char* message) {
4050 dyld::log("dyld: lazy symbol binding failed: %s\n", message);
4051 halt(message);
4052 }
4053 // release read-lock on dyld's data structures
4054 #if 0
4055 if ( gLibSystemHelpers != NULL )
4056 (*gLibSystemHelpers->unlockForReading)();
4057 #endif
4058 // return target address to glue which jumps to it with real parameters restored
4059 return result;
4060 }
4061
4062
4063 uintptr_t fastBindLazySymbol(ImageLoader** imageLoaderCache, uintptr_t lazyBindingInfoOffset)
4064 {
4065 uintptr_t result = 0;
4066 // get image
4067 if ( *imageLoaderCache == NULL ) {
4068 // save in cache
4069 *imageLoaderCache = dyld::findMappedRange((uintptr_t)imageLoaderCache);
4070 if ( *imageLoaderCache == NULL ) {
4071 #if SUPPORT_ACCELERATE_TABLES
4072 if ( sAllCacheImagesProxy != NULL ) {
4073 const mach_header* mh;
4074 const char* path;
4075 unsigned index;
4076 if ( sAllCacheImagesProxy->addressInCache(imageLoaderCache, &mh, &path, &index) ) {
4077 result = sAllCacheImagesProxy->bindLazy(lazyBindingInfoOffset, gLinkContext, mh, index);
4078 if ( result == 0 ) {
4079 halt("dyld: lazy symbol binding failed for image in dyld shared\n");
4080 }
4081 return result;
4082 }
4083 }
4084 #endif
4085 const char* message = "fast lazy binding from unknown image";
4086 dyld::log("dyld: %s\n", message);
4087 halt(message);
4088 }
4089 }
4090
4091 // bind lazy pointer and return it
4092 try {
4093 result = (*imageLoaderCache)->doBindFastLazySymbol((uint32_t)lazyBindingInfoOffset, gLinkContext,
4094 (dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->acquireGlobalDyldLock : NULL,
4095 (dyld::gLibSystemHelpers != NULL) ? dyld::gLibSystemHelpers->releaseGlobalDyldLock : NULL);
4096 }
4097 catch (const char* message) {
4098 dyld::log("dyld: lazy symbol binding failed: %s\n", message);
4099 halt(message);
4100 }
4101
4102 // return target address to glue which jumps to it with real parameters restored
4103 return result;
4104 }
4105
4106
4107
4108 void registerUndefinedHandler(UndefinedHandler handler)
4109 {
4110 sUndefinedHandler = handler;
4111 }
4112
4113 static void undefinedHandler(const char* symboName)
4114 {
4115 if ( sUndefinedHandler != NULL ) {
4116 (*sUndefinedHandler)(symboName);
4117 }
4118 }
4119
4120 static bool findExportedSymbol(const char* name, bool onlyInCoalesced, const ImageLoader::Symbol** sym, const ImageLoader** image, ImageLoader::CoalesceNotifier notifier=NULL)
4121 {
4122 // search all images in order
4123 const ImageLoader* firstWeakImage = NULL;
4124 const ImageLoader::Symbol* firstWeakSym = NULL;
4125 const ImageLoader* firstNonWeakImage = NULL;
4126 const ImageLoader::Symbol* firstNonWeakSym = NULL;
4127 const size_t imageCount = sAllImages.size();
4128 for(size_t i=0; i < imageCount; ++i) {
4129 ImageLoader* anImage = sAllImages[i];
4130 // the use of inserted libraries alters search order
4131 // so that inserted libraries are found before the main executable
4132 if ( sInsertedDylibCount > 0 ) {
4133 if ( i < sInsertedDylibCount )
4134 anImage = sAllImages[i+1];
4135 else if ( i == sInsertedDylibCount )
4136 anImage = sAllImages[0];
4137 }
4138 //dyld::log("findExportedSymbol(%s) looking at %s\n", name, anImage->getPath());
4139 if ( ! anImage->hasHiddenExports() && (!onlyInCoalesced || anImage->hasCoalescedExports()) ) {
4140 const ImageLoader* foundInImage;
4141 *sym = anImage->findExportedSymbol(name, false, &foundInImage);
4142 //dyld::log("findExportedSymbol(%s) found: sym=%p, anImage=%p, foundInImage=%p\n", name, *sym, anImage, foundInImage /*, (foundInImage ? foundInImage->getPath() : "")*/);
4143 if ( *sym != NULL ) {
4144 if ( notifier && (foundInImage == anImage) )
4145 notifier(*sym, foundInImage, foundInImage->machHeader());
4146 // if weak definition found, record first one found
4147 if ( (foundInImage->getExportedSymbolInfo(*sym) & ImageLoader::kWeakDefinition) != 0 ) {
4148 if ( firstWeakImage == NULL ) {
4149 firstWeakImage = foundInImage;
4150 firstWeakSym = *sym;
4151 }
4152 }
4153 else {
4154 // found non-weak
4155 if ( !onlyInCoalesced ) {
4156 // for flat lookups, return first found
4157 *image = foundInImage;
4158 return true;
4159 }
4160 if ( firstNonWeakImage == NULL ) {
4161 firstNonWeakImage = foundInImage;
4162 firstNonWeakSym = *sym;
4163 }
4164 }
4165 }
4166 }
4167 }
4168 if ( firstNonWeakImage != NULL ) {
4169 // found a weak definition, but no non-weak, so return first weak found
4170 *sym = firstNonWeakSym;
4171 *image = firstNonWeakImage;
4172 return true;
4173 }
4174 if ( firstWeakSym != NULL ) {
4175 // found a weak definition, but no non-weak, so return first weak found
4176 *sym = firstWeakSym;
4177 *image = firstWeakImage;
4178 return true;
4179 }
4180 #if SUPPORT_ACCELERATE_TABLES
4181 if ( sAllCacheImagesProxy != NULL ) {
4182 if ( sAllCacheImagesProxy->flatFindSymbol(name, onlyInCoalesced, sym, image, notifier) )
4183 return true;
4184 }
4185 #endif
4186
4187 return false;
4188 }
4189
4190 bool flatFindExportedSymbol(const char* name, const ImageLoader::Symbol** sym, const ImageLoader** image)
4191 {
4192 return findExportedSymbol(name, false, sym, image);
4193 }
4194
4195 bool findCoalescedExportedSymbol(const char* name, const ImageLoader::Symbol** sym, const ImageLoader** image, ImageLoader::CoalesceNotifier notifier)
4196 {
4197 return findExportedSymbol(name, true, sym, image, notifier);
4198 }
4199
4200
4201 bool flatFindExportedSymbolWithHint(const char* name, const char* librarySubstring, const ImageLoader::Symbol** sym, const ImageLoader** image)
4202 {
4203 // search all images in order
4204 const size_t imageCount = sAllImages.size();
4205 for(size_t i=0; i < imageCount; ++i){
4206 ImageLoader* anImage = sAllImages[i];
4207 // only look at images whose paths contain the hint string (NULL hint string is wildcard)
4208 if ( ! anImage->isBundle() && ((librarySubstring==NULL) || (strstr(anImage->getPath(), librarySubstring) != NULL)) ) {
4209 *sym = anImage->findExportedSymbol(name, false, image);
4210 if ( *sym != NULL ) {
4211 return true;
4212 }
4213 }
4214 }
4215 return false;
4216 }
4217
4218
4219 unsigned int getCoalescedImages(ImageLoader* images[], unsigned imageIndex[])
4220 {
4221 unsigned int count = 0;
4222 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4223 ImageLoader* image = *it;
4224 if ( image->participatesInCoalescing() ) {
4225 images[count] = *it;
4226 imageIndex[count] = 0;
4227 ++count;
4228 }
4229 }
4230 #if SUPPORT_ACCELERATE_TABLES
4231 if ( sAllCacheImagesProxy != NULL ) {
4232 sAllCacheImagesProxy->appendImagesNeedingCoalescing(images, imageIndex, count);
4233 }
4234 #endif
4235 return count;
4236 }
4237
4238
4239 static ImageLoader::MappedRegion* getMappedRegions(ImageLoader::MappedRegion* regions)
4240 {
4241 ImageLoader::MappedRegion* end = regions;
4242 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4243 (*it)->getMappedRegions(end);
4244 }
4245 return end;
4246 }
4247
4248 void registerImageStateSingleChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler)
4249 {
4250 // mark the image that the handler is in as never-unload because dyld has a reference into it
4251 ImageLoader* handlerImage = findImageContainingAddress((void*)handler);
4252 if ( handlerImage != NULL )
4253 handlerImage->setNeverUnload();
4254
4255 // add to list of handlers
4256 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sSingleHandlers);
4257 if ( handlers != NULL ) {
4258 // <rdar://problem/10332417> need updateAllImages() to be last in dyld_image_state_mapped list
4259 // so that if ObjC adds a handler that prevents a load, it happens before the gdb list is updated
4260 if ( state == dyld_image_state_mapped )
4261 handlers->insert(handlers->begin(), handler);
4262 else
4263 handlers->push_back(handler);
4264
4265 // call callback with all existing images
4266 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4267 ImageLoader* image = *it;
4268 dyld_image_info info;
4269 info.imageLoadAddress = image->machHeader();
4270 info.imageFilePath = image->getRealPath();
4271 info.imageFileModDate = image->lastModified();
4272 // should only call handler if state == image->state
4273 if ( image->getState() == state )
4274 (*handler)(state, 1, &info);
4275 // ignore returned string, too late to do anything
4276 }
4277 }
4278 }
4279
4280 void registerImageStateBatchChangeHandler(dyld_image_states state, dyld_image_state_change_handler handler)
4281 {
4282 // mark the image that the handler is in as never-unload because dyld has a reference into it
4283 ImageLoader* handlerImage = findImageContainingAddress((void*)handler);
4284 if ( handlerImage != NULL )
4285 handlerImage->setNeverUnload();
4286
4287 // add to list of handlers
4288 std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sBatchHandlers);
4289 if ( handlers != NULL ) {
4290 // insert at front, so that gdb handler is always last
4291 handlers->insert(handlers->begin(), handler);
4292
4293 // call callback with all existing images
4294 try {
4295 notifyBatchPartial(state, true, handler, false, false);
4296 }
4297 catch (const char* msg) {
4298 // ignore request to abort during registration
4299 }
4300 }
4301 }
4302
4303
4304 void registerObjCNotifiers(_dyld_objc_notify_mapped mapped, _dyld_objc_notify_init init, _dyld_objc_notify_unmapped unmapped)
4305 {
4306 // record functions to call
4307 sNotifyObjCMapped = mapped;
4308 sNotifyObjCInit = init;
4309 sNotifyObjCUnmapped = unmapped;
4310
4311 // call 'mapped' function with all images mapped so far
4312 try {
4313 notifyBatchPartial(dyld_image_state_bound, true, NULL, false, true);
4314 }
4315 catch (const char* msg) {
4316 // ignore request to abort during registration
4317 }
4318
4319 // <rdar://problem/32209809> call 'init' function on all images already init'ed (below libSystem)
4320 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4321 ImageLoader* image = *it;
4322 if ( (image->getState() == dyld_image_state_initialized) && image->notifyObjC() ) {
4323 dyld3::ScopedTimer timer(DBG_DYLD_TIMING_OBJC_INIT, (uint64_t)image->machHeader(), 0, 0);
4324 (*sNotifyObjCInit)(image->getRealPath(), image->machHeader());
4325 }
4326 }
4327 }
4328
4329 bool sharedCacheUUID(uuid_t uuid)
4330 {
4331 if ( sSharedCacheLoadInfo.loadAddress == nullptr )
4332 return false;
4333
4334 sSharedCacheLoadInfo.loadAddress->getUUID(uuid);
4335 return true;
4336 }
4337
4338 #if SUPPORT_ACCELERATE_TABLES
4339
4340 bool dlopenFromCache(const char* path, int mode, void** handle)
4341 {
4342 if ( sAllCacheImagesProxy == NULL )
4343 return false;
4344 char fallbackPath[PATH_MAX];
4345 bool result = sAllCacheImagesProxy->dlopenFromCache(gLinkContext, path, mode, handle);
4346 if ( !result && (strchr(path, '/') == NULL) ) {
4347 // POSIX says you can call dlopen() with a leaf name (e.g. dlopen("libz.dylb"))
4348 strcpy(fallbackPath, "/usr/lib/");
4349 strlcat(fallbackPath, path, PATH_MAX);
4350 result = sAllCacheImagesProxy->dlopenFromCache(gLinkContext, fallbackPath, mode, handle);
4351 if ( !result )
4352 path = fallbackPath;
4353 }
4354 if ( !result ) {
4355 // leaf name could be a symlink
4356 char resolvedPath[PATH_MAX];
4357 realpath(path, resolvedPath);
4358 int realpathErrno = errno;
4359 // If realpath() resolves to a path which does not exist on disk, errno is set to ENOENT
4360 if ( (realpathErrno == ENOENT) || (realpathErrno == 0) ) {
4361 result = sAllCacheImagesProxy->dlopenFromCache(gLinkContext, resolvedPath, mode, handle);
4362 }
4363 }
4364
4365 return result;
4366 }
4367
4368 bool makeCacheHandle(ImageLoader* image, unsigned cacheIndex, int mode, void** result)
4369 {
4370 if ( sAllCacheImagesProxy == NULL )
4371 return false;
4372 return sAllCacheImagesProxy->makeCacheHandle(gLinkContext, cacheIndex, mode, result);
4373 }
4374
4375 bool isCacheHandle(void* handle)
4376 {
4377 if ( sAllCacheImagesProxy == NULL )
4378 return false;
4379 return sAllCacheImagesProxy->isCacheHandle(handle, NULL, NULL);
4380 }
4381
4382 bool isPathInCache(const char* path)
4383 {
4384 if ( sAllCacheImagesProxy == NULL )
4385 return false;
4386 unsigned index;
4387 return sAllCacheImagesProxy->hasDylib(path, &index);
4388 }
4389
4390 const char* getPathFromIndex(unsigned cacheIndex)
4391 {
4392 if ( sAllCacheImagesProxy == NULL )
4393 return NULL;
4394 return sAllCacheImagesProxy->getIndexedPath(cacheIndex);
4395 }
4396
4397 void* dlsymFromCache(void* handle, const char* symName, unsigned index)
4398 {
4399 if ( sAllCacheImagesProxy == NULL )
4400 return NULL;
4401 return sAllCacheImagesProxy->dlsymFromCache(gLinkContext, handle, symName, index);
4402 }
4403
4404 bool addressInCache(const void* address, const mach_header** mh, const char** path, unsigned* index)
4405 {
4406 if ( sAllCacheImagesProxy == NULL )
4407 return false;
4408 unsigned ignore;
4409 return sAllCacheImagesProxy->addressInCache(address, mh, path, index ? index : &ignore);
4410 }
4411
4412 bool findUnwindSections(const void* addr, dyld_unwind_sections* info)
4413 {
4414 if ( sAllCacheImagesProxy == NULL )
4415 return false;
4416 return sAllCacheImagesProxy->findUnwindSections(addr, info);
4417 }
4418
4419 bool dladdrFromCache(const void* address, Dl_info* info)
4420 {
4421 if ( sAllCacheImagesProxy == NULL )
4422 return false;
4423 return sAllCacheImagesProxy->dladdrFromCache(address, info);
4424 }
4425 #endif
4426
4427 static ImageLoader* libraryLocator(const char* libraryName, bool search, const char* origin, const ImageLoader::RPathChain* rpaths, bool enforceIOSMac, unsigned& cacheIndex)
4428 {
4429 dyld::LoadContext context;
4430 context.useSearchPaths = search;
4431 context.useFallbackPaths = search;
4432 context.useLdLibraryPath = false;
4433 context.implicitRPath = false;
4434 context.matchByInstallName = false;
4435 context.dontLoad = false;
4436 context.mustBeBundle = false;
4437 context.mustBeDylib = true;
4438 context.canBePIE = false;
4439 context.enforceIOSMac = enforceIOSMac;
4440 context.origin = origin;
4441 context.rpath = rpaths;
4442 return load(libraryName, context, cacheIndex);
4443 }
4444
4445 static const char* basename(const char* path)
4446 {
4447 const char* last = path;
4448 for (const char* s = path; *s != '\0'; s++) {
4449 if (*s == '/')
4450 last = s+1;
4451 }
4452 return last;
4453 }
4454
4455 static void setContext(const macho_header* mainExecutableMH, int argc, const char* argv[], const char* envp[], const char* apple[])
4456 {
4457 gLinkContext.loadLibrary = &libraryLocator;
4458 gLinkContext.terminationRecorder = &terminationRecorder;
4459 gLinkContext.flatExportFinder = &flatFindExportedSymbol;
4460 gLinkContext.coalescedExportFinder = &findCoalescedExportedSymbol;
4461 gLinkContext.getCoalescedImages = &getCoalescedImages;
4462 gLinkContext.undefinedHandler = &undefinedHandler;
4463 gLinkContext.getAllMappedRegions = &getMappedRegions;
4464 gLinkContext.bindingHandler = NULL;
4465 gLinkContext.notifySingle = &notifySingle;
4466 gLinkContext.notifyBatch = &notifyBatch;
4467 gLinkContext.removeImage = &removeImage;
4468 gLinkContext.registerDOFs = &registerDOFs;
4469 gLinkContext.clearAllDepths = &clearAllDepths;
4470 gLinkContext.printAllDepths = &printAllDepths;
4471 gLinkContext.imageCount = &imageCount;
4472 gLinkContext.setNewProgramVars = &setNewProgramVars;
4473 gLinkContext.inSharedCache = &inSharedCache;
4474 gLinkContext.setErrorStrings = &setErrorStrings;
4475 #if SUPPORT_OLD_CRT_INITIALIZATION
4476 gLinkContext.setRunInitialzersOldWay= &setRunInitialzersOldWay;
4477 #endif
4478 gLinkContext.findImageContainingAddress = &findImageContainingAddress;
4479 gLinkContext.addDynamicReference = &addDynamicReference;
4480 #if SUPPORT_ACCELERATE_TABLES
4481 gLinkContext.notifySingleFromCache = &notifySingleFromCache;
4482 gLinkContext.getPreInitNotifyHandler= &getPreInitNotifyHandler;
4483 gLinkContext.getBoundBatchHandler = &getBoundBatchHandler;
4484 #endif
4485 gLinkContext.bindingOptions = ImageLoader::kBindingNone;
4486 gLinkContext.argc = argc;
4487 gLinkContext.argv = argv;
4488 gLinkContext.envp = envp;
4489 gLinkContext.apple = apple;
4490 gLinkContext.progname = (argv[0] != NULL) ? basename(argv[0]) : "";
4491 gLinkContext.programVars.mh = mainExecutableMH;
4492 gLinkContext.programVars.NXArgcPtr = &gLinkContext.argc;
4493 gLinkContext.programVars.NXArgvPtr = &gLinkContext.argv;
4494 gLinkContext.programVars.environPtr = &gLinkContext.envp;
4495 gLinkContext.programVars.__prognamePtr=&gLinkContext.progname;
4496 gLinkContext.mainExecutable = NULL;
4497 gLinkContext.imageSuffix = NULL;
4498 gLinkContext.dynamicInterposeArray = NULL;
4499 gLinkContext.dynamicInterposeCount = 0;
4500 gLinkContext.prebindUsage = ImageLoader::kUseAllPrebinding;
4501 #if TARGET_IPHONE_SIMULATOR
4502 gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
4503 #else
4504 gLinkContext.sharedRegionMode = ImageLoader::kUseSharedRegion;
4505 #endif
4506 }
4507
4508
4509
4510 //
4511 // Look for a special segment in the mach header.
4512 // Its presences means that the binary wants to have DYLD ignore
4513 // DYLD_ environment variables.
4514 //
4515 #if __MAC_OS_X_VERSION_MIN_REQUIRED
4516 static bool hasRestrictedSegment(const macho_header* mh)
4517 {
4518 const uint32_t cmd_count = mh->ncmds;
4519 const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
4520 const struct load_command* cmd = cmds;
4521 for (uint32_t i = 0; i < cmd_count; ++i) {
4522 switch (cmd->cmd) {
4523 case LC_SEGMENT_COMMAND:
4524 {
4525 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
4526
4527 //dyld::log("seg name: %s\n", seg->segname);
4528 if (strcmp(seg->segname, "__RESTRICT") == 0) {
4529 const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
4530 const struct macho_section* const sectionsEnd = &sectionsStart[seg->nsects];
4531 for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
4532 if (strcmp(sect->sectname, "__restrict") == 0)
4533 return true;
4534 }
4535 }
4536 }
4537 break;
4538 }
4539 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
4540 }
4541
4542 return false;
4543 }
4544 #endif
4545
4546 #if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR
4547 static bool isFairPlayEncrypted(const macho_header* mh)
4548 {
4549 const uint32_t cmd_count = mh->ncmds;
4550 const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
4551 const struct load_command* cmd = cmds;
4552 for (uint32_t i = 0; i < cmd_count; ++i) {
4553 if ( cmd->cmd == LC_ENCRYPT_COMMAND ) {
4554 const encryption_info_command* enc = (encryption_info_command*)cmd;
4555 return (enc->cryptid != 0);
4556 }
4557 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
4558 }
4559
4560 return false;
4561 }
4562 #endif
4563
4564 #if SUPPORT_VERSIONED_PATHS
4565
4566 static bool readFirstPage(const char* dylibPath, uint8_t firstPage[4096])
4567 {
4568 firstPage[0] = 0;
4569 // open file (automagically closed when this function exits)
4570 FileOpener file(dylibPath);
4571
4572 if ( file.getFileDescriptor() == -1 )
4573 return false;
4574
4575 if ( pread(file.getFileDescriptor(), firstPage, 4096, 0) != 4096 )
4576 return false;
4577
4578 // if fat wrapper, find usable sub-file
4579 const fat_header* fileStartAsFat = (fat_header*)firstPage;
4580 if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
4581 uint64_t fileOffset;
4582 uint64_t fileLength;
4583 if ( fatFindBest(fileStartAsFat, &fileOffset, &fileLength) ) {
4584 if ( pread(file.getFileDescriptor(), firstPage, 4096, fileOffset) != 4096 )
4585 return false;
4586 }
4587 else {
4588 return false;
4589 }
4590 }
4591
4592 return true;
4593 }
4594
4595 //
4596 // Peeks at a dylib file and returns its current_version and install_name.
4597 // Returns false on error.
4598 //
4599 static bool getDylibVersionAndInstallname(const char* dylibPath, uint32_t* version, char* installName)
4600 {
4601 uint8_t firstPage[4096];
4602 const macho_header* mh = (macho_header*)firstPage;
4603 if ( !readFirstPage(dylibPath, firstPage) ) {
4604 // If file cannot be read, check to see if path is in shared cache
4605 const macho_header* mhInCache;
4606 const char* pathInCache;
4607 long slideInCache;
4608 if ( !findInSharedCacheImage(dylibPath, true, NULL, &mhInCache, &pathInCache, &slideInCache) )
4609 return false;
4610 mh = mhInCache;
4611 }
4612
4613 // check mach-o header
4614 if ( mh->magic != sMainExecutableMachHeader->magic )
4615 return false;
4616 if ( mh->cputype != sMainExecutableMachHeader->cputype )
4617 return false;
4618
4619 // scan load commands for LC_ID_DYLIB
4620 const uint32_t cmd_count = mh->ncmds;
4621 const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
4622 const struct load_command* const cmdsReadEnd = (struct load_command*)(((char*)mh)+4096);
4623 const struct load_command* cmd = cmds;
4624 for (uint32_t i = 0; i < cmd_count; ++i) {
4625 switch (cmd->cmd) {
4626 case LC_ID_DYLIB:
4627 {
4628 const struct dylib_command* id = (struct dylib_command*)cmd;
4629 *version = id->dylib.current_version;
4630 if ( installName != NULL )
4631 strlcpy(installName, (char *)id + id->dylib.name.offset, PATH_MAX);
4632 return true;
4633 }
4634 break;
4635 }
4636 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
4637 if ( cmd > cmdsReadEnd )
4638 return false;
4639 }
4640
4641 return false;
4642 }
4643 #endif // SUPPORT_VERSIONED_PATHS
4644
4645
4646 #if 0
4647 static void printAllImages()
4648 {
4649 dyld::log("printAllImages()\n");
4650 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4651 ImageLoader* image = *it;
4652 dyld_image_states imageState = image->getState();
4653 dyld::log(" state=%d, dlopen-count=%d, never-unload=%d, in-use=%d, name=%s\n",
4654 imageState, image->dlopenCount(), image->neverUnload(), image->isMarkedInUse(), image->getShortName());
4655 }
4656 }
4657 #endif
4658
4659 void link(ImageLoader* image, bool forceLazysBound, bool neverUnload, const ImageLoader::RPathChain& loaderRPaths, unsigned cacheIndex)
4660 {
4661 // add to list of known images. This did not happen at creation time for bundles
4662 if ( image->isBundle() && !image->isLinked() )
4663 addImage(image);
4664
4665 // we detect root images as those not linked in yet
4666 if ( !image->isLinked() )
4667 addRootImage(image);
4668
4669 // process images
4670 try {
4671 const char* path = image->getPath();
4672 #if SUPPORT_ACCELERATE_TABLES
4673 if ( image == sAllCacheImagesProxy )
4674 path = sAllCacheImagesProxy->getIndexedPath(cacheIndex);
4675 #endif
4676 image->link(gLinkContext, forceLazysBound, false, neverUnload, loaderRPaths, path);
4677 }
4678 catch (const char* msg) {
4679 garbageCollectImages();
4680 throw;
4681 }
4682 }
4683
4684
4685 void runInitializers(ImageLoader* image)
4686 {
4687 // do bottom up initialization
4688 ImageLoader::InitializerTimingList initializerTimes[allImagesCount()];
4689 initializerTimes[0].count = 0;
4690 image->runInitializers(gLinkContext, initializerTimes[0]);
4691 }
4692
4693 // This function is called at the end of dlclose() when the reference count goes to zero.
4694 // The dylib being unloaded may have brought in other dependent dylibs when it was loaded.
4695 // Those dependent dylibs need to be unloaded, but only if they are not referenced by
4696 // something else. We use a standard mark and sweep garbage collection.
4697 //
4698 // The tricky part is that when a dylib is unloaded it may have a termination function that
4699 // can run and itself call dlclose() on yet another dylib. The problem is that this
4700 // sort of gabage collection is not re-entrant. Instead a terminator's call to dlclose()
4701 // which calls garbageCollectImages() will just set a flag to re-do the garbage collection
4702 // when the current pass is done.
4703 //
4704 // Also note that this is done within the dyld global lock, so it is always single threaded.
4705 //
4706 void garbageCollectImages()
4707 {
4708 static bool sDoingGC = false;
4709 static bool sRedo = false;
4710
4711 if ( sDoingGC ) {
4712 // GC is currently being run, just set a flag to have it run again.
4713 sRedo = true;
4714 return;
4715 }
4716
4717 sDoingGC = true;
4718 do {
4719 sRedo = false;
4720
4721 // mark phase: mark all images not-in-use
4722 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4723 ImageLoader* image = *it;
4724 //dyld::log("gc: neverUnload=%d name=%s\n", image->neverUnload(), image->getShortName());
4725 image->markNotUsed();
4726 }
4727
4728 // sweep phase: mark as in-use, images reachable from never-unload or in-use image
4729 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4730 ImageLoader* image = *it;
4731 if ( (image->dlopenCount() != 0) || image->neverUnload() || (image == sMainExecutable) ) {
4732 OSSpinLockLock(&sDynamicReferencesLock);
4733 image->markedUsedRecursive(sDynamicReferences);
4734 OSSpinLockUnlock(&sDynamicReferencesLock);
4735 }
4736 }
4737
4738 // collect phase: build array of images not marked in-use
4739 ImageLoader* deadImages[sAllImages.size()];
4740 unsigned deadCount = 0;
4741 int maxRangeCount = 0;
4742 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4743 ImageLoader* image = *it;
4744 if ( ! image->isMarkedInUse() ) {
4745 deadImages[deadCount++] = image;
4746 if (gLogAPIs) dyld::log("dlclose(), found unused image %p %s\n", image, image->getShortName());
4747 maxRangeCount += image->segmentCount();
4748 }
4749 }
4750
4751 // collect phase: run termination routines for images not marked in-use
4752 if ( maxRangeCount != 0 ) {
4753 __cxa_range_t ranges[maxRangeCount];
4754 int rangeCount = 0;
4755 for (unsigned i=0; i < deadCount; ++i) {
4756 ImageLoader* image = deadImages[i];
4757 for (unsigned int j=0; j < image->segmentCount(); ++j) {
4758 if ( !image->segExecutable(j) )
4759 continue;
4760 if ( rangeCount < maxRangeCount ) {
4761 ranges[rangeCount].addr = (const void*)image->segActualLoadAddress(j);
4762 ranges[rangeCount].length = image->segSize(j);
4763 ++rangeCount;
4764 }
4765 }
4766 try {
4767 runImageStaticTerminators(image);
4768 }
4769 catch (const char* msg) {
4770 dyld::warn("problem running terminators for image: %s\n", msg);
4771 }
4772 }
4773
4774 // <rdar://problem/14718598> dyld should call __cxa_finalize_ranges()
4775 if ( (rangeCount > 0) && (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 13) )
4776 (*gLibSystemHelpers->cxa_finalize_ranges)(ranges, rangeCount);
4777 }
4778
4779 // collect phase: delete all images which are not marked in-use
4780 bool mightBeMore;
4781 do {
4782 mightBeMore = false;
4783 for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
4784 ImageLoader* image = *it;
4785 if ( ! image->isMarkedInUse() ) {
4786 try {
4787 if (gLogAPIs) dyld::log("dlclose(), deleting %p %s\n", image, image->getShortName());
4788 removeImage(image);
4789 ImageLoader::deleteImage(image);
4790 mightBeMore = true;
4791 break; // interator in invalidated by this removal
4792 }
4793 catch (const char* msg) {
4794 dyld::warn("problem deleting image: %s\n", msg);
4795 }
4796 }
4797 }
4798 } while ( mightBeMore );
4799 } while (sRedo);
4800 sDoingGC = false;
4801
4802 //printAllImages();
4803
4804 }
4805
4806
4807 static void preflight_finally(ImageLoader* image)
4808 {
4809 if ( image->isBundle() ) {
4810 removeImageFromAllImages(image->machHeader());
4811 ImageLoader::deleteImage(image);
4812 }
4813 sBundleBeingLoaded = NULL;
4814 dyld::garbageCollectImages();
4815 }
4816
4817
4818 void preflight(ImageLoader* image, const ImageLoader::RPathChain& loaderRPaths, unsigned cacheIndex)
4819 {
4820 try {
4821 if ( image->isBundle() )
4822 sBundleBeingLoaded = image; // hack
4823 const char* path = image->getPath();
4824 #if SUPPORT_ACCELERATE_TABLES
4825 if ( image == sAllCacheImagesProxy )
4826 path = sAllCacheImagesProxy->getIndexedPath(cacheIndex);
4827 #endif
4828 image->link(gLinkContext, false, true, false, loaderRPaths, path);
4829 }
4830 catch (const char* msg) {
4831 preflight_finally(image);
4832 throw;
4833 }
4834 preflight_finally(image);
4835 }
4836
4837 static void loadInsertedDylib(const char* path)
4838 {
4839 ImageLoader* image = NULL;
4840 unsigned cacheIndex;
4841 try {
4842 LoadContext context;
4843 context.useSearchPaths = false;
4844 context.useFallbackPaths = false;
4845 context.useLdLibraryPath = false;
4846 context.implicitRPath = false;
4847 context.matchByInstallName = false;
4848 context.dontLoad = false;
4849 context.mustBeBundle = false;
4850 context.mustBeDylib = true;
4851 context.canBePIE = false;
4852 context.enforceIOSMac = true;
4853 context.origin = NULL; // can't use @loader_path with DYLD_INSERT_LIBRARIES
4854 context.rpath = NULL;
4855 image = load(path, context, cacheIndex);
4856 }
4857 catch (const char* msg) {
4858 if ( gLinkContext.allowInsertFailures )
4859 dyld::log("dyld: warning: could not load inserted library '%s' into hardened process because %s\n", path, msg);
4860 else
4861 halt(dyld::mkstringf("could not load inserted library '%s' because %s\n", path, msg));
4862 }
4863 catch (...) {
4864 halt(dyld::mkstringf("could not load inserted library '%s'\n", path));
4865 }
4866 }
4867
4868
4869 static void configureProcessRestrictions(const macho_header* mainExecutableMH)
4870 {
4871 uint64_t amfiInputFlags = 0;
4872 #if TARGET_IPHONE_SIMULATOR
4873 amfiInputFlags |= AMFI_DYLD_INPUT_PROC_IN_SIMULATOR;
4874 #elif __MAC_OS_X_VERSION_MIN_REQUIRED
4875 if ( hasRestrictedSegment(mainExecutableMH) )
4876 amfiInputFlags |= AMFI_DYLD_INPUT_PROC_HAS_RESTRICT_SEG;
4877 #elif __IPHONE_OS_VERSION_MIN_REQUIRED
4878 if ( isFairPlayEncrypted(mainExecutableMH) )
4879 amfiInputFlags |= AMFI_DYLD_INPUT_PROC_IS_ENCRYPTED;
4880 #endif
4881 uint64_t amfiOutputFlags = 0;
4882 if ( amfi_check_dyld_policy_self(amfiInputFlags, &amfiOutputFlags) == 0 ) {
4883 gLinkContext.allowAtPaths = (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_AT_PATH);
4884 gLinkContext.allowEnvVarsPrint = (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_PRINT_VARS);
4885 gLinkContext.allowEnvVarsPath = (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_PATH_VARS);
4886 gLinkContext.allowEnvVarsSharedCache = (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_CUSTOM_SHARED_CACHE);
4887 gLinkContext.allowClassicFallbackPaths = (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_FALLBACK_PATHS);
4888 gLinkContext.allowInsertFailures = (amfiOutputFlags & AMFI_DYLD_OUTPUT_ALLOW_FAILED_LIBRARY_INSERTION);
4889 }
4890 else {
4891 #if __MAC_OS_X_VERSION_MIN_REQUIRED
4892 // support chrooting from old kernel
4893 bool isRestricted = false;
4894 bool libraryValidation = false;
4895 // any processes with setuid or setgid bit set or with __RESTRICT segment is restricted
4896 if ( issetugid() || hasRestrictedSegment(mainExecutableMH) ) {
4897 isRestricted = true;
4898 }
4899 bool usingSIP = (csr_check(CSR_ALLOW_TASK_FOR_PID) != 0);
4900 uint32_t flags;
4901 if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
4902 // On OS X CS_RESTRICT means the program was signed with entitlements
4903 if ( ((flags & CS_RESTRICT) == CS_RESTRICT) && usingSIP ) {
4904 isRestricted = true;
4905 }
4906 // Library Validation loosens searching but requires everything to be code signed
4907 if ( flags & CS_REQUIRE_LV ) {
4908 isRestricted = false;
4909 libraryValidation = true;
4910 }
4911 }
4912 gLinkContext.allowAtPaths = !isRestricted;
4913 gLinkContext.allowEnvVarsPrint = !isRestricted;
4914 gLinkContext.allowEnvVarsPath = !isRestricted;
4915 gLinkContext.allowEnvVarsSharedCache = !libraryValidation || !usingSIP;
4916 gLinkContext.allowClassicFallbackPaths = !isRestricted;
4917 gLinkContext.allowInsertFailures = false;
4918 #else
4919 halt("amfi_check_dyld_policy_self() failed\n");
4920 #endif
4921 }
4922 }
4923
4924
4925 bool processIsRestricted()
4926 {
4927 #if __MAC_OS_X_VERSION_MIN_REQUIRED
4928 return !gLinkContext.allowEnvVarsPath;
4929 #else
4930 return false;
4931 #endif
4932 }
4933
4934
4935 // <rdar://problem/10583252> Add dyld to uuidArray to enable symbolication of stackshots
4936 static void addDyldImageToUUIDList()
4937 {
4938 const struct macho_header* mh = (macho_header*)&__dso_handle;
4939 const uint32_t cmd_count = mh->ncmds;
4940 const struct load_command* const cmds = (struct load_command*)((char*)mh + sizeof(macho_header));
4941 const struct load_command* cmd = cmds;
4942 for (uint32_t i = 0; i < cmd_count; ++i) {
4943 switch (cmd->cmd) {
4944 case LC_UUID: {
4945 uuid_command* uc = (uuid_command*)cmd;
4946 dyld_uuid_info info;
4947 info.imageLoadAddress = (mach_header*)mh;
4948 memcpy(info.imageUUID, uc->uuid, 16);
4949 addNonSharedCacheImageUUID(info);
4950 return;
4951 }
4952 }
4953 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
4954 }
4955 }
4956
4957 void notifyKernelAboutImage(const struct macho_header* mh, const char* fileInfo)
4958 {
4959 const char *endptr = nullptr;
4960 uint64_t fsid_scalar = hexToUInt64(fileInfo, &endptr);
4961 uint64_t fsobj_id_scalar = 0;
4962 if (endptr != nullptr) {
4963 fsobj_id_scalar = hexToUInt64(endptr+1, &endptr);
4964 }
4965 const uint32_t cmd_count = mh->ncmds;
4966 const struct load_command* const cmds = (struct load_command*)((char*)mh + sizeof(macho_header));
4967 const struct load_command* cmd = cmds;
4968 for (uint32_t i = 0; i < cmd_count; ++i) {
4969 switch (cmd->cmd) {
4970 case LC_UUID: {
4971 // Add dyld to the kernel image info
4972 uuid_command* uc = (uuid_command*)cmd;
4973 dyld3::kdebug_trace_dyld_image(DBG_DYLD_UUID_MAP_A, (const uuid_t *)&uc->uuid[0], *reinterpret_cast<fsobj_id_t *>(&fsobj_id_scalar), *reinterpret_cast<fsid_t *>(&fsid_scalar), (const mach_header *)mh);
4974 return;
4975 }
4976 }
4977 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
4978 }
4979 }
4980
4981 #if __MAC_OS_X_VERSION_MIN_REQUIRED
4982 typedef int (*open_proc_t)(const char*, int, int);
4983 typedef int (*fcntl_proc_t)(int, int, void*);
4984 typedef int (*ioctl_proc_t)(int, unsigned long, void*);
4985 static void* getProcessInfo() { return dyld::gProcessInfo; }
4986 static SyscallHelpers sSysCalls = {
4987 12,
4988 // added in version 1
4989 (open_proc_t)&open,
4990 &close,
4991 &pread,
4992 &write,
4993 &mmap,
4994 &munmap,
4995 &madvise,
4996 &stat,
4997 (fcntl_proc_t)&fcntl,
4998 (ioctl_proc_t)&ioctl,
4999 &issetugid,
5000 &getcwd,
5001 &realpath,
5002 &vm_allocate,
5003 &vm_deallocate,
5004 &vm_protect,
5005 &vlog,
5006 &vwarn,
5007 &pthread_mutex_lock,
5008 &pthread_mutex_unlock,
5009 &mach_thread_self,
5010 &mach_port_deallocate,
5011 &task_self_trap,
5012 &mach_timebase_info,
5013 &OSAtomicCompareAndSwapPtrBarrier,
5014 &OSMemoryBarrier,
5015 &getProcessInfo,
5016 &__error,
5017 &mach_absolute_time,
5018 // added in version 2
5019 &thread_switch,
5020 // added in version 3
5021 &opendir,
5022 &readdir_r,
5023 &closedir,
5024 // added in version 4
5025 &coresymbolication_load_notifier,
5026 &coresymbolication_unload_notifier,
5027 // Added in version 5
5028 &proc_regionfilename,
5029 &getpid,
5030 &mach_port_insert_right,
5031 &mach_port_allocate,
5032 &mach_msg,
5033 // Added in version 6
5034 &abort_with_payload,
5035 // Added in version 7
5036 &task_register_dyld_image_infos,
5037 &task_unregister_dyld_image_infos,
5038 &task_get_dyld_image_infos,
5039 &task_register_dyld_shared_cache_image_info,
5040 &task_register_dyld_set_dyld_state,
5041 &task_register_dyld_get_process_state,
5042 // Added in version 8
5043 &task_info,
5044 &thread_info,
5045 &kdebug_is_enabled,
5046 &kdebug_trace,
5047 // Added in version 9
5048 &kdebug_trace_string,
5049 // Added in version 10
5050 &amfi_check_dyld_policy_self,
5051 // Added in version 11
5052 &notifyMonitoringDyldMain,
5053 &notifyMonitoringDyld,
5054 // Add in version 12
5055 &mach_msg_destroy,
5056 &mach_port_construct,
5057 &mach_port_destruct
5058 };
5059
5060 __attribute__((noinline))
5061 static const char* useSimulatorDyld(int fd, const macho_header* mainExecutableMH, const char* dyldPath,
5062 int argc, const char* argv[], const char* envp[], const char* apple[],
5063 uintptr_t* startGlue, uintptr_t* mainAddr)
5064 {
5065 *startGlue = 0;
5066 *mainAddr = 0;
5067
5068 // <rdar://35873436> HACK to allow marzipan dyld_sim to run entitled processes
5069 if ( strncmp(dyldPath, "/System/", 8) != 0 ) {
5070 uint32_t flags;
5071 if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) == -1 )
5072 return "csops() failed";
5073 if ( (flags & CS_RESTRICT) == CS_RESTRICT )
5074 return "dyld_sim cannot be loaded in a restricted process";
5075 }
5076
5077 // <rdar://problem/25311921> simulator does not support restricted processes
5078 if ( issetugid() )
5079 return "dyld_sim cannot be loaded in a setuid process";
5080 if ( hasRestrictedSegment(mainExecutableMH) )
5081 return "dyld_sim cannot be loaded in a restricted process";
5082
5083 // get file size of dyld_sim
5084 struct stat sb;
5085 if ( fstat(fd, &sb) == -1 )
5086 return "stat(dyld_sim) failed";
5087
5088 // read first page of dyld_sim file
5089 uint8_t firstPage[4096];
5090 if ( pread(fd, firstPage, 4096, 0) != 4096 )
5091 return "pread(dyld_sim) failed";
5092
5093 // if fat file, pick matching slice
5094 uint64_t fileOffset = 0;
5095 uint64_t fileLength = sb.st_size;
5096 const fat_header* fileStartAsFat = (fat_header*)firstPage;
5097 if ( fileStartAsFat->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
5098 if ( !fatFindBest(fileStartAsFat, &fileOffset, &fileLength) )
5099 return "no matching arch in dyld_sim";
5100 // re-read buffer from start of mach-o slice in fat file
5101 if ( pread(fd, firstPage, 4096, fileOffset) != 4096 )
5102 return "pread(dyld_sim) failed";
5103 }
5104 else if ( !isCompatibleMachO(firstPage, dyldPath) ) {
5105 return "dyld_sim is not compatible with the loaded process, likely due to architecture mismatch";
5106 }
5107
5108 // calculate total size of dyld segments
5109 const macho_header* mh = (const macho_header*)firstPage;
5110 struct macho_segment_command* lastSeg = NULL;
5111 struct macho_segment_command* firstSeg = NULL;
5112 uintptr_t mappingSize = 0;
5113 uintptr_t preferredLoadAddress = 0;
5114 const uint32_t cmd_count = mh->ncmds;
5115 if ( mh->sizeofcmds > 4096 )
5116 return "dyld_sim load commands to large";
5117 if ( (sizeof(macho_header) + mh->sizeofcmds) > 4096 )
5118 return "dyld_sim load commands to large";
5119 struct linkedit_data_command* codeSigCmd = NULL;
5120 const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
5121 const struct load_command* const endCmds = (struct load_command*)(((char*)mh) + sizeof(macho_header) + mh->sizeofcmds);
5122 const struct load_command* cmd = cmds;
5123 for (uint32_t i = 0; i < cmd_count; ++i) {
5124 uint32_t cmdLength = cmd->cmdsize;
5125 if ( cmdLength < 8 )
5126 return "dyld_sim load command too small";
5127 const struct load_command* const nextCmd = (const struct load_command*)(((char*)cmd)+cmdLength);
5128 if ( (nextCmd > endCmds) || (nextCmd < cmd) )
5129 return "dyld_sim load command too large";
5130 switch (cmd->cmd) {
5131 case LC_SEGMENT_COMMAND:
5132 {
5133 struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
5134 if ( seg->vmaddr + seg->vmsize < seg->vmaddr )
5135 return "dyld_sim seg wraps address space";
5136 if ( seg->vmsize < seg->filesize )
5137 return "dyld_sim seg vmsize too small";
5138 if ( (seg->fileoff + seg->filesize) < seg->fileoff )
5139 return "dyld_sim seg size wraps address space";
5140 if ( lastSeg == NULL ) {
5141 // first segment must be __TEXT and start at beginning of file/slice
5142 firstSeg = seg;
5143 if ( strcmp(seg->segname, "__TEXT") != 0 )
5144 return "dyld_sim first segment not __TEXT";
5145 if ( seg->fileoff != 0 )
5146 return "dyld_sim first segment not at file offset zero";
5147 if ( seg->filesize < (sizeof(macho_header) + mh->sizeofcmds) )
5148 return "dyld_sim first segment smaller than load commands";
5149 preferredLoadAddress = seg->vmaddr;
5150 }
5151 else {
5152 // other sements must be continguous with previous segment and not executable
5153 if ( lastSeg->fileoff + lastSeg->filesize != seg->fileoff )
5154 return "dyld_sim segments not contiguous";
5155 if ( lastSeg->vmaddr + lastSeg->vmsize != seg->vmaddr )
5156 return "dyld_sim segments not address contiguous";
5157 if ( (seg->initprot & VM_PROT_EXECUTE) != 0 )
5158 return "dyld_sim non-first segment is executable";
5159 }
5160 mappingSize += seg->vmsize;
5161 lastSeg = seg;
5162 }
5163 break;
5164 case LC_SEGMENT_COMMAND_WRONG:
5165 return "dyld_sim wrong load segment load command";
5166 case LC_CODE_SIGNATURE:
5167 codeSigCmd = (struct linkedit_data_command*)cmd;
5168 break;
5169 }
5170 cmd = nextCmd;
5171 }
5172 // last segment must be named __LINKEDIT and not writable
5173 if ( lastSeg == NULL )
5174 return "dyld_sim has no segments";
5175 if ( strcmp(lastSeg->segname, "__LINKEDIT") != 0 )
5176 return "dyld_sim last segment not __LINKEDIT";
5177 if ( lastSeg->initprot & VM_PROT_WRITE )
5178 return "dyld_sim __LINKEDIT segment writable";
5179
5180 // must have code signature which is contained within LINKEDIT segment
5181 if ( codeSigCmd == NULL )
5182 return "dyld_sim not code signed";
5183 if ( codeSigCmd->dataoff < lastSeg->fileoff )
5184 return "dyld_sim code signature not in __LINKEDIT";
5185 if ( (codeSigCmd->dataoff + codeSigCmd->datasize) < codeSigCmd->dataoff )
5186 return "dyld_sim code signature size wraps";
5187 if ( (codeSigCmd->dataoff + codeSigCmd->datasize) > (lastSeg->fileoff + lastSeg->filesize) )
5188 return "dyld_sim code signature extends beyond __LINKEDIT";
5189
5190 // register code signature with kernel before mmap()ing segments
5191 fsignatures_t siginfo;
5192 siginfo.fs_file_start=fileOffset; // start of mach-o slice in fat file
5193 siginfo.fs_blob_start=(void*)(long)(codeSigCmd->dataoff); // start of code-signature in mach-o file
5194 siginfo.fs_blob_size=codeSigCmd->datasize; // size of code-signature
5195 int result = fcntl(fd, F_ADDFILESIGS_FOR_DYLD_SIM, &siginfo);
5196 if ( result == -1 ) {
5197 return mkstringf("dyld_sim fcntl(F_ADDFILESIGS_FOR_DYLD_SIM) failed with errno=%d", errno);
5198 }
5199 // file range covered by code signature must extend up to code signature itself
5200 if ( siginfo.fs_file_start < codeSigCmd->dataoff )
5201 return mkstringf("dyld_sim code signature does not cover all of dyld_sim. Signature covers up to 0x%08lX. Signature starts at 0x%08X", (unsigned long)siginfo.fs_file_start, codeSigCmd->dataoff);
5202
5203 // reserve space, then mmap each segment
5204 vm_address_t loadAddress = 0;
5205 if ( ::vm_allocate(mach_task_self(), &loadAddress, mappingSize, VM_FLAGS_ANYWHERE) != 0 )
5206 return "dyld_sim cannot allocate space";
5207 cmd = cmds;
5208 struct source_version_command* dyldVersionCmd = NULL;
5209 for (uint32_t i = 0; i < cmd_count; ++i) {
5210 switch (cmd->cmd) {
5211 case LC_SEGMENT_COMMAND:
5212 {
5213 struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
5214 uintptr_t requestedLoadAddress = seg->vmaddr - preferredLoadAddress + loadAddress;
5215 void* segAddress = ::mmap((void*)requestedLoadAddress, seg->filesize, seg->initprot, MAP_FIXED | MAP_PRIVATE, fd, fileOffset + seg->fileoff);
5216 //dyld::log("dyld_sim %s mapped at %p\n", seg->segname, segAddress);
5217 if ( segAddress == (void*)(-1) )
5218 return "dyld_sim mmap() of segment failed";
5219 if ( ((uintptr_t)segAddress < loadAddress) || ((uintptr_t)segAddress+seg->filesize > loadAddress+mappingSize) )
5220 return "dyld_sim mmap() to wrong location";
5221 }
5222 break;
5223 case LC_SOURCE_VERSION:
5224 dyldVersionCmd = (struct source_version_command*)cmd;
5225 break;
5226 }
5227 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
5228 }
5229 close(fd);
5230
5231 // walk newly mapped dyld_sim __TEXT load commands to find entry point
5232 uintptr_t entry = 0;
5233 cmd = (struct load_command*)(((char*)loadAddress)+sizeof(macho_header));
5234 const uint32_t count = ((macho_header*)(loadAddress))->ncmds;
5235 for (uint32_t i = 0; i < count; ++i) {
5236 if (cmd->cmd == LC_UNIXTHREAD) {
5237 #if __i386__
5238 const i386_thread_state_t* registers = (i386_thread_state_t*)(((char*)cmd) + 16);
5239 // entry point must be in first segment
5240 if ( registers->__eip < firstSeg->vmaddr )
5241 return "dyld_sim entry point not in __TEXT segment";
5242 if ( registers->__eip > (firstSeg->vmaddr + firstSeg->vmsize) )
5243 return "dyld_sim entry point not in __TEXT segment";
5244 entry = (registers->__eip + loadAddress - preferredLoadAddress);
5245 #elif __x86_64__
5246 const x86_thread_state64_t* registers = (x86_thread_state64_t*)(((char*)cmd) + 16);
5247 // entry point must be in first segment
5248 if ( registers->__rip < firstSeg->vmaddr )
5249 return "dyld_sim entry point not in __TEXT segment";
5250 if ( registers->__rip > (firstSeg->vmaddr + firstSeg->vmsize) )
5251 return "dyld_sim entry point not in __TEXT segment";
5252 entry = (registers->__rip + loadAddress - preferredLoadAddress);
5253 #endif
5254 }
5255 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
5256 }
5257 if ( entry == 0 )
5258 return "dyld_sim entry not found";
5259
5260 // notify debugger that dyld_sim is loaded
5261 dyld_image_info info;
5262 info.imageLoadAddress = (mach_header*)loadAddress;
5263 info.imageFilePath = strdup(dyldPath);
5264 info.imageFileModDate = sb.st_mtime;
5265 addImagesToAllImages(1, &info);
5266 dyld::gProcessInfo->notification(dyld_image_adding, 1, &info);
5267
5268 const char** appleParams = apple;
5269 // jump into new simulator dyld
5270 typedef uintptr_t (*sim_entry_proc_t)(int argc, const char* argv[], const char* envp[], const char* apple[],
5271 const macho_header* mainExecutableMH, const macho_header* dyldMH, uintptr_t dyldSlide,
5272 const dyld::SyscallHelpers* vtable, uintptr_t* startGlue);
5273 sim_entry_proc_t newDyld = (sim_entry_proc_t)entry;
5274 *mainAddr = (*newDyld)(argc, argv, envp, appleParams, mainExecutableMH, (macho_header*)loadAddress,
5275 loadAddress - preferredLoadAddress,
5276 &sSysCalls, startGlue);
5277 return NULL;
5278 }
5279 #endif
5280
5281 //
5282 // If the DYLD_SKIP_MAIN environment is set to 1, dyld will return the
5283 // address of this function instead of main() in the target program which
5284 // __dyld_start jumps to. Useful for qualifying dyld itself.
5285 //
5286 int
5287 fake_main()
5288 {
5289 return 0;
5290 }
5291
5292
5293
5294
5295 static bool envVarMatches(const dyld3::closure::LaunchClosure* mainClosure, const char* envp[], const char* varName)
5296 {
5297 __block const char* valueFromClosure = nullptr;
5298 mainClosure->forEachEnvVar(^(const char* keyEqualValue, bool& stop) {
5299 size_t keyLen = strlen(varName);
5300 if ( (strncmp(varName, keyEqualValue, keyLen) == 0) && (keyEqualValue[keyLen] == '=') ) {
5301 valueFromClosure = &keyEqualValue[keyLen+1];
5302 stop = true;
5303 }
5304 });
5305
5306 const char* valueFromEnv = _simple_getenv(envp, varName);
5307
5308 bool inClosure = (valueFromClosure != nullptr);
5309 bool inEnv = (valueFromEnv != nullptr);
5310 if ( inClosure != inEnv )
5311 return false;
5312 if ( !inClosure && !inEnv )
5313 return true;
5314 return ( strcmp(valueFromClosure, valueFromEnv) == 0 );
5315 }
5316
5317 static const char* const sEnvVarsToCheck[] = {
5318 "DYLD_LIBRARY_PATH",
5319 "DYLD_FRAMEWORK_PATH",
5320 "DYLD_FALLBACK_LIBRARY_PATH",
5321 "DYLD_FALLBACK_FRAMEWORK_PATH",
5322 "DYLD_INSERT_LIBRARIES",
5323 "DYLD_IMAGE_SUFFIX",
5324 "DYLD_VERSIONED_FRAMEWORK_PATH",
5325 "DYLD_VERSIONED_LIBRARY_PATH",
5326 "DYLD_ROOT_PATH"
5327 };
5328
5329 static bool envVarsMatch(const dyld3::closure::LaunchClosure* mainClosure, const char* envp[])
5330 {
5331 for (const char* envVar : sEnvVarsToCheck) {
5332 if ( !envVarMatches(mainClosure, envp, envVar) ) {
5333 if ( gLinkContext.verboseWarnings )
5334 dyld::log("dyld: closure %p not used because %s changed\n", mainClosure, envVar);
5335 return false;
5336 }
5337 }
5338
5339 // FIXME: dyld3 doesn't support versioned paths so we need to fall back to dyld2 if we have them.
5340 // <rdar://problem/37004660> dyld3: support DYLD_VERSIONED_*_PATHs ?
5341 if ( sEnv.DYLD_VERSIONED_LIBRARY_PATH != nullptr ) {
5342 if ( gLinkContext.verboseWarnings )
5343 dyld::log("dyld: closure %p not used because DYLD_VERSIONED_LIBRARY_PATH used\n", mainClosure);
5344 return false;
5345 }
5346 if ( sEnv.DYLD_VERSIONED_FRAMEWORK_PATH != nullptr ) {
5347 if ( gLinkContext.verboseWarnings )
5348 dyld::log("dyld: closure %p not used because DYLD_VERSIONED_FRAMEWORK_PATH used\n", mainClosure);
5349 return false;
5350 }
5351
5352 return true;
5353 }
5354
5355 static bool closureValid(const dyld3::closure::LaunchClosure* mainClosure, const dyld3::closure::LoadedFileInfo& mainFileInfo,
5356 const uint8_t* mainExecutableCDHash, bool closureInCache, const char* envp[])
5357 {
5358 if ( !closureInCache ) {
5359 // verify current dyld cache is same as expected
5360 uuid_t expectedCacheUUID;
5361 if ( mainClosure->builtAgainstDyldCache(expectedCacheUUID) ) {
5362 if ( sSharedCacheLoadInfo.loadAddress == nullptr ) {
5363 if ( gLinkContext.verboseWarnings )
5364 dyld::log("dyld: closure %p dyld cache not loaded\n", mainClosure);
5365 return false;
5366 }
5367 else {
5368 uuid_t actualCacheUUID;
5369 sSharedCacheLoadInfo.loadAddress->getUUID(actualCacheUUID);
5370 if ( memcmp(expectedCacheUUID, actualCacheUUID, sizeof(uuid_t)) != 0 ) {
5371 if ( gLinkContext.verboseWarnings )
5372 dyld::log("dyld: closure %p not used because built against different dyld cache\n", mainClosure);
5373 return false;
5374 }
5375 }
5376 }
5377 else {
5378 // closure built assume there is no dyld cache
5379 if ( sSharedCacheLoadInfo.loadAddress != nullptr ) {
5380 if ( gLinkContext.verboseWarnings )
5381 dyld::log("dyld: closure %p built expecting no dyld cache\n", mainClosure);
5382 return false;
5383 }
5384 }
5385 #if __IPHONE_OS_VERSION_MIN_REQUIRED
5386 // verify this closure is not from a previous reboot
5387 const char* expectedBootUUID = mainClosure->bootUUID();
5388 char actualBootSessionUUID[256] = { 0 };
5389 size_t bootSize = sizeof(actualBootSessionUUID);
5390 bool gotActualBootUUID = (sysctlbyname("kern.bootsessionuuid", actualBootSessionUUID, &bootSize, NULL, 0) == 0);
5391 if ( !gotActualBootUUID || (expectedBootUUID == nullptr) || (strcmp(expectedBootUUID, actualBootSessionUUID) != 0) ) {
5392 if ( gLinkContext.verboseWarnings )
5393 dyld::log("dyld: closure %p built in different boot context\n", mainClosure);
5394 return false;
5395 }
5396 #endif
5397 }
5398
5399 // verify all mach-o files have not changed since closure was built
5400 __block bool foundFileThatInvalidatesClosure = false;
5401 mainClosure->images()->forEachImage(^(const dyld3::closure::Image* image, bool& stop) {
5402 __block uint64_t expectedInode;
5403 __block uint64_t expectedMtime;
5404 if ( image->hasFileModTimeAndInode(expectedInode, expectedMtime) ) {
5405 struct stat statBuf;
5406 if ( ::stat(image->path(), &statBuf) == 0 ) {
5407 if ( (statBuf.st_mtime != expectedMtime) || (statBuf.st_ino != expectedInode) ) {
5408 if ( gLinkContext.verboseWarnings )
5409 dyld::log("dyld: closure %p not used because mtime/inode for '%s' has changed since closure was built\n", mainClosure, image->path());
5410 foundFileThatInvalidatesClosure = true;
5411 stop = true;
5412 }
5413 }
5414 else {
5415 if ( gLinkContext.verboseWarnings )
5416 dyld::log("dyld: closure %p not used because '%s' is needed by closure but is missing\n", mainClosure, image->path());
5417 foundFileThatInvalidatesClosure = true;
5418 stop = true;
5419 }
5420 }
5421 });
5422 if ( foundFileThatInvalidatesClosure )
5423 return false;
5424
5425 // verify cdHash of main executable is same as recorded in closure
5426 uint8_t expectedHash[20];
5427 const dyld3::closure::Image* mainImage = mainClosure->images()->imageForNum(mainClosure->topImage());
5428 if ( mainImage->hasCdHash(expectedHash) ) {
5429 if ( mainExecutableCDHash == nullptr ) {
5430 if ( gLinkContext.verboseWarnings )
5431 dyld::log("dyld: closure %p not used because main executable is not code signed but was expected to be\n", mainClosure);
5432 return false;
5433 }
5434 if ( memcmp(mainExecutableCDHash, expectedHash, 20) != 0 ) {
5435 if ( gLinkContext.verboseWarnings )
5436 dyld::log("dyld: closure %p not used because main executable cd-hash changed since closure was built\n", mainClosure);
5437 return false;
5438 }
5439 }
5440
5441 // verify UUID of main executable is same as recorded in closure
5442 uuid_t expectedUUID;
5443 bool hasExpect = mainImage->getUuid(expectedUUID);
5444 uuid_t actualUUID;
5445 const dyld3::MachOLoaded* mainExecutableMH = (const dyld3::MachOLoaded*)mainFileInfo.fileContent;
5446 bool hasActual = mainExecutableMH->getUuid(actualUUID);
5447 if ( hasExpect != hasActual ) {
5448 if ( gLinkContext.verboseWarnings )
5449 dyld::log("dyld: closure %p not used because UUID of executable changed since closure was built\n", mainClosure);
5450 return false;
5451 }
5452 if ( hasExpect && hasActual && memcmp(actualUUID, expectedUUID, sizeof(uuid_t)) != 0 ) {
5453 if ( gLinkContext.verboseWarnings )
5454 dyld::log("dyld: closure %p not used because UUID of executable changed since closure was built\n", mainClosure);
5455 return false;
5456 }
5457
5458 // verify DYLD_* env vars are same as when closure was built
5459 if ( !envVarsMatch(mainClosure, envp) ) {
5460 return false;
5461 }
5462
5463 // verify files that are supposed to be missing actually are missing
5464 mainClosure->forEachMustBeMissingFile(^(const char* path, bool& stop) {
5465 struct stat statBuf;
5466 if ( ::stat(path, &statBuf) == 0 ) {
5467 stop = true;
5468 foundFileThatInvalidatesClosure = true;
5469 if ( gLinkContext.verboseWarnings )
5470 dyld::log("dyld: closure %p not used because found unexpected file '%s'\n", mainClosure, path);
5471 }
5472 });
5473
5474 // verify closure did not require anything unavailable
5475 if ( mainClosure->usedAtPaths() && !gLinkContext.allowAtPaths ) {
5476 if ( gLinkContext.verboseWarnings )
5477 dyld::log("dyld: closure %p not used because is used @paths, but process does not allow that\n", mainClosure);
5478 return false;
5479 }
5480 if ( mainClosure->usedFallbackPaths() && !gLinkContext.allowClassicFallbackPaths ) {
5481 if ( gLinkContext.verboseWarnings )
5482 dyld::log("dyld: closure %p not used because is used default fallback paths, but process does not allow that\n", mainClosure);
5483 return false;
5484 }
5485
5486 return !foundFileThatInvalidatesClosure;
5487 }
5488
5489 static bool nolog(const char* format, ...)
5490 {
5491 return false;
5492 }
5493
5494 static bool dolog(const char* format, ...)
5495 {
5496 va_list list;
5497 va_start(list, format);
5498 vlog(format, list);
5499 va_end(list);
5500 return true;
5501 }
5502
5503 static bool launchWithClosure(const dyld3::closure::LaunchClosure* mainClosure,
5504 const DyldSharedCache* dyldCache,
5505 const dyld3::MachOLoaded* mainExecutableMH, uintptr_t mainExecutableSlide,
5506 int argc, const char* argv[], const char* envp[], const char* apple[],
5507 uintptr_t* entry, uintptr_t* startGlue)
5508 {
5509 // build list of all known ImageArrays (at most three: cached dylibs, other OS dylibs, and main prog)
5510 STACK_ALLOC_ARRAY(const dyld3::closure::ImageArray*, imagesArrays, 3);
5511 const dyld3::closure::ImageArray* mainClosureImages = mainClosure->images();
5512 if ( dyldCache != nullptr ) {
5513 imagesArrays.push_back(dyldCache->cachedDylibsImageArray());
5514 if ( auto others = dyldCache->otherOSImageArray() )
5515 imagesArrays.push_back(others);
5516 }
5517 imagesArrays.push_back(mainClosureImages);
5518
5519 // allocate space for Array<LoadedImage>
5520 STACK_ALLOC_ARRAY(dyld3::LoadedImage, allImages, mainClosure->initialLoadCount());
5521
5522 __block dyld3::Loader loader(allImages, dyldCache, imagesArrays, (gLinkContext.verboseLoading ? &dolog : &nolog),
5523 (gLinkContext.verboseMapping ? &dolog : &nolog),
5524 (gLinkContext.verboseBind ? &dolog : &nolog),
5525 (gLinkContext.verboseDOF ? &dolog : &nolog));
5526 dyld3::closure::ImageNum mainImageNum = mainClosure->topImage();
5527 mainClosureImages->forEachImage(^(const dyld3::closure::Image* image, bool& stop) {
5528 if ( image->imageNum() == mainImageNum ) {
5529 // add main executable (which is already mapped by kernel) to list
5530 dyld3::LoadedImage mainLoadedImage = dyld3::LoadedImage::make(image, mainExecutableMH);
5531 mainLoadedImage.setState(dyld3::LoadedImage::State::mapped);
5532 mainLoadedImage.markLeaveMapped();
5533 loader.addImage(mainLoadedImage);
5534 stop = true;
5535 }
5536 else {
5537 // add inserted library to initial list
5538 loader.addImage(dyld3::LoadedImage::make(image));
5539 }
5540 });
5541
5542 // recursively load all dependents and fill in allImages array
5543 Diagnostics diag;
5544 loader.completeAllDependents(diag);
5545 if ( diag.noError() )
5546 loader.mapAndFixupAllImages(diag, dyld3::Loader::dtraceUserProbesEnabled());
5547 if ( diag.hasError() ) {
5548 if ( gLinkContext.verboseWarnings )
5549 dyld::log("dyld: %s\n", diag.errorMessage());
5550 return false;
5551 }
5552
5553 //dyld::log("loaded image list:\n");
5554 //for (const dyld3::LoadedImage& info : allImages) {
5555 // dyld::log("mh=%p, path=%s\n", info.loadedAddress(), info.image()->path());
5556 //}
5557
5558 // find libdyld entry
5559 dyld3::closure::Image::ResolvedSymbolTarget dyldEntry;
5560 mainClosure->libDyldEntry(dyldEntry);
5561 const dyld3::LibDyldEntryVector* libDyldEntry = (dyld3::LibDyldEntryVector*)loader.resolveTarget(dyldEntry);
5562
5563 // send info on all images to libdyld.dylb
5564 libDyldEntry->setVars(mainExecutableMH, argc, argv, envp, apple);
5565 if ( libDyldEntry->vectorVersion > 4 )
5566 libDyldEntry->setRestrictions(gLinkContext.allowAtPaths, gLinkContext.allowEnvVarsPath);
5567 libDyldEntry->setHaltFunction(&halt);
5568 if ( libDyldEntry->vectorVersion > 5 ) {
5569 libDyldEntry->setNotifyMonitoringDyldMain(&notifyMonitoringDyldMain);
5570 libDyldEntry->setNotifyMonitoringDyld(&notifyMonitoringDyld);
5571 }
5572 if ( libDyldEntry->vectorVersion > 2 )
5573 libDyldEntry->setChildForkFunction(&_dyld_fork_child);
5574 #if !TARGET_IPHONE_SIMULATOR
5575 if ( libDyldEntry->vectorVersion > 3 )
5576 libDyldEntry->setLogFunction(&dyld::vlog);
5577 #endif
5578 libDyldEntry->setOldAllImageInfo(gProcessInfo);
5579 const dyld3::LoadedImage* libSys = loader.findImage(mainClosure->libSystemImageNum());
5580 libDyldEntry->setInitialImageList(mainClosure, dyldCache, sSharedCacheLoadInfo.path, allImages, *libSys);
5581 // run initializers
5582 CRSetCrashLogMessage("dyld3: launch, running initializers");
5583 libDyldEntry->runInitialzersBottomUp((mach_header*)mainExecutableMH);
5584 //dyld::log("returned from runInitialzersBottomUp()\n");
5585
5586 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE)) {
5587 dyld3::kdebug_trace_dyld_duration_end(launchTraceID, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE, 0, 0, 3);
5588 }
5589 dyld3::closure::Image::ResolvedSymbolTarget progEntry;
5590 if ( mainClosure->mainEntry(progEntry) ) {
5591 // modern app with LC_MAIN
5592 // set startGlue to "start" function in libdyld.dylib
5593 // set entry to "main" function in program
5594 *startGlue = (uintptr_t)(libDyldEntry->startFunc);
5595 *entry = loader.resolveTarget(progEntry);
5596 }
5597 else if ( mainClosure->startEntry(progEntry) ) {
5598 // old style app linked with crt1.o
5599 // entry is "start" function in program
5600 *startGlue = 0;
5601 *entry = loader.resolveTarget(progEntry);
5602 }
5603 else {
5604 assert(0);
5605 }
5606
5607 CRSetCrashLogMessage("dyld3 mode");
5608 return true;
5609 }
5610
5611
5612 #if !TARGET_IPHONE_SIMULATOR
5613
5614 static void putHexNibble(uint8_t value, char*& p)
5615 {
5616 if ( value < 10 )
5617 *p++ = '0' + value;
5618 else
5619 *p++ = 'A' + value - 10;
5620 }
5621
5622 static void putHexByte(uint8_t value, char*& p)
5623 {
5624 value &= 0xFF;
5625 putHexNibble(value >> 4, p);
5626 putHexNibble(value & 0x0F, p);
5627 }
5628
5629 #if __MAC_OS_X_VERSION_MIN_REQUIRED
5630 static void makeHashOfProgramAndEnv(const char* mainExecutablePath, const uint8_t* mainExecutableCDHash, const char* envp[], uint8_t hash32[32])
5631 {
5632 // create hash of main path, main cd hash, cache UUID, DYLD_* env vars
5633 const struct ccdigest_info* di = ccsha256_di();
5634 ccdigest_di_decl(di, hashTemp); // defines hashTemp array in stack
5635 ccdigest_init(di, hashTemp);
5636 // hash in main executable path
5637 ccdigest_update(di, hashTemp, strlen(mainExecutablePath), mainExecutablePath);
5638 // hash in cdHash of main executable
5639 if ( mainExecutableCDHash != nullptr )
5640 ccdigest_update(di, hashTemp, 20, mainExecutableCDHash);
5641 // hash in shared cache UUID
5642 if ( sSharedCacheLoadInfo.loadAddress != nullptr ) {
5643 uuid_t cacheUUID;
5644 sSharedCacheLoadInfo.loadAddress->getUUID(cacheUUID);
5645 ccdigest_update(di, hashTemp, sizeof(uuid_t), cacheUUID);
5646 }
5647 #if __MAC_OS_X_VERSION_MIN_REQUIRED
5648 // hash in if process is restricted
5649 ccdigest_update(di, hashTemp, sizeof(gLinkContext.allowEnvVarsPath), &gLinkContext.allowEnvVarsPath);
5650 #endif
5651 // include dyld's UUID so changing dyld invalidates closures
5652 uuid_t dyldUUID;
5653 if ( ((const dyld3::MachOLoaded*)&__dso_handle)->getUuid(dyldUUID) )
5654 ccdigest_update(di, hashTemp, sizeof(uuid_t), dyldUUID);
5655
5656 // hash in DYLD_* env vars
5657 for (const char* envVar : sEnvVarsToCheck) {
5658 if ( const char* keyValue = _simple_getenv(envp, envVar) )
5659 ccdigest_update(di, hashTemp, strlen(keyValue), keyValue);
5660 }
5661 // finish SHA256 into 32-byte value
5662 ccdigest_final(di, hashTemp, hash32);
5663 ccdigest_di_clear(di, hashTemp);
5664 }
5665 #endif
5666
5667 static void buildClosureCachePath(const char* mainExecutablePath,const dyld3::MachOLoaded* mainExecutableMH,
5668 const uint8_t* mainExecutableCDHash, const char* envp[], char closurePath[])
5669 {
5670 // build base path of $TMPDIR/dyld/<prog-name>-
5671 const char* tempDir = _simple_getenv(envp, "TMPDIR");
5672 if ( tempDir == nullptr )
5673 #if __MAC_OS_X_VERSION_MIN_REQUIRED
5674 tempDir = "/private/tmp/";
5675 #else
5676 tempDir = "/private/var/tmp/";
5677 #endif
5678 strlcpy(closurePath, tempDir, PATH_MAX);
5679 strlcat(closurePath, "/com.apple.dyld/", PATH_MAX);
5680
5681 // make sure dyld sub-dir exists
5682 struct stat statbuf;
5683 if ( ::stat(closurePath, &statbuf) != 0 ) {
5684 ::mkdir(closurePath, S_IRWXU);
5685 }
5686
5687 const char* leafName = strrchr(mainExecutablePath, '/');
5688 if ( leafName == nullptr )
5689 leafName = mainExecutablePath;
5690 else
5691 ++leafName;
5692 strlcat(closurePath, leafName, PATH_MAX);
5693
5694 #if __MAC_OS_X_VERSION_MIN_REQUIRED
5695 // on macOS we allow multiple closures by hashing the env vars into the cache filename
5696 strlcat(closurePath, "-", PATH_MAX);
5697 uint8_t hash32[32];
5698 makeHashOfProgramAndEnv(mainExecutablePath, mainExecutableCDHash, envp, hash32);
5699 char hashString[72];
5700 char* s = hashString;
5701 for (int i=0; i < 32; ++i)
5702 putHexByte(hash32[i], s);
5703 *s = '\0';
5704 strlcat(closurePath, hashString, PATH_MAX);
5705 #else
5706 // on iOS, the file name is the leaf name and UUID
5707 uuid_t mainExeUUID;
5708 if ( mainExecutableMH->getUuid(mainExeUUID) ) {
5709 char mainUuidStr[40];
5710 bytesToHex(mainExeUUID, sizeof(uuid_t), mainUuidStr);
5711 strlcat(closurePath, "-", PATH_MAX);
5712 strlcat(closurePath, mainUuidStr, PATH_MAX);
5713 }
5714 #endif
5715 strlcat(closurePath, ".closure", PATH_MAX);
5716 }
5717
5718 static const dyld3::closure::LaunchClosure* mapClosureFile(const char* closurePath)
5719 {
5720 struct stat statbuf;
5721 if ( ::stat(closurePath, &statbuf) == -1 )
5722 return nullptr;
5723
5724 int fd = ::open(closurePath, O_RDONLY);
5725 if ( fd < 0 )
5726 return nullptr;
5727
5728 const dyld3::closure::LaunchClosure* closure = (dyld3::closure::LaunchClosure*)::mmap(NULL, (size_t)statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
5729 ::close(fd);
5730
5731 if ( closure == MAP_FAILED )
5732 return nullptr;
5733
5734 return closure;
5735 }
5736
5737 static const dyld3::closure::LaunchClosure* buildLaunchClosure(const uint8_t* mainExecutableCDHash,
5738 const dyld3::closure::LoadedFileInfo& mainFileInfo, const char* envp[])
5739 {
5740 const dyld3::MachOLoaded* mainExecutableMH = (const dyld3::MachOLoaded*)mainFileInfo.fileContent;
5741 dyld3::closure::PathOverrides pathOverrides;
5742 pathOverrides.setFallbackPathHandling(gLinkContext.allowClassicFallbackPaths ? dyld3::closure::PathOverrides::FallbackPathMode::classic : dyld3::closure::PathOverrides::FallbackPathMode::restricted);
5743 pathOverrides.setEnvVars(envp, mainExecutableMH, mainFileInfo.path);
5744 STACK_ALLOC_ARRAY(const dyld3::closure::ImageArray*, imagesArrays, 3);
5745 if ( sSharedCacheLoadInfo.loadAddress != nullptr ) {
5746 imagesArrays.push_back(sSharedCacheLoadInfo.loadAddress->cachedDylibsImageArray());
5747 if ( auto others = sSharedCacheLoadInfo.loadAddress->otherOSImageArray() )
5748 imagesArrays.push_back(others);
5749 }
5750
5751 dyld3::closure::ClosureBuilder::LaunchErrorInfo* errorInfo = (dyld3::closure::ClosureBuilder::LaunchErrorInfo*)&gProcessInfo->errorKind;
5752 dyld3::closure::FileSystemPhysical fileSystem;
5753 dyld3::closure::ClosureBuilder::AtPath atPathHanding = (gLinkContext.allowAtPaths ? dyld3::closure::ClosureBuilder::AtPath::all : dyld3::closure::ClosureBuilder::AtPath::none);
5754 dyld3::closure::ClosureBuilder builder(dyld3::closure::kFirstLaunchClosureImageNum, fileSystem, sSharedCacheLoadInfo.loadAddress, true, pathOverrides, atPathHanding, errorInfo, mainExecutableMH->archName());
5755 const dyld3::closure::LaunchClosure* result = builder.makeLaunchClosure(mainFileInfo, gLinkContext.allowInsertFailures);
5756 if ( builder.diagnostics().hasError() )
5757 halt(builder.diagnostics().errorMessage());
5758
5759 if ( result == nullptr )
5760 return nullptr;
5761
5762 if ( !closureValid(result, mainFileInfo, mainExecutableCDHash, false, envp) ) {
5763 // some how the freshly generated closure is invalid...
5764 if ( gLinkContext.verboseWarnings )
5765 dyld::log("dyld: somehow just built closure is invalid\n");
5766 return nullptr;
5767 }
5768 // try to save closure to disk for next launch (atomically)
5769 char closurePath[PATH_MAX];
5770 buildClosureCachePath(mainFileInfo.path, mainExecutableMH, mainExecutableCDHash, envp, closurePath);
5771 char closurePathTemp[PATH_MAX];
5772 strlcpy(closurePathTemp, closurePath, PATH_MAX);
5773 int mypid = getpid();
5774 char pidBuf[16];
5775 char* s = pidBuf;
5776 *s++ = '.';
5777 putHexByte(mypid >> 24, s);
5778 putHexByte(mypid >> 16, s);
5779 putHexByte(mypid >> 8, s);
5780 putHexByte(mypid, s);
5781 *s = '\0';
5782 strlcat(closurePathTemp, pidBuf, PATH_MAX);
5783 int fd = ::open(closurePathTemp, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
5784 if ( fd != -1 ) {
5785 ::ftruncate(fd, result->size());
5786 ::write(fd, result, result->size());
5787 ::fchmod(fd, S_IRUSR);
5788 ::close(fd);
5789 ::rename(closurePathTemp, closurePath);
5790 // free built closure and mmap file() to reduce dirty memory
5791 result->deallocate();
5792 result = mapClosureFile(closurePath);
5793 }
5794 else if ( gLinkContext.verboseWarnings ) {
5795 dyld::log("could not save closure (errno=%d) to: %s\n", errno, closurePathTemp);
5796 }
5797
5798 if ( gLinkContext.verboseWarnings )
5799 dyld::log("dyld: just built closure %p (size=%lu) for %s\n", result, result->size(), sExecPath);
5800
5801 return result;
5802 }
5803
5804 static const dyld3::closure::LaunchClosure* findCachedLaunchClosure(const uint8_t* mainExecutableCDHash,
5805 const dyld3::closure::LoadedFileInfo& mainFileInfo,
5806 const char* envp[])
5807 {
5808 char closurePath[PATH_MAX];
5809 buildClosureCachePath(mainFileInfo.path, (const dyld3::MachOLoaded*)mainFileInfo.fileContent, mainExecutableCDHash, envp, closurePath);
5810 const dyld3::closure::LaunchClosure* closure = mapClosureFile(closurePath);
5811 if ( closure == nullptr )
5812 return nullptr;
5813
5814 if ( !closureValid(closure, mainFileInfo, mainExecutableCDHash, false, envp) ) {
5815 ::munmap((void*)closure, closure->size());
5816 return nullptr;
5817 }
5818
5819 if ( gLinkContext.verboseWarnings )
5820 dyld::log("dyld: used cached closure %p (size=%lu) for %s\n", closure, closure->size(), sExecPath);
5821
5822 return closure;
5823 }
5824
5825 #endif // !TARGET_IPHONE_SIMULATOR
5826
5827
5828
5829 #if !__MAC_OS_X_VERSION_MIN_REQUIRED
5830 static const char* sWhiteListDirs[] = {
5831 "/bin/",
5832 "/sbin/",
5833 "/usr/bin/"
5834 };
5835 #endif
5836
5837 static bool inWhiteList(const char* execPath)
5838 {
5839 // First test to see if we forced in dyld2 via a kernel boot-arg
5840 if ( dyld3::bootArgsContains("force_dyld2=1") )
5841 return false;
5842
5843 #if __MAC_OS_X_VERSION_MIN_REQUIRED
5844
5845 // rdar://problem/32701418: Don't use dyld3 for i386 for now.
5846 #if __i386__
5847 return false;
5848 #else
5849
5850
5851 return true;
5852 #endif // #if __i386__
5853
5854 #else
5855
5856
5857 // <rdar://problem/33171968> enable dyld3 mode for all OS programs when using customer dyld cache (no roots)
5858 if ( (sSharedCacheLoadInfo.loadAddress != nullptr) && (sSharedCacheLoadInfo.loadAddress->header.cacheType == kDyldSharedCacheTypeProduction) )
5859 return true;
5860
5861 return dyld3::bootArgsContains("force_dyld3=1");
5862 #endif
5863 }
5864
5865 #if !TARGET_IPHONE_SIMULATOR
5866 static bool isStagedApp(const dyld3::MachOFile* mainExecutableMH, const char* mainExecutablePath)
5867 {
5868 #if !__MAC_OS_X_VERSION_MIN_REQUIRED
5869 if ( (strncmp(mainExecutablePath, "/var/containers/Bundle/Application/", 35) == 0)
5870 || (strncmp(mainExecutablePath, "/private/var/containers/Bundle/Application/", 43) == 0) ) {
5871 // staged apps are built without LC_ENCRYPTION_INFO
5872 if ( !mainExecutableMH->canBeFairPlayEncrypted() )
5873 return true;
5874 }
5875 #endif
5876 return false;
5877 }
5878 #endif
5879
5880 //
5881 // Entry point for dyld. The kernel loads dyld and jumps to __dyld_start which
5882 // sets up some registers and call this function.
5883 //
5884 // Returns address of main() in target program which __dyld_start jumps to
5885 //
5886 uintptr_t
5887 _main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
5888 int argc, const char* argv[], const char* envp[], const char* apple[],
5889 uintptr_t* startGlue)
5890 {
5891 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE)) {
5892 launchTraceID = dyld3::kdebug_trace_dyld_duration_start(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE, (uint64_t)mainExecutableMH, 0, 0);
5893 }
5894
5895 // Grab the cdHash of the main executable from the environment
5896 uint8_t mainExecutableCDHashBuffer[20];
5897 const uint8_t* mainExecutableCDHash = nullptr;
5898 if ( hexToBytes(_simple_getenv(apple, "executable_cdhash"), 40, mainExecutableCDHashBuffer) )
5899 mainExecutableCDHash = mainExecutableCDHashBuffer;
5900
5901 // Trace dyld's load
5902 notifyKernelAboutImage((macho_header*)&__dso_handle, _simple_getenv(apple, "dyld_file"));
5903 #if !TARGET_IPHONE_SIMULATOR
5904 // Trace the main executable's load
5905 notifyKernelAboutImage(mainExecutableMH, _simple_getenv(apple, "executable_file"));
5906 #endif
5907
5908 uintptr_t result = 0;
5909 sMainExecutableMachHeader = mainExecutableMH;
5910 sMainExecutableSlide = mainExecutableSlide;
5911 #if __MAC_OS_X_VERSION_MIN_REQUIRED
5912 // if this is host dyld, check to see if iOS simulator is being run
5913 const char* rootPath = _simple_getenv(envp, "DYLD_ROOT_PATH");
5914 if ( (rootPath != NULL) ) {
5915 // look to see if simulator has its own dyld
5916 char simDyldPath[PATH_MAX];
5917 strlcpy(simDyldPath, rootPath, PATH_MAX);
5918 strlcat(simDyldPath, "/usr/lib/dyld_sim", PATH_MAX);
5919 int fd = my_open(simDyldPath, O_RDONLY, 0);
5920 if ( fd != -1 ) {
5921 const char* errMessage = useSimulatorDyld(fd, mainExecutableMH, simDyldPath, argc, argv, envp, apple, startGlue, &result);
5922 if ( errMessage != NULL )
5923 halt(errMessage);
5924 return result;
5925 }
5926 }
5927 #endif
5928
5929 CRSetCrashLogMessage("dyld: launch started");
5930
5931 setContext(mainExecutableMH, argc, argv, envp, apple);
5932
5933 // Pickup the pointer to the exec path.
5934 sExecPath = _simple_getenv(apple, "executable_path");
5935
5936 // <rdar://problem/13868260> Remove interim apple[0] transition code from dyld
5937 if (!sExecPath) sExecPath = apple[0];
5938
5939 if ( sExecPath[0] != '/' ) {
5940 // have relative path, use cwd to make absolute
5941 char cwdbuff[MAXPATHLEN];
5942 if ( getcwd(cwdbuff, MAXPATHLEN) != NULL ) {
5943 // maybe use static buffer to avoid calling malloc so early...
5944 char* s = new char[strlen(cwdbuff) + strlen(sExecPath) + 2];
5945 strcpy(s, cwdbuff);
5946 strcat(s, "/");
5947 strcat(s, sExecPath);
5948 sExecPath = s;
5949 }
5950 }
5951
5952 // Remember short name of process for later logging
5953 sExecShortName = ::strrchr(sExecPath, '/');
5954 if ( sExecShortName != NULL )
5955 ++sExecShortName;
5956 else
5957 sExecShortName = sExecPath;
5958
5959 configureProcessRestrictions(mainExecutableMH);
5960
5961 #if __MAC_OS_X_VERSION_MIN_REQUIRED
5962 if ( !gLinkContext.allowEnvVarsPrint && !gLinkContext.allowEnvVarsPath && !gLinkContext.allowEnvVarsSharedCache ) {
5963 pruneEnvironmentVariables(envp, &apple);
5964 // set again because envp and apple may have changed or moved
5965 setContext(mainExecutableMH, argc, argv, envp, apple);
5966 }
5967 else
5968 #endif
5969 {
5970 checkEnvironmentVariables(envp);
5971 defaultUninitializedFallbackPaths(envp);
5972 }
5973 #if __MAC_OS_X_VERSION_MIN_REQUIRED
5974 if ( ((dyld3::MachOFile*)mainExecutableMH)->supportsPlatform(dyld3::Platform::iOSMac)
5975 && !((dyld3::MachOFile*)mainExecutableMH)->supportsPlatform(dyld3::Platform::macOS)) {
5976 gLinkContext.rootPaths = parseColonList("/System/iOSSupport", NULL);
5977 gLinkContext.marzipan = true;
5978 if ( sEnv.DYLD_FALLBACK_LIBRARY_PATH == sLibraryFallbackPaths )
5979 sEnv.DYLD_FALLBACK_LIBRARY_PATH = sRestrictedLibraryFallbackPaths;
5980 if ( sEnv.DYLD_FALLBACK_FRAMEWORK_PATH == sFrameworkFallbackPaths )
5981 sEnv.DYLD_FALLBACK_FRAMEWORK_PATH = sRestrictedFrameworkFallbackPaths;
5982 }
5983 #endif
5984 if ( sEnv.DYLD_PRINT_OPTS )
5985 printOptions(argv);
5986 if ( sEnv.DYLD_PRINT_ENV )
5987 printEnvironmentVariables(envp);
5988 getHostInfo(mainExecutableMH, mainExecutableSlide);
5989
5990 // load shared cache
5991 checkSharedRegionDisable((dyld3::MachOLoaded*)mainExecutableMH, mainExecutableSlide);
5992 #if TARGET_IPHONE_SIMULATOR
5993 // <HACK> until <rdar://30773711> is fixed
5994 gLinkContext.sharedRegionMode = ImageLoader::kUsePrivateSharedRegion;
5995 // </HACK>
5996 #endif
5997 if ( gLinkContext.sharedRegionMode != ImageLoader::kDontUseSharedRegion ) {
5998 mapSharedCache();
5999 }
6000 bool cacheCompatible = (sSharedCacheLoadInfo.loadAddress == nullptr) || (sSharedCacheLoadInfo.loadAddress->header.formatVersion == dyld3::closure::kFormatVersion);
6001 if ( cacheCompatible && (sEnableClosures || inWhiteList(sExecPath)) ) {
6002 const dyld3::closure::LaunchClosure* mainClosure = nullptr;
6003 dyld3::closure::LoadedFileInfo mainFileInfo;
6004 mainFileInfo.fileContent = mainExecutableMH;
6005 mainFileInfo.path = sExecPath;
6006 // FIXME: If we are saving this closure, this slice offset/length is probably wrong in the case of FAT files.
6007 mainFileInfo.sliceOffset = 0;
6008 mainFileInfo.sliceLen = std::numeric_limits<__typeof(mainFileInfo.sliceLen)>::max();
6009 struct stat mainExeStatBuf;
6010 if ( ::stat(sExecPath, &mainExeStatBuf) == 0 ) {
6011 mainFileInfo.inode = mainExeStatBuf.st_ino;
6012 mainFileInfo.mtime = mainExeStatBuf.st_mtime;
6013 }
6014 // check for closure in cache first
6015 if ( sSharedCacheLoadInfo.loadAddress != nullptr ) {
6016 mainClosure = sSharedCacheLoadInfo.loadAddress->findClosure(sExecPath);
6017 if ( gLinkContext.verboseWarnings && (mainClosure != nullptr) )
6018 dyld::log("dyld: found closure %p (size=%lu) in dyld shared cache\n", mainClosure, mainClosure->size());
6019 }
6020 #if !TARGET_IPHONE_SIMULATOR
6021 if ( (mainClosure == nullptr) || !closureValid(mainClosure, mainFileInfo, mainExecutableCDHash, true, envp) ) {
6022 mainClosure = nullptr;
6023 if ( sEnableClosures || isStagedApp((dyld3::MachOFile*)mainExecutableMH, sExecPath) ) {
6024 // if forcing closures, and no closure in cache, or it is invalid, check for cached closure
6025 mainClosure = findCachedLaunchClosure(mainExecutableCDHash, mainFileInfo, envp);
6026 if ( mainClosure == nullptr ) {
6027 // if no cached closure found, build new one
6028 mainClosure = buildLaunchClosure(mainExecutableCDHash, mainFileInfo, envp);
6029 }
6030 }
6031 }
6032 #endif
6033 // try using launch closure
6034 if ( mainClosure != nullptr ) {
6035 CRSetCrashLogMessage("dyld3: launch started");
6036 bool launched = launchWithClosure(mainClosure, sSharedCacheLoadInfo.loadAddress, (dyld3::MachOLoaded*)mainExecutableMH,
6037 mainExecutableSlide, argc, argv, envp, apple, &result, startGlue);
6038 #if !TARGET_IPHONE_SIMULATOR
6039 if ( !launched ) {
6040 // closure is out of date, build new one
6041 mainClosure = buildLaunchClosure(mainExecutableCDHash, mainFileInfo, envp);
6042 if ( mainClosure != nullptr ) {
6043 launched = launchWithClosure(mainClosure, sSharedCacheLoadInfo.loadAddress, (dyld3::MachOLoaded*)mainExecutableMH,
6044 mainExecutableSlide, argc, argv, envp, apple, &result, startGlue);
6045 }
6046 }
6047 #endif
6048 if ( launched ) {
6049 #if __has_feature(ptrauth_calls)
6050 // start() calls the result pointer as a function pointer so we need to sign it.
6051 result = (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)result, 0, 0);
6052 #endif
6053 if (sSkipMain)
6054 result = (uintptr_t)&fake_main;
6055 return result;
6056 }
6057 else {
6058 if ( gLinkContext.verboseWarnings )
6059 dyld::log("dyld: unable to use closure %p\n", mainClosure);
6060 }
6061 }
6062 }
6063 else {
6064 if ( gLinkContext.verboseWarnings )
6065 dyld::log("dyld: not using closure because shared cache format version does not match dyld's\n");
6066 }
6067 // could not use closure info, launch old way
6068
6069
6070
6071 // install gdb notifier
6072 stateToHandlers(dyld_image_state_dependents_mapped, sBatchHandlers)->push_back(notifyGDB);
6073 stateToHandlers(dyld_image_state_mapped, sSingleHandlers)->push_back(updateAllImages);
6074 // make initial allocations large enough that it is unlikely to need to be re-alloced
6075 sImageRoots.reserve(16);
6076 sAddImageCallbacks.reserve(4);
6077 sRemoveImageCallbacks.reserve(4);
6078 sAddLoadImageCallbacks.reserve(4);
6079 sImageFilesNeedingTermination.reserve(16);
6080 sImageFilesNeedingDOFUnregistration.reserve(8);
6081
6082 #if !TARGET_IPHONE_SIMULATOR
6083 #ifdef WAIT_FOR_SYSTEM_ORDER_HANDSHAKE
6084 // <rdar://problem/6849505> Add gating mechanism to dyld support system order file generation process
6085 WAIT_FOR_SYSTEM_ORDER_HANDSHAKE(dyld::gProcessInfo->systemOrderFlag);
6086 #endif
6087 #endif
6088
6089
6090 try {
6091 // add dyld itself to UUID list
6092 addDyldImageToUUIDList();
6093
6094 #if SUPPORT_ACCELERATE_TABLES
6095 #if __arm64e__
6096 // Disable accelerator tables when we have threaded rebase/bind, which is arm64e executables only for now.
6097 if (sMainExecutableMachHeader->cpusubtype == CPU_SUBTYPE_ARM64_E)
6098 sDisableAcceleratorTables = true;
6099 #endif
6100 bool mainExcutableAlreadyRebased = false;
6101 if ( (sSharedCacheLoadInfo.loadAddress != nullptr) && !dylibsCanOverrideCache() && !sDisableAcceleratorTables && (sSharedCacheLoadInfo.loadAddress->header.accelerateInfoAddr != 0) ) {
6102 struct stat statBuf;
6103 if ( ::stat(IPHONE_DYLD_SHARED_CACHE_DIR "no-dyld2-accelerator-tables", &statBuf) != 0 )
6104 sAllCacheImagesProxy = ImageLoaderMegaDylib::makeImageLoaderMegaDylib(&sSharedCacheLoadInfo.loadAddress->header, sSharedCacheLoadInfo.slide, mainExecutableMH, gLinkContext);
6105 }
6106
6107 reloadAllImages:
6108 #endif
6109
6110 CRSetCrashLogMessage(sLoadingCrashMessage);
6111 // instantiate ImageLoader for main executable
6112 sMainExecutable = instantiateFromLoadedImage(mainExecutableMH, mainExecutableSlide, sExecPath);
6113 gLinkContext.mainExecutable = sMainExecutable;
6114 gLinkContext.mainExecutableCodeSigned = hasCodeSignatureLoadCommand(mainExecutableMH);
6115
6116 #if TARGET_IPHONE_SIMULATOR
6117 // check main executable is not too new for this OS
6118 {
6119 if ( ! isSimulatorBinary((uint8_t*)mainExecutableMH, sExecPath) ) {
6120 throwf("program was built for a platform that is not supported by this runtime");
6121 }
6122 uint32_t mainMinOS = sMainExecutable->minOSVersion();
6123
6124 // dyld is always built for the current OS, so we can get the current OS version
6125 // from the load command in dyld itself.
6126 uint32_t dyldMinOS = ImageLoaderMachO::minOSVersion((const mach_header*)&__dso_handle);
6127 if ( mainMinOS > dyldMinOS ) {
6128 #if TARGET_OS_WATCH
6129 throwf("app was built for watchOS %d.%d which is newer than this simulator %d.%d",
6130 mainMinOS >> 16, ((mainMinOS >> 8) & 0xFF),
6131 dyldMinOS >> 16, ((dyldMinOS >> 8) & 0xFF));
6132 #elif TARGET_OS_TV
6133 throwf("app was built for tvOS %d.%d which is newer than this simulator %d.%d",
6134 mainMinOS >> 16, ((mainMinOS >> 8) & 0xFF),
6135 dyldMinOS >> 16, ((dyldMinOS >> 8) & 0xFF));
6136 #else
6137 throwf("app was built for iOS %d.%d which is newer than this simulator %d.%d",
6138 mainMinOS >> 16, ((mainMinOS >> 8) & 0xFF),
6139 dyldMinOS >> 16, ((dyldMinOS >> 8) & 0xFF));
6140 #endif
6141 }
6142 }
6143 #endif
6144
6145
6146 #if __MAC_OS_X_VERSION_MIN_REQUIRED
6147 // <rdar://problem/22805519> be less strict about old mach-o binaries
6148 uint32_t mainSDK = sMainExecutable->sdkVersion();
6149 gLinkContext.strictMachORequired = (mainSDK >= DYLD_MACOSX_VERSION_10_12) || gLinkContext.allowInsertFailures;
6150 #else
6151 // simulators, iOS, tvOS, and watchOS are always strict
6152 gLinkContext.strictMachORequired = true;
6153 #endif
6154
6155 #if SUPPORT_ACCELERATE_TABLES
6156 sAllImages.reserve((sAllCacheImagesProxy != NULL) ? 16 : INITIAL_IMAGE_COUNT);
6157 #else
6158 sAllImages.reserve(INITIAL_IMAGE_COUNT);
6159 #endif
6160
6161 // Now that shared cache is loaded, setup an versioned dylib overrides
6162 #if SUPPORT_VERSIONED_PATHS
6163 checkVersionedPaths();
6164 #endif
6165
6166
6167 // dyld_all_image_infos image list does not contain dyld
6168 // add it as dyldPath field in dyld_all_image_infos
6169 // for simulator, dyld_sim is in image list, need host dyld added
6170 #if TARGET_IPHONE_SIMULATOR
6171 // get path of host dyld from table of syscall vectors in host dyld
6172 void* addressInDyld = gSyscallHelpers;
6173 #else
6174 // get path of dyld itself
6175 void* addressInDyld = (void*)&__dso_handle;
6176 #endif
6177 char dyldPathBuffer[MAXPATHLEN+1];
6178 int len = proc_regionfilename(getpid(), (uint64_t)(long)addressInDyld, dyldPathBuffer, MAXPATHLEN);
6179 if ( len > 0 ) {
6180 dyldPathBuffer[len] = '\0'; // proc_regionfilename() does not zero terminate returned string
6181 if ( strcmp(dyldPathBuffer, gProcessInfo->dyldPath) != 0 )
6182 gProcessInfo->dyldPath = strdup(dyldPathBuffer);
6183 }
6184
6185 // load any inserted libraries
6186 if ( sEnv.DYLD_INSERT_LIBRARIES != NULL ) {
6187 for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib)
6188 loadInsertedDylib(*lib);
6189 }
6190 // record count of inserted libraries so that a flat search will look at
6191 // inserted libraries, then main, then others.
6192 sInsertedDylibCount = sAllImages.size()-1;
6193
6194 // link main executable
6195 gLinkContext.linkingMainExecutable = true;
6196 #if SUPPORT_ACCELERATE_TABLES
6197 if ( mainExcutableAlreadyRebased ) {
6198 // previous link() on main executable has already adjusted its internal pointers for ASLR
6199 // work around that by rebasing by inverse amount
6200 sMainExecutable->rebase(gLinkContext, -mainExecutableSlide);
6201 }
6202 #endif
6203 link(sMainExecutable, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL), -1);
6204 sMainExecutable->setNeverUnloadRecursive();
6205 if ( sMainExecutable->forceFlat() ) {
6206 gLinkContext.bindFlat = true;
6207 gLinkContext.prebindUsage = ImageLoader::kUseNoPrebinding;
6208 }
6209
6210 // link any inserted libraries
6211 // do this after linking main executable so that any dylibs pulled in by inserted
6212 // dylibs (e.g. libSystem) will not be in front of dylibs the program uses
6213 if ( sInsertedDylibCount > 0 ) {
6214 for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
6215 ImageLoader* image = sAllImages[i+1];
6216 link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL), -1);
6217 image->setNeverUnloadRecursive();
6218 }
6219 // only INSERTED libraries can interpose
6220 // register interposing info after all inserted libraries are bound so chaining works
6221 for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
6222 ImageLoader* image = sAllImages[i+1];
6223 image->registerInterposing(gLinkContext);
6224 }
6225 }
6226
6227 // <rdar://problem/19315404> dyld should support interposition even without DYLD_INSERT_LIBRARIES
6228 for (long i=sInsertedDylibCount+1; i < sAllImages.size(); ++i) {
6229 ImageLoader* image = sAllImages[i];
6230 if ( image->inSharedCache() )
6231 continue;
6232 image->registerInterposing(gLinkContext);
6233 }
6234 #if SUPPORT_ACCELERATE_TABLES
6235 if ( (sAllCacheImagesProxy != NULL) && ImageLoader::haveInterposingTuples() ) {
6236 // Accelerator tables cannot be used with implicit interposing, so relaunch with accelerator tables disabled
6237 ImageLoader::clearInterposingTuples();
6238 // unmap all loaded dylibs (but not main executable)
6239 for (long i=1; i < sAllImages.size(); ++i) {
6240 ImageLoader* image = sAllImages[i];
6241 if ( image == sMainExecutable )
6242 continue;
6243 if ( image == sAllCacheImagesProxy )
6244 continue;
6245 image->setCanUnload();
6246 ImageLoader::deleteImage(image);
6247 }
6248 // note: we don't need to worry about inserted images because if DYLD_INSERT_LIBRARIES was set we would not be using the accelerator table
6249 sAllImages.clear();
6250 sImageRoots.clear();
6251 sImageFilesNeedingTermination.clear();
6252 sImageFilesNeedingDOFUnregistration.clear();
6253 sAddImageCallbacks.clear();
6254 sRemoveImageCallbacks.clear();
6255 sAddLoadImageCallbacks.clear();
6256 sDisableAcceleratorTables = true;
6257 sAllCacheImagesProxy = NULL;
6258 sMappedRangesStart = NULL;
6259 mainExcutableAlreadyRebased = true;
6260 gLinkContext.linkingMainExecutable = false;
6261 resetAllImages();
6262 goto reloadAllImages;
6263 }
6264 #endif
6265
6266 // apply interposing to initial set of images
6267 for(int i=0; i < sImageRoots.size(); ++i) {
6268 sImageRoots[i]->applyInterposing(gLinkContext);
6269 }
6270 ImageLoader::applyInterposingToDyldCache(gLinkContext);
6271 gLinkContext.linkingMainExecutable = false;
6272
6273 // Bind and notify for the main executable now that interposing has been registered
6274 uint64_t bindMainExecutableStartTime = mach_absolute_time();
6275 sMainExecutable->recursiveBindWithAccounting(gLinkContext, sEnv.DYLD_BIND_AT_LAUNCH, true);
6276 uint64_t bindMainExecutableEndTime = mach_absolute_time();
6277 ImageLoaderMachO::fgTotalBindTime += bindMainExecutableEndTime - bindMainExecutableStartTime;
6278 gLinkContext.notifyBatch(dyld_image_state_bound, false);
6279
6280 // Bind and notify for the inserted images now interposing has been registered
6281 if ( sInsertedDylibCount > 0 ) {
6282 for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
6283 ImageLoader* image = sAllImages[i+1];
6284 image->recursiveBind(gLinkContext, sEnv.DYLD_BIND_AT_LAUNCH, true);
6285 }
6286 }
6287
6288 // <rdar://problem/12186933> do weak binding only after all inserted images linked
6289 sMainExecutable->weakBind(gLinkContext);
6290
6291 // If cache has branch island dylibs, tell debugger about them
6292 if ( (sSharedCacheLoadInfo.loadAddress != NULL) && (sSharedCacheLoadInfo.loadAddress->header.mappingOffset >= 0x78) && (sSharedCacheLoadInfo.loadAddress->header.branchPoolsOffset != 0) ) {
6293 uint32_t count = sSharedCacheLoadInfo.loadAddress->header.branchPoolsCount;
6294 dyld_image_info info[count];
6295 const uint64_t* poolAddress = (uint64_t*)((char*)sSharedCacheLoadInfo.loadAddress + sSharedCacheLoadInfo.loadAddress->header.branchPoolsOffset);
6296 // <rdar://problem/20799203> empty branch pools can be in development cache
6297 if ( ((mach_header*)poolAddress)->magic == sMainExecutableMachHeader->magic ) {
6298 for (int poolIndex=0; poolIndex < count; ++poolIndex) {
6299 uint64_t poolAddr = poolAddress[poolIndex] + sSharedCacheLoadInfo.slide;
6300 info[poolIndex].imageLoadAddress = (mach_header*)(long)poolAddr;
6301 info[poolIndex].imageFilePath = "dyld_shared_cache_branch_islands";
6302 info[poolIndex].imageFileModDate = 0;
6303 }
6304 // add to all_images list
6305 addImagesToAllImages(count, info);
6306 // tell gdb about new branch island images
6307 gProcessInfo->notification(dyld_image_adding, count, info);
6308 }
6309 }
6310
6311 CRSetCrashLogMessage("dyld: launch, running initializers");
6312 #if SUPPORT_OLD_CRT_INITIALIZATION
6313 // Old way is to run initializers via a callback from crt1.o
6314 if ( ! gRunInitializersOldWay )
6315 initializeMainExecutable();
6316 #else
6317 // run all initializers
6318 initializeMainExecutable();
6319 #endif
6320
6321 // notify any montoring proccesses that this process is about to enter main()
6322 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE)) {
6323 dyld3::kdebug_trace_dyld_duration_end(launchTraceID, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE, 0, 0, 2);
6324 }
6325 notifyMonitoringDyldMain();
6326
6327 // find entry point for main executable
6328 result = (uintptr_t)sMainExecutable->getEntryFromLC_MAIN();
6329 if ( result != 0 ) {
6330 // main executable uses LC_MAIN, we need to use helper in libdyld to call into main()
6331 if ( (gLibSystemHelpers != NULL) && (gLibSystemHelpers->version >= 9) )
6332 *startGlue = (uintptr_t)gLibSystemHelpers->startGlueToCallExit;
6333 else
6334 halt("libdyld.dylib support not present for LC_MAIN");
6335 }
6336 else {
6337 // main executable uses LC_UNIXTHREAD, dyld needs to let "start" in program set up for main()
6338 result = (uintptr_t)sMainExecutable->getEntryFromLC_UNIXTHREAD();
6339 *startGlue = 0;
6340 }
6341 #if __has_feature(ptrauth_calls)
6342 // start() calls the result pointer as a function pointer so we need to sign it.
6343 result = (uintptr_t)__builtin_ptrauth_sign_unauthenticated((void*)result, 0, 0);
6344 #endif
6345 }
6346 catch(const char* message) {
6347 syncAllImages();
6348 halt(message);
6349 }
6350 catch(...) {
6351 dyld::log("dyld: launch failed\n");
6352 }
6353
6354 CRSetCrashLogMessage("dyld2 mode");
6355
6356 if (sSkipMain) {
6357 if (dyld3::kdebug_trace_dyld_enabled(DBG_DYLD_TIMING_LAUNCH_EXECUTABLE)) {
6358 dyld3::kdebug_trace_dyld_duration_end(launchTraceID, DBG_DYLD_TIMING_LAUNCH_EXECUTABLE, 0, 0, 2);
6359 }
6360 result = (uintptr_t)&fake_main;
6361 *startGlue = (uintptr_t)gLibSystemHelpers->startGlueToCallExit;
6362 }
6363
6364 return result;
6365 }
6366
6367
6368 } // namespace
6369
6370
6371