Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606/* * Copyright (c) 2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */
#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 <mach-o/dyld_priv.h>#include <mach-o/dyld_images.h>
#include <algorithm>
#include "dlfcn.h"
#include "AllImages.h"#include "Loading.h"#include "Logging.h"#include "Diagnostics.h"#include "DyldSharedCache.h"#include "APIs.h"
namespace dyld3 {
// from APIs.cppvoid parseDlHandle(void* h, const MachOLoaded** mh, bool* dontContinue);
// only in macOS and deprecated #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.// NSCreateObjectFileImageFrom*() just maps in the bundle mach-o file.// NSLinkModule() does the load of dependent modules and rebasing/binding.// To unload one of these, you must call NSUnLinkModule() and NSDestroyObjectFileImage() in any order!//
NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile(const char* path, NSObjectFileImage* ofi){ log_apis("NSCreateObjectFileImageFromFile(\"%s\", %p)\n", path, ofi);
// verify path exists struct stat statbuf; 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);
return NSObjectFileImageSuccess;}
NSObjectFileImageReturnCode NSCreateObjectFileImageFromMemory(const void* memImage, size_t memImageSize, NSObjectFileImage *ofi){ log_apis("NSCreateObjectFileImageFromMemory(%p, 0x%0lX, %p)\n", memImage, memImageSize, ofi);
// 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) != 0); } else if ( const FatFile* ff = FatFile::isFatFile(memImage) ) { uint64_t sliceOffset; uint64_t sliceLen; bool missingSlice; if ( ff->isFatFileWithSlice(diag, memImageSize, gAllImages.archs(), sliceOffset, sliceLen, missingSlice) ) { mf = (MachOFile*)((long)memImage+sliceOffset); if ( mf->isMachO(diag, sliceLen) ) { usable = true; } } } if ( usable ) { if ( !mf->supportsPlatform(Platform::macOS) ) usable = false; } if ( !usable ) { 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"); 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);
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); 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"); } ::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); } });
log_apis("NSLinkModule() => %p\n", loadAddress); return (NSModule)loadAddress;}
// NSUnLinkModule unmaps the image, but does not release the NSObjectFileImagebool 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;}
// NSDestroyObjectFileImage releases the NSObjectFileImage, but the mapped image may remain in usebool 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) return false;
// remove from list gAllImages.removeNSObjectFileImage(imageHandle);
// 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 if ( memSource != nullptr ) { // we don't know if memory came from malloc or vm_allocate, so ask malloc 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 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); });
// ofi is invalid if not in list if (!foundImage) 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; });
// ofi is invalid if not in list if (!foundImage) 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){ __block bool result = false; gAllImages.forEachImage(^(const LoadedImage& loadedImage, bool& stop) { bool resultPointsToInstructions = false; if ( loadedImage.loadedAddress()->hasExportedSymbol(symbolName, nullptr, symbolAddress, &resultPointsToInstructions) ) { *foundInImageAtLoadAddress = loadedImage.loadedAddress(); stop = true; result = true; } }); return result;}
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);
void* addr; bool resultPointsToInstructions = false; return ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions);}
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);
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){ 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; } if ( options & NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ) { log_apis(" NSLookupSymbolInImage() => NULL\n"); return nullptr; } // FIXME: abort(); return nullptr;}
const char* NSNameOfSymbol(NSSymbol symbol){ halt("NSNameOfSymbol() is obsolete");}
void* NSAddressOfSymbol(NSSymbol symbol){ log_apis("NSAddressOfSymbol(%p)\n", symbol);
// in dyld 1.0, NSSymbol was a pointer to the nlist entry in the symbol table return (void*)symbol;}
NSModule NSModuleForSymbol(NSSymbol symbol){ 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;}
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);
void* callerAddress = __builtin_return_address(1); // note layers: 1: real client, 0: libSystem glue return ( dlopen_internal(pathName, 0, callerAddress) != 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);}
const mach_header* NSAddImage(const char* imageName, uint32_t options){ log_apis("NSAddImage(\"%s\", 0x%08X)\n", imageName, options);
// Note: this is a quick and dirty implementation that just uses dlopen() and ignores some option flags uint32_t dloptions = 0; 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); if ( h != nullptr ) { const MachOLoaded* 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);
// in dyld3, everything is always fully bound 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
} // namespace dyld3