]> git.saurik.com Git - apple/dyld.git/blob - src/ImageLoader.cpp
58b22829d8b5bb5fe507f715e2d2f96964f7373a
[apple/dyld.git] / src / ImageLoader.cpp
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 #define __STDC_LIMIT_MACROS
26 #include <stdint.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <mach/mach.h>
30 #include <mach-o/fat.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/mman.h>
34 #include <sys/param.h>
35 #include <sys/mount.h>
36 #include <libkern/OSAtomic.h>
37
38 #include "ImageLoader.h"
39
40
41 uint32_t ImageLoader::fgImagesUsedFromSharedCache = 0;
42 uint32_t ImageLoader::fgImagesWithUsedPrebinding = 0;
43 uint32_t ImageLoader::fgImagesRequiringCoalescing = 0;
44 uint32_t ImageLoader::fgImagesHasWeakDefinitions = 0;
45 uint32_t ImageLoader::fgTotalRebaseFixups = 0;
46 uint32_t ImageLoader::fgTotalBindFixups = 0;
47 uint32_t ImageLoader::fgTotalBindSymbolsResolved = 0;
48 uint32_t ImageLoader::fgTotalBindImageSearches = 0;
49 uint32_t ImageLoader::fgTotalLazyBindFixups = 0;
50 uint32_t ImageLoader::fgTotalPossibleLazyBindFixups = 0;
51 uint32_t ImageLoader::fgTotalSegmentsMapped = 0;
52 uint64_t ImageLoader::fgTotalBytesMapped = 0;
53 uint64_t ImageLoader::fgTotalBytesPreFetched = 0;
54 uint64_t ImageLoader::fgTotalLoadLibrariesTime;
55 uint64_t ImageLoader::fgTotalRebaseTime;
56 uint64_t ImageLoader::fgTotalBindTime;
57 uint64_t ImageLoader::fgTotalWeakBindTime;
58 uint64_t ImageLoader::fgTotalDOF;
59 uint64_t ImageLoader::fgTotalInitTime;
60 uint16_t ImageLoader::fgLoadOrdinal = 0;
61 std::vector<ImageLoader::InterposeTuple>ImageLoader::fgInterposingTuples;
62 uintptr_t ImageLoader::fgNextPIEDylibAddress = 0;
63
64
65
66 ImageLoader::ImageLoader(const char* path, unsigned int libCount)
67 : fPath(path), fRealPath(NULL), fDevice(0), fInode(0), fLastModified(0),
68 fPathHash(0), fDlopenReferenceCount(0), fStaticReferenceCount(0),
69 fDynamicReferenceCount(0), fDynamicReferences(NULL), fInitializerRecursiveLock(NULL),
70 fDepth(0), fLoadOrder(fgLoadOrdinal++), fState(0), fLibraryCount(libCount),
71 fAllLibraryChecksumsAndLoadAddressesMatch(false), fLeaveMapped(false), fNeverUnload(false),
72 fHideSymbols(false), fMatchByInstallName(false),
73 fInterposed(false), fRegisteredDOF(false), fAllLazyPointersBound(false),
74 fBeingRemoved(false), fAddFuncNotified(false),
75 fPathOwnedByImage(false), fIsReferencedDownward(false),
76 fIsReferencedUpward(false), fWeakSymbolsBound(false)
77 {
78 if ( fPath != NULL )
79 fPathHash = hash(fPath);
80 }
81
82
83 void ImageLoader::deleteImage(ImageLoader* image)
84 {
85 // this cannot be done in destructor because libImage() is implemented
86 // in a subclass
87 DependentLibraryInfo libraryInfos[image->libraryCount()];
88 image->doGetDependentLibraries(libraryInfos);
89 for(unsigned int i=0; i < image->libraryCount(); ++i) {
90 ImageLoader* lib = image->libImage(i);
91 if ( (lib != NULL) && ! libraryInfos[i].upward )
92 lib->fStaticReferenceCount--;
93 }
94 delete image;
95 }
96
97
98 ImageLoader::~ImageLoader()
99 {
100 if ( fRealPath != NULL )
101 delete [] fRealPath;
102 if ( fPathOwnedByImage && (fPath != NULL) )
103 delete [] fPath;
104 if ( fDynamicReferences != NULL ) {
105 for (std::vector<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
106 const_cast<ImageLoader*>(*it)->fDynamicReferenceCount--;
107 }
108 delete fDynamicReferences;
109 }
110 }
111
112 void ImageLoader::setFileInfo(dev_t device, ino_t inode, time_t modDate)
113 {
114 fDevice = device;
115 fInode = inode;
116 fLastModified = modDate;
117 }
118
119 void ImageLoader::setMapped(const LinkContext& context)
120 {
121 fState = dyld_image_state_mapped;
122 context.notifySingle(dyld_image_state_mapped, this); // note: can throw exception
123 }
124
125 void ImageLoader::addDynamicReference(const ImageLoader* target)
126 {
127 bool alreadyInVector = false;
128 if ( fDynamicReferences == NULL ) {
129 fDynamicReferences = new std::vector<const ImageLoader*>();
130 }
131 else {
132 for (std::vector<const ImageLoader*>::iterator it = fDynamicReferences->begin(); it != fDynamicReferences->end(); ++it ) {
133 if ( *it == target ) {
134 alreadyInVector = true;
135 break;
136 }
137 }
138 }
139 if ( ! alreadyInVector ) {
140 fDynamicReferences->push_back(target);
141 const_cast<ImageLoader*>(target)->fDynamicReferenceCount++;
142 }
143 //dyld::log("dyld: addDynamicReference() from %s to %s, fDynamicReferences->size()=%lu\n", this->getPath(), target->getPath(), fDynamicReferences->size());
144 }
145
146 int ImageLoader::compare(const ImageLoader* right) const
147 {
148 if ( this->fDepth == right->fDepth ) {
149 if ( this->fLoadOrder == right->fLoadOrder )
150 return 0;
151 else if ( this->fLoadOrder < right->fLoadOrder )
152 return -1;
153 else
154 return 1;
155 }
156 else {
157 if ( this->fDepth < right->fDepth )
158 return -1;
159 else
160 return 1;
161 }
162 }
163
164 void ImageLoader::setPath(const char* path)
165 {
166 if ( fPathOwnedByImage && (fPath != NULL) )
167 delete [] fPath;
168 fPath = new char[strlen(path)+1];
169 strcpy((char*)fPath, path);
170 fPathOwnedByImage = true; // delete fPath when this image is destructed
171 fPathHash = hash(fPath);
172 fRealPath = NULL;
173 }
174
175 void ImageLoader::setPathUnowned(const char* path)
176 {
177 if ( fPathOwnedByImage && (fPath != NULL) ) {
178 delete [] fPath;
179 }
180 fPath = path;
181 fPathOwnedByImage = false;
182 fPathHash = hash(fPath);
183 }
184
185 void ImageLoader::setPaths(const char* path, const char* realPath)
186 {
187 this->setPath(path);
188 fRealPath = new char[strlen(realPath)+1];
189 strcpy((char*)fRealPath, realPath);
190 }
191
192 const char* ImageLoader::getRealPath() const
193 {
194 if ( fRealPath != NULL )
195 return fRealPath;
196 else
197 return fPath;
198 }
199
200
201 uint32_t ImageLoader::hash(const char* path)
202 {
203 // this does not need to be a great hash
204 // it is just used to reduce the number of strcmp() calls
205 // of existing images when loading a new image
206 uint32_t h = 0;
207 for (const char* s=path; *s != '\0'; ++s)
208 h = h*5 + *s;
209 return h;
210 }
211
212 bool ImageLoader::matchInstallPath() const
213 {
214 return fMatchByInstallName;
215 }
216
217 void ImageLoader::setMatchInstallPath(bool match)
218 {
219 fMatchByInstallName = match;
220 }
221
222 bool ImageLoader::statMatch(const struct stat& stat_buf) const
223 {
224 return ( (this->fDevice == stat_buf.st_dev) && (this->fInode == stat_buf.st_ino) );
225 }
226
227 const char* ImageLoader::getShortName() const
228 {
229 // try to return leaf name
230 if ( fPath != NULL ) {
231 const char* s = strrchr(fPath, '/');
232 if ( s != NULL )
233 return &s[1];
234 }
235 return fPath;
236 }
237
238 void ImageLoader::setLeaveMapped()
239 {
240 fLeaveMapped = true;
241 }
242
243 void ImageLoader::setHideExports(bool hide)
244 {
245 fHideSymbols = hide;
246 }
247
248 bool ImageLoader::hasHiddenExports() const
249 {
250 return fHideSymbols;
251 }
252
253 bool ImageLoader::isLinked() const
254 {
255 return (fState >= dyld_image_state_bound);
256 }
257
258 time_t ImageLoader::lastModified() const
259 {
260 return fLastModified;
261 }
262
263 bool ImageLoader::containsAddress(const void* addr) const
264 {
265 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
266 const uint8_t* start = (const uint8_t*)segActualLoadAddress(i);
267 const uint8_t* end = (const uint8_t*)segActualEndAddress(i);
268 if ( (start <= addr) && (addr < end) && !segUnaccessible(i) )
269 return true;
270 }
271 return false;
272 }
273
274 bool ImageLoader::overlapsWithAddressRange(const void* start, const void* end) const
275 {
276 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
277 const uint8_t* segStart = (const uint8_t*)segActualLoadAddress(i);
278 const uint8_t* segEnd = (const uint8_t*)segActualEndAddress(i);
279 if ( strcmp(segName(i), "__UNIXSTACK") == 0 ) {
280 // __UNIXSTACK never slides. This is the only place that cares
281 // and checking for that segment name in segActualLoadAddress()
282 // is too expensive.
283 segStart -= getSlide();
284 segEnd -= getSlide();
285 }
286 if ( (start <= segStart) && (segStart < end) )
287 return true;
288 if ( (start <= segEnd) && (segEnd < end) )
289 return true;
290 if ( (segStart < start) && (end < segEnd) )
291 return true;
292 }
293 return false;
294 }
295
296 void ImageLoader::getMappedRegions(MappedRegion*& regions) const
297 {
298 for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
299 MappedRegion region;
300 region.address = segActualLoadAddress(i);
301 region.size = segSize(i);
302 *regions++ = region;
303 }
304 }
305
306
307 static bool notInImgageList(const ImageLoader* image, const ImageLoader** dsiStart, const ImageLoader** dsiCur)
308 {
309 for (const ImageLoader** p = dsiStart; p < dsiCur; ++p)
310 if ( *p == image )
311 return false;
312 return true;
313 }
314
315
316 // private method that handles circular dependencies by only search any image once
317 const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcept(const char* name,
318 const ImageLoader** dsiStart, const ImageLoader**& dsiCur, const ImageLoader** dsiEnd, const ImageLoader** foundIn) const
319 {
320 const ImageLoader::Symbol* sym;
321 // search self
322 if ( notInImgageList(this, dsiStart, dsiCur) ) {
323 sym = this->findExportedSymbol(name, false, foundIn);
324 if ( sym != NULL )
325 return sym;
326 *dsiCur++ = this;
327 }
328
329 // search directly dependent libraries
330 for(unsigned int i=0; i < libraryCount(); ++i) {
331 ImageLoader* dependentImage = libImage(i);
332 if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) {
333 const ImageLoader::Symbol* sym = dependentImage->findExportedSymbol(name, false, foundIn);
334 if ( sym != NULL )
335 return sym;
336 }
337 }
338
339 // search indirectly dependent libraries
340 for(unsigned int i=0; i < libraryCount(); ++i) {
341 ImageLoader* dependentImage = libImage(i);
342 if ( (dependentImage != NULL) && notInImgageList(dependentImage, dsiStart, dsiCur) ) {
343 *dsiCur++ = dependentImage;
344 const ImageLoader::Symbol* sym = dependentImage->findExportedSymbolInDependentImagesExcept(name, dsiStart, dsiCur, dsiEnd, foundIn);
345 if ( sym != NULL )
346 return sym;
347 }
348 }
349
350 return NULL;
351 }
352
353
354 const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const
355 {
356 unsigned int imageCount = context.imageCount();
357 const ImageLoader* dontSearchImages[imageCount];
358 dontSearchImages[0] = this; // don't search this image
359 const ImageLoader** cur = &dontSearchImages[1];
360 return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn);
361 }
362
363 const ImageLoader::Symbol* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name, const LinkContext& context, const ImageLoader** foundIn) const
364 {
365 unsigned int imageCount = context.imageCount();
366 const ImageLoader* dontSearchImages[imageCount];
367 const ImageLoader** cur = &dontSearchImages[0];
368 return this->findExportedSymbolInDependentImagesExcept(name, &dontSearchImages[0], cur, &dontSearchImages[imageCount], foundIn);
369 }
370
371 // this is called by initializeMainExecutable() to interpose on the initial set of images
372 void ImageLoader::applyInterposing(const LinkContext& context)
373 {
374 if ( fgInterposingTuples.size() != 0 )
375 this->recursiveApplyInterposing(context);
376 }
377
378 void ImageLoader::link(const LinkContext& context, bool forceLazysBound, bool preflightOnly, const RPathChain& loaderRPaths)
379 {
380 //dyld::log("ImageLoader::link(%s) refCount=%d, neverUnload=%d\n", this->getPath(), fStaticReferenceCount, fNeverUnload);
381
382 // clear error strings
383 (*context.setErrorStrings)(dyld_error_kind_none, NULL, NULL, NULL);
384
385 uint64_t t0 = mach_absolute_time();
386 this->recursiveLoadLibraries(context, preflightOnly, loaderRPaths);
387 context.notifyBatch(dyld_image_state_dependents_mapped);
388
389 // we only do the loading step for preflights
390 if ( preflightOnly )
391 return;
392
393 uint64_t t1 = mach_absolute_time();
394 context.clearAllDepths();
395 this->recursiveUpdateDepth(context.imageCount());
396
397 uint64_t t2 = mach_absolute_time();
398 this->recursiveRebase(context);
399 context.notifyBatch(dyld_image_state_rebased);
400
401 uint64_t t3 = mach_absolute_time();
402 this->recursiveBind(context, forceLazysBound);
403
404 uint64_t t4 = mach_absolute_time();
405 this->weakBind(context);
406 uint64_t t5 = mach_absolute_time();
407
408 context.notifyBatch(dyld_image_state_bound);
409 uint64_t t6 = mach_absolute_time();
410
411 std::vector<DOFInfo> dofs;
412 this->recursiveGetDOFSections(context, dofs);
413 context.registerDOFs(dofs);
414 uint64_t t7 = mach_absolute_time();
415
416 // interpose any dynamically loaded images
417 if ( !context.linkingMainExecutable && (fgInterposingTuples.size() != 0) ) {
418 this->recursiveApplyInterposing(context);
419 }
420
421 // clear error strings
422 (*context.setErrorStrings)(dyld_error_kind_none, NULL, NULL, NULL);
423
424 fgTotalLoadLibrariesTime += t1 - t0;
425 fgTotalRebaseTime += t3 - t2;
426 fgTotalBindTime += t4 - t3;
427 fgTotalWeakBindTime += t5 - t4;
428 fgTotalDOF += t7 - t6;
429
430 // done with initial dylib loads
431 fgNextPIEDylibAddress = 0;
432 }
433
434
435 void ImageLoader::printReferenceCounts()
436 {
437 dyld::log(" dlopen=%d, static=%d, dynamic=%d for %s\n",
438 fDlopenReferenceCount, fStaticReferenceCount, fDynamicReferenceCount, getPath() );
439 }
440
441
442 bool ImageLoader::decrementDlopenReferenceCount()
443 {
444 if ( fDlopenReferenceCount == 0 )
445 return true;
446 --fDlopenReferenceCount;
447 return false;
448 }
449
450 void ImageLoader::runInitializers(const LinkContext& context, InitializerTimingList& timingInfo)
451 {
452 uint64_t t1 = mach_absolute_time();
453 mach_port_t this_thread = mach_thread_self();
454 this->recursiveInitialization(context, this_thread, timingInfo);
455 context.notifyBatch(dyld_image_state_initialized);
456 mach_port_deallocate(mach_task_self(), this_thread);
457 uint64_t t2 = mach_absolute_time();
458 fgTotalInitTime += (t2 - t1);
459 }
460
461
462 void ImageLoader::bindAllLazyPointers(const LinkContext& context, bool recursive)
463 {
464 if ( ! fAllLazyPointersBound ) {
465 fAllLazyPointersBound = true;
466
467 if ( recursive ) {
468 // bind lower level libraries first
469 for(unsigned int i=0; i < libraryCount(); ++i) {
470 ImageLoader* dependentImage = libImage(i);
471 if ( dependentImage != NULL )
472 dependentImage->bindAllLazyPointers(context, recursive);
473 }
474 }
475 // bind lazies in this image
476 this->doBindJustLazies(context);
477 }
478 }
479
480
481 bool ImageLoader::allDependentLibrariesAsWhenPreBound() const
482 {
483 return fAllLibraryChecksumsAndLoadAddressesMatch;
484 }
485
486
487 unsigned int ImageLoader::recursiveUpdateDepth(unsigned int maxDepth)
488 {
489 // the purpose of this phase is to make the images sortable such that
490 // in a sort list of images, every image that an image depends on
491 // occurs in the list before it.
492 if ( fDepth == 0 ) {
493 // break cycles
494 fDepth = maxDepth;
495
496 // get depth of dependents
497 unsigned int minDependentDepth = maxDepth;
498 for(unsigned int i=0; i < libraryCount(); ++i) {
499 ImageLoader* dependentImage = libImage(i);
500 if ( (dependentImage != NULL) && !libIsUpward(i) ) {
501 unsigned int d = dependentImage->recursiveUpdateDepth(maxDepth);
502 if ( d < minDependentDepth )
503 minDependentDepth = d;
504 }
505 }
506
507 // make me less deep then all my dependents
508 fDepth = minDependentDepth - 1;
509 }
510
511 return fDepth;
512 }
513
514
515 void ImageLoader::recursiveLoadLibraries(const LinkContext& context, bool preflightOnly, const RPathChain& loaderRPaths)
516 {
517 if ( fState < dyld_image_state_dependents_mapped ) {
518 // break cycles
519 fState = dyld_image_state_dependents_mapped;
520
521 // get list of libraries this image needs
522 //dyld::log("ImageLoader::recursiveLoadLibraries() %ld = %d*%ld\n", fLibrariesCount*sizeof(DependentLibrary), fLibrariesCount, sizeof(DependentLibrary));
523 DependentLibraryInfo libraryInfos[fLibraryCount];
524 this->doGetDependentLibraries(libraryInfos);
525
526 // get list of rpaths that this image adds
527 std::vector<const char*> rpathsFromThisImage;
528 this->getRPaths(context, rpathsFromThisImage);
529 const RPathChain thisRPaths(&loaderRPaths, &rpathsFromThisImage);
530
531 // try to load each
532 bool canUsePrelinkingInfo = true;
533 for(unsigned int i=0; i < fLibraryCount; ++i){
534 ImageLoader* dependentLib;
535 bool depLibReExported = false;
536 bool depLibReRequired = false;
537 bool depLibCheckSumsMatch = false;
538 DependentLibraryInfo& requiredLibInfo = libraryInfos[i];
539 #if DYLD_SHARED_CACHE_SUPPORT
540 if ( preflightOnly && context.inSharedCache(requiredLibInfo.name) ) {
541 // <rdar://problem/5910137> dlopen_preflight() on image in shared cache leaves it loaded but not objc initialized
542 // in preflight mode, don't even load dylib that are in the shared cache because they will never be unloaded
543 setLibImage(i, NULL, false, false);
544 continue;
545 }
546 #endif
547 try {
548 dependentLib = context.loadLibrary(requiredLibInfo.name, true, this->getPath(), &thisRPaths);
549 if ( dependentLib == this ) {
550 // found circular reference, perhaps DYLD_LIBARY_PATH is causing this rdar://problem/3684168
551 dependentLib = context.loadLibrary(requiredLibInfo.name, false, NULL, NULL);
552 if ( dependentLib != this )
553 dyld::warn("DYLD_ setting caused circular dependency in %s\n", this->getPath());
554 }
555 if ( fNeverUnload )
556 dependentLib->setNeverUnload();
557 if ( requiredLibInfo.upward ) {
558 dependentLib->fIsReferencedUpward = true;
559 }
560 else {
561 dependentLib->fStaticReferenceCount += 1;
562 dependentLib->fIsReferencedDownward = true;
563 }
564 LibraryInfo actualInfo = dependentLib->doGetLibraryInfo();
565 depLibReRequired = requiredLibInfo.required;
566 depLibCheckSumsMatch = ( actualInfo.checksum == requiredLibInfo.info.checksum );
567 depLibReExported = requiredLibInfo.reExported;
568 if ( ! depLibReExported ) {
569 // for pre-10.5 binaries that did not use LC_REEXPORT_DYLIB
570 depLibReExported = dependentLib->isSubframeworkOf(context, this) || this->hasSubLibrary(context, dependentLib);
571 }
572 // check found library version is compatible
573 // <rdar://problem/89200806> 0xFFFFFFFF is wildcard that matches any version
574 if ( (requiredLibInfo.info.minVersion != 0xFFFFFFFF) && (actualInfo.minVersion < requiredLibInfo.info.minVersion) ) {
575 // record values for possible use by CrashReporter or Finder
576 dyld::throwf("Incompatible library version: %s requires version %d.%d.%d or later, but %s provides version %d.%d.%d",
577 this->getShortName(), requiredLibInfo.info.minVersion >> 16, (requiredLibInfo.info.minVersion >> 8) & 0xff, requiredLibInfo.info.minVersion & 0xff,
578 dependentLib->getShortName(), actualInfo.minVersion >> 16, (actualInfo.minVersion >> 8) & 0xff, actualInfo.minVersion & 0xff);
579 }
580 // prebinding for this image disabled if any dependent library changed
581 if ( !depLibCheckSumsMatch )
582 canUsePrelinkingInfo = false;
583 // prebinding for this image disabled unless both this and dependent are in the shared cache
584 if ( !dependentLib->inSharedCache() || !this->inSharedCache() )
585 canUsePrelinkingInfo = false;
586
587 //if ( context.verbosePrebinding ) {
588 // if ( !requiredLib.checksumMatches )
589 // fprintf(stderr, "dyld: checksum mismatch, (%u v %u) for %s referencing %s\n",
590 // requiredLibInfo.info.checksum, actualInfo.checksum, this->getPath(), dependentLib->getPath());
591 // if ( dependentLib->getSlide() != 0 )
592 // fprintf(stderr, "dyld: dependent library slid for %s referencing %s\n", this->getPath(), dependentLib->getPath());
593 //}
594 }
595 catch (const char* msg) {
596 //if ( context.verbosePrebinding )
597 // fprintf(stderr, "dyld: exception during processing for %s referencing %s\n", this->getPath(), dependentLib->getPath());
598 if ( requiredLibInfo.required ) {
599 fState = dyld_image_state_mapped;
600 // record values for possible use by CrashReporter or Finder
601 if ( strstr(msg, "Incompatible") != NULL )
602 (*context.setErrorStrings)(dyld_error_kind_dylib_version, this->getPath(), requiredLibInfo.name, NULL);
603 else if ( strstr(msg, "architecture") != NULL )
604 (*context.setErrorStrings)(dyld_error_kind_dylib_wrong_arch, this->getPath(), requiredLibInfo.name, NULL);
605 else
606 (*context.setErrorStrings)(dyld_error_kind_dylib_missing, this->getPath(), requiredLibInfo.name, NULL);
607 dyld::throwf("Library not loaded: %s\n Referenced from: %s\n Reason: %s", requiredLibInfo.name, this->getRealPath(), msg);
608 }
609 // ok if weak library not found
610 dependentLib = NULL;
611 canUsePrelinkingInfo = false; // this disables all prebinding, we may want to just slam import vectors for this lib to zero
612 }
613 setLibImage(i, dependentLib, depLibReExported, requiredLibInfo.upward);
614 }
615 fAllLibraryChecksumsAndLoadAddressesMatch = canUsePrelinkingInfo;
616
617 // tell each to load its dependents
618 for(unsigned int i=0; i < libraryCount(); ++i) {
619 ImageLoader* dependentImage = libImage(i);
620 if ( dependentImage != NULL ) {
621 dependentImage->recursiveLoadLibraries(context, preflightOnly, thisRPaths);
622 }
623 }
624
625 // do deep prebind check
626 if ( fAllLibraryChecksumsAndLoadAddressesMatch ) {
627 for(unsigned int i=0; i < libraryCount(); ++i){
628 ImageLoader* dependentImage = libImage(i);
629 if ( dependentImage != NULL ) {
630 if ( !dependentImage->allDependentLibrariesAsWhenPreBound() )
631 fAllLibraryChecksumsAndLoadAddressesMatch = false;
632 }
633 }
634 }
635
636 // free rpaths (getRPaths() malloc'ed each string)
637 for(std::vector<const char*>::iterator it=rpathsFromThisImage.begin(); it != rpathsFromThisImage.end(); ++it) {
638 const char* str = *it;
639 free((void*)str);
640 }
641
642 }
643 }
644
645 void ImageLoader::recursiveRebase(const LinkContext& context)
646 {
647 if ( fState < dyld_image_state_rebased ) {
648 // break cycles
649 fState = dyld_image_state_rebased;
650
651 try {
652 // rebase lower level libraries first
653 for(unsigned int i=0; i < libraryCount(); ++i) {
654 ImageLoader* dependentImage = libImage(i);
655 if ( dependentImage != NULL )
656 dependentImage->recursiveRebase(context);
657 }
658
659 // rebase this image
660 doRebase(context);
661
662 // notify
663 context.notifySingle(dyld_image_state_rebased, this);
664 }
665 catch (const char* msg) {
666 // this image is not rebased
667 fState = dyld_image_state_dependents_mapped;
668 CRSetCrashLogMessage2(NULL);
669 throw;
670 }
671 }
672 }
673
674 void ImageLoader::recursiveApplyInterposing(const LinkContext& context)
675 {
676 if ( ! fInterposed ) {
677 // break cycles
678 fInterposed = true;
679
680 try {
681 // interpose lower level libraries first
682 for(unsigned int i=0; i < libraryCount(); ++i) {
683 ImageLoader* dependentImage = libImage(i);
684 if ( dependentImage != NULL )
685 dependentImage->recursiveApplyInterposing(context);
686 }
687
688 // interpose this image
689 doInterpose(context);
690 }
691 catch (const char* msg) {
692 // this image is not interposed
693 fInterposed = false;
694 throw;
695 }
696 }
697 }
698
699
700
701 void ImageLoader::recursiveBind(const LinkContext& context, bool forceLazysBound)
702 {
703 // Normally just non-lazy pointers are bound immediately.
704 // The exceptions are:
705 // 1) DYLD_BIND_AT_LAUNCH will cause lazy pointers to be bound immediately
706 // 2) some API's (e.g. RTLD_NOW) can cause lazy pointers to be bound immediately
707 if ( fState < dyld_image_state_bound ) {
708 // break cycles
709 fState = dyld_image_state_bound;
710
711 try {
712 // bind lower level libraries first
713 for(unsigned int i=0; i < libraryCount(); ++i) {
714 ImageLoader* dependentImage = libImage(i);
715 if ( dependentImage != NULL )
716 dependentImage->recursiveBind(context, forceLazysBound);
717 }
718 // bind this image
719 this->doBind(context, forceLazysBound);
720 // mark if lazys are also bound
721 if ( forceLazysBound || this->usablePrebinding(context) )
722 fAllLazyPointersBound = true;
723
724 context.notifySingle(dyld_image_state_bound, this);
725 }
726 catch (const char* msg) {
727 // restore state
728 fState = dyld_image_state_rebased;
729 CRSetCrashLogMessage2(NULL);
730 throw;
731 }
732 }
733 }
734
735 void ImageLoader::weakBind(const LinkContext& context)
736 {
737 if ( context.verboseWeakBind )
738 dyld::log("dyld: weak bind start:\n");
739 // get set of ImageLoaders that participate in coalecsing
740 ImageLoader* imagesNeedingCoalescing[fgImagesRequiringCoalescing];
741 int count = context.getCoalescedImages(imagesNeedingCoalescing);
742
743 // count how many have not already had weakbinding done
744 int countNotYetWeakBound = 0;
745 int countOfImagesWithWeakDefinitions = 0;
746 int countOfImagesWithWeakDefinitionsNotInSharedCache = 0;
747 for(int i=0; i < count; ++i) {
748 if ( ! imagesNeedingCoalescing[i]->fWeakSymbolsBound )
749 ++countNotYetWeakBound;
750 if ( imagesNeedingCoalescing[i]->hasCoalescedExports() ) {
751 ++countOfImagesWithWeakDefinitions;
752 if ( ! imagesNeedingCoalescing[i]->inSharedCache() )
753 ++countOfImagesWithWeakDefinitionsNotInSharedCache;
754 }
755 }
756
757 // don't need to do any coalescing if only one image has overrides, or all have already been done
758 if ( (countOfImagesWithWeakDefinitionsNotInSharedCache > 0) && (countNotYetWeakBound > 0) ) {
759 // make symbol iterators for each
760 ImageLoader::CoalIterator iterators[count];
761 ImageLoader::CoalIterator* sortedIts[count];
762 for(int i=0; i < count; ++i) {
763 imagesNeedingCoalescing[i]->initializeCoalIterator(iterators[i], i);
764 sortedIts[i] = &iterators[i];
765 if ( context.verboseWeakBind )
766 dyld::log("dyld: weak bind load order %d/%d for %s\n", i, count, imagesNeedingCoalescing[i]->getPath());
767 }
768
769 // walk all symbols keeping iterators in sync by
770 // only ever incrementing the iterator with the lowest symbol
771 int doneCount = 0;
772 while ( doneCount != count ) {
773 //for(int i=0; i < count; ++i)
774 // dyld::log("sym[%d]=%s ", sortedIts[i]->loadOrder, sortedIts[i]->symbolName);
775 //dyld::log("\n");
776 // increment iterator with lowest symbol
777 if ( sortedIts[0]->image->incrementCoalIterator(*sortedIts[0]) )
778 ++doneCount;
779 // re-sort iterators
780 for(int i=1; i < count; ++i) {
781 int result = strcmp(sortedIts[i-1]->symbolName, sortedIts[i]->symbolName);
782 if ( result == 0 )
783 sortedIts[i-1]->symbolMatches = true;
784 if ( result > 0 ) {
785 // new one is bigger then next, so swap
786 ImageLoader::CoalIterator* temp = sortedIts[i-1];
787 sortedIts[i-1] = sortedIts[i];
788 sortedIts[i] = temp;
789 }
790 if ( result < 0 )
791 break;
792 }
793 // process all matching symbols just before incrementing the lowest one that matches
794 if ( sortedIts[0]->symbolMatches && !sortedIts[0]->done ) {
795 const char* nameToCoalesce = sortedIts[0]->symbolName;
796 // pick first symbol in load order (and non-weak overrides weak)
797 uintptr_t targetAddr = 0;
798 ImageLoader* targetImage = NULL;
799 for(int i=0; i < count; ++i) {
800 if ( strcmp(iterators[i].symbolName, nameToCoalesce) == 0 ) {
801 if ( context.verboseWeakBind )
802 dyld::log("dyld: weak bind, found %s weak=%d in %s \n", nameToCoalesce, iterators[i].weakSymbol, iterators[i].image->getPath());
803 if ( iterators[i].weakSymbol ) {
804 if ( targetAddr == 0 ) {
805 targetAddr = iterators[i].image->getAddressCoalIterator(iterators[i], context);
806 if ( targetAddr != 0 )
807 targetImage = iterators[i].image;
808 }
809 }
810 else {
811 targetAddr = iterators[i].image->getAddressCoalIterator(iterators[i], context);
812 if ( targetAddr != 0 ) {
813 targetImage = iterators[i].image;
814 // strong implementation found, stop searching
815 break;
816 }
817 }
818 }
819 }
820 if ( context.verboseWeakBind )
821 dyld::log("dyld: weak binding all uses of %s to copy from %s\n", nameToCoalesce, targetImage->getShortName());
822
823 // tell each to bind to this symbol (unless already bound)
824 if ( targetAddr != 0 ) {
825 for(int i=0; i < count; ++i) {
826 if ( strcmp(iterators[i].symbolName, nameToCoalesce) == 0 ) {
827 if ( context.verboseWeakBind )
828 dyld::log("dyld: weak bind, setting all uses of %s in %s to 0x%lX from %s\n", nameToCoalesce, iterators[i].image->getShortName(), targetAddr, targetImage->getShortName());
829 if ( ! iterators[i].image->fWeakSymbolsBound )
830 iterators[i].image->updateUsesCoalIterator(iterators[i], targetAddr, targetImage, context);
831 iterators[i].symbolMatches = false;
832 }
833 }
834 }
835
836 }
837 }
838
839 // mark all as having all weak symbols bound
840 for(int i=0; i < count; ++i) {
841 imagesNeedingCoalescing[i]->fWeakSymbolsBound = true;
842 }
843 }
844 if ( context.verboseWeakBind )
845 dyld::log("dyld: weak bind end\n");
846 }
847
848
849
850 void ImageLoader::recursiveGetDOFSections(const LinkContext& context, std::vector<DOFInfo>& dofs)
851 {
852 if ( ! fRegisteredDOF ) {
853 // break cycles
854 fRegisteredDOF = true;
855
856 // gather lower level libraries first
857 for(unsigned int i=0; i < libraryCount(); ++i) {
858 ImageLoader* dependentImage = libImage(i);
859 if ( dependentImage != NULL )
860 dependentImage->recursiveGetDOFSections(context, dofs);
861 }
862 this->doGetDOFSections(context, dofs);
863 }
864 }
865
866
867 void ImageLoader::recursiveSpinLock(recursive_lock& rlock)
868 {
869 // try to set image's ivar fInitializerRecursiveLock to point to this lock_info
870 // keep trying until success (spin)
871 while ( ! OSAtomicCompareAndSwapPtrBarrier(NULL, &rlock, (void**)&fInitializerRecursiveLock) ) {
872 // if fInitializerRecursiveLock already points to a different lock_info, if it is for
873 // the same thread we are on, the increment the lock count, otherwise continue to spin
874 if ( (fInitializerRecursiveLock != NULL) && (fInitializerRecursiveLock->thread == rlock.thread) )
875 break;
876 }
877 ++(fInitializerRecursiveLock->count);
878 }
879
880 void ImageLoader::recursiveSpinUnLock()
881 {
882 if ( --(fInitializerRecursiveLock->count) == 0 )
883 fInitializerRecursiveLock = NULL;
884 }
885
886
887 void ImageLoader::recursiveInitialization(const LinkContext& context, mach_port_t this_thread, InitializerTimingList& timingInfo)
888 {
889 recursive_lock lock_info(this_thread);
890 recursiveSpinLock(lock_info);
891
892 if ( fState < dyld_image_state_dependents_initialized-1 ) {
893 uint8_t oldState = fState;
894 // break cycles
895 fState = dyld_image_state_dependents_initialized-1;
896 try {
897 bool hasUpwards = false;
898 // initialize lower level libraries first
899 for(unsigned int i=0; i < libraryCount(); ++i) {
900 ImageLoader* dependentImage = libImage(i);
901 if ( dependentImage != NULL ) {
902 // don't try to initialize stuff "above" me
903 bool isUpward = libIsUpward(i);
904 if ( (dependentImage->fDepth >= fDepth) && !isUpward ) {
905 dependentImage->recursiveInitialization(context, this_thread, timingInfo);
906 }
907 hasUpwards |= isUpward;
908 }
909 }
910
911 // record termination order
912 if ( this->needsTermination() )
913 context.terminationRecorder(this);
914
915 // let objc know we are about to initialize this image
916 uint64_t t1 = mach_absolute_time();
917 fState = dyld_image_state_dependents_initialized;
918 oldState = fState;
919 context.notifySingle(dyld_image_state_dependents_initialized, this);
920
921 // initialize this image
922 bool hasInitializers = this->doInitialization(context);
923
924 // <rdar://problem/10491874> initialize any upward depedencies
925 if ( hasUpwards ) {
926 for(unsigned int i=0; i < libraryCount(); ++i) {
927 ImageLoader* dependentImage = libImage(i);
928 // <rdar://problem/10643239> ObjC CG hang
929 // only init upward lib here if lib is not downwardly referenced somewhere
930 if ( (dependentImage != NULL) && libIsUpward(i) && !dependentImage->isReferencedDownward() ) {
931 dependentImage->recursiveInitialization(context, this_thread, timingInfo);
932 }
933 }
934 }
935
936 // let anyone know we finished initializing this image
937 fState = dyld_image_state_initialized;
938 oldState = fState;
939 context.notifySingle(dyld_image_state_initialized, this);
940
941 if ( hasInitializers ) {
942 uint64_t t2 = mach_absolute_time();
943 timingInfo.images[timingInfo.count].image = this;
944 timingInfo.images[timingInfo.count].initTime = (t2-t1);
945 timingInfo.count++;
946 }
947 }
948 catch (const char* msg) {
949 // this image is not initialized
950 fState = oldState;
951 recursiveSpinUnLock();
952 throw;
953 }
954 }
955
956 recursiveSpinUnLock();
957 }
958
959
960 static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
961 {
962 static uint64_t sUnitsPerSecond = 0;
963 if ( sUnitsPerSecond == 0 ) {
964 struct mach_timebase_info timeBaseInfo;
965 if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
966 sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
967 }
968 }
969 if ( partTime < sUnitsPerSecond ) {
970 uint32_t milliSecondsTimesHundred = (partTime*100000)/sUnitsPerSecond;
971 uint32_t milliSeconds = milliSecondsTimesHundred/100;
972 uint32_t percentTimesTen = (partTime*1000)/totalTime;
973 uint32_t percent = percentTimesTen/10;
974 dyld::log("%s: %u.%02u milliseconds (%u.%u%%)\n", msg, milliSeconds, milliSecondsTimesHundred-milliSeconds*100, percent, percentTimesTen-percent*10);
975 }
976 else {
977 uint32_t secondsTimeTen = (partTime*10)/sUnitsPerSecond;
978 uint32_t seconds = secondsTimeTen/10;
979 uint32_t percentTimesTen = (partTime*1000)/totalTime;
980 uint32_t percent = percentTimesTen/10;
981 dyld::log("%s: %u.%u seconds (%u.%u%%)\n", msg, seconds, secondsTimeTen-seconds*10, percent, percentTimesTen-percent*10);
982 }
983 }
984
985 static char* commatize(uint64_t in, char* out)
986 {
987 uint64_t div10 = in / 10;
988 uint8_t delta = in - div10*10;
989 char* s = &out[32];
990 int digitCount = 1;
991 *s = '\0';
992 *(--s) = '0' + delta;
993 in = div10;
994 while ( in != 0 ) {
995 if ( (digitCount % 3) == 0 )
996 *(--s) = ',';
997 div10 = in / 10;
998 delta = in - div10*10;
999 *(--s) = '0' + delta;
1000 in = div10;
1001 ++digitCount;
1002 }
1003 return s;
1004 }
1005
1006
1007 void ImageLoader::printStatistics(unsigned int imageCount, const InitializerTimingList& timingInfo)
1008 {
1009 uint64_t totalTime = fgTotalLoadLibrariesTime + fgTotalRebaseTime + fgTotalBindTime + fgTotalWeakBindTime + fgTotalDOF + fgTotalInitTime;
1010 char commaNum1[40];
1011 char commaNum2[40];
1012
1013 printTime("total time", totalTime, totalTime);
1014 #if __IPHONE_OS_VERSION_MIN_REQUIRED
1015 if ( fgImagesUsedFromSharedCache != 0 )
1016 dyld::log("total images loaded: %d (%u from dyld shared cache)\n", imageCount, fgImagesUsedFromSharedCache);
1017 else
1018 dyld::log("total images loaded: %d\n", imageCount);
1019 #else
1020 dyld::log("total images loaded: %d (%u from dyld shared cache)\n", imageCount, fgImagesUsedFromSharedCache);
1021 #endif
1022 dyld::log("total segments mapped: %u, into %llu pages with %llu pages pre-fetched\n", fgTotalSegmentsMapped, fgTotalBytesMapped/4096, fgTotalBytesPreFetched/4096);
1023 printTime("total images loading time", fgTotalLoadLibrariesTime, totalTime);
1024 printTime("total dtrace DOF registration time", fgTotalDOF, totalTime);
1025 dyld::log("total rebase fixups: %s\n", commatize(fgTotalRebaseFixups, commaNum1));
1026 printTime("total rebase fixups time", fgTotalRebaseTime, totalTime);
1027 dyld::log("total binding fixups: %s\n", commatize(fgTotalBindFixups, commaNum1));
1028 if ( fgTotalBindSymbolsResolved != 0 ) {
1029 uint32_t avgTimesTen = (fgTotalBindImageSearches * 10) / fgTotalBindSymbolsResolved;
1030 uint32_t avgInt = fgTotalBindImageSearches / fgTotalBindSymbolsResolved;
1031 uint32_t avgTenths = avgTimesTen - (avgInt*10);
1032 dyld::log("total binding symbol lookups: %s, average images searched per symbol: %u.%u\n",
1033 commatize(fgTotalBindSymbolsResolved, commaNum1), avgInt, avgTenths);
1034 }
1035 printTime("total binding fixups time", fgTotalBindTime, totalTime);
1036 printTime("total weak binding fixups time", fgTotalWeakBindTime, totalTime);
1037 dyld::log("total bindings lazily fixed up: %s of %s\n", commatize(fgTotalLazyBindFixups, commaNum1), commatize(fgTotalPossibleLazyBindFixups, commaNum2));
1038 printTime("total initializer time", fgTotalInitTime, totalTime);
1039 for (uintptr_t i=0; i < timingInfo.count; ++i) {
1040 dyld::log("%21s ", timingInfo.images[i].image->getShortName());
1041 printTime("", timingInfo.images[i].initTime, totalTime);
1042 }
1043
1044 }
1045
1046
1047 //
1048 // copy path and add suffix to result
1049 //
1050 // /path/foo.dylib _debug => /path/foo_debug.dylib
1051 // foo.dylib _debug => foo_debug.dylib
1052 // foo _debug => foo_debug
1053 // /path/bar _debug => /path/bar_debug
1054 // /path/bar.A.dylib _debug => /path/bar.A_debug.dylib
1055 //
1056 void ImageLoader::addSuffix(const char* path, const char* suffix, char* result)
1057 {
1058 strcpy(result, path);
1059
1060 char* start = strrchr(result, '/');
1061 if ( start != NULL )
1062 start++;
1063 else
1064 start = result;
1065
1066 char* dot = strrchr(start, '.');
1067 if ( dot != NULL ) {
1068 strcpy(dot, suffix);
1069 strcat(&dot[strlen(suffix)], &path[dot-result]);
1070 }
1071 else {
1072 strcat(result, suffix);
1073 }
1074 }
1075
1076
1077
1078