1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
   3  * Copyright (c) 2004-2010 Apple Inc. All rights reserved. 
   5  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  22  * @APPLE_LICENSE_HEADER_END@ 
  25 #define __STDC_LIMIT_MACROS 
  30 #include <mach/mach.h> 
  31 #include <mach-o/fat.h>  
  32 #include <sys/types.h> 
  35 #include <sys/param.h> 
  36 #include <sys/mount.h> 
  37 #include <libkern/OSAtomic.h> 
  39 #include "ImageLoader.h" 
  42 uint32_t                                                                ImageLoader::fgImagesUsedFromSharedCache 
= 0; 
  43 uint32_t                                                                ImageLoader::fgImagesWithUsedPrebinding 
= 0; 
  44 uint32_t                                                                ImageLoader::fgImagesRequiringCoalescing 
= 0; 
  45 uint32_t                                                                ImageLoader::fgImagesHasWeakDefinitions 
= 0; 
  46 uint32_t                                                                ImageLoader::fgTotalRebaseFixups 
= 0; 
  47 uint32_t                                                                ImageLoader::fgTotalBindFixups 
= 0; 
  48 uint32_t                                                                ImageLoader::fgTotalBindSymbolsResolved 
= 0; 
  49 uint32_t                                                                ImageLoader::fgTotalBindImageSearches 
= 0; 
  50 uint32_t                                                                ImageLoader::fgTotalLazyBindFixups 
= 0; 
  51 uint32_t                                                                ImageLoader::fgTotalPossibleLazyBindFixups 
= 0; 
  52 uint32_t                                                                ImageLoader::fgTotalSegmentsMapped 
= 0; 
  53 uint64_t                                                                ImageLoader::fgTotalBytesMapped 
= 0; 
  54 uint64_t                                                                ImageLoader::fgTotalBytesPreFetched 
= 0; 
  55 uint64_t                                                                ImageLoader::fgTotalLoadLibrariesTime
; 
  56 uint64_t                                                                ImageLoader::fgTotalObjCSetupTime 
= 0; 
  57 uint64_t                                                                ImageLoader::fgTotalDebuggerPausedTime 
= 0; 
  58 uint64_t                                                                ImageLoader::fgTotalRebindCacheTime 
= 0; 
  59 uint64_t                                                                ImageLoader::fgTotalRebaseTime
; 
  60 uint64_t                                                                ImageLoader::fgTotalBindTime
; 
  61 uint64_t                                                                ImageLoader::fgTotalWeakBindTime
; 
  62 uint64_t                                                                ImageLoader::fgTotalDOF
; 
  63 uint64_t                                                                ImageLoader::fgTotalInitTime
; 
  64 uint16_t                                                                ImageLoader::fgLoadOrdinal 
= 0; 
  65 uint32_t                                                                ImageLoader::fgSymbolTrieSearchs 
= 0; 
  66 std::vector
<ImageLoader::InterposeTuple
>ImageLoader::fgInterposingTuples
; 
  67 uintptr_t                                                               ImageLoader::fgNextPIEDylibAddress 
= 0; 
  71 ImageLoader::ImageLoader(const char* path
, unsigned int libCount
) 
  72         : fPath(path
), fRealPath(NULL
), fDevice(0), fInode(0), fLastModified(0),  
  73         fPathHash(0), fDlopenReferenceCount(0), fInitializerRecursiveLock(NULL
),  
  74         fDepth(0), fLoadOrder(fgLoadOrdinal
++), fState(0), fLibraryCount(libCount
),  
  75         fAllLibraryChecksumsAndLoadAddressesMatch(false), fLeaveMapped(false), fNeverUnload(false), 
  76         fHideSymbols(false), fMatchByInstallName(false), 
  77         fInterposed(false), fRegisteredDOF(false), fAllLazyPointersBound(false),  
  78     fBeingRemoved(false), fAddFuncNotified(false), 
  79         fPathOwnedByImage(false), fIsReferencedDownward(false),  
  80         fWeakSymbolsBound(false) 
  83                 fPathHash 
= hash(fPath
); 
  85                 dyld::throwf("too many dependent dylibs in %s", path
); 
  89 void ImageLoader::deleteImage(ImageLoader
* image
) 
  95 ImageLoader::~ImageLoader() 
  97         if ( fRealPath 
!= NULL 
)  
  99         if ( fPathOwnedByImage 
&& (fPath 
!= NULL
) )  
 103 void ImageLoader::setFileInfo(dev_t device
, ino_t inode
, time_t modDate
) 
 107         fLastModified 
= modDate
; 
 110 void ImageLoader::setMapped(const LinkContext
& context
) 
 112         fState 
= dyld_image_state_mapped
; 
 113         context
.notifySingle(dyld_image_state_mapped
, this, NULL
);  // note: can throw exception 
 116 int ImageLoader::compare(const ImageLoader
* right
) const 
 118         if ( this->fDepth 
== right
->fDepth 
) { 
 119                 if ( this->fLoadOrder 
== right
->fLoadOrder 
) 
 121                 else if ( this->fLoadOrder 
< right
->fLoadOrder 
) 
 127                 if ( this->fDepth 
< right
->fDepth 
) 
 134 void ImageLoader::setPath(const char* path
) 
 136         if ( fPathOwnedByImage 
&& (fPath 
!= NULL
) )  
 138         fPath 
= new char[strlen(path
)+1]; 
 139         strcpy((char*)fPath
, path
); 
 140         fPathOwnedByImage 
= true;  // delete fPath when this image is destructed 
 141         fPathHash 
= hash(fPath
); 
 145 void ImageLoader::setPathUnowned(const char* path
) 
 147         if ( fPathOwnedByImage 
&& (fPath 
!= NULL
) ) { 
 151         fPathOwnedByImage 
= false;   
 152         fPathHash 
= hash(fPath
); 
 155 void ImageLoader::setPaths(const char* path
, const char* realPath
) 
 158         fRealPath 
= new char[strlen(realPath
)+1]; 
 159         strcpy((char*)fRealPath
, realPath
); 
 162 const char* ImageLoader::getRealPath() const  
 164         if ( fRealPath 
!= NULL 
)  
 171 uint32_t ImageLoader::hash(const char* path
) 
 173         // this does not need to be a great hash 
 174         // it is just used to reduce the number of strcmp() calls 
 175         // of existing images when loading a new image 
 177         for (const char* s
=path
; *s 
!= '\0'; ++s
) 
 182 bool ImageLoader::matchInstallPath() const 
 184         return fMatchByInstallName
; 
 187 void ImageLoader::setMatchInstallPath(bool match
) 
 189         fMatchByInstallName 
= match
; 
 192 bool ImageLoader::statMatch(const struct stat
& stat_buf
) const 
 194         return ( (this->fDevice 
== stat_buf
.st_dev
) && (this->fInode 
== stat_buf
.st_ino
) );      
 197 const char* ImageLoader::shortName(const char* fullName
) 
 199         // try to return leaf name 
 200         if ( fullName 
!= NULL 
) { 
 201                 const char* s 
= strrchr(fullName
, '/'); 
 208 const char* ImageLoader::getShortName() const 
 210         return shortName(fPath
); 
 213 void ImageLoader::setLeaveMapped() 
 218 void ImageLoader::setHideExports(bool hide
) 
 223 bool ImageLoader::hasHiddenExports() const 
 228 bool ImageLoader::isLinked() const 
 230         return (fState 
>= dyld_image_state_bound
); 
 233 time_t ImageLoader::lastModified() const 
 235         return fLastModified
; 
 238 bool ImageLoader::containsAddress(const void* addr
) const 
 240         for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
 241                 const uint8_t* start 
= (const uint8_t*)segActualLoadAddress(i
); 
 242                 const uint8_t* end 
= (const uint8_t*)segActualEndAddress(i
); 
 243                 if ( (start 
<= addr
) && (addr 
< end
) && !segUnaccessible(i
) ) 
 249 bool ImageLoader::overlapsWithAddressRange(const void* start
, const void* end
) const 
 251         for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
 252                 const uint8_t* segStart 
= (const uint8_t*)segActualLoadAddress(i
); 
 253                 const uint8_t* segEnd 
= (const uint8_t*)segActualEndAddress(i
); 
 254                 if ( strcmp(segName(i
), "__UNIXSTACK") == 0 ) { 
 255                         // __UNIXSTACK never slides.  This is the only place that cares 
 256                         // and checking for that segment name in segActualLoadAddress() 
 258                         segStart 
-= getSlide(); 
 259                         segEnd 
-= getSlide(); 
 261                 if ( (start 
<= segStart
) && (segStart 
< end
) ) 
 263                 if ( (start 
<= segEnd
) && (segEnd 
< end
) ) 
 265                 if ( (segStart 
< start
) && (end 
< segEnd
) ) 
 271 void ImageLoader::getMappedRegions(MappedRegion
*& regions
) const 
 273         for(unsigned int i
=0, e
=segmentCount(); i 
< e
; ++i
) { 
 275                 region
.address 
= segActualLoadAddress(i
); 
 276                 region
.size 
= segSize(i
); 
 283 bool ImageLoader::dependsOn(ImageLoader
* image
) { 
 284         for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 285                 if ( libImage(i
) == image 
) 
 292 static bool notInImgageList(const ImageLoader
* image
, const ImageLoader
** dsiStart
, const ImageLoader
** dsiCur
) 
 294         for (const ImageLoader
** p 
= dsiStart
; p 
< dsiCur
; ++p
) 
 300 bool ImageLoader::findExportedSymbolAddress(const LinkContext
& context
, const char* symbolName
, 
 301                                                                                         const ImageLoader
* requestorImage
, int requestorOrdinalOfDef
, 
 302                                                                                         bool runResolver
, const ImageLoader
** foundIn
, uintptr_t* address
) const 
 304         const Symbol
* sym 
= this->findExportedSymbol(symbolName
, true, foundIn
); 
 306                 *address 
= (*foundIn
)->getExportedSymbolAddress(sym
, context
, requestorImage
, runResolver
); 
 313 // private method that handles circular dependencies by only search any image once 
 314 const ImageLoader::Symbol
* ImageLoader::findExportedSymbolInDependentImagesExcept(const char* name
,  
 315                         const ImageLoader
** dsiStart
, const ImageLoader
**& dsiCur
, const ImageLoader
** dsiEnd
, const ImageLoader
** foundIn
) const 
 317         const ImageLoader::Symbol
* sym
; 
 319         if ( notInImgageList(this, dsiStart
, dsiCur
) ) { 
 320                 sym 
= this->findExportedSymbol(name
, false, this->getPath(), foundIn
); 
 326         // search directly dependent libraries 
 327         for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 328                 ImageLoader
* dependentImage 
= libImage(i
); 
 329                 if ( (dependentImage 
!= NULL
) && notInImgageList(dependentImage
, dsiStart
, dsiCur
) ) { 
 330                         sym 
= dependentImage
->findExportedSymbol(name
, false, libPath(i
), foundIn
); 
 336         // search indirectly dependent libraries 
 337         for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 338                 ImageLoader
* dependentImage 
= libImage(i
); 
 339                 if ( (dependentImage 
!= NULL
) && notInImgageList(dependentImage
, dsiStart
, dsiCur
) ) { 
 340                         *dsiCur
++ = dependentImage
;  
 341                         sym 
= dependentImage
->findExportedSymbolInDependentImagesExcept(name
, dsiStart
, dsiCur
, dsiEnd
, foundIn
); 
 351 const ImageLoader::Symbol
* ImageLoader::findExportedSymbolInDependentImages(const char* name
, const LinkContext
& context
, const ImageLoader
** foundIn
) const 
 353         unsigned int imageCount 
= context
.imageCount()+2; 
 354         const ImageLoader
* dontSearchImages
[imageCount
]; 
 355         dontSearchImages
[0] = this; // don't search this image 
 356         const ImageLoader
** cur 
= &dontSearchImages
[1]; 
 357         return this->findExportedSymbolInDependentImagesExcept(name
, &dontSearchImages
[0], cur
, &dontSearchImages
[imageCount
], foundIn
); 
 360 const ImageLoader::Symbol
* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name
, const LinkContext
& context
, const ImageLoader
** foundIn
) const 
 362         unsigned int imageCount 
= context
.imageCount()+2; 
 363         const ImageLoader
* dontSearchImages
[imageCount
]; 
 364         const ImageLoader
** cur 
= &dontSearchImages
[0]; 
 365         return this->findExportedSymbolInDependentImagesExcept(name
, &dontSearchImages
[0], cur
, &dontSearchImages
[imageCount
], foundIn
); 
 368 // this is called by initializeMainExecutable() to interpose on the initial set of images 
 369 void ImageLoader::applyInterposing(const LinkContext
& context
) 
 371         if ( fgInterposingTuples
.size() != 0 ) 
 372                 this->recursiveApplyInterposing(context
); 
 376 uintptr_t ImageLoader::interposedAddress(const LinkContext
& context
, uintptr_t address
, const ImageLoader
* inImage
, const ImageLoader
* onlyInImage
) 
 378         //dyld::log("interposedAddress(0x%08llX), tupleCount=%lu\n", (uint64_t)address, fgInterposingTuples.size()); 
 379         for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it 
!= fgInterposingTuples
.end(); it
++) { 
 380                 //dyld::log("    interposedAddress: replacee=0x%08llX, replacement=0x%08llX, neverImage=%p, onlyImage=%p, inImage=%p\n",  
 381                 //                              (uint64_t)it->replacee, (uint64_t)it->replacement,  it->neverImage, it->onlyImage, inImage); 
 382                 // replace all references to 'replacee' with 'replacement' 
 383                 if ( (address 
== it
->replacee
) && (inImage 
!= it
->neverImage
) && ((it
->onlyImage 
== NULL
) || (inImage 
== it
->onlyImage
)) ) { 
 384                         if ( context
.verboseInterposing 
) { 
 385                                 dyld::log("dyld interposing: replace 0x%lX with 0x%lX\n", it
->replacee
, it
->replacement
); 
 387                         return it
->replacement
; 
 393 void ImageLoader::addDynamicInterposingTuples(const struct dyld_interpose_tuple array
[], size_t count
) 
 395         for(size_t i
=0; i 
< count
; ++i
) { 
 396                 ImageLoader::InterposeTuple tuple
; 
 397                 tuple
.replacement               
= (uintptr_t)array
[i
].replacement
; 
 398                 tuple
.neverImage                
= NULL
; 
 399                 tuple
.onlyImage             
= this; 
 400                 tuple
.replacee                  
= (uintptr_t)array
[i
].replacee
; 
 401                 // chain to any existing interpositions 
 402                 for (std::vector
<InterposeTuple
>::iterator it
=fgInterposingTuples
.begin(); it 
!= fgInterposingTuples
.end(); it
++) { 
 403                         if ( (it
->replacee 
== tuple
.replacee
) && (it
->onlyImage 
== this) ) { 
 404                                 tuple
.replacee 
= it
->replacement
; 
 407                 ImageLoader::fgInterposingTuples
.push_back(tuple
); 
 412 void ImageLoader::link(const LinkContext
& context
, bool forceLazysBound
, bool preflightOnly
, bool neverUnload
, const RPathChain
& loaderRPaths
, const char* imagePath
) 
 414         //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", imagePath, fDlopenReferenceCount, fNeverUnload); 
 416         // clear error strings 
 417         (*context
.setErrorStrings
)(0, NULL
, NULL
, NULL
); 
 419         uint64_t t0 
= mach_absolute_time(); 
 420         this->recursiveLoadLibraries(context
, preflightOnly
, loaderRPaths
, imagePath
); 
 421         context
.notifyBatch(dyld_image_state_dependents_mapped
, preflightOnly
); 
 423         // we only do the loading step for preflights 
 427         uint64_t t1 
= mach_absolute_time(); 
 428         context
.clearAllDepths(); 
 429         this->recursiveUpdateDepth(context
.imageCount()); 
 431         uint64_t t2 
= mach_absolute_time(); 
 432         this->recursiveRebase(context
); 
 433         context
.notifyBatch(dyld_image_state_rebased
, false); 
 435         uint64_t t3 
= mach_absolute_time(); 
 436         this->recursiveBind(context
, forceLazysBound
, neverUnload
); 
 438         uint64_t t4 
= mach_absolute_time(); 
 439         if ( !context
.linkingMainExecutable 
) 
 440                 this->weakBind(context
); 
 441         uint64_t t5 
= mach_absolute_time();      
 443         context
.notifyBatch(dyld_image_state_bound
, false); 
 444         uint64_t t6 
= mach_absolute_time();      
 446         std::vector
<DOFInfo
> dofs
; 
 447         this->recursiveGetDOFSections(context
, dofs
); 
 448         context
.registerDOFs(dofs
); 
 449         uint64_t t7 
= mach_absolute_time();      
 451         // interpose any dynamically loaded images 
 452         if ( !context
.linkingMainExecutable 
&& (fgInterposingTuples
.size() != 0) ) { 
 453                 this->recursiveApplyInterposing(context
); 
 456         // clear error strings 
 457         (*context
.setErrorStrings
)(0, NULL
, NULL
, NULL
); 
 459         fgTotalLoadLibrariesTime 
+= t1 
- t0
; 
 460         fgTotalRebaseTime 
+= t3 
- t2
; 
 461         fgTotalBindTime 
+= t4 
- t3
; 
 462         fgTotalWeakBindTime 
+= t5 
- t4
; 
 463         fgTotalDOF 
+= t7 
- t6
; 
 465         // done with initial dylib loads 
 466         fgNextPIEDylibAddress 
= 0; 
 470 void ImageLoader::printReferenceCounts() 
 472         dyld::log("      dlopen=%d for %s\n", fDlopenReferenceCount
, getPath() ); 
 476 bool ImageLoader::decrementDlopenReferenceCount()  
 478         if ( fDlopenReferenceCount 
== 0 ) 
 480         --fDlopenReferenceCount
; 
 485 // <rdar://problem/14412057> upward dylib initializers can be run too soon 
 486 // To handle dangling dylibs which are upward linked but not downward, all upward linked dylibs 
 487 // have their initialization postponed until after the recursion through downward dylibs 
 489 void ImageLoader::processInitializers(const LinkContext
& context
, mach_port_t thisThread
, 
 490                                                                          InitializerTimingList
& timingInfo
, ImageLoader::UninitedUpwards
& images
) 
 492         uint32_t maxImageCount 
= context
.imageCount()+2; 
 493         ImageLoader::UninitedUpwards upsBuffer
[maxImageCount
]; 
 494         ImageLoader::UninitedUpwards
& ups 
= upsBuffer
[0]; 
 496         // Calling recursive init on all images in images list, building a new list of 
 497         // uninitialized upward dependencies. 
 498         for (uintptr_t i
=0; i 
< images
.count
; ++i
) { 
 499                 images
.images
[i
]->recursiveInitialization(context
, thisThread
, images
.images
[i
]->getPath(), timingInfo
, ups
); 
 501         // If any upward dependencies remain, init them. 
 503                 processInitializers(context
, thisThread
, timingInfo
, ups
); 
 507 void ImageLoader::runInitializers(const LinkContext
& context
, InitializerTimingList
& timingInfo
) 
 509         uint64_t t1 
= mach_absolute_time(); 
 510         mach_port_t thisThread 
= mach_thread_self(); 
 511         ImageLoader::UninitedUpwards up
; 
 514         processInitializers(context
, thisThread
, timingInfo
, up
); 
 515         context
.notifyBatch(dyld_image_state_initialized
, false); 
 516         mach_port_deallocate(mach_task_self(), thisThread
); 
 517         uint64_t t2 
= mach_absolute_time(); 
 518         fgTotalInitTime 
+= (t2 
- t1
); 
 522 void ImageLoader::bindAllLazyPointers(const LinkContext
& context
, bool recursive
) 
 524         if ( ! fAllLazyPointersBound 
) { 
 525                 fAllLazyPointersBound 
= true; 
 528                         // bind lower level libraries first 
 529                         for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 530                                 ImageLoader
* dependentImage 
= libImage(i
); 
 531                                 if ( dependentImage 
!= NULL 
) 
 532                                         dependentImage
->bindAllLazyPointers(context
, recursive
); 
 535                 // bind lazies in this image 
 536                 this->doBindJustLazies(context
); 
 541 bool ImageLoader::allDependentLibrariesAsWhenPreBound() const 
 543         return fAllLibraryChecksumsAndLoadAddressesMatch
; 
 547 void ImageLoader::markedUsedRecursive(const std::vector
<DynamicReference
>& dynamicReferences
) 
 549         // already visited here 
 554         // clear mark on all statically dependent dylibs 
 555         for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 556                 ImageLoader
* dependentImage 
= libImage(i
); 
 557                 if ( dependentImage 
!= NULL 
) { 
 558                         dependentImage
->markedUsedRecursive(dynamicReferences
); 
 562         // clear mark on all dynamically dependent dylibs 
 563         for (std::vector
<ImageLoader::DynamicReference
>::const_iterator it
=dynamicReferences
.begin(); it 
!= dynamicReferences
.end(); ++it
) { 
 564                 if ( it
->from 
== this ) 
 565                         it
->to
->markedUsedRecursive(dynamicReferences
); 
 570 unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth
) 
 572         // the purpose of this phase is to make the images sortable such that  
 573         // in a sort list of images, every image that an image depends on 
 574         // occurs in the list before it. 
 579                 // get depth of dependents 
 580                 unsigned int minDependentDepth 
= maxDepth
; 
 581                 for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 582                         ImageLoader
* dependentImage 
= libImage(i
); 
 583                         if ( (dependentImage 
!= NULL
) && !libIsUpward(i
) ) { 
 584                                 unsigned int d 
= dependentImage
->recursiveUpdateDepth(maxDepth
); 
 585                                 if ( d 
< minDependentDepth 
) 
 586                                         minDependentDepth 
= d
; 
 590                 // make me less deep then all my dependents 
 591                 fDepth 
= minDependentDepth 
- 1; 
 598 void ImageLoader::recursiveLoadLibraries(const LinkContext
& context
, bool preflightOnly
, const RPathChain
& loaderRPaths
, const char* loadPath
) 
 600         if ( fState 
< dyld_image_state_dependents_mapped 
) { 
 602                 fState 
= dyld_image_state_dependents_mapped
; 
 604                 // get list of libraries this image needs 
 605                 DependentLibraryInfo libraryInfos
[fLibraryCount
];  
 606                 this->doGetDependentLibraries(libraryInfos
); 
 608                 // get list of rpaths that this image adds 
 609                 std::vector
<const char*> rpathsFromThisImage
; 
 610                 this->getRPaths(context
, rpathsFromThisImage
); 
 611                 const RPathChain 
thisRPaths(&loaderRPaths
, &rpathsFromThisImage
); 
 614                 bool canUsePrelinkingInfo 
= true;  
 615                 for(unsigned int i
=0; i 
< fLibraryCount
; ++i
){ 
 616                         ImageLoader
* dependentLib
; 
 617                         bool depLibReExported 
= false; 
 618                         bool depLibRequired 
= false; 
 619                         bool depLibCheckSumsMatch 
= false; 
 620                         DependentLibraryInfo
& requiredLibInfo 
= libraryInfos
[i
]; 
 621 #if DYLD_SHARED_CACHE_SUPPORT 
 622                         if ( preflightOnly 
&& context
.inSharedCache(requiredLibInfo
.name
) ) { 
 623                                 // <rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized 
 624                                 // in preflight mode, don't even load dylib that are in the shared cache because they will never be unloaded 
 625                                 setLibImage(i
, NULL
, false, false); 
 631                                 dependentLib 
= context
.loadLibrary(requiredLibInfo
.name
, true, this->getPath(), &thisRPaths
, cacheIndex
); 
 632                                 if ( dependentLib 
== this ) { 
 633                                         // found circular reference, perhaps DYLD_LIBARY_PATH is causing this rdar://problem/3684168  
 634                                         dependentLib 
= context
.loadLibrary(requiredLibInfo
.name
, false, NULL
, NULL
, cacheIndex
); 
 635                                         if ( dependentLib 
!= this ) 
 636                                                 dyld::warn("DYLD_ setting caused circular dependency in %s\n", this->getPath()); 
 639                                         dependentLib
->setNeverUnload(); 
 640                                 if ( requiredLibInfo
.upward 
) { 
 643                                         dependentLib
->fIsReferencedDownward 
= true; 
 645                                 LibraryInfo actualInfo 
= dependentLib
->doGetLibraryInfo(requiredLibInfo
.info
); 
 646                                 depLibRequired 
= requiredLibInfo
.required
; 
 647                                 depLibCheckSumsMatch 
= ( actualInfo
.checksum 
== requiredLibInfo
.info
.checksum 
); 
 648                                 depLibReExported 
= requiredLibInfo
.reExported
; 
 649                                 if ( ! depLibReExported 
) { 
 650                                         // for pre-10.5 binaries that did not use LC_REEXPORT_DYLIB 
 651                                         depLibReExported 
= dependentLib
->isSubframeworkOf(context
, this) || this->hasSubLibrary(context
, dependentLib
); 
 653                                 // check found library version is compatible 
 654                                 // <rdar://problem/89200806> 0xFFFFFFFF is wildcard that matches any version 
 655                                 if ( (requiredLibInfo
.info
.minVersion 
!= 0xFFFFFFFF) && (actualInfo
.minVersion 
< requiredLibInfo
.info
.minVersion
) ) { 
 656                                         // record values for possible use by CrashReporter or Finder 
 657                                         dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d", 
 658                                                         this->getShortName(), requiredLibInfo
.info
.minVersion 
>> 16, (requiredLibInfo
.info
.minVersion 
>> 8) & 0xff, requiredLibInfo
.info
.minVersion 
& 0xff, 
 659                                                         dependentLib
->getShortName(), actualInfo
.minVersion 
>> 16, (actualInfo
.minVersion 
>> 8) & 0xff, actualInfo
.minVersion 
& 0xff); 
 661                                 // prebinding for this image disabled if any dependent library changed 
 662                                 //if ( !depLibCheckSumsMatch ) 
 663                                 //      canUsePrelinkingInfo = false; 
 664                                 // prebinding for this image disabled unless both this and dependent are in the shared cache 
 665                                 if ( !dependentLib
->inSharedCache() || !this->inSharedCache() ) 
 666                                         canUsePrelinkingInfo 
= false; 
 668                                 //if ( context.verbosePrebinding ) { 
 669                                 //      if ( !requiredLib.checksumMatches ) 
 670                                 //              fprintf(stderr, "dyld: checksum mismatch, (%u v %u) for %s referencing %s\n",  
 671                                 //                      requiredLibInfo.info.checksum, actualInfo.checksum, this->getPath(),    dependentLib->getPath());                
 672                                 //      if ( dependentLib->getSlide() != 0 ) 
 673                                 //              fprintf(stderr, "dyld: dependent library slid for %s referencing %s\n", this->getPath(), dependentLib->getPath());               
 676                         catch (const char* msg
) { 
 677                                 //if ( context.verbosePrebinding ) 
 678                                 //      fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), dependentLib->getPath());          
 679                                 if ( requiredLibInfo
.required 
) { 
 680                                         fState 
= dyld_image_state_mapped
; 
 681                                         // record values for possible use by CrashReporter or Finder 
 682                                         if ( strstr(msg
, "Incompatible library version") != NULL 
) 
 683                                                 (*context
.setErrorStrings
)(DYLD_EXIT_REASON_DYLIB_WRONG_VERSION
, this->getPath(), requiredLibInfo
.name
, NULL
); 
 684                                         else if ( strstr(msg
, "architecture") != NULL 
) 
 685                                                 (*context
.setErrorStrings
)(DYLD_EXIT_REASON_DYLIB_WRONG_ARCH
, this->getPath(), requiredLibInfo
.name
, NULL
); 
 686                                         else if ( strstr(msg
, "file system sandbox") != NULL 
) 
 687                                                 (*context
.setErrorStrings
)(DYLD_EXIT_REASON_FILE_SYSTEM_SANDBOX
, this->getPath(), requiredLibInfo
.name
, NULL
); 
 688                                         else if ( strstr(msg
, "code signature") != NULL 
) 
 689                                                 (*context
.setErrorStrings
)(DYLD_EXIT_REASON_CODE_SIGNATURE
, this->getPath(), requiredLibInfo
.name
, NULL
); 
 690                                         else if ( strstr(msg
, "malformed") != NULL 
) 
 691                                                 (*context
.setErrorStrings
)(DYLD_EXIT_REASON_MALFORMED_MACHO
, this->getPath(), requiredLibInfo
.name
, NULL
); 
 693                                                 (*context
.setErrorStrings
)(DYLD_EXIT_REASON_DYLIB_MISSING
, this->getPath(), requiredLibInfo
.name
, NULL
); 
 694                                         const char* newMsg 
= dyld::mkstringf("Library not loaded: %s\n  Referenced from: %s\n  Reason: %s", requiredLibInfo
.name
, this->getRealPath(), msg
); 
 695                                         free((void*)msg
);       // our free() will do nothing if msg is a string literal 
 698                                 free((void*)msg
);       // our free() will do nothing if msg is a string literal 
 699                                 // ok if weak library not found 
 701                                 canUsePrelinkingInfo 
= false;  // this disables all prebinding, we may want to just slam import vectors for this lib to zero 
 703                         setLibImage(i
, dependentLib
, depLibReExported
, requiredLibInfo
.upward
); 
 705                 fAllLibraryChecksumsAndLoadAddressesMatch 
= canUsePrelinkingInfo
; 
 707                 // tell each to load its dependents 
 708                 for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 709                         ImageLoader
* dependentImage 
= libImage(i
); 
 710                         if ( dependentImage 
!= NULL 
) {  
 711                                 dependentImage
->recursiveLoadLibraries(context
, preflightOnly
, thisRPaths
, libraryInfos
[i
].name
); 
 715                 // do deep prebind check 
 716                 if ( fAllLibraryChecksumsAndLoadAddressesMatch 
) { 
 717                         for(unsigned int i
=0; i 
< libraryCount(); ++i
){ 
 718                                 ImageLoader
* dependentImage 
= libImage(i
); 
 719                                 if ( dependentImage 
!= NULL 
) {  
 720                                         if ( !dependentImage
->allDependentLibrariesAsWhenPreBound() ) 
 721                                                 fAllLibraryChecksumsAndLoadAddressesMatch 
= false; 
 726                 // free rpaths (getRPaths() malloc'ed each string) 
 727                 for(std::vector
<const char*>::iterator it
=rpathsFromThisImage
.begin(); it 
!= rpathsFromThisImage
.end(); ++it
) { 
 728                         const char* str 
= *it
; 
 735 void ImageLoader::recursiveRebase(const LinkContext
& context
) 
 737         if ( fState 
< dyld_image_state_rebased 
) { 
 739                 fState 
= dyld_image_state_rebased
; 
 742                         // rebase lower level libraries first 
 743                         for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 744                                 ImageLoader
* dependentImage 
= libImage(i
); 
 745                                 if ( dependentImage 
!= NULL 
) 
 746                                         dependentImage
->recursiveRebase(context
); 
 753                         context
.notifySingle(dyld_image_state_rebased
, this, NULL
); 
 755                 catch (const char* msg
) { 
 756                         // this image is not rebased 
 757                         fState 
= dyld_image_state_dependents_mapped
; 
 758             CRSetCrashLogMessage2(NULL
); 
 764 void ImageLoader::recursiveApplyInterposing(const LinkContext
& context
) 
 766         if ( ! fInterposed 
) { 
 771                         // interpose lower level libraries first 
 772                         for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 773                                 ImageLoader
* dependentImage 
= libImage(i
); 
 774                                 if ( dependentImage 
!= NULL 
) 
 775                                         dependentImage
->recursiveApplyInterposing(context
); 
 778                         // interpose this image 
 779                         doInterpose(context
); 
 781                 catch (const char* msg
) { 
 782                         // this image is not interposed 
 791 void ImageLoader::recursiveBind(const LinkContext
& context
, bool forceLazysBound
, bool neverUnload
) 
 793         // Normally just non-lazy pointers are bound immediately. 
 794         // The exceptions are: 
 795         //   1) DYLD_BIND_AT_LAUNCH will cause lazy pointers to be bound immediately 
 796         //   2) some API's (e.g. RTLD_NOW) can cause lazy pointers to be bound immediately 
 797         if ( fState 
< dyld_image_state_bound 
) { 
 799                 fState 
= dyld_image_state_bound
; 
 802                         // bind lower level libraries first 
 803                         for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 804                                 ImageLoader
* dependentImage 
= libImage(i
); 
 805                                 if ( dependentImage 
!= NULL 
) 
 806                                         dependentImage
->recursiveBind(context
, forceLazysBound
, neverUnload
); 
 809                         this->doBind(context
, forceLazysBound
);  
 810                         // mark if lazys are also bound 
 811                         if ( forceLazysBound 
|| this->usablePrebinding(context
) ) 
 812                                 fAllLazyPointersBound 
= true; 
 813                         // mark as never-unload if requested 
 815                                 this->setNeverUnload(); 
 817                         context
.notifySingle(dyld_image_state_bound
, this, NULL
); 
 819                 catch (const char* msg
) { 
 821                         fState 
= dyld_image_state_rebased
; 
 822             CRSetCrashLogMessage2(NULL
); 
 828 void ImageLoader::weakBind(const LinkContext
& context
) 
 830         if ( context
.verboseWeakBind 
) 
 831                 dyld::log("dyld: weak bind start:\n"); 
 832         uint64_t t1 
= mach_absolute_time(); 
 833         // get set of ImageLoaders that participate in coalecsing 
 834         ImageLoader
* imagesNeedingCoalescing
[fgImagesRequiringCoalescing
]; 
 835         unsigned imageIndexes
[fgImagesRequiringCoalescing
]; 
 836         int count 
= context
.getCoalescedImages(imagesNeedingCoalescing
, imageIndexes
); 
 838         // count how many have not already had weakbinding done 
 839         int countNotYetWeakBound 
= 0; 
 840         int countOfImagesWithWeakDefinitionsNotInSharedCache 
= 0; 
 841         for(int i
=0; i 
< count
; ++i
) { 
 842                 if ( ! imagesNeedingCoalescing
[i
]->weakSymbolsBound(imageIndexes
[i
]) ) 
 843                         ++countNotYetWeakBound
; 
 844                 if ( ! imagesNeedingCoalescing
[i
]->inSharedCache() ) 
 845                         ++countOfImagesWithWeakDefinitionsNotInSharedCache
; 
 848         // don't need to do any coalescing if only one image has overrides, or all have already been done 
 849         if ( (countOfImagesWithWeakDefinitionsNotInSharedCache 
> 0) && (countNotYetWeakBound 
> 0) ) { 
 850                 // make symbol iterators for each 
 851                 ImageLoader::CoalIterator iterators
[count
]; 
 852                 ImageLoader::CoalIterator
* sortedIts
[count
]; 
 853                 for(int i
=0; i 
< count
; ++i
) { 
 854                         imagesNeedingCoalescing
[i
]->initializeCoalIterator(iterators
[i
], i
, imageIndexes
[i
]); 
 855                         sortedIts
[i
] = &iterators
[i
]; 
 856                         if ( context
.verboseWeakBind 
) 
 857                                 dyld::log("dyld: weak bind load order %d/%d for %s\n", i
, count
, imagesNeedingCoalescing
[i
]->getIndexedPath(imageIndexes
[i
])); 
 860                 // walk all symbols keeping iterators in sync by  
 861                 // only ever incrementing the iterator with the lowest symbol  
 863                 while ( doneCount 
!= count 
) { 
 864                         //for(int i=0; i < count; ++i) 
 865                         //      dyld::log("sym[%d]=%s ", sortedIts[i]->loadOrder, sortedIts[i]->symbolName); 
 867                         // increment iterator with lowest symbol 
 868                         if ( sortedIts
[0]->image
->incrementCoalIterator(*sortedIts
[0]) ) 
 871                         for(int i
=1; i 
< count
; ++i
) { 
 872                                 int result 
= strcmp(sortedIts
[i
-1]->symbolName
, sortedIts
[i
]->symbolName
); 
 874                                         sortedIts
[i
-1]->symbolMatches 
= true; 
 876                                         // new one is bigger then next, so swap 
 877                                         ImageLoader::CoalIterator
* temp 
= sortedIts
[i
-1]; 
 878                                         sortedIts
[i
-1] = sortedIts
[i
]; 
 884                         // process all matching symbols just before incrementing the lowest one that matches 
 885                         if ( sortedIts
[0]->symbolMatches 
&& !sortedIts
[0]->done 
) { 
 886                                 const char* nameToCoalesce 
= sortedIts
[0]->symbolName
; 
 887                                 // pick first symbol in load order (and non-weak overrides weak) 
 888                                 uintptr_t targetAddr 
= 0; 
 889                                 ImageLoader
* targetImage 
= NULL
; 
 890                                 unsigned targetImageIndex 
= 0; 
 891                                 for(int i
=0; i 
< count
; ++i
) { 
 892                                         if ( strcmp(iterators
[i
].symbolName
, nameToCoalesce
) == 0 ) { 
 893                                                 if ( context
.verboseWeakBind 
) 
 894                                                         dyld::log("dyld: weak bind, found %s weak=%d in %s \n", nameToCoalesce
, iterators
[i
].weakSymbol
, iterators
[i
].image
->getIndexedPath((unsigned)iterators
[i
].imageIndex
)); 
 895                                                 if ( iterators
[i
].weakSymbol 
) { 
 896                                                         if ( targetAddr 
== 0 ) { 
 897                                                                 targetAddr 
= iterators
[i
].image
->getAddressCoalIterator(iterators
[i
], context
); 
 898                                                                 if ( targetAddr 
!= 0 ) { 
 899                                                                         targetImage 
= iterators
[i
].image
; 
 900                                                                         targetImageIndex 
= (unsigned)iterators
[i
].imageIndex
; 
 905                                                         targetAddr 
= iterators
[i
].image
->getAddressCoalIterator(iterators
[i
], context
); 
 906                                                         if ( targetAddr 
!= 0 ) { 
 907                                                                 targetImage 
= iterators
[i
].image
; 
 908                                                                 targetImageIndex 
= (unsigned)iterators
[i
].imageIndex
; 
 909                                                                 // strong implementation found, stop searching 
 915                                 // tell each to bind to this symbol (unless already bound) 
 916                                 if ( targetAddr 
!= 0 ) { 
 917                                         if ( context
.verboseWeakBind 
) { 
 918                                                 dyld::log("dyld: weak binding all uses of %s to copy from %s\n", 
 919                                                                         nameToCoalesce
, targetImage
->getIndexedShortName(targetImageIndex
)); 
 921                                         for(int i
=0; i 
< count
; ++i
) { 
 922                                                 if ( strcmp(iterators
[i
].symbolName
, nameToCoalesce
) == 0 ) { 
 923                                                         if ( context
.verboseWeakBind 
) { 
 924                                                                 dyld::log("dyld: weak bind, setting all uses of %s in %s to 0x%lX from %s\n", 
 925                                                                                         nameToCoalesce
, iterators
[i
].image
->getIndexedShortName((unsigned)iterators
[i
].imageIndex
), 
 926                                                                                         targetAddr
, targetImage
->getIndexedShortName(targetImageIndex
)); 
 928                                                         if ( ! iterators
[i
].image
->weakSymbolsBound(imageIndexes
[i
]) ) 
 929                                                                 iterators
[i
].image
->updateUsesCoalIterator(iterators
[i
], targetAddr
, targetImage
, targetImageIndex
, context
); 
 930                                                         iterators
[i
].symbolMatches 
= false;  
 938                 // mark all as having all weak symbols bound 
 939                 for(int i
=0; i 
< count
; ++i
) { 
 940                         imagesNeedingCoalescing
[i
]->setWeakSymbolsBound(imageIndexes
[i
]); 
 943         uint64_t t2 
= mach_absolute_time(); 
 944         fgTotalWeakBindTime 
+= t2  
- t1
; 
 946         if ( context
.verboseWeakBind 
) 
 947                 dyld::log("dyld: weak bind end\n"); 
 952 void ImageLoader::recursiveGetDOFSections(const LinkContext
& context
, std::vector
<DOFInfo
>& dofs
) 
 954         if ( ! fRegisteredDOF 
) { 
 956                 fRegisteredDOF 
= true; 
 958                 // gather lower level libraries first 
 959                 for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 960                         ImageLoader
* dependentImage 
= libImage(i
); 
 961                         if ( dependentImage 
!= NULL 
) 
 962                                 dependentImage
->recursiveGetDOFSections(context
, dofs
); 
 964                 this->doGetDOFSections(context
, dofs
); 
 968 void ImageLoader::setNeverUnloadRecursive() { 
 969         if ( ! fNeverUnload 
) { 
 973                 // gather lower level libraries first 
 974                 for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
 975                         ImageLoader
* dependentImage 
= libImage(i
); 
 976                         if ( dependentImage 
!= NULL 
) 
 977                                 dependentImage
->setNeverUnloadRecursive(); 
 982 void ImageLoader::recursiveSpinLock(recursive_lock
& rlock
) 
 984         // try to set image's ivar fInitializerRecursiveLock to point to this lock_info 
 985         // keep trying until success (spin) 
 986         while ( ! OSAtomicCompareAndSwapPtrBarrier(NULL
, &rlock
, (void**)&fInitializerRecursiveLock
) ) { 
 987                 // if fInitializerRecursiveLock already points to a different lock_info, if it is for 
 988                 // the same thread we are on, the increment the lock count, otherwise continue to spin 
 989                 if ( (fInitializerRecursiveLock 
!= NULL
) && (fInitializerRecursiveLock
->thread 
== rlock
.thread
) ) 
 992         ++(fInitializerRecursiveLock
->count
);  
 995 void ImageLoader::recursiveSpinUnLock() 
 997         if ( --(fInitializerRecursiveLock
->count
) == 0 ) 
 998                 fInitializerRecursiveLock 
= NULL
; 
1001 void ImageLoader::InitializerTimingList::addTime(const char* name
, uint64_t time
) 
1003         for (int i
=0; i 
< count
; ++i
) { 
1004                 if ( strcmp(images
[i
].shortName
, name
) == 0 ) { 
1005                         images
[i
].initTime 
+= time
; 
1009         images
[count
].initTime 
= time
; 
1010         images
[count
].shortName 
= name
; 
1014 void ImageLoader::recursiveInitialization(const LinkContext
& context
, mach_port_t this_thread
, const char* pathToInitialize
, 
1015                                                                                   InitializerTimingList
& timingInfo
, UninitedUpwards
& uninitUps
) 
1017         recursive_lock 
lock_info(this_thread
); 
1018         recursiveSpinLock(lock_info
); 
1020         if ( fState 
< dyld_image_state_dependents_initialized
-1 ) { 
1021                 uint8_t oldState 
= fState
; 
1023                 fState 
= dyld_image_state_dependents_initialized
-1; 
1025                         // initialize lower level libraries first 
1026                         for(unsigned int i
=0; i 
< libraryCount(); ++i
) { 
1027                                 ImageLoader
* dependentImage 
= libImage(i
); 
1028                                 if ( dependentImage 
!= NULL 
) { 
1029                                         // don't try to initialize stuff "above" me yet 
1030                                         if ( libIsUpward(i
) ) { 
1031                                                 uninitUps
.images
[uninitUps
.count
] = dependentImage
; 
1034                                         else if ( dependentImage
->fDepth 
>= fDepth 
) { 
1035                                                 dependentImage
->recursiveInitialization(context
, this_thread
, libPath(i
), timingInfo
, uninitUps
); 
1040                         // record termination order 
1041                         if ( this->needsTermination() ) 
1042                                 context
.terminationRecorder(this); 
1044                         // let objc know we are about to initialize this image 
1045                         uint64_t t1 
= mach_absolute_time(); 
1046                         fState 
= dyld_image_state_dependents_initialized
; 
1048                         context
.notifySingle(dyld_image_state_dependents_initialized
, this, &timingInfo
); 
1050                         // initialize this image 
1051                         bool hasInitializers 
= this->doInitialization(context
); 
1053                         // let anyone know we finished initializing this image 
1054                         fState 
= dyld_image_state_initialized
; 
1056                         context
.notifySingle(dyld_image_state_initialized
, this, NULL
); 
1058                         if ( hasInitializers 
) { 
1059                                 uint64_t t2 
= mach_absolute_time(); 
1060                                 timingInfo
.addTime(this->getShortName(), t2
-t1
); 
1063                 catch (const char* msg
) { 
1064                         // this image is not initialized 
1066                         recursiveSpinUnLock(); 
1071         recursiveSpinUnLock(); 
1075 static void printTime(const char* msg
, uint64_t partTime
, uint64_t totalTime
) 
1077         static uint64_t sUnitsPerSecond 
= 0; 
1078         if ( sUnitsPerSecond 
== 0 ) { 
1079                 struct mach_timebase_info timeBaseInfo
; 
1080                 if ( mach_timebase_info(&timeBaseInfo
) == KERN_SUCCESS 
) { 
1081                         sUnitsPerSecond 
= 1000000000ULL * timeBaseInfo
.denom 
/ timeBaseInfo
.numer
; 
1084         if ( partTime 
< sUnitsPerSecond 
) { 
1085                 uint32_t milliSecondsTimesHundred 
= (uint32_t)((partTime
*100000)/sUnitsPerSecond
); 
1086                 uint32_t milliSeconds 
= (uint32_t)(milliSecondsTimesHundred
/100); 
1087                 uint32_t percentTimesTen 
= (uint32_t)((partTime
*1000)/totalTime
); 
1088                 uint32_t percent 
= percentTimesTen
/10; 
1089                 if ( milliSeconds 
>= 100 ) 
1090                         dyld::log("%s: %u.%02u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimesHundred
-milliSeconds
*100, percent
, percentTimesTen
-percent
*10); 
1091                 else if ( milliSeconds 
>= 10 ) 
1092                         dyld::log("%s:  %u.%02u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimesHundred
-milliSeconds
*100, percent
, percentTimesTen
-percent
*10); 
1094                         dyld::log("%s:   %u.%02u milliseconds (%u.%u%%)\n", msg
, milliSeconds
, milliSecondsTimesHundred
-milliSeconds
*100, percent
, percentTimesTen
-percent
*10); 
1097                 uint32_t secondsTimeTen 
= (uint32_t)((partTime
*10)/sUnitsPerSecond
); 
1098                 uint32_t seconds 
= secondsTimeTen
/10; 
1099                 uint32_t percentTimesTen 
= (uint32_t)((partTime
*1000)/totalTime
); 
1100                 uint32_t percent 
= percentTimesTen
/10; 
1101                 dyld::log("%s: %u.%u seconds (%u.%u%%)\n", msg
, seconds
, secondsTimeTen
-seconds
*10, percent
, percentTimesTen
-percent
*10); 
1105 static char* commatize(uint64_t in
, char* out
) 
1107         uint64_t div10 
= in 
/ 10; 
1108         uint8_t delta 
= in 
- div10
*10; 
1112         *(--s
) = '0' + delta
; 
1115                 if ( (digitCount 
% 3) == 0 ) 
1118                 delta 
= in 
- div10
*10; 
1119                 *(--s
) = '0' + delta
; 
1127 void ImageLoader::printStatistics(unsigned int imageCount
, const InitializerTimingList
& timingInfo
) 
1129         uint64_t totalTime 
= fgTotalLoadLibrariesTime  
+ fgTotalRebaseTime 
+ fgTotalBindTime 
+ fgTotalWeakBindTime 
+ fgTotalDOF 
+ fgTotalInitTime
; 
1131         uint64_t totalDyldTime 
= totalTime 
- fgTotalDebuggerPausedTime 
- fgTotalRebindCacheTime
; 
1132         printTime("Total pre-main time", totalDyldTime
, totalDyldTime
); 
1133         printTime("         dylib loading time", fgTotalLoadLibrariesTime
-fgTotalDebuggerPausedTime
, totalDyldTime
); 
1134         printTime("        rebase/binding time", fgTotalRebaseTime
+fgTotalBindTime
+fgTotalWeakBindTime
-fgTotalRebindCacheTime
, totalDyldTime
); 
1135         printTime("            ObjC setup time", fgTotalObjCSetupTime
, totalDyldTime
); 
1136         printTime("           initializer time", fgTotalInitTime
-fgTotalObjCSetupTime
, totalDyldTime
); 
1137         dyld::log("           slowest intializers :\n"); 
1138         for (uintptr_t i
=0; i 
< timingInfo
.count
; ++i
) { 
1139                 uint64_t t 
= timingInfo
.images
[i
].initTime
; 
1140                 if ( t
*50 < totalDyldTime 
) 
1142                 dyld::log("%30s ", timingInfo
.images
[i
].shortName
); 
1143                 if ( strncmp(timingInfo
.images
[i
].shortName
, "libSystem.", 10) == 0 ) 
1144                         t 
-= fgTotalObjCSetupTime
; 
1145                         printTime("", t
, totalDyldTime
); 
1150 void ImageLoader::printStatisticsDetails(unsigned int imageCount
, const InitializerTimingList
& timingInfo
) 
1152         uint64_t totalTime 
= fgTotalLoadLibrariesTime  
+ fgTotalRebaseTime 
+ fgTotalBindTime 
+ fgTotalWeakBindTime 
+ fgTotalDOF 
+ fgTotalInitTime
; 
1156         printTime("  total time", totalTime
, totalTime
); 
1157         dyld::log("  total images loaded:  %d (%u from dyld shared cache)\n", imageCount
, fgImagesUsedFromSharedCache
); 
1158         dyld::log("  total segments mapped: %u, into %llu pages with %llu pages pre-fetched\n", fgTotalSegmentsMapped
, fgTotalBytesMapped
/4096, fgTotalBytesPreFetched
/4096); 
1159         printTime("  total images loading time", fgTotalLoadLibrariesTime
, totalTime
); 
1160         printTime("  total load time in ObjC", fgTotalObjCSetupTime
, totalTime
); 
1161         printTime("  total debugger pause time", fgTotalDebuggerPausedTime
, totalTime
); 
1162         printTime("  total dtrace DOF registration time", fgTotalDOF
, totalTime
); 
1163         dyld::log("  total rebase fixups:  %s\n", commatize(fgTotalRebaseFixups
, commaNum1
)); 
1164         printTime("  total rebase fixups time", fgTotalRebaseTime
, totalTime
); 
1165         dyld::log("  total binding fixups: %s\n", commatize(fgTotalBindFixups
, commaNum1
)); 
1166         if ( fgTotalBindSymbolsResolved 
!= 0 ) { 
1167                 uint32_t avgTimesTen 
= (fgTotalBindImageSearches 
* 10) / fgTotalBindSymbolsResolved
; 
1168                 uint32_t avgInt 
= fgTotalBindImageSearches 
/ fgTotalBindSymbolsResolved
; 
1169                 uint32_t avgTenths 
= avgTimesTen 
- (avgInt
*10); 
1170                 dyld::log("total binding symbol lookups: %s, average images searched per symbol: %u.%u\n",  
1171                                 commatize(fgTotalBindSymbolsResolved
, commaNum1
), avgInt
, avgTenths
); 
1173         printTime("  total binding fixups time", fgTotalBindTime
, totalTime
); 
1174         printTime("  total weak binding fixups time", fgTotalWeakBindTime
, totalTime
); 
1175         printTime("  total redo shared cached bindings time", fgTotalRebindCacheTime
, totalTime
); 
1176         dyld::log("  total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups
, commaNum1
), commatize(fgTotalPossibleLazyBindFixups
, commaNum2
)); 
1177         printTime("  total time in initializers and ObjC +load", fgTotalInitTime
-fgTotalObjCSetupTime
, totalTime
); 
1178         for (uintptr_t i
=0; i 
< timingInfo
.count
; ++i
) { 
1179                 uint64_t t 
= timingInfo
.images
[i
].initTime
; 
1180                 if ( t
*1000 < totalTime 
) 
1182                 dyld::log("%42s ", timingInfo
.images
[i
].shortName
); 
1183                 if ( strncmp(timingInfo
.images
[i
].shortName
, "libSystem.", 10) == 0 ) 
1184                         t 
-= fgTotalObjCSetupTime
; 
1185                 printTime("", t
, totalTime
); 
1192 // copy path and add suffix to result 
1194 //  /path/foo.dylib             _debug   =>   /path/foo_debug.dylib      
1195 //  foo.dylib                   _debug   =>   foo_debug.dylib 
1196 //  foo                         _debug   =>   foo_debug 
1197 //  /path/bar                   _debug   =>   /path/bar_debug   
1198 //  /path/bar.A.dylib   _debug   =>   /path/bar.A_debug.dylib 
1200 void ImageLoader::addSuffix(const char* path
, const char* suffix
, char* result
) 
1202         strcpy(result
, path
); 
1204         char* start 
= strrchr(result
, '/'); 
1205         if ( start 
!= NULL 
) 
1210         char* dot 
= strrchr(start
, '.'); 
1211         if ( dot 
!= NULL 
) { 
1212                 strcpy(dot
, suffix
); 
1213                 strcat(&dot
[strlen(suffix
)], &path
[dot
-result
]); 
1216                 strcat(result
, suffix
); 
1222 // This function is the hotspot of symbol lookup.  It was pulled out of findExportedSymbol() 
1223 // to enable it to be re-written in assembler if needed. 
1225 const uint8_t* ImageLoader::trieWalk(const uint8_t* start
, const uint8_t* end
, const char* s
) 
1227         //dyld::log("trieWalk(%p, %p, %s)\n", start, end, s); 
1228         ++fgSymbolTrieSearchs
; 
1229         const uint8_t* p 
= start
; 
1230         while ( p 
!= NULL 
) { 
1231                 uintptr_t terminalSize 
= *p
++; 
1232                 if ( terminalSize 
> 127 ) { 
1233                         // except for re-export-with-rename, all terminal sizes fit in one byte 
1235                         terminalSize 
= read_uleb128(p
, end
); 
1237                 if ( (*s 
== '\0') && (terminalSize 
!= 0) ) { 
1238                         //dyld::log("trieWalk(%p) returning %p\n", start, p); 
1241                 const uint8_t* children 
= p 
+ terminalSize
; 
1242                 if ( children 
> end 
) { 
1243                         dyld::log("trieWalk() malformed trie node, terminalSize=0x%lx extends past end of trie\n", terminalSize
); 
1246                 //dyld::log("trieWalk(%p) sym=%s, terminalSize=%lu, children=%p\n", start, s, terminalSize, children); 
1247                 uint8_t childrenRemaining 
= *children
++; 
1249                 uintptr_t nodeOffset 
= 0; 
1250                 for (; childrenRemaining 
> 0; --childrenRemaining
) { 
1252                         //dyld::log("trieWalk(%p) child str=%s\n", start, (char*)p); 
1253                         bool wrongEdge 
= false; 
1254                         // scan whole edge to get to next edge 
1255                         // if edge is longer than target symbol name, don't read past end of symbol name 
1257                         while ( c 
!= '\0' ) { 
1267                                 // advance to next child 
1268                                 ++p
; // skip over zero terminator 
1269                                 // skip over uleb128 until last byte is found 
1270                                 while ( (*p 
& 0x80) != 0 ) 
1272                                 ++p
; // skip over last byte of uleb128 
1274                                         dyld::log("trieWalk() malformed trie node, child node extends past end of trie\n"); 
1279                                 // the symbol so far matches this edge (child) 
1280                                 // so advance to the child's node 
1282                                 nodeOffset 
= read_uleb128(p
, end
); 
1283                                 if ( (nodeOffset 
== 0) || ( &start
[nodeOffset
] > end
) ) { 
1284                                         dyld::log("trieWalk() malformed trie child, nodeOffset=0x%lx out of range\n", nodeOffset
); 
1288                                 //dyld::log("trieWalk() found matching edge advancing to node 0x%lx\n", nodeOffset); 
1292                 if ( nodeOffset 
!= 0 ) 
1293                         p 
= &start
[nodeOffset
]; 
1297         //dyld::log("trieWalk(%p) return NULL\n", start); 
1303 uintptr_t ImageLoader::read_uleb128(const uint8_t*& p
, const uint8_t* end
) 
1305         uint64_t result 
= 0; 
1309                         dyld::throwf("malformed uleb128"); 
1311                 uint64_t slice 
= *p 
& 0x7f; 
1314                         dyld::throwf("uleb128 too big for uint64, bit=%d, result=0x%0llX", bit
, result
); 
1316                         result 
|= (slice 
<< bit
); 
1319         } while (*p
++ & 0x80); 
1324 intptr_t ImageLoader::read_sleb128(const uint8_t*& p
, const uint8_t* end
) 
1331                         throw "malformed sleb128"; 
1333                 result 
|= (((int64_t)(byte 
& 0x7f)) << bit
); 
1335         } while (byte 
& 0x80); 
1336         // sign extend negative numbers 
1337         if ( (byte 
& 0x40) != 0 ) 
1338                 result 
|= (-1LL) << bit
; 
1343 VECTOR_NEVER_DESTRUCTED_IMPL(ImageLoader::InterposeTuple
); 
1344 VECTOR_NEVER_DESTRUCTED_IMPL(ImagePair
);