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