Loading...
dyld3/APIs_macOS.cpp dyld-519.2.2 dyld-832.7.3
--- dyld/dyld-519.2.2/dyld3/APIs_macOS.cpp
+++ dyld/dyld-832.7.3/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,19 +48,14 @@
 #include "APIs.h"
 
 
-
-typedef dyld3::launch_cache::binary_format::Image BinaryImage;
-
-
 namespace dyld3 {
 
 // from APIs.cpp
-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);
+void                    parseDlHandle(void* h, const MachOLoaded** mh, bool* dontContinue);
 
 
 // only in macOS and deprecated 
-#if __MAC_OS_X_VERSION_MIN_REQUIRED
+#if TARGET_OS_OSX
 
 // 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.
@@ -75,19 +70,19 @@
 
     // verify path exists
      struct stat statbuf;
-    if ( ::stat(path, &statbuf) == -1 )
+    if ( dyld3::stat(path, &statbuf) == -1 )
         return NSObjectFileImageFailure;
 
     // create ofi that just contains path. NSLinkModule does all the work
-    __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);
+    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;
 }
@@ -98,150 +93,161 @@
 
     // sanity check the buffer is a mach-o file
     __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;
+
+	// 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;
             }
-        });
-    }
-    if ( foundMH == nullptr ) {
+        }
+    }
+    if ( usable ) {
+        if ( !mf->builtForPlatform(Platform::macOS) )
+            usable = false;
+    }
+    if ( !usable ) {
         log_apis("NSCreateObjectFileImageFromMemory() not mach-o\n");
         return NSObjectFileImageFailure;
     }
 
     // this API can only be used with bundles
-    if ( foundMH->filetype != MH_BUNDLE ) {
-        log_apis("NSCreateObjectFileImageFromMemory() not a bundle, filetype=%d\n", foundMH->filetype);
+    if ( !mf->isBundle() ) {
+        log_apis("NSCreateObjectFileImageFromMemory() not a bundle\n");
         return NSObjectFileImageInappropriateFile;
     }
 
     // allocate ofi that just lists the memory range
-    __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);
+    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);
 
-    // 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);
+    __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, ofi->memSource, ofi->memLength, 0);
-                if ( writtenSize == ofi->memLength )
-                    successfullyWritten = true;
+                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);
             }
         }
-        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;
+        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);
         }
-    }
-    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;
+    });
+
+    log_apis("NSLinkModule() => %p\n", loadAddress);
+    return (NSModule)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);
 
-    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;
+    __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 use
-bool NSDestroyObjectFileImage(NSObjectFileImage ofi)
-{
-    log_apis("NSDestroyObjectFileImage(%p)\n", ofi);
-
-    // ofi is invalid if not in list
-    if ( !gAllImages.hasNSObjectFileImage(ofi) )
+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)
         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(ofi);
+    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
@@ -277,79 +283,81 @@
     halt("NSSymbolReferenceNameInObjectFileImage() is obsolete");
 }
 
-bool NSIsSymbolDefinedInObjectFileImage(NSObjectFileImage ofi, const char* symbolName)
-{
-    log_apis("NSIsSymbolDefinedInObjectFileImage(%p, %s)\n", ofi, symbolName);
+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 ( !gAllImages.hasNSObjectFileImage(ofi) )
+    if (!foundImage)
         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)
-{
+    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 ( !gAllImages.hasNSObjectFileImage(ofi) )
+    if (!foundImage)
         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;
+	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();
             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)
@@ -374,14 +382,9 @@
 {
     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);
+    void* addr;
+    bool resultPointsToInstructions = false;
+    return ((MachOLoaded*)mh)->hasExportedSymbol(symbolName, nullptr, &addr, &resultPointsToInstructions);
 }
 
 NSSymbol NSLookupAndBindSymbol(const char* symbolName)
@@ -412,43 +415,30 @@
 {
     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;
-        }
+    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 struct mach_header* mh, const char* symbolName, uint32_t options)
+NSSymbol NSLookupSymbolInImage(const 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;
-    }
-
+    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;
 }
 
@@ -469,12 +459,12 @@
 {
     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;
+    __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)
@@ -490,14 +480,16 @@
 {
     log_apis("NSAddLibrary(%s)\n", pathName);
 
-    return ( dlopen(pathName, 0) != nullptr);
+    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);
 
-    return ( dlopen(pathName, 0) != nullptr);
+    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)
@@ -509,9 +501,10 @@
     if ( (options & NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED) != 0 )
         dloptions |= RTLD_NOLOAD;
 
-    void* h = dlopen(imageName, dloptions);
+    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 mach_header* mh;
+        const MachOLoaded* mh;
         bool dontContinue;
         parseDlHandle(h, &mh, &dontContinue);
         return mh;