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