#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mach-o/dyld_priv.h>
#include <dlfcn.h>
#include <sys/syslimits.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
#endif
#include "test_support.h"
struct dyld_cache_header
{
char magic[16];
uint64_t other[9];
uuid_t uuid;
};
static void forEachCacheInDir(const char* dirPath, void (^handler)(const uuid_t uuid))
{
DIR* dirp = opendir(dirPath);
if ( dirp != NULL) {
struct dirent entry;
struct dirent* entp = NULL;
char cachePath[PATH_MAX];
while ( readdir_r(dirp, &entry, &entp) == 0 ) {
if ( entp == NULL )
break;
if ( entp->d_type != DT_REG )
continue;
if ( strlcpy(cachePath, dirPath, PATH_MAX) >= PATH_MAX )
continue;
if ( strlcat(cachePath, "/", PATH_MAX) >= PATH_MAX )
continue;
if ( strlcat(cachePath, entp->d_name, PATH_MAX) >= PATH_MAX )
continue;
int fd = open(cachePath, O_RDONLY);
if ( fd < 0 )
continue;
struct dyld_cache_header cacheHeader;
ssize_t amount = pread(fd, &cacheHeader, sizeof(cacheHeader), 0);
close(fd);
if ( amount != sizeof(cacheHeader) )
continue;
if ( memcmp(cacheHeader.magic, "dyld_v", 6) == 0 )
handler(cacheHeader.uuid);
}
closedir(dirp);
}
}
int main(int argc, const char* argv[], const char* envp[], const char* apple[]) {
size_t cacheLen;
const void* cacheStart = _dyld_get_shared_cache_range(&cacheLen);
uuid_t currentCacheUUID;
if ( _dyld_get_shared_cache_uuid(currentCacheUUID) ) {
const uint8_t* currentCacheUUIDptr = currentCacheUUID;
__block unsigned count = 0;
__block bool badVersion = false;
int result = dyld_shared_cache_iterate_text(currentCacheUUID, ^(const dyld_shared_cache_dylib_text_info* info) {
if ( info->version != 2 )
badVersion = true;
++count;
});
if ( result != 0 ) {
FAIL("dyld_shared_cache_iterate_text() returned non-zero: %d", result);
}
if ( count < 100 ) {
FAIL("dyld_shared_cache_iterate_text() iterated over less than 100 images: %d", count);
}
if ( badVersion ) {
FAIL("dyld_shared_cache_iterate_text() some dyld_shared_cache_dylib_text_info was not 2");
}
count = 0;
const char* extraSearchDirsStorage[] = { "/tmp/", NULL };
const char** extraSearchDirs = extraSearchDirsStorage;
result = dyld_shared_cache_find_iterate_text(currentCacheUUID, extraSearchDirs, ^(const dyld_shared_cache_dylib_text_info* info) {
if ( info->version != 2 )
badVersion = true;
++count;
});
if ( result != 0 ) {
FAIL("dyld_shared_cache_find_iterate_text() returned non-zero: %d", result);
}
if ( count < 100 ) {
FAIL("dyld_shared_cache_find_iterate_text() iterated over less than 100 images: %d", count);
}
if ( badVersion ) {
FAIL("dyld_shared_cache_find_iterate_text() some dyld_shared_cache_dylib_text_info was not 2");
}
count = 0;
uuid_t badCacheUUID;
bzero(&badCacheUUID, sizeof(uuid_t));
badCacheUUID[1] = 0x33;
result = dyld_shared_cache_find_iterate_text(badCacheUUID, extraSearchDirs, ^(const dyld_shared_cache_dylib_text_info* info) {
++count;
});
if ( result == 0 ) {
FAIL("dyld_shared_cache_find_iterate_text() expected result to be nonzero: %d", result);
}
if ( count != 0 ) {
FAIL("dyld_shared_cache_find_iterate_text() expected iteration count is zero: %d", count);
}
const char* curCachePath = dyld_shared_cache_file_path();
if ( curCachePath == NULL ) {
FAIL("dyld_shared_cache_file_path() returned NULL");
}
char cacheDir[PATH_MAX];
strlcpy(cacheDir, curCachePath, PATH_MAX);
char* end = strrchr(cacheDir, '/');
if ( end == NULL ) {
FAIL("cache path has no '/'");
}
*end = '\0';
forEachCacheInDir(cacheDir, ^(const uuid_t uuid) {
if ( uuid_compare(uuid, currentCacheUUIDptr) != 0 ) {
count = 0;
int res = dyld_shared_cache_find_iterate_text(uuid, extraSearchDirs, ^(const dyld_shared_cache_dylib_text_info* info) {
++count;
});
if ( res != 0 ) {
FAIL("dyld_shared_cache_find_iterate_text() expected result to be nonzero: %d", result);
}
if ( count < 100 ) {
FAIL("dyld_shared_cache_find_iterate_text() iterated over less than 100 images: %d", count);
}
}
});
}
else {
LOG("no dyld cache");
}
PASS("Success");
}