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