Loading...
--- dyld/dyld-43/src/ImageLoader.cpp
+++ dyld/dyld-44.4/src/ImageLoader.cpp
@@ -31,6 +31,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/mount.h>
#include "ImageLoader.h"
@@ -262,21 +264,22 @@
return ( --fReferenceCount == 0 );
}
-
-const ImageLoader::Symbol* ImageLoader::resolveSymbol(const char* name, bool searchSelf, ImageLoader** foundIn) const
+// private method that handles circular dependencies by only search any image once
+const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImagesExcept(const char* name, std::set<const ImageLoader*>& dontSearchImages, ImageLoader** foundIn) const
{
const ImageLoader::Symbol* sym;
// search self
- if ( searchSelf ) {
+ if ( dontSearchImages.count(this) == 0 ) {
sym = this->findExportedSymbol(name, NULL, false, foundIn);
if ( sym != NULL )
return sym;
+ dontSearchImages.insert(this);
}
// search directly dependent libraries
for (uint32_t i=0; i < fLibrariesCount; ++i) {
ImageLoader* dependentImage = fLibraries[i].image;
- if ( dependentImage != NULL ) {
+ if ( (dependentImage != NULL) && (dontSearchImages.count(dependentImage) == 0) ) {
const ImageLoader::Symbol* sym = dependentImage->findExportedSymbol(name, NULL, false, foundIn);
if ( sym != NULL )
return sym;
@@ -286,16 +289,30 @@
// search indirectly dependent libraries
for (uint32_t i=0; i < fLibrariesCount; ++i) {
ImageLoader* dependentImage = fLibraries[i].image;
- if ( dependentImage != NULL ) {
- const ImageLoader::Symbol* sym = dependentImage->resolveSymbol(name, false, foundIn);
+ if ( (dependentImage != NULL) && (dontSearchImages.count(dependentImage) == 0) ) {
+ const ImageLoader::Symbol* sym = dependentImage->findExportedSymbolInDependentImagesExcept(name, dontSearchImages, foundIn);
if ( sym != NULL )
return sym;
+ dontSearchImages.insert(dependentImage);
}
}
return NULL;
}
+
+const ImageLoader::Symbol* ImageLoader::findExportedSymbolInDependentImages(const char* name, ImageLoader** foundIn) const
+{
+ std::set<const ImageLoader*> dontSearchImages;
+ dontSearchImages.insert(this); // don't search this image
+ return this->findExportedSymbolInDependentImagesExcept(name, dontSearchImages, foundIn);
+}
+
+const ImageLoader::Symbol* ImageLoader::findExportedSymbolInImageOrDependentImages(const char* name, ImageLoader** foundIn) const
+{
+ std::set<const ImageLoader*> dontSearchImages;
+ return this->findExportedSymbolInDependentImagesExcept(name, dontSearchImages, foundIn);
+}
void ImageLoader::link(const LinkContext& context, BindingLaziness bindness, InitializerRunning inits, uint32_t notifyCount)
@@ -489,6 +506,7 @@
const char* referencedFrom = this->getPath();
char buf[strlen(requiredLib.name)+strlen(referencedFrom)+strlen(formatString)+strlen(msg)+2];
sprintf(buf, formatString, requiredLib.name, referencedFrom, msg);
+ fLibrariesLoaded = false;
throw strdup(buf); // this is a leak if exception doesn't halt program
}
// ok if weak library not found
@@ -688,7 +706,7 @@
}
}
-void ImageLoader::reprebindCommit(const LinkContext& context, bool commit)
+void ImageLoader::reprebindCommit(const LinkContext& context, bool commit, bool unmapOld)
{
// do nothing on unprebound images
if ( ! this->isPrebindable() )
@@ -704,7 +722,7 @@
throwf("realpath() failed on %s, errno=%d", this->getPath(), errno);
}
// recreate temp file name
- char tempFilePath[PATH_MAX];
+ char tempFilePath[strlen(realFilePath)+strlen("_redoprebinding")+2];
ImageLoader::addSuffix(realFilePath, "_redoprebinding", tempFilePath);
if ( commit ) {
@@ -718,6 +736,9 @@
else
throwf("can't swap temporary re-prebound file: rename(%s,%s) returned errno=%d", tempFilePath, realFilePath, errno);
}
+ else if ( unmapOld ) {
+ this->prebindUnmap(context);
+ }
}
else {
// something went wrong during prebinding, delete the temp files
@@ -725,25 +746,30 @@
}
}
-void ImageLoader::reprebind(const LinkContext& context, time_t timestamp)
+uint64_t ImageLoader::reprebind(const LinkContext& context, time_t timestamp)
{
// do nothing on unprebound images
if ( ! this->isPrebindable() )
- return;
+ return INT64_MAX;
// do nothing if prebinding is up to date
if ( this->usablePrebinding(context) ) {
if ( context.verbosePrebinding )
fprintf(stderr, "dyld: no need to re-prebind: %s\n", this->getPath());
- return;
- }
+ return INT64_MAX;
+ }
+ // recreate temp file name
+ char realFilePath[PATH_MAX];
+ if ( realpath(this->getPath(), realFilePath) == NULL ) {
+ throwf("realpath() failed on %s, errno=%d", this->getPath(), errno);
+ }
+ char tempFilePath[strlen(realFilePath)+strlen("_redoprebinding")+2];
+ ImageLoader::addSuffix(realFilePath, "_redoprebinding", tempFilePath);
+
// make copy of file and map it in
- char tempFilePath[PATH_MAX];
- realpath(this->getPath(), tempFilePath);
- ImageLoader::addSuffix(this->getPath(), "_redoprebinding", tempFilePath);
uint8_t* fileToPrebind;
uint64_t fileToPrebindSize;
- this->copyAndMap(tempFilePath, &fileToPrebind, &fileToPrebindSize);
+ uint64_t freespace = this->copyAndMap(tempFilePath, &fileToPrebind, &fileToPrebindSize);
// do format specific prebinding
this->doPrebinding(context, timestamp, fileToPrebind);
@@ -758,10 +784,12 @@
// log
if ( context.verbosePrebinding )
- fprintf(stderr, "dyld: re-prebound: %s\n", this->getPath());
-}
-
-void ImageLoader::copyAndMap(const char* tempFile, uint8_t** fileToPrebind, uint64_t* fileToPrebindSize)
+ fprintf(stderr, "dyld: re-prebound: %p %s\n", this->machHeader(), this->getPath());
+
+ return freespace;
+}
+
+uint64_t ImageLoader::copyAndMap(const char* tempFile, uint8_t** fileToPrebind, uint64_t* fileToPrebindSize)
{
// reopen dylib
int src = open(this->getPath(), O_RDONLY);
@@ -778,16 +806,16 @@
int dst = open(tempFile, O_CREAT | O_RDWR | O_TRUNC, stat_buf.st_mode);
if ( dst == -1 )
throw "can't create temp image";
-
+
// mark source as "don't cache"
(void)fcntl(src, F_NOCACHE, 1);
// we want to cache the dst because we are about to map it in and modify it
// copy permission bits
if ( chmod(tempFile, stat_buf.st_mode & 07777) == -1 )
- throw "can't chmod temp image";
+ throwf("can't chmod temp image. errno=%d for %s", errno, this->getPath());
if ( chown(tempFile, stat_buf.st_uid, stat_buf.st_gid) == -1)
- throw "can't chown temp image";
+ throwf("can't chown temp image. errno=%d for %s", errno, this->getPath());
// copy contents
ssize_t len;
@@ -801,7 +829,8 @@
throw "can't allcoate copy buffer";
}
while ( (len = read(src, buffer, kBufferSize)) > 0 ) {
- write(dst, buffer, len);
+ if ( write(dst, buffer, len) == -1 )
+ throwf("write failure copying dylib errno=%d for %s", errno, this->getPath());
}
// map in dst file
@@ -810,6 +839,12 @@
if ( *fileToPrebind == (uint8_t*)(-1) )
throw "can't mmap temp image";
+ // get free space remaining on dst volume
+ struct statfs statfs_buf;
+ if ( fstatfs(dst, &statfs_buf) != 0 )
+ throwf("can't fstatfs(), errno=%d for %s", errno, tempFile);
+ uint64_t freespace = statfs_buf.f_bavail * statfs_buf.f_bsize;
+
// closing notes:
// ok to close file after mapped in
// ok to throw above without closing file because the throw will terminate update_prebinding
@@ -817,6 +852,8 @@
int result2 = close(src);
if ( (result1 != 0) || (result2 != 0) )
throw "can't close file";
+
+ return freespace;
}