Loading...
--- dyld/dyld-832.7.1/dyld3/APIs_macOS.cpp
+++ dyld/dyld-519.2.2/dyld3/APIs_macOS.cpp
@@ -33,14 +33,14 @@
#include <fcntl.h>
#include <TargetConditionals.h>
#include <malloc/malloc.h>
-#include <mach-o/dyld_priv.h>
-#include <mach-o/dyld_images.h>
#include <algorithm>
#include "dlfcn.h"
+#include "dyld_priv.h"
#include "AllImages.h"
+#include "MachOParser.h"
#include "Loading.h"
#include "Logging.h"
#include "Diagnostics.h"
@@ -48,14 +48,19 @@
#include "APIs.h"
+
+typedef dyld3::launch_cache::binary_format::Image BinaryImage;
+
+
namespace dyld3 {
// from APIs.cpp
-void parseDlHandle(void* h, const MachOLoaded** mh, bool* dontContinue);
+void parseDlHandle(void* h, const mach_header** mh, bool* dontContinue);
+const mach_header* loadImageAndDependents(Diagnostics& diag, const launch_cache::binary_format::Image* imageToLoad, bool bumpDlopenCount);
// only in macOS and deprecated
-#if TARGET_OS_OSX
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
// macOS needs to support an old API that only works with fileype==MH_BUNDLE.
// In this deprecated API (unlike dlopen), loading and linking are separate steps.
@@ -70,19 +75,19 @@
// verify path exists
struct stat statbuf;
- if ( dyld3::stat(path, &statbuf) == -1 )
+ if ( ::stat(path, &statbuf) == -1 )
return NSObjectFileImageFailure;
// create ofi that just contains path. NSLinkModule does all the work
- OFIInfo result;
- result.path = strdup(path);
- result.memSource = nullptr;
- result.memLength = 0;
- result.loadAddress = nullptr;
- result.imageNum = 0;
- *ofi = gAllImages.addNSObjectFileImage(result);
-
- log_apis("NSCreateObjectFileImageFromFile() => %p\n", *ofi);
+ __NSObjectFileImage* result = gAllImages.addNSObjectFileImage();
+ result->path = strdup(path);
+ result->memSource = nullptr;
+ result->memLength = 0;
+ result->loadAddress = nullptr;
+ result->binImage = nullptr;
+ *ofi = result;
+
+ log_apis("NSCreateObjectFileImageFromFile() => %p\n", result);
return NSObjectFileImageSuccess;
}
@@ -93,161 +98,150 @@
// sanity check the buffer is a mach-o file
__block Diagnostics diag;
-
- // check if it is current arch mach-o or fat with slice for current arch
- bool usable = false;
- const MachOFile* mf = (MachOFile*)memImage;
- if ( mf->hasMachOMagic() && mf->isMachO(diag, memImageSize) ) {
- usable = (gAllImages.archs().grade(mf->cputype, mf->cpusubtype, false) != 0);
- }
- else if ( const FatFile* ff = FatFile::isFatFile(memImage) ) {
- uint64_t sliceOffset;
- uint64_t sliceLen;
- bool missingSlice;
- if ( ff->isFatFileWithSlice(diag, memImageSize, gAllImages.archs(), false, sliceOffset, sliceLen, missingSlice) ) {
- mf = (MachOFile*)((long)memImage+sliceOffset);
- if ( mf->isMachO(diag, sliceLen) ) {
- usable = true;
+ __block const mach_header* foundMH = nullptr;
+ if ( MachOParser::isMachO(diag, memImage, memImageSize) ) {
+ foundMH = (mach_header*)memImage;
+ }
+ else {
+ FatUtil::forEachSlice(diag, memImage, memImageSize, ^(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void* sliceStart, size_t sliceSize, bool& stop) {
+ if ( MachOParser::isMachO(diag, sliceStart, sliceSize) ) {
+ foundMH = (mach_header*)sliceStart;
+ stop = true;
}
- }
- }
- if ( usable ) {
- if ( !mf->builtForPlatform(Platform::macOS) )
- usable = false;
- }
- if ( !usable ) {
+ });
+ }
+ if ( foundMH == nullptr ) {
log_apis("NSCreateObjectFileImageFromMemory() not mach-o\n");
return NSObjectFileImageFailure;
}
// this API can only be used with bundles
- if ( !mf->isBundle() ) {
- log_apis("NSCreateObjectFileImageFromMemory() not a bundle\n");
+ if ( foundMH->filetype != MH_BUNDLE ) {
+ log_apis("NSCreateObjectFileImageFromMemory() not a bundle, filetype=%d\n", foundMH->filetype);
return NSObjectFileImageInappropriateFile;
}
// allocate ofi that just lists the memory range
- OFIInfo result;
- result.path = nullptr;
- result.memSource = memImage;
- result.memLength = memImageSize;
- result.loadAddress = nullptr;
- result.imageNum = 0;
- *ofi = gAllImages.addNSObjectFileImage(result);
-
- log_apis("NSCreateObjectFileImageFromMemory() => %p\n", *ofi);
+ __NSObjectFileImage* result = gAllImages.addNSObjectFileImage();
+ result->path = nullptr;
+ result->memSource = memImage;
+ result->memLength = memImageSize;
+ result->loadAddress = nullptr;
+ result->binImage = nullptr;
+ *ofi = result;
+
+ log_apis("NSCreateObjectFileImageFromMemory() => %p\n", result);
return NSObjectFileImageSuccess;
}
NSModule NSLinkModule(NSObjectFileImage ofi, const char* moduleName, uint32_t options)
{
- DYLD_LOAD_LOCK_THIS_BLOCK
log_apis("NSLinkModule(%p, \"%s\", 0x%08X)\n", ofi, moduleName, options);
- __block const char* path = nullptr;
- bool foundImage = gAllImages.forNSObjectFileImage(ofi, ^(OFIInfo &image) {
- // if this is memory based image, write to temp file, then use file based loading
- if ( image.memSource != nullptr ) {
- // make temp file with content of memory buffer
- image.path = nullptr;
- char tempFileName[PATH_MAX];
- const char* tmpDir = getenv("TMPDIR");
- if ( (tmpDir != nullptr) && (strlen(tmpDir) > 2) ) {
- strlcpy(tempFileName, tmpDir, PATH_MAX);
- if ( tmpDir[strlen(tmpDir)-1] != '/' )
- strlcat(tempFileName, "/", PATH_MAX);
- }
- else
- strlcpy(tempFileName,"/tmp/", PATH_MAX);
- strlcat(tempFileName, "NSCreateObjectFileImageFromMemory-XXXXXXXX", PATH_MAX);
- int fd = ::mkstemp(tempFileName);
+ // ofi is invalid if not in list
+ if ( !gAllImages.hasNSObjectFileImage(ofi) ) {
+ log_apis("NSLinkModule() => NULL (invalid NSObjectFileImage)\n");
+ return nullptr;
+ }
+
+ // if this is memory based image, write to temp file, then use file based loading
+ const BinaryImage* imageToLoad = nullptr;
+ if ( ofi->memSource != nullptr ) {
+ // make temp file with content of memory buffer
+ bool successfullyWritten = false;
+ ofi->path = ::tempnam(nullptr, "NSCreateObjectFileImageFromMemory-");
+ if ( ofi->path != nullptr ) {
+ int fd = ::open(ofi->path, O_WRONLY | O_CREAT | O_EXCL, 0644);
if ( fd != -1 ) {
- ssize_t writtenSize = ::pwrite(fd, image.memSource, image.memLength, 0);
- if ( writtenSize == image.memLength ) {
- image.path = strdup(tempFileName);
- }
- else {
- log_apis("NSLinkModule() => NULL (could not save memory image to temp file)\n");
- }
+ ssize_t writtenSize = ::pwrite(fd, ofi->memSource, ofi->memLength, 0);
+ if ( writtenSize == ofi->memLength )
+ successfullyWritten = true;
::close(fd);
}
}
- path = image.path;
- });
-
- if (!foundImage) {
- // ofi is invalid if not in list
- log_apis("NSLinkModule() => NULL (invalid NSObjectFileImage)\n");
- return nullptr;
- }
-
- if (!path)
- return nullptr;
-
- // dlopen the binary outside of the read lock as we don't want to risk deadlock
- Diagnostics diag;
- void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
- const MachOLoaded* loadAddress = gAllImages.dlopen(diag, path, false, false, false, false, true, callerAddress);
- if ( diag.hasError() ) {
- log_apis(" NSLinkModule: failed: %s\n", diag.errorMessage());
- return nullptr;
- }
-
- // Now update the load address of this object
- gAllImages.forNSObjectFileImage(ofi, ^(OFIInfo &image) {
- image.loadAddress = loadAddress;
-
- // if memory based load, delete temp file
- if ( image.memSource != nullptr ) {
- log_apis(" NSLinkModule: delete temp file: %s\n", image.path);
- ::unlink(image.path);
+ if ( !successfullyWritten ) {
+ if ( ofi->path != nullptr ) {
+ free((void*)ofi->path);
+ ofi->path = nullptr;
+ }
+ log_apis("NSLinkModule() => NULL (could not save memory image to temp file)\n");
+ return nullptr;
}
- });
-
- log_apis("NSLinkModule() => %p\n", loadAddress);
- return (NSModule)loadAddress;
+ }
+ else {
+ // check if image is in a known ImageGroup, but not loaded. if so, load using existing closure info
+ log_apis(" NSLinkModule: checking for pre-built closure for path: %s\n", ofi->path);
+ imageToLoad = gAllImages.findImageInKnownGroups(ofi->path);
+ // TODO: check symlinks, realpath
+ }
+
+ // if no existing closure, RPC to closured to create one
+ if ( imageToLoad == nullptr ) {
+ const char* closuredErrorMessages[3];
+ int closuredErrorMessagesCount = 0;
+ if ( imageToLoad == nullptr ) {
+ imageToLoad = gAllImages.messageClosured(ofi->path, "NSLinkModule", closuredErrorMessages, closuredErrorMessagesCount);
+ }
+ for (int i=0; i < closuredErrorMessagesCount; ++i) {
+ log_apis(" NSLinkModule: failed: %s\n", closuredErrorMessages[i]);
+ free((void*)closuredErrorMessages[i]);
+ }
+ }
+
+ // use Image info to load and fixup image and all its dependents
+ if ( imageToLoad != nullptr ) {
+ Diagnostics diag;
+ ofi->loadAddress = loadImageAndDependents(diag, imageToLoad, true);
+ if ( diag.hasError() )
+ log_apis(" NSLinkModule: failed: %s\n", diag.errorMessage());
+ }
+
+ // if memory based load, delete temp file
+ if ( ofi->memSource != nullptr ) {
+ log_apis(" NSLinkModule: delete temp file: %s\n", ofi->path);
+ ::unlink(ofi->path);
+ }
+
+ log_apis("NSLinkModule() => %p\n", ofi->loadAddress);
+ return (NSModule)ofi->loadAddress;
}
// NSUnLinkModule unmaps the image, but does not release the NSObjectFileImage
bool NSUnLinkModule(NSModule module, uint32_t options)
{
- DYLD_LOAD_LOCK_THIS_BLOCK
log_apis("NSUnLinkModule(%p, 0x%08X)\n", module, options);
- __block const mach_header* mh = nullptr;
- gAllImages.infoForImageMappedAt(module, ^(const LoadedImage& foundImage, uint8_t permissions) {
- mh = foundImage.loadedAddress();
- });
-
- if ( mh != nullptr )
- gAllImages.decRefCount(mh); // removes image if reference count went to zero
-
- log_apis("NSUnLinkModule() => %d\n", mh != nullptr);
-
- return mh != nullptr;
+ bool result = false;
+ const mach_header* mh = (mach_header*)module;
+ launch_cache::Image image = gAllImages.findByLoadAddress(mh);
+ if ( image.valid() ) {
+ // removes image if reference count went to zero
+ gAllImages.decRefCount(mh);
+ result = true;
+ }
+
+ log_apis("NSUnLinkModule() => %d\n", result);
+
+ return result;
}
// NSDestroyObjectFileImage releases the NSObjectFileImage, but the mapped image may remain in use
-bool NSDestroyObjectFileImage(NSObjectFileImage imageHandle)
-{
- log_apis("NSDestroyObjectFileImage(%p)\n", imageHandle);
-
- __block const void* memSource = nullptr;
- __block size_t memLength = 0;
- __block const char* path = nullptr;
- bool foundImage = gAllImages.forNSObjectFileImage(imageHandle, ^(OFIInfo &image) {
- // keep copy of info
- memSource = image.memSource;
- memLength = image.memLength;
- path = image.path;
- });
-
- if (!foundImage)
+bool NSDestroyObjectFileImage(NSObjectFileImage ofi)
+{
+ log_apis("NSDestroyObjectFileImage(%p)\n", ofi);
+
+ // ofi is invalid if not in list
+ if ( !gAllImages.hasNSObjectFileImage(ofi) )
return false;
+ // keep copy of info
+ const void* memSource = ofi->memSource;
+ size_t memLength = ofi->memLength;
+ const char* path = ofi->path;
+
// remove from list
- gAllImages.removeNSObjectFileImage(imageHandle);
+ gAllImages.removeNSObjectFileImage(ofi);
// if object was created from a memory, release that memory
// NOTE: this is the way dyld has always done this. NSCreateObjectFileImageFromMemory() hands ownership of the memory to dyld
@@ -283,83 +277,81 @@
halt("NSSymbolReferenceNameInObjectFileImage() is obsolete");
}
-bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage imageHandle, const char* symbolName)
-{
- log_apis("NSIsSymbolDefinedInObjectFileImage(%p, %s)\n", imageHandle, symbolName);
-
- __block bool hasSymbol = false;
- bool foundImage = gAllImages.forNSObjectFileImage(imageHandle, ^(OFIInfo &image) {
- void* addr;
- bool resultPointsToInstructions = false;
- hasSymbol = image.loadAddress->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions);
- });
+bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage ofi, const char* symbolName)
+{
+ log_apis("NSIsSymbolDefinedInObjectFileImage(%p, %s)\n", ofi, symbolName);
// ofi is invalid if not in list
- if (!foundImage)
+ if ( !gAllImages.hasNSObjectFileImage(ofi) )
return false;
- return hasSymbol;
-}
-
-void* NSGetSectionDataInObjectFileImage(NSObjectFileImage imageHandle, const char* segmentName, const char* sectionName, size_t* size)
-{
- __block const void* result = nullptr;
- bool foundImage = gAllImages.forNSObjectFileImage(imageHandle, ^(OFIInfo &image) {
- uint64_t sz;
- result = image.loadAddress->findSectionContent(segmentName, sectionName, sz);
- *size = (size_t)sz;
- });
-
+ void* addr;
+ MachOParser parser(ofi->loadAddress);
+ return parser.hasExportedSymbol(symbolName, ^(uint32_t , const char*, void*, const mach_header**, void**) {
+ return false;
+ }, &addr);
+}
+
+void* NSGetSectionDataInObjectFileImage(NSObjectFileImage ofi, const char* segmentName, const char* sectionName, size_t* size)
+{
// ofi is invalid if not in list
- if (!foundImage)
+ if ( !gAllImages.hasNSObjectFileImage(ofi) )
return nullptr;
- return (void*)result;
-}
-
-const char* NSNameOfModule(NSModule m)
-{
- log_apis("NSNameOfModule(%p)\n", m);
-
- __block const char* result = nullptr;
- gAllImages.infoForImageMappedAt(m, ^(const LoadedImage& foundImage, uint8_t permissions) {
- result = gAllImages.imagePath(foundImage.image());
- });
-
- return result;
-}
-
-const char* NSLibraryNameForModule(NSModule m)
-{
- log_apis("NSLibraryNameForModule(%p)\n", m);
-
- __block const char* result = nullptr;
- gAllImages.infoForImageMappedAt(m, ^(const LoadedImage& foundImage, uint8_t permissions) {
- result = gAllImages.imagePath(foundImage.image());
- });
- return result;
- }
-
-
-static bool flatFindSymbol(const char* symbolName, void** symbolAddress, const mach_header** foundInImageAtLoadAddress)
-{
- // <rdar://problem/59265987> allow flat lookup to find "_memcpy" even though it is not implemented as that name in any dylib
- MachOLoaded::DependentToMachOLoaded finder = ^(const MachOLoaded* mh, uint32_t depIndex) {
- return gAllImages.findDependent(mh, depIndex);
- };
-
- __block bool result = false;
- gAllImages.forEachImage(^(const LoadedImage& loadedImage, bool& stop) {
- bool resultPointsToInstructions = false;
- if ( loadedImage.loadedAddress()->hasExportedSymbol(symbolName, finder, symbolAddress, &resultPointsToInstructions) ) {
- *foundInImageAtLoadAddress = loadedImage.loadedAddress();
+ __block void* result = nullptr;
+ MachOParser parser(ofi->loadAddress);
+ parser.forEachSection(^(const char* aSegName, const char* aSectName, uint32_t flags, const void* content, size_t aSize, bool illegalSectionSize, bool& stop) {
+ if ( (strcmp(sectionName, aSectName) == 0) && (strcmp(segmentName, aSegName) == 0) ) {
+ result = (void*)content;
+ if ( size != nullptr )
+ *size = aSize;
stop = true;
- result = true;
}
});
return result;
}
+const char* NSNameOfModule(NSModule m)
+{
+ log_apis("NSNameOfModule(%p)\n", m);
+
+ const mach_header* foundInLoadAddress;
+ launch_cache::Image image = gAllImages.findByOwnedAddress(m, &foundInLoadAddress);
+ if ( image.valid() ) {
+ return gAllImages.imagePath(image.binaryData());
+ }
+ return nullptr;
+}
+
+const char* NSLibraryNameForModule(NSModule m)
+{
+ log_apis("NSLibraryNameForModule(%p)\n", m);
+
+ const mach_header* foundInLoadAddress;
+ launch_cache::Image image = gAllImages.findByOwnedAddress(m, &foundInLoadAddress);
+ if ( image.valid() ) {
+ return gAllImages.imagePath(image.binaryData());
+ }
+ return nullptr;
+}
+
+
+static bool flatFindSymbol(const char* symbolName, void** symbolAddress, const mach_header** foundInImageAtLoadAddress)
+{
+ for (uint32_t index=0; index < gAllImages.count(); ++index) {
+ const mach_header* loadAddress;
+ launch_cache::Image image = gAllImages.findByLoadOrder(index, &loadAddress);
+ if ( image.valid() ) {
+ MachOParser parser(loadAddress);
+ if ( parser.hasExportedSymbol(symbolName, ^(uint32_t , const char* , void* , const mach_header** , void**) { return false; }, symbolAddress) ) {
+ *foundInImageAtLoadAddress = loadAddress;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool NSIsSymbolNameDefined(const char* symbolName)
{
log_apis("NSIsSymbolNameDefined(%s)\n", symbolName);
@@ -382,9 +374,14 @@
{
log_apis("NSIsSymbolNameDefinedInImage(%p, %s)\n", mh, symbolName);
- void* addr;
- bool resultPointsToInstructions = false;
- return ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions);
+ MachOParser::DependentFinder reExportFollower = ^(uint32_t depIndex, const char* depLoadPath, void* extra, const mach_header** foundMH, void** foundExtra) {
+ *foundMH = gAllImages.alreadyLoaded(depLoadPath, false);
+ return (*foundMH != nullptr);
+ };
+
+ MachOParser parser(mh);
+ void* result;
+ return parser.hasExportedSymbol(symbolName, reExportFollower, &result);
}
NSSymbol NSLookupAndBindSymbol(const char* symbolName)
@@ -415,30 +412,43 @@
{
log_apis("NSLookupSymbolInModule(%p. %s)\n", module, symbolName);
- const MachOLoaded* mh = (const MachOLoaded*)module;
- void* addr;
- bool resultPointsToInstructions = false;
- if ( mh->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions) ) {
- return (NSSymbol)addr;
- }
- return nullptr;
-}
-
-NSSymbol NSLookupSymbolInImage(const mach_header* mh, const char* symbolName, uint32_t options)
+ MachOParser::DependentFinder reExportFollower = ^(uint32_t depIndex, const char* depLoadPath, void* extra, const mach_header** foundMH, void** foundExtra) {
+ *foundMH = gAllImages.alreadyLoaded(depLoadPath, false);
+ return (*foundMH != nullptr);
+ };
+
+ const mach_header* mh = (const mach_header*)module;
+ uint32_t loadIndex;
+ if ( gAllImages.findIndexForLoadAddress(mh, loadIndex) ) {
+ MachOParser parser(mh);
+ void* symAddress;
+ if ( parser.hasExportedSymbol(symbolName, reExportFollower, &symAddress) ) {
+ return (NSSymbol)symAddress;
+ }
+ }
+ return nullptr;
+}
+
+NSSymbol NSLookupSymbolInImage(const struct mach_header* mh, const char* symbolName, uint32_t options)
{
log_apis("NSLookupSymbolInImage(%p, \"%s\", 0x%08X)\n", mh, symbolName, options);
- void* addr;
- bool resultPointsToInstructions = false;
- if ( ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions) ) {
- log_apis(" NSLookupSymbolInImage() => %p\n", addr);
- return (NSSymbol)addr;
- }
+ MachOParser::DependentFinder reExportFollower = ^(uint32_t depIndex, const char* depLoadPath, void* extra, const mach_header** foundMH, void** foundExtra) {
+ *foundMH = gAllImages.alreadyLoaded(depLoadPath, false);
+ return (*foundMH != nullptr);
+ };
+
+ MachOParser parser(mh);
+ void* result;
+ if ( parser.hasExportedSymbol(symbolName, reExportFollower, &result) ) {
+ log_apis(" NSLookupSymbolInImage() => %p\n", result);
+ return (NSSymbol)result;
+ }
+
if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ) {
log_apis(" NSLookupSymbolInImage() => NULL\n");
return nullptr;
}
- // FIXME: abort();
return nullptr;
}
@@ -459,12 +469,12 @@
{
log_apis("NSModuleForSymbol(%p)\n", symbol);
- __block NSModule result = nullptr;
- gAllImages.infoForImageMappedAt(symbol, ^(const LoadedImage& foundImage, uint8_t permissions) {
- result = (NSModule)foundImage.loadedAddress();
- });
-
- return result;
+ const mach_header* foundInLoadAddress;
+ launch_cache::Image image = gAllImages.findByOwnedAddress(symbol, &foundInLoadAddress);
+ if ( image.valid() ) {
+ return (NSModule)foundInLoadAddress;
+ }
+ return nullptr;
}
void NSLinkEditError(NSLinkEditErrors *c, int *errorNumber, const char** fileName, const char** errorString)
@@ -480,16 +490,14 @@
{
log_apis("NSAddLibrary(%s)\n", pathName);
- void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
- return ( dlopen_internal(pathName, 0, callerAddress) != nullptr);
+ return ( dlopen(pathName, 0) != nullptr);
}
bool NSAddLibraryWithSearching(const char* pathName)
{
log_apis("NSAddLibraryWithSearching(%s)\n", pathName);
- void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
- return ( dlopen_internal(pathName, 0, callerAddress) != nullptr);
+ return ( dlopen(pathName, 0) != nullptr);
}
const mach_header* NSAddImage(const char* imageName, uint32_t options)
@@ -501,10 +509,9 @@
if ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 )
dloptions |= RTLD_NOLOAD;
- void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue
- void* h = dlopen_internal(imageName, dloptions, callerAddress);
+ void* h = dlopen(imageName, dloptions);
if ( h != nullptr ) {
- const MachOLoaded* mh;
+ const mach_header* mh;
bool dontContinue;
parseDlHandle(h, &mh, &dontContinue);
return mh;