#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <_simple.h>
#include <sys/errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <TargetConditionals.h>
#include <malloc/malloc.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"
#include "DyldSharedCache.h"
#include "APIs.h"
typedef dyld3::launch_cache::binary_format::Image BinaryImage;
namespace dyld3 {
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);
#if __MAC_OS_X_VERSION_MIN_REQUIRED
NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* path, NSObjectFileImage* ofi)
{
log_apis("NSCreateObjectFileImageFromFile(\"%s\", %p)\n", path, ofi);
struct stat statbuf;
if ( ::stat(path, &statbuf) == -1 )
return NSObjectFileImageFailure;
__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;
}
NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* memImage, size_t memImageSize, NSObjectFileImage *ofi)
{
log_apis("NSCreateObjectFileImageFromMemory(%p, 0x%0lX, %p)\n", memImage, memImageSize, ofi);
__block Diagnostics diag;
__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 ( foundMH == nullptr ) {
log_apis("NSCreateObjectFileImageFromMemory() not mach-o\n");
return NSObjectFileImageFailure;
}
if ( foundMH->filetype != MH_BUNDLE ) {
log_apis("NSCreateObjectFileImageFromMemory() not a bundle, filetype=%d\n", foundMH->filetype);
return NSObjectFileImageInappropriateFile;
}
__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)
{
log_apis("NSLinkModule(%p, \"%s\", 0x%08X)\n", ofi, moduleName, options);
if ( !gAllImages.hasNSObjectFileImage(ofi) ) {
log_apis("NSLinkModule() => NULL (invalid NSObjectFileImage)\n");
return nullptr;
}
const BinaryImage* imageToLoad = nullptr;
if ( ofi->memSource != nullptr ) {
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, ofi->memSource, ofi->memLength, 0);
if ( writtenSize == ofi->memLength )
successfullyWritten = true;
::close(fd);
}
}
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;
}
}
else {
log_apis(" NSLinkModule: checking for pre-built closure for path: %s\n", ofi->path);
imageToLoad = gAllImages.findImageInKnownGroups(ofi->path);
}
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]);
}
}
if ( imageToLoad != nullptr ) {
Diagnostics diag;
ofi->loadAddress = loadImageAndDependents(diag, imageToLoad, true);
if ( diag.hasError() )
log_apis(" NSLinkModule: failed: %s\n", diag.errorMessage());
}
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;
}
bool NSUnLinkModule(NSModule module, uint32_t options)
{
log_apis("NSUnLinkModule(%p, 0x%08X)\n", module, options);
bool result = false;
const mach_header* mh = (mach_header*)module;
launch_cache::Image image = gAllImages.findByLoadAddress(mh);
if ( image.valid() ) {
gAllImages.decRefCount(mh);
result = true;
}
log_apis("NSUnLinkModule() => %d\n", result);
return result;
}
bool NSDestroyObjectFileImage(NSObjectFileImage ofi)
{
log_apis("NSDestroyObjectFileImage(%p)\n", ofi);
if ( !gAllImages.hasNSObjectFileImage(ofi) )
return false;
const void* memSource = ofi->memSource;
size_t memLength = ofi->memLength;
const char* path = ofi->path;
gAllImages.removeNSObjectFileImage(ofi);
if ( memSource != nullptr ) {
if ( malloc_size(memSource) != 0 )
free((void*)(memSource));
else
vm_deallocate(mach_task_self(), (vm_address_t)memSource, memLength);
}
free((void*)path);
return true;
}
uint32_t NSSymbolDefinitionCountInObjectFileImage(NSObjectFileImage objectFileImage)
{
halt("NSSymbolDefinitionCountInObjectFileImage() is obsolete");
}
const char* NSSymbolDefinitionNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal)
{
halt("NSSymbolDefinitionNameInObjectFileImage() is obsolete");
}
uint32_t NSSymbolReferenceCountInObjectFileImage(NSObjectFileImage objectFileImage)
{
halt("NSSymbolReferenceCountInObjectFileImage() is obsolete");
}
const char* NSSymbolReferenceNameInObjectFileImage(NSObjectFileImage objectFileImage, uint32_t ordinal, bool *tentative_definition)
{
halt("NSSymbolReferenceNameInObjectFileImage() is obsolete");
}
bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage ofi, const char* symbolName)
{
log_apis("NSIsSymbolDefinedInObjectFileImage(%p, %s)\n", ofi, symbolName);
if ( !gAllImages.hasNSObjectFileImage(ofi) )
return false;
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)
{
if ( !gAllImages.hasNSObjectFileImage(ofi) )
return nullptr;
__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;
}
});
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);
const mach_header* foundInImageAtLoadAddress;
void* address;
return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
}
bool NSIsSymbolNameDefinedWithHint(const char* symbolName, const char* libraryNameHint)
{
log_apis("NSIsSymbolNameDefinedWithHint(%s, %s)\n", symbolName, libraryNameHint);
const mach_header* foundInImageAtLoadAddress;
void* address;
return flatFindSymbol(symbolName, &address, &foundInImageAtLoadAddress);
}
bool NSIsSymbolNameDefinedInImage(const struct mach_header* mh, const char* symbolName)
{
log_apis("NSIsSymbolNameDefinedInImage(%p, %s)\n", mh, symbolName);
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)
{
log_apis("NSLookupAndBindSymbol(%s)\n", symbolName);
const mach_header* foundInImageAtLoadAddress;
void* symbolAddress;
if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
return (NSSymbol)symbolAddress;
}
return nullptr;
}
NSSymbol NSLookupAndBindSymbolWithHint(const char* symbolName, const char* libraryNameHint)
{
log_apis("NSLookupAndBindSymbolWithHint(%s, %s)\n", symbolName, libraryNameHint);
const mach_header* foundInImageAtLoadAddress;
void* symbolAddress;
if ( flatFindSymbol(symbolName, &symbolAddress, &foundInImageAtLoadAddress) ) {
return (NSSymbol)symbolAddress;
}
return nullptr;
}
NSSymbol NSLookupSymbolInModule(NSModule module, const char* symbolName)
{
log_apis("NSLookupSymbolInModule(%p. %s)\n", module, symbolName);
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);
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;
}
return nullptr;
}
const char* NSNameOfSymbol(NSSymbol symbol)
{
halt("NSNameOfSymbol() is obsolete");
}
void* NSAddressOfSymbol(NSSymbol symbol)
{
log_apis("NSAddressOfSymbol(%p)\n", symbol);
return (void*)symbol;
}
NSModule NSModuleForSymbol(NSSymbol symbol)
{
log_apis("NSModuleForSymbol(%p)\n", symbol);
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)
{
log_apis("NSLinkEditError(%p, %p, %p, %p)\n", c, errorNumber, fileName, errorString);
*c = NSLinkEditOtherError;
*errorNumber = 0;
*fileName = NULL;
*errorString = NULL;
}
bool NSAddLibrary(const char* pathName)
{
log_apis("NSAddLibrary(%s)\n", pathName);
return ( dlopen(pathName, 0) != nullptr);
}
bool NSAddLibraryWithSearching(const char* pathName)
{
log_apis("NSAddLibraryWithSearching(%s)\n", pathName);
return ( dlopen(pathName, 0) != nullptr);
}
const mach_header* NSAddImage(const char* imageName, uint32_t options)
{
log_apis("NSAddImage(\"%s\", 0x%08X)\n", imageName, options);
uint32_t dloptions = 0;
if ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 )
dloptions |= RTLD_NOLOAD;
void* h = dlopen(imageName, dloptions);
if ( h != nullptr ) {
const mach_header* mh;
bool dontContinue;
parseDlHandle(h, &mh, &dontContinue);
return mh;
}
if ( (options & (NSADDIMAGE_OPTION_RETURN_ON_ERROR|NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED)) == 0 ) {
halt("NSAddImage() image not found");
}
return nullptr;
}
void NSInstallLinkEditErrorHandlers(const NSLinkEditErrorHandlers *handlers)
{
halt("NSInstallLinkEditErrorHandlers() is obsolete");
}
bool _dyld_present(void)
{
log_apis("_dyld_present()\n");
return true;
}
bool _dyld_launched_prebound(void)
{
halt("_dyld_launched_prebound() is obsolete");
}
bool _dyld_all_twolevel_modules_prebound(void)
{
halt("_dyld_all_twolevel_modules_prebound() is obsolete");
}
bool _dyld_bind_fully_image_containing_address(const void* address)
{
log_apis("_dyld_bind_fully_image_containing_address(%p)\n", address);
return true;
}
bool _dyld_image_containing_address(const void* address)
{
log_apis("_dyld_image_containing_address(%p)\n", address);
return (dyld_image_header_containing_address(address) != nullptr);
}
void _dyld_lookup_and_bind(const char* symbolName, void **address, NSModule* module)
{
log_apis("_dyld_lookup_and_bind(%s, %p, %p)\n", symbolName, address, module);
const mach_header* foundInImageAtLoadAddress;
if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
*module = (NSModule)foundInImageAtLoadAddress;
return;
}
*address = 0;
*module = 0;
}
void _dyld_lookup_and_bind_with_hint(const char* symbolName, const char* libraryNameHint, void** address, NSModule* module)
{
log_apis("_dyld_lookup_and_bind_with_hint(%s, %s, %p, %p)\n", symbolName, libraryNameHint, address, module);
const mach_header* foundInImageAtLoadAddress;
if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
*module = (NSModule)foundInImageAtLoadAddress;
return;
}
*address = 0;
*module = 0;
}
void _dyld_lookup_and_bind_fully(const char* symbolName, void** address, NSModule* module)
{
log_apis("_dyld_lookup_and_bind_fully(%s, %p, %p)\n", symbolName, address, module);
const mach_header* foundInImageAtLoadAddress;
if ( flatFindSymbol(symbolName, address, &foundInImageAtLoadAddress) ) {
*module = (NSModule)foundInImageAtLoadAddress;
return;
}
*address = 0;
*module = 0;
}
const struct mach_header* _dyld_get_image_header_containing_address(const void* address)
{
log_apis("_dyld_get_image_header_containing_address(%p)\n", address);
return dyld_image_header_containing_address(address);
}
#endif
}