test: Fix framework to work on MacOS

Main issue was getting function redireciton to work, dyld-interposer accomplishes that.
It required making the shim-library a dylib, but otherwise only required minor changes.

Change-Id: I7b7e2c86cc0c0b082f58241a7e146b74af72e792
This commit is contained in:
Charles Giessen
2021-06-07 20:08:16 -06:00
committed by Charles Giessen
parent 1ff4c76125
commit 820fc25d1d
6 changed files with 60 additions and 34 deletions
+2 -2
View File
@@ -17,7 +17,7 @@
add_library(testing_framework_util STATIC test_util.cpp test_util.h)
target_link_libraries(testing_framework_util PUBLIC Vulkan::Headers)
if(UNIX)
if(UNIX OR APPLE)
target_link_libraries(testing_framework_util PUBLIC ${CMAKE_DL_LIBS})
endif()
@@ -30,7 +30,7 @@ target_compile_options(testing_framework_util INTERFACE
$<$<BUILD_WSI_XLIB_SUPPORT>:-DVK_USE_PLATFORM_XLIB_KHR>
$<$<BUILD_WSI_WAYLAND_SUPPORT>:-DVK_USE_PLATFORM_WAYLAND_KHR>>
)
if(UNIX AND NOT APPLE)
if(UNIX)
target_compile_options(testing_framework_util PUBLIC -fPIC)
endif()
target_include_directories(testing_framework_util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+5 -4
View File
@@ -21,10 +21,11 @@ if (WIN32)
target_include_directories(shim-library PUBLIC ${CMAKE_SOURCE_DIR}/loader ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
elseif(UNIX)
add_library(shim-library STATIC shim.h linux_shim.cpp)
if(APPLE)
add_library(shim-library SHARED shim.h unix_shim.cpp)
else()
add_library(shim-library STATIC shim.h unix_shim.cpp)
endif()
target_link_libraries(shim-library PRIVATE testing_framework_util)
target_include_directories(shim-library PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
elseif(APPLE)
endif()
+5 -5
View File
@@ -148,17 +148,17 @@ struct PlatformShim {
};
std::vector<std::string> parse_env_var_list(std::string const& var);
// dynamically link on windows
#if defined(WIN32)
extern "C" {
// dynamically link on windows and macos
#if defined(WIN32) || defined(__APPLE__)
using PFN_get_platform_shim = PlatformShim& (*)();
#define GET_PLATFORM_SHIM_STR "get_platform_shim"
#elif defined(__linux__) || defined(__APPLE__)
#elif defined(__linux__)
// statically link on linux
PlatformShim& get_platform_shim();
#endif
}
// Functions which are called by the Test Framework need a definition, but since the shim is a DLL, this
// would require loading the functions before using. To get around this, most PlatformShim functions are member
// functions, so only the `get_platform_shim()` is needed to be loaded. As a consequence, all the member functions
@@ -28,37 +28,53 @@
#include "shim.h"
static PlatformShim platform_shim;
extern "C" {
#if defined(__linux__)
PlatformShim& get_platform_shim() {
platform_shim = PlatformShim();
return platform_shim;
}
#elif defined(__APPLE__)
FRAMEWORK_EXPORT PlatformShim &get_platform_shim() {
platform_shim = PlatformShim();
return platform_shim;
}
#endif
extern "C" {
// Necessary for MacOS function himming
#if defined(__linux__)
#define OPENDIR_FUNC_NAME opendir
#define ACCESS_FUNC_NAME access
#define FOPEN_FUNC_NAME fopen
#elif defined(__APPLE__)
#define OPENDIR_FUNC_NAME my_opendir
#define ACCESS_FUNC_NAME my_access
#define FOPEN_FUNC_NAME my_fopen
#endif
using PFN_OPENDIR = DIR* (*)(const char* path_name);
using PFN_ACCESS = int (*)(const char* pathname, int mode);
using PFN_FOPEN = FILE* (*)(const char* filename, const char* mode);
FRAMEWORK_EXPORT DIR* opendir(const char* path_name) {
static PFN_OPENDIR real_opendir = nullptr;
static PFN_OPENDIR real_opendir = nullptr;
static PFN_ACCESS real_access = nullptr;
static PFN_FOPEN real_fopen = nullptr;
FRAMEWORK_EXPORT DIR* OPENDIR_FUNC_NAME(const char* path_name) {
if (!real_opendir) real_opendir = (PFN_OPENDIR)dlsym(RTLD_NEXT, "opendir");
DIR* dir;
if (platform_shim.is_fake_path(path_name)) {
auto fake_path_name = platform_shim.get_fake_path(fs::path(path_name));
//printf("Open Dir %s as %s\n", path_name, fake_path_name.c_str());
dir = real_opendir(fake_path_name.c_str());
} else {
// printf("Open Dir %s\n", path_name);
dir = real_opendir(path_name);
}
return dir;
}
using PFN_ACCESS = int (*)(const char* pathname, int mode);
FRAMEWORK_EXPORT int access(const char* in_pathname, int mode) {
static PFN_ACCESS real_access = nullptr;
FRAMEWORK_EXPORT int ACCESS_FUNC_NAME(const char* in_pathname, int mode) {
if (!real_access) real_access = (PFN_ACCESS)dlsym(RTLD_NEXT, "access");
fs::path path{in_pathname};
@@ -69,36 +85,45 @@ FRAMEWORK_EXPORT int access(const char* in_pathname, int mode) {
if (platform_shim.is_fake_path(path.parent_path())) {
fs::path fake_path = platform_shim.get_fake_path(path.parent_path());
fake_path /= path.filename();
// printf("ACCESS: in_pathname %s as %s\n", split.path.c_str(), fake_path.c_str());
return real_access(fake_path.c_str(), mode);
}
return real_access(in_pathname, mode);
}
using PFN_FOPEN = FILE* (*)(const char* filename, const char* mode);
FRAMEWORK_EXPORT FILE* fopen(const char* in_filename, const char* mode) {
static PFN_FOPEN real_fopen = nullptr;
FRAMEWORK_EXPORT FILE* FOPEN_FUNC_NAME(const char* in_filename, const char* mode) {
if (!real_fopen) real_fopen = (PFN_FOPEN)dlsym(RTLD_NEXT, "fopen");
//printf("fopen file %s\n", in_filename);
fs::path path{in_filename};
if (!path.has_parent_path()) {
return real_fopen(in_filename, mode);
}
// printf("path %s as %s\n", split.path.c_str(), split.name.c_str());
FILE* f_ptr;
if (platform_shim.is_fake_path(path.parent_path())) {
auto fake_path = platform_shim.get_fake_path(path.parent_path()) / path.filename();
// printf("fopen %s as %s\n", in_filename, fake_path.c_str());
f_ptr = real_fopen(fake_path.c_str(), mode);
} else {
// printf("fopen %s\n", filename);
f_ptr = real_fopen(in_filename, mode);
}
return f_ptr;
}
/* Shiming functions on apple is limited by the linker prefering to not use functions in the
* executable in loaded dylibs. By adding an interposer, we redirect the linker to use our
* version of the function over the real one, thus shimming the system function.
*/
#if defined(__APPLE__)
#define MACOS_ATTRIB __attribute__((section("__DATA,__interpose")))
#define VOIDP_CAST(_func) reinterpret_cast<const void*>(&_func)
struct Interposer {
const void* shim_function;
const void* underlying_function;
};
__attribute__((used)) static Interposer _interpose_opendir MACOS_ATTRIB = {VOIDP_CAST(my_opendir), VOIDP_CAST(opendir)};
__attribute__((used)) static Interposer _interpose_access MACOS_ATTRIB = {VOIDP_CAST(my_access), VOIDP_CAST(access)};
__attribute__((used)) static Interposer _interpose_fopen MACOS_ATTRIB = {VOIDP_CAST(my_fopen), VOIDP_CAST(fopen)};
#endif
} // extern "C"
+2 -2
View File
@@ -29,12 +29,12 @@
namespace detail {
PlatformShimWrapper::PlatformShimWrapper(DebugMode debug_mode) : debug_mode(debug_mode) {
#if defined(WIN32)
#if defined(WIN32) || defined(__APPLE__)
shim_library = LibraryWrapper(SHIM_LIBRARY_NAME);
auto get_platform_shim_func = shim_library.get_symbol<PFN_get_platform_shim>(GET_PLATFORM_SHIM_STR);
assert(get_platform_shim_func != NULL && "Must be able to get \"platform_shim\"");
platform_shim = &get_platform_shim_func();
#elif defined(__linux__) || defined(__APPLE__)
#elif defined(__linux__)
platform_shim = &get_platform_shim();
#endif
platform_shim->setup_override(debug_mode);
+1 -1
View File
@@ -222,7 +222,7 @@ std::string make_native(std::string const& in_path) {
else
out += c;
}
#elif defined(__linux__) || defined(APPLE)
#elif defined(__linux__) || defined(__APPLE__)
for (size_t i = 0; i < in_path.size(); i++) {
if (i + 1 < in_path.size() && in_path[i] == '\\' && in_path[i + 1] == '\\') {
out += '/';