#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <mach-o/dyld.h>
#include <mach-o/dyld_priv.h>
#include <unordered_set>
#include "test_support.h"
extern "C" void foo();
extern mach_header __dso_handle;
static std::unordered_set<const mach_header*> sCurrentImages;
static bool expectedUnloadableState = false;
static void notify(const mach_header* mh, const char* path, bool unloadable)
{
LOG("mh=%p, path=%s, unloadable=%d", mh, path, unloadable);
if ( sCurrentImages.count(mh) != 0 ) {
FAIL("notified twice about %p", mh);
}
sCurrentImages.insert(mh);
const char* leaf = strrchr(path, '/');
if ( unloadable != expectedUnloadableState ) {
FAIL("image incorrectly marked unloadable(%s) but expected unloadable(%s) %p %s",
unloadable ? "true" : "true", expectedUnloadableState ? "true" : "false", mh, path);
}
}
int main(int argc, const char* argv[], const char* envp[], const char* apple[]) {
expectedUnloadableState = false;
_dyld_register_for_image_loads(¬ify);
if ( sCurrentImages.count(&__dso_handle) == 0 ) {
FAIL("did not notify us about main executable");
}
const mach_header* libSysMH = dyld_image_header_containing_address((void*)&printf);
if ( sCurrentImages.count(libSysMH) == 0 ) {
FAIL("did not notify us about libsystem_c.dylib");
}
const mach_header* libFoo = dyld_image_header_containing_address((void*)&foo);
if ( sCurrentImages.count(libFoo) == 0 ) {
FAIL("did not notify us about libfoo.dylib");
}
expectedUnloadableState = true;
void* handle2 = dlopen(RUN_DIR "/libfoo2.dylib", RTLD_FIRST);
if ( handle2 == NULL ) {
FAIL("dlopen(\"%s\") failed with: %s", RUN_DIR "/libfoo.dylib", dlerror());
}
const void* libfoo2Foo = dlsym(handle2, "foo");
const mach_header* libfoo2MH = dyld_image_header_containing_address(libfoo2Foo);
if ( sCurrentImages.count(libfoo2MH) == 0 ) {
FAIL("did not notify us about libfoo2.dylib");
}
void* handleB = dlopen(RUN_DIR "/foo.bundle", RTLD_FIRST);
if ( handleB == NULL ) {
FAIL("dlopen(\"%s\") failed with: %s", RUN_DIR "/foo.bundle", dlerror());
}
const void* libfooBFoo = dlsym(handle2, "foo");
const mach_header* libfooB = dyld_image_header_containing_address(libfooBFoo);
if ( sCurrentImages.count(libfooB) == 0 ) {
FAIL("_dyld_register_for_image_loads() did not notify us about foo.bundle");
}
void* handleBar = dlopen(RUN_DIR "/libbar.dylib", RTLD_FIRST);
if ( handleBar == NULL ) {
FAIL("dlopen(\"%s\") failed with: %s", RUN_DIR "/libbar.dylib", dlerror());
}
PASS("Success");
}