diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 25f3dd0b6..9c5585275 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -65,7 +65,7 @@ jobs: # Note the current convention is to use the -S and -B options here to specify source # and build directories, but this is only available with CMake 3.13 and higher. # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True -DENABLE_INTERPRETER=True + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -G Ninja -DENABLE_LTO=False -DENABLE_ASSERTIONS=True -DENABLE_X86_HOST_DEBUG=True -DENABLE_INTERPRETER=True -DBUILD_FEX_LINUX_TESTS=True - name: Build working-directory: ${{runner.workspace}}/build @@ -167,6 +167,17 @@ jobs: working-directory: ${{runner.workspace}}/build run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_APITests.log || true + - name: FEXLinuxTests + working-directory: ${{runner.workspace}}/build + shell: bash + run: cmake --build . --config $BUILD_TYPE --target fex_linux_tests_all + + - name: FEXLinuxTests Results move + if: ${{ always() }} + shell: bash + working-directory: ${{runner.workspace}}/build + run: mv ${{runner.workspace}}/build/Testing/Temporary/LastTest.log ${{runner.workspace}}/build/Testing/Temporary/LastTest_FEXLinuxTests.log || true + - name: Truncate test results if: ${{ always() }} shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a83746a2..ccdcd4552 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.14) project(FEX) option(BUILD_TESTS "Build unit tests to ensure sanity" TRUE) +option(BUILD_FEX_LINUX_TESTS "Build FEXLinuxTests, requires g++/g++-multilib or g++-x86-64-linux-gnu/g++-multilib-x86-64-linux-gnu" FALSE) option(BUILD_THUNKS "Build thunks" FALSE) option(ENABLE_CLANG_FORMAT "Run clang format over the source" FALSE) option(ENABLE_IWYU "Enables include what you use program" FALSE) diff --git a/Scripts/guest_test_runner.py b/Scripts/guest_test_runner.py index ec400029d..1fdde331d 100644 --- a/Scripts/guest_test_runner.py +++ b/Scripts/guest_test_runner.py @@ -14,7 +14,8 @@ known_failures_file = sys.argv[1] expected_output_file = sys.argv[2] disabled_tests_file = sys.argv[3] test_name = sys.argv[4] -fexecutable = sys.argv[5] +mode = sys.argv[5] +fexecutable = sys.argv[6] known_failures = { } expected_output = { } @@ -46,14 +47,15 @@ RunnerArgs = [] RunnerArgs.append(fexecutable) -ROOTFS_ENV = os.getenv("ROOTFS") -if ROOTFS_ENV != None: - RunnerArgs.append("-R") - RunnerArgs.append(ROOTFS_ENV) +if (mode == "guest"): + ROOTFS_ENV = os.getenv("ROOTFS") + if ROOTFS_ENV != None: + RunnerArgs.append("-R") + RunnerArgs.append(ROOTFS_ENV) # Add the rest of the arguments -for i in range(len(sys.argv) - 6): - RunnerArgs.append(sys.argv[6 + i]) +for i in range(len(sys.argv) - 7): + RunnerArgs.append(sys.argv[7 + i]) #print(RunnerArgs) diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 2f0b718f9..0b5b590ce 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -9,3 +9,8 @@ add_subdirectory(gcc-target-tests-64/) if (BUILD_THUNKS) add_subdirectory(ThunkLibs) endif() + + +if (BUILD_FEX_LINUX_TESTS) + add_subdirectory(FEXLinuxTests/) +endif() \ No newline at end of file diff --git a/unittests/FEXLinuxTests/CMakeLists.txt b/unittests/FEXLinuxTests/CMakeLists.txt new file mode 100644 index 000000000..c4f29e831 --- /dev/null +++ b/unittests/FEXLinuxTests/CMakeLists.txt @@ -0,0 +1,104 @@ +include(ExternalProject) +ExternalProject_Add(FEXLinuxTests + PREFIX FEXLinuxTests + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/FEXLinuxTests" + CMAKE_ARGS + "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" + "-DX86_C_COMPILER:STRING=${X86_C_COMPILER}" + "-DX86_CXX_COMPILER:STRING=${X86_CXX_COMPILER}" + INSTALL_COMMAND "" + BUILD_ALWAYS ON +) + +# this kind of sucks, but reglob +file(GLOB_RECURSE TESTS CONFIGURE_DEPENDS tests/*.cpp) +foreach(TEST ${TESTS}) + + get_filename_component(TEST_NAME ${TEST} NAME_WLE) + + file(READ ${TEST} TEST_CODE) + + # Used to insert a configuration dependency to the test file + CONFIGURE_FILE(${TEST} ${CMAKE_BINARY_DIR}/junk.file) + + set(ARGS_REGEX "auto args = \"([^\"]+)\";") + string(REGEX MATCH ${ARGS_REGEX} TEST_ARGS ${TEST_CODE}) + # if cannot handle multiline variables, so we have to match the line first + if(${TEST_ARGS} MATCHES ${ARGS_REGEX}) + string(REGEX REPLACE " |," ";" ARGS "${CMAKE_MATCH_1}") + set(VARIATIONS "") + foreach(ARG ${ARGS}) + list(APPEND VARIATIONS "${TEST_NAME}-${ARG}:${ARG}") + endforeach() + else() + set(VARIATIONS "${TEST_NAME}:") + endif() + + set(ALL_BITNESS 32 64) + foreach(VARIATION ${VARIATIONS}) + foreach(BITNESS ${ALL_BITNESS}) + string(REGEX REPLACE ":" ";" VARIATION "${VARIATION}") + list(GET VARIATION 0 VARIATION_NAME) + list(GET VARIATION 1 VARIATION_ARG) + set(BIN_PATH "${CMAKE_CURRENT_BINARY_DIR}/FEXLinuxTests/${TEST_NAME}.${BITNESS}") + + set(TEST_CASE "${VARIATION_NAME}.${BITNESS}") + + # Add jit test case + add_test(NAME "${TEST_CASE}.jit.flt" + COMMAND "python3" "${CMAKE_SOURCE_DIR}/Scripts/guest_test_runner.py" + "${CMAKE_CURRENT_SOURCE_DIR}/Known_Failures" + "${CMAKE_CURRENT_SOURCE_DIR}/Expected_Output" + "${CMAKE_CURRENT_SOURCE_DIR}/Disabled_Tests" + "${TEST_CASE}" + "guest" + "$" + "--no-silent" "-c" "irjit" "-n" "500" "--" + "${BIN_PATH}" + "${VARIATION_ARG}") + if (_M_X86_64) + # Add host test case + add_test(NAME "${TEST_CASE}.host.flt" + COMMAND "python3" "${CMAKE_SOURCE_DIR}/Scripts/guest_test_runner.py" + "${CMAKE_CURRENT_SOURCE_DIR}/Known_Failures_Host" + "${CMAKE_CURRENT_SOURCE_DIR}/Expected_Output" + "${CMAKE_CURRENT_SOURCE_DIR}/Disabled_Tests_Host" + "${TEST_CASE}" + "host" + "${BIN_PATH}" + "${VARIATION_ARG}") + endif() + endforeach() + endforeach() +endforeach() + +execute_process(COMMAND "nproc" OUTPUT_VARIABLE CORES) +string(STRIP ${CORES} CORES) + +# Only emulated +add_custom_target( + fex_linux_tests + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + USES_TERMINAL + COMMAND "ctest" "--timeout" "30" "-j${CORES}" "-R" "\.*\.jit\.flt$$" "--output-on-failure" + DEPENDS FEXLinuxTests FEXLoader +) + +# Only host +add_custom_target( + fex_linux_tests_host + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + USES_TERMINAL + COMMAND "ctest" "--timeout" "30" "-j${CORES}" "-R" "\.*\.host\.flt$$" "--output-on-failure" + DEPENDS FEXLinuxTests +) + +# Both host and emulated +add_custom_target( + fex_linux_tests_all + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + USES_TERMINAL + COMMAND "ctest" "--timeout" "30" "-j${CORES}" "-R" "\.*\.flt$$" "--output-on-failure" + DEPENDS FEXLinuxTests FEXLoader +) \ No newline at end of file diff --git a/unittests/FEXLinuxTests/Disabled_Tests b/unittests/FEXLinuxTests/Disabled_Tests new file mode 100644 index 000000000..903110f78 --- /dev/null +++ b/unittests/FEXLinuxTests/Disabled_Tests @@ -0,0 +1,17 @@ +### +### Disabled tests ### +### + +# These sometimes crash FEX with SIGSEGV +timer-sigev-thread.32 +timer-sigev-thread.64 + +# These fail on arm because of sigbus handling +synchronous-signal-block-sbus.32 +synchronous-signal-block-sbus.64 +synchronous-signal-block-abus.32 +synchronous-signal-block-abus.64 + +# These fail on arm because we don't raise FPE +synchronous-signal-block-sfpe.32 +synchronous-signal-block-sfpe.64 \ No newline at end of file diff --git a/unittests/FEXLinuxTests/Disabled_Tests_Host b/unittests/FEXLinuxTests/Disabled_Tests_Host new file mode 100644 index 000000000..e69de29bb diff --git a/unittests/FEXLinuxTests/Expected_Output b/unittests/FEXLinuxTests/Expected_Output new file mode 100644 index 000000000..da747ccef --- /dev/null +++ b/unittests/FEXLinuxTests/Expected_Output @@ -0,0 +1,8 @@ +synchronous-signal-block-ssegv.32 -11 +synchronous-signal-block-ssegv.64 -11 +synchronous-signal-block-sill.32 -4 +synchronous-signal-block-sill.64 -4 +synchronous-signal-block-sbus.32 -7 +synchronous-signal-block-sbus.64 -7 +synchronous-signal-block-sfpe.32 -8 +synchronous-signal-block-sfpe.64 -8 \ No newline at end of file diff --git a/unittests/FEXLinuxTests/Known_Failures b/unittests/FEXLinuxTests/Known_Failures new file mode 100644 index 000000000..203ed21f3 --- /dev/null +++ b/unittests/FEXLinuxTests/Known_Failures @@ -0,0 +1,39 @@ +### +### Disabled tests ### +### + +# These sometimes crash FEX with SIGSEGV +timer-sigev-thread.32 +timer-sigev-thread.64 + +# These fail on arm because of sigbus handling +synchronous-signal-block-sbus.32 +synchronous-signal-block-sbus.64 +synchronous-signal-block-abus.32 +synchronous-signal-block-abus.64 + +# These fail on arm because we don't raise FPE +synchronous-signal-block-sfpe.32 +synchronous-signal-block-sfpe.64 + +### +### Failing Tests ### +### + +# these will be fixed with FEX_TICKET(1725) +sigtest_samask.32 +sigtest_samask.64 +sigtest_sigmask.32 +sigtest_sigmask.64 + +# These fail to do default signal catching behaviour +synchronous-signal-block-ssegv.32 +synchronous-signal-block-ssegv.64 +synchronous-signal-block-sill.32 +synchronous-signal-block-sill.64 + +# These fail to queue the signals +synchronous-signal-block-asegv.32 +synchronous-signal-block-asegv.64 +synchronous-signal-block-aill.32 +synchronous-signal-block-aill.64 \ No newline at end of file diff --git a/unittests/FEXLinuxTests/Known_Failures_Host b/unittests/FEXLinuxTests/Known_Failures_Host new file mode 100644 index 000000000..e69de29bb diff --git a/unittests/FEXLinuxTests/tests/CMakeLists.txt b/unittests/FEXLinuxTests/tests/CMakeLists.txt new file mode 100644 index 000000000..96fd1d02b --- /dev/null +++ b/unittests/FEXLinuxTests/tests/CMakeLists.txt @@ -0,0 +1,68 @@ +cmake_minimum_required(VERSION 3.14) +project(FEXLinuxTests) + +set(CMAKE_CXX_STANDARD 17) + +set (X86_C_COMPILER "x86_64-linux-gnu-gcc" CACHE STRING "c compiler for compiling x86 guest libs") +set (X86_CXX_COMPILER "x86_64-linux-gnu-g++" CACHE STRING "c++ compiler for compiling x86 guest libs") + +set(CMAKE_C_COMPILER "${X86_C_COMPILER}") +set(CMAKE_CXX_COMPILER "${X86_CXX_COMPILER}") + +unset (CMAKE_C_FLAGS) +unset (CMAKE_CXX_FLAGS) + +set(GENERATE_GUEST_INSTALL_TARGETS TRUE) + +file(GLOB_RECURSE TESTS CONFIGURE_DEPENDS *.cpp) + +foreach(TEST ${TESTS}) + get_filename_component(TEST_NAME ${TEST} NAME_WLE) + + # Used to insert a configuration dependency to the test file + CONFIGURE_FILE(${TEST} ${CMAKE_BINARY_DIR}/junk.file) + + file(READ ${TEST} TEST_CODE) + set(FLAGS_REGEX "//[ ]*append cxxflags: ([^\n]+)") + + string(REGEX MATCH ${FLAGS_REGEX} APPEND_CXX_FLAGS ${TEST_CODE}) + # if cannot handle multiline variables, so we have to match the line first + if(${APPEND_CXX_FLAGS} MATCHES ${FLAGS_REGEX}) + set(APPEND_CXX_FLAGS "${CMAKE_MATCH_1}") + else() + set(APPEND_CXX_FLAGS "") + endif() + + set(FLAGS_REGEX "//[ ]*append ldflags: ([^\n]+)") + + string(REGEX MATCH ${FLAGS_REGEX} APPEND_LD_FLAGS ${TEST_CODE}) + # if cannot handle multiline variables, so we have to match the line first + if(${APPEND_LD_FLAGS} MATCHES ${FLAGS_REGEX}) + set(APPEND_LD_FLAGS "${CMAKE_MATCH_1}" ) + else() + set(APPEND_LD_FLAGS "") + endif() + + set(FLAGS_REGEX "//[ ]*libs: ([^\n]+)") + + string(REGEX MATCH ${FLAGS_REGEX} LIBS ${TEST_CODE}) + # if cannot handle multiline variables, so we have to match the line first + if(${LIBS} MATCHES ${FLAGS_REGEX}) + set(LIBS "${CMAKE_MATCH_1}" ) + string(REGEX REPLACE " |," ";" LIBS "${LIBS}") + else() + set(LIBS "") + endif() + + set(BIN_NAME_32 "${TEST_NAME}.32") + set(BIN_NAME_64 "${TEST_NAME}.64") + + add_executable(${BIN_NAME_32} ${TEST}) + set_target_properties(${BIN_NAME_32} PROPERTIES COMPILE_FLAGS "${APPEND_CXX_FLAGS} -m32 -g -O2 " LINK_FLAGS "${APPEND_LD_FLAGS} -m32") + target_link_libraries(${BIN_NAME_32} ${LIBS}) + + add_executable(${BIN_NAME_64} ${TEST}) + set_target_properties(${BIN_NAME_64} PROPERTIES COMPILE_FLAGS "${APPEND_CXX_FLAGS} -g -O2" LINK_FLAGS "${APPEND_LD_FLAGS}") + target_link_libraries(${BIN_NAME_64} ${LIBS}) + +endforeach() diff --git a/unittests/FEXLinuxTests/tests/signal/pthread_cancel.cpp b/unittests/FEXLinuxTests/tests/signal/pthread_cancel.cpp new file mode 100644 index 000000000..10a40ae3c --- /dev/null +++ b/unittests/FEXLinuxTests/tests/signal/pthread_cancel.cpp @@ -0,0 +1,95 @@ +//libs: pthread +#include +#include +#include +#include +#include +#include + +// Derived from example in https://manual.cs50.io/3/pthread_cancel +// <> + +std::atomic thread_ready; +std::atomic cancel_sent; + +static pthread_key_t key; + +void key_dtor(void *ptr) { + puts("key_dtor: Thread aborted\n"); + free(ptr); +} + +#define handle_error_en(en, msg) \ + do { \ + errno = en; \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + +static void *thread_func(void *ignored_argument) { + pthread_key_create(&key, &key_dtor); + pthread_setspecific(key, malloc(32)); + int s; + + /* Disable cancellation for a while, so that we don't + immediately react to a cancellation request. */ + + s = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + if (s != 0) + handle_error_en(s, "pthread_setcancelstate"); + + printf("thread_func(): started; cancellation disabled\n"); + thread_ready = true; + + while (!cancel_sent.load()) + ; + printf("thread_func(): about to enable cancellation\n"); + + s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + if (s != 0) + handle_error_en(s, "pthread_setcancelstate"); + + /* sleep() is a cancellation point. */ + + for (;;) + sleep(1000); /* Should get canceled while we sleep */ + + /* Should never get here. */ + + printf("thread_func(): not canceled!\n"); + return NULL; +} + +int main(void) { + pthread_t thr; + void *res; + int s; + + /* Start a thread and then send it a cancellation request. */ + + s = pthread_create(&thr, NULL, &thread_func, NULL); + if (s != 0) + handle_error_en(s, "pthread_create"); + + while (!thread_ready.load()) + ; + + printf("main(): sending cancellation request\n"); + s = pthread_cancel(thr); + if (s != 0) + handle_error_en(s, "pthread_cancel"); + + cancel_sent = true; + + /* Join with thread to see what its exit status was. */ + + s = pthread_join(thr, &res); + if (s != 0) + handle_error_en(s, "pthread_join"); + + if (res == PTHREAD_CANCELED) + printf("main(): thread was canceled\n"); + else + printf("main(): thread wasn't canceled (shouldn't happen!)\n"); + exit(EXIT_SUCCESS); +} diff --git a/unittests/FEXLinuxTests/tests/signal/sigtest_no_defer.cpp b/unittests/FEXLinuxTests/tests/signal/sigtest_no_defer.cpp new file mode 100644 index 000000000..307fc9813 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/signal/sigtest_no_defer.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +volatile bool loop = false; +volatile int count = 0; +volatile int count2 = 0; + +#define NUMCOUNT 10 +#define SIGN SIGTSTP + +void sig_handler(int signum, siginfo_t *info, void *context) { + loop = false; + + printf("Inside handler function\n"); + if (count != 0) { + printf("SA_NODEFER bug\n"); + exit(-1); + } + + if (count2 != 0) { + printf("Nested raise correctly raised, trying sigprocmask\n"); + sigset_t old; + // test if sigmask returned by sigprocmask is the one currently active + sigprocmask(0, 0, &old); + sigprocmask(SIG_SETMASK, &old, 0); + } + + if (count2 < NUMCOUNT) { + printf("Nested Raising %d, %d of %d times\n", signum, 1 + count, NUMCOUNT); + count2++; + raise(signum); + count++; + } else { + exit(0); + printf("Exiting\n"); + } +} + +int main() { + struct sigaction act = {0}; + + act.sa_flags = SA_SIGINFO | SA_NODEFER; + act.sa_sigaction = &sig_handler; + if (sigaction(SIGN, &act, NULL) != 0) { + printf("sigaction failed\n"); + return -3; + } + loop = true; + while (loop) { + printf("Inside main loop, raising signal\n"); + raise(SIGN); + if (loop) { + printf("Error: Signal did not get raised\n"); + return -3; + } + } + return -2; +} diff --git a/unittests/FEXLinuxTests/tests/signal/sigtest_samask.cpp b/unittests/FEXLinuxTests/tests/signal/sigtest_samask.cpp new file mode 100644 index 000000000..4faafc938 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/signal/sigtest_samask.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +volatile bool loop = true; +volatile bool last = false; +volatile int count = 0; +volatile int count2 = 0; + +// OPTIONS +// TESTSIGPROCMASK + +#define NUMCOUNT 10 +#define SIGN SIGTSTP + +void sig_handler(int signum) { + loop = false; + printf("Inside handler function\n"); + + if (last) { + printf("Handling last raise\n"); + return; + } + + if (count2 != count) { + printf("Signal reentering bug\n"); + exit(-1); + } + + if (count < NUMCOUNT) { + printf("Nested Raising sig%d, %d of %d times\n", signum, 1 + count, NUMCOUNT); + count2++; + raise(signum); + printf("Nested raise correctly blocked, trying sigprocmask\n"); + sigset_t old; + // test if sigmask returned by sigprocmask is the one currently active + sigprocmask(0, 0, &old); + sigprocmask(SIG_SETMASK, &old, 0); + printf("sigprocmask worked correctly, should trigger next iteration on signal return\n"); + count++; + } +} + +int main() { + if (signal(SIGN, sig_handler) != 0) { + printf("Signal() failed\n"); + return -2; + } + + // test if sigmask blocks during execution as expected + last = false; + loop = true; + while (loop) { + printf("Inside main loop, raising signal\n"); + raise(SIGN); + if (loop) { + printf("Error: Signal did not get raised\n"); + return -4; + } + } + last = true; + loop = true; + + // test if sigmask returned by sigprocmask is the one set by the signal return + sigset_t old; + sigprocmask(0, 0, &old); + sigprocmask(SIG_SETMASK, &old, 0); + + while (loop) { + printf("Inside last loop, raising signal\n"); + raise(SIGN); + if (loop) { + printf("Error: Signal did not get raised\n"); + return -3; + } + } + printf("All good, Exiting\n"); + return 0; +} diff --git a/unittests/FEXLinuxTests/tests/signal/sigtest_sigmask.cpp b/unittests/FEXLinuxTests/tests/signal/sigtest_sigmask.cpp new file mode 100644 index 000000000..458cef85e --- /dev/null +++ b/unittests/FEXLinuxTests/tests/signal/sigtest_sigmask.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +volatile bool loop = false; +volatile bool inhandler = false; + +#define SIGN SIGTSTP + +void sig_handler(int signum, siginfo_t *info, void *context) { + loop = false; + printf("Inside handler function\n"); + if (inhandler) { + printf("Signal reentering bug\n"); + exit(-1); + } + inhandler = true; + raise(signum); + + auto uctx = (ucontext_t *)context; + sigfillset(&uctx->uc_sigmask); +} + +int main() { + struct sigaction act = {0}; + + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = &sig_handler; + if (sigaction(SIGN, &act, NULL) != 0) { + printf("sigaction() failed\n"); + return -2; + } + + loop = true; + while (loop) { + printf("Inside main loop, raising signal\n"); + raise(SIGN); + if (loop) { + printf("Error: Signal did not get raised\n"); + return -3; + } + } + + printf("Exiting\n"); + return 0; +} diff --git a/unittests/FEXLinuxTests/tests/signal/synchronous-signal-block.cpp b/unittests/FEXLinuxTests/tests/signal/synchronous-signal-block.cpp new file mode 100644 index 000000000..aefe5904e --- /dev/null +++ b/unittests/FEXLinuxTests/tests/signal/synchronous-signal-block.cpp @@ -0,0 +1,73 @@ +auto args = "ssegv, asegv, sill, aill, sbus, abus, sfpe, afpe"; + +#include +#include +#include +#include +#include +#include +#include + +#define handle_error(msg) \ + do { \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + +char *buffer; +int flag = 0; + +static void handler(int sig, siginfo_t *si, void *unused) { + printf("Got %d at address: 0x%lx\n", sig, (long)si->si_addr); + exit(1); +} + +int main(int argc, char *argv[]) { + if (argc == 1) { + printf("please specify one of %s\n", args); + } + + struct sigaction sa; + + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = handler; + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); + + auto map1 = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); + auto map2 = (char *)mremap(map1, 4096, 8192, MREMAP_MAYMOVE); + + sigset_t set; + sigfillset(&set); + + sigprocmask(SIG_SETMASK, &set, nullptr); + + if (strcmp(argv[1], "ssegv") == 0) { + *(int *)(0x32) = 0x64; + } else if (strcmp(argv[1], "sill") == 0) { + asm volatile("ud2\n"); + } else if (strcmp(argv[1], "sbus") == 0) { + map2[4096] = 2; + } else if (strcmp(argv[1], "sfpe") == 0) { + volatile int a = 10; + volatile int b = 0; + volatile int c = a / b; + printf("result: %d\n", c); + } else if (strcmp(argv[1], "asegv") == 0) { + raise(SIGSEGV); + } else if (strcmp(argv[1], "aill") == 0) { + raise(SIGILL); + } else if (strcmp(argv[1], "abus") == 0) { + raise(SIGBUS); + } else if (strcmp(argv[1], "afpe") == 0) { + raise(SIGFPE); + } else { + printf("Invalid argument %s\n", argv[1]); + printf("please specify one of %s\n", args); + } + + exit(0); +} diff --git a/unittests/FEXLinuxTests/tests/signal/timer-sigev-thread.cpp b/unittests/FEXLinuxTests/tests/signal/timer-sigev-thread.cpp new file mode 100644 index 000000000..12d2faca1 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/signal/timer-sigev-thread.cpp @@ -0,0 +1,49 @@ +//libs: rt pthread + +// Simple test of timer_create + SIGEV_THREAD, glibc implements it via SIG32 + +#include +#include +#include +#include + +#include +#include +#include + +int test; + +void timer_handler(union sigval sv) { + auto ok = sv.sival_ptr == &test; + printf("timer_handler called, ok = %d\n", ok); + + exit(ok ? 0 : -1); +} + +int main() { + + timer_t timer; + sigevent sige; + itimerspec spec; + + memset(&sige, 0, sizeof(sige)); + + sige.sigev_notify = SIGEV_THREAD; + sige.sigev_notify_function = &timer_handler; + sige.sigev_value.sival_ptr = &test; + + timer_create(CLOCK_REALTIME, &sige, &timer); + + memset(&spec, 0, sizeof(spec)); + + spec.it_value.tv_sec = 0; + spec.it_value.tv_nsec = 1; + + timer_settime(timer, 0, &spec, NULL); + + for (;;) + sleep(1); + + assert(false && "should never get here"); + return -2; +} \ No newline at end of file diff --git a/unittests/FEXLinuxTests/tests/smc/smc-1-dynamic.cpp b/unittests/FEXLinuxTests/tests/smc/smc-1-dynamic.cpp new file mode 100644 index 000000000..d18f1ed62 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/smc/smc-1-dynamic.cpp @@ -0,0 +1,11 @@ +// append ldflags: -z execstack +auto args = "stack, data_sym, text_sym"; + +#define EXECSTACK +#include "smc-1.inl" + +/* +We cannot test the omagic or the static version of this, due to cross compiling issues +//#define OMAGIC // when the g++ driver is used to link, -Wl,--omagic breaks -static, so this can't be tested +#include "smc-1.inl" +*/ diff --git a/unittests/FEXLinuxTests/tests/smc/smc-1.inl b/unittests/FEXLinuxTests/tests/smc/smc-1.inl new file mode 100644 index 000000000..739a1478e --- /dev/null +++ b/unittests/FEXLinuxTests/tests/smc/smc-1.inl @@ -0,0 +1,45 @@ +/* + tests for smc changes in .text, stack and bss +*/ + +char data_sym[16384]; +char text_sym[16384] __attribute__((section(".text"))); + +#include "smc-common.h" + +int main(int argc, char *argv[]) { + + if (argc == 2) { + + if (strcmp(argv[1], "stack") == 0) { + // stack, depends on -z execstack or mprotect + char stack[16384]; + auto code = (char *)(((uintptr_t)stack + 4095) & ~4095); + +#if !defined(EXECSTACK) + mprotect(code, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); +#endif + + return test(code, "stack"); + } else if (strcmp(argv[1], "data_sym") == 0) { + // data_sym, must use mprotect + auto code = (char *)(((uintptr_t)data_sym + 4095) & ~4095); + mprotect(code, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); + return test(code, "data_sym"); + } else if (strcmp(argv[1], "text_sym") == 0) { + // text_sym, depends on -Wl,omagic or mprotect + auto code = (char *)(((uintptr_t)text_sym + 4095) & ~4095); + +#if !defined(OMAGIC) + mprotect(code, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); +#endif + + return test(code, "text_sym"); + } + } + + printf("Invalid arguments\n"); + printf("please specify one of %s\n", args); + + return -1; +} diff --git a/unittests/FEXLinuxTests/tests/smc/smc-2.cpp b/unittests/FEXLinuxTests/tests/smc/smc-2.cpp new file mode 100644 index 000000000..3a15114e5 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/smc/smc-2.cpp @@ -0,0 +1,43 @@ +/* + tests for smc changes memory mapped via mmap, mremap, shmat without mirroring +*/ + +auto args = "mmap, mremap, shmat, shmat_mremap, mmap_shmdt"; + +#include "smc-common.h" + +int main(int argc, char *argv[]) { + + if (argc == 2) { + if (strcmp(argv[1], "mmap") == 0) { + auto code = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, 0, 0); + return test(code, argv[1]); + } else if (strcmp(argv[1], "mremap") == 0) { + auto code = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANON, 0, 0); + auto code2 = (char *)mremap(code, 0, 4096, MREMAP_MAYMOVE); + return test(code2, argv[1]); + } else if (strcmp(argv[1], "shmat") == 0) { + auto shm = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0777); + auto code = (char *)shmat(shm, nullptr, SHM_EXEC); + return test(code, argv[1]); + } else if (strcmp(argv[1], "shmat_mremap") == 0) { + auto shm = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0777); + auto code = (char *)shmat(shm, nullptr, SHM_EXEC); + auto code2 = (char *)mremap(code, 0, 4096, MREMAP_MAYMOVE); + return test(code2, argv[1]); + } else if (strcmp(argv[1], "mmap_shmdt") == 0) { + auto shmid = shmget(IPC_PRIVATE, 4096 * 3, IPC_CREAT | 0777); + auto ptrshm = (char *)shmat(shmid, 0, 0); + shmctl(shmid, IPC_RMID, NULL); + auto ptrmmap = (char *)mmap(ptrshm + 4096, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0); + shmdt(ptrshm); + test(ptrmmap, argv[1]); + return 0; + } + } + + printf("Invalid arguments\n"); + printf("please specify one of %s\n", args); + + return -1; +} diff --git a/unittests/FEXLinuxTests/tests/smc/smc-common.h b/unittests/FEXLinuxTests/tests/smc/smc-common.h new file mode 100644 index 000000000..fa9d2bbd7 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/smc/smc-common.h @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +int test(char *code, const char *name) { + // mov eax, imm32 + code[0] = 0xB8; + code[1] = 0xAA; + code[2] = 0xBB; + code[3] = 0xCC; + code[4] = 0xDD; + + // ret + code[5] = 0xC3; + + auto fn = (int (*)())code; + auto e1 = fn(); + + // patch imm + code[3] = 0xFE; + auto e2 = fn(); + + mprotect(code, 4096, PROT_READ | PROT_EXEC); + + mprotect(code, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); + + // patch imm + code[3] = 0xF3; + + mprotect(code, 4096, PROT_READ | PROT_EXEC); + + auto e3 = fn(); + + mprotect(code, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); + + // patch imm + code[3] = 0xF1; + + auto e4 = fn(); + + int failure_set = 0; + + failure_set |= (e1 != 0xDDCCBBAA) << 0; + printf("%s-1: %X, %s\n", name, e1, e1 != 0xDDCCBBAA ? "FAIL" : "PASS"); + failure_set |= (e2 != 0xDDFEBBAA) << 1; + printf("%s-2: %X, %s\n", name, e2, e2 != 0xDDFEBBAA ? "FAIL" : "PASS"); + failure_set |= (e3 != 0xDDF3BBAA) << 2; + printf("%s-3: %X, %s\n", name, e3, e3 != 0xDDF3BBAA ? "FAIL" : "PASS"); + failure_set |= (e4 != 0xDDF1BBAA) << 3; + printf("%s-4: %X, %s\n", name, e4, e4 != 0xDDF1BBAA ? "FAIL" : "PASS"); + + return failure_set; +} + +int test_shared(char* code, char* codeexec, const char* name) { + assert(code != codeexec); + code[0] = 0xB8; + code[1] = 0xAA; + code[2] = 0xBB; + code[3] = 0xCC; + code[4] = 0xDD; + + code[5] = 0xC3; + + auto fn = (int(*)())codeexec; + auto e1 = fn(); + code[3]=0xFE; + auto e2 = fn(); + + int failure_set = 0; + + failure_set |= (e1 != 0xDDCCBBAA) << 0; + printf("%s-1: %X, %s\n", name, e1, e1 != 0xDDCCBBAA? "FAIL" : "PASS"); + failure_set |= (e2 != 0xDDFEBBAA) << 1; + printf("%s-2: %X, %s\n", name, e2, e2 != 0xDDFEBBAA? "FAIL" : "PASS"); + + return failure_set; +} + +int test_forked(char* code, char* codeexec, const char* name) { + code[0] = 0xB8; + code[1] = 0xAA; + code[2] = 0xBB; + code[3] = 0xCC; + code[4] = 0xDD; + + code[5] = 0xC3; + + auto fn = (int(*)())codeexec; + auto e1 = fn(); + auto pid = fork(); + if (pid == 0) { + code[3]=0xFE; + exit(0); + } else { + int status; + wait(&status); + return WEXITSTATUS(status); + } + auto e2 = fn(); + + printf("%s-1: %X, %s\n", name, e1, e1 != 0xDDCCBBAA? "FAIL" : "PASS"); + printf("%s-2: %X, %s\n", name, e2, e2 != 0xDDFEBBAA? "FAIL" : "PASS"); +} diff --git a/unittests/FEXLinuxTests/tests/smc/smc-mt-1.cpp b/unittests/FEXLinuxTests/tests/smc/smc-mt-1.cpp new file mode 100644 index 000000000..d949b5030 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/smc/smc-mt-1.cpp @@ -0,0 +1,82 @@ +// libs: pthread + +/* + tests concurrent invalidation of different code from different threads + + creates 10 threads + each thread does an smc test 10 times + +*/ +#include +#include +#include + +#include + +std::atomic result; +std::atomic go; + +void *thread(void *) { + + auto code = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, 0, 0); + + for (int k = 0; k < 10; k++) { + code[0] = 0xB8; + code[1] = 0xAA; + code[2] = 0xBB; + code[3] = 0xCC; + code[4] = 0xDD; + + code[5] = 0xC3; + + while(!go) ; + + auto fn = (int (*)())code; + auto e1 = fn(); + code[3] = 0xFE; + auto e2 = fn(); + + mprotect(code, 4096, PROT_READ | PROT_EXEC); + + mprotect(code, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); + + code[3] = 0xF3; + + mprotect(code, 4096, PROT_READ | PROT_EXEC); + + auto e3 = fn(); + + mprotect(code, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); + + code[3] = 0xF1; + + auto e4 = fn(); + + result |= e1 != 0xDDCCBBAA; + printf("Exec1: %X, %s\n", e1, e1 != 0xDDCCBBAA ? "FAIL" : "PASS"); + result |= e2 != 0xDDFEBBAA; + printf("Exec2: %X, %s\n", e2, e2 != 0xDDFEBBAA ? "FAIL" : "PASS"); + result |= e3 != 0xDDF3BBAA; + printf("Exec3: %X, %s\n", e3, e3 != 0xDDF3BBAA ? "FAIL" : "PASS"); + result |= e4 != 0xDDF1BBAA; + printf("Exec4: %X, %s\n", e4, e4 != 0xDDF1BBAA ? "FAIL" : "PASS"); + } + + return 0; +} + +int main() { + pthread_t tid[10]; + for (int i = 0; i < 10; i++) { + pthread_create(&tid[i], 0, &thread, 0); + } + + go = true; + + for (int i = 0; i < 10; i++) { + void *rv; + pthread_join(tid[i], &rv); + } + + return result; +} diff --git a/unittests/FEXLinuxTests/tests/smc/smc-mt-2.cpp b/unittests/FEXLinuxTests/tests/smc/smc-mt-2.cpp new file mode 100644 index 000000000..847b5faa8 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/smc/smc-mt-2.cpp @@ -0,0 +1,99 @@ +// libs: pthread + +/* + tests one thread modifying another thread's code + + main thread + - allocates code buffer + - starts secondary thread + - waits to be signaled from secondary thread + - modifies the code + - waits for secondary thread to exit, while making sure it doesn't run the old code after modification + - exits + + + secondary thread + - generates some code and runs it once + - signals main thread to modify the code + - calls the to be code and checks if the result is the modified or non modified one + - exits + +*/ + +#include +#include +#include +#include +#include + +#include + +std::atomic ready_for_modification; +std::atomic thread_unblocked; +std::atomic thread_counter; + +char *code; + +void *thread(void *) { + printf("Generating code on thread\n"); + code[0] = 0xB8; + code[1] = 0xAA; + code[2] = 0xBB; + code[3] = 0xCC; + code[4] = 0xDD; + + code[5] = 0xC3; + + auto fn = (int (*)())code; + + fn(); + + ready_for_modification = true; + printf("Waiting for code to be modified\n"); + + while (fn() == 0xDDCCBBAA) + thread_counter++; + + thread_unblocked = true; + printf("Thread exiting\n"); + + return 0; +} + +int main() { + code = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, 0, 0); + + pthread_t tid; + pthread_create(&tid, 0, &thread, 0); + + while (!ready_for_modification) + ; + + printf("Modifying code from another thread\n"); + + code[3] = 0xFE; + + auto counter = thread_counter.load(); + + printf("Waiting for thread to get unblocked\n"); + + bool once = false; + while (!thread_unblocked) { + if (thread_counter != counter) { + // depending on the patch timing, this might happen once + if (once) { + printf("Thread should have been patched to not modify counter here\n"); + exit(1); + } + printf("Thread overshoot once, this is non fatal\n"); + once = true; + counter = thread_counter.load(); + } + } + + printf("Should exit now\n"); + void *rv; + pthread_join(tid, &rv); + + return 0; +} diff --git a/unittests/FEXLinuxTests/tests/smc/smc-shared-1.cpp b/unittests/FEXLinuxTests/tests/smc/smc-shared-1.cpp new file mode 100644 index 000000000..61054fd00 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/smc/smc-shared-1.cpp @@ -0,0 +1,90 @@ +/* + tests shared / mirrored mappings +*/ + +// libs: rt pthread + +auto args = "mmap_mremap, mmap_mremap_mid, shmat, shmat_mremap, shmat_mremap_mid, mmap_mmap, mmap_mmap_fd_fd2, shm_open_mmap_mmap, shm_open_mmap_mmap_fd_fd2"; + +#include "smc-common.h" + +int main(int argc, char *argv[]) { + + if (argc == 2) { + if (strcmp(argv[1], "mmap_mremap") == 0) { + auto code = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANON, 0, 0); + + auto code2 = (char *)mremap(code, 0, 4096, MREMAP_MAYMOVE); + + return test_shared(code, code2, argv[1]); + } else if (strcmp(argv[1], "mmap_mremap_mid") == 0) { + auto code = (char *)mmap(0, 8192, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANON, 0, 0); + + auto code2 = (char *)mremap(code + 4096, 0, 4096, MREMAP_MAYMOVE); + + return test_shared(code + 4096, code2, argv[1]); + } else if (strcmp(argv[1], "shmat") == 0) { + auto shm = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0777); + auto code3 = (char *)shmat(shm, nullptr, 0); + auto code4 = (char *)shmat(shm, nullptr, SHM_EXEC); + return test_shared(code3, code4, "shmat"); + } else if (strcmp(argv[1], "shmat_mremap") == 0) { + auto shm2 = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0777); + auto code5 = (char *)shmat(shm2, nullptr, SHM_EXEC); + auto code6 = (char *)mremap(code5, 0, 4096, MREMAP_MAYMOVE); + + return test_shared(code5, code6, argv[1]); + } else if (strcmp(argv[1], "shmat_mremap_mid") == 0) { + auto shm2 = shmget(IPC_PRIVATE, 8192, IPC_CREAT | 0777); + auto code5 = (char *)shmat(shm2, nullptr, SHM_EXEC); + auto code6 = (char *)mremap(code5 + 4096, 0, 4096, MREMAP_MAYMOVE); + + return test_shared(code5 + 4096, code6, argv[1]); + } else if (strcmp(argv[1], "mmap_mmap") == 0) { + char file[] = "smc-tests.XXXXXXXX"; + int fd = mkstemp(file); + unlink(file); + ftruncate(fd, 4096); + + auto code7 = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + auto code8 = (char *)mmap(0, 4096, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0); + return test_shared(code7, code8, argv[1]); + } else if (strcmp(argv[1], "mmap_mmap_fd_fd2") == 0) { + char file[] = "smc-tests.XXXXXXXX"; + int fd = mkstemp(file); + int fd2 = open(file, O_RDONLY); + unlink(file); + ftruncate(fd, 4096); + + auto code = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + auto code2 = (char *)mmap(0, 4096, PROT_READ | PROT_EXEC, MAP_SHARED, fd2, 0); + return test_shared(code, code2, argv[1]); + } else if (strcmp(argv[1], "shm_open_mmap_mmap") == 0) { + char file[] = "smc-tests.XXXXXXXX"; + mktemp(file); + int fd = shm_open(file, O_RDWR | O_CREAT, 0700); + shm_unlink(file); + ftruncate(fd, 4096); + + auto code7 = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + auto code8 = (char *)mmap(0, 4096, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0); + return test_shared(code7, code8, argv[1]); + } else if (strcmp(argv[1], "shm_open_mmap_mmap_fd_fd2") == 0) { + char file[] = "smc-tests.XXXXXXXX"; + mktemp(file); + int fd = shm_open(file, O_RDWR | O_CREAT, 0700); + int fd2 = shm_open(file, O_RDONLY, 0700); + shm_unlink(file); + ftruncate(fd, 4096); + + auto code7 = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + auto code8 = (char *)mmap(0, 4096, PROT_READ | PROT_EXEC, MAP_SHARED, fd2, 0); + return test_shared(code7, code8, argv[1]); + } + } + + printf("Invalid arguments\n"); + printf("please specify one of %s\n", args); + + return -1; +} diff --git a/unittests/FEXLinuxTests/tests/smc/smc-shared-2.cpp b/unittests/FEXLinuxTests/tests/smc/smc-shared-2.cpp new file mode 100644 index 000000000..7592ca362 --- /dev/null +++ b/unittests/FEXLinuxTests/tests/smc/smc-shared-2.cpp @@ -0,0 +1,42 @@ + +/* + tests shared / mirrored mappings +*/ + +// libs: rt pthread + +auto args = "mmap_fork, shmat_fork, fork_shmat_same_shmid"; + +#include "smc-common.h" + +int main(int argc, char *argv[]) { + + if (argc == 2) { + + if (strcmp(argv[1], "mmap_fork") == 0) { + auto code = (char *)mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANON, 0, 0); + + return test_forked(code, code, argv[1]); + } else if (strcmp(argv[1], "shmat_fork") == 0) { + auto shm = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0777); + auto code = (char *)shmat(shm, nullptr, SHM_EXEC); + return test_forked(code, code, argv[1]); + } else if (strcmp(argv[1], "fork_shmat_same_shmid") == 0) { + auto shm = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0777); + auto code3 = (char *)shmat(shm, nullptr, 0); + if (fork() == 0) { + auto code4 = (char *)shmat(shm, nullptr, SHM_EXEC); + return test_shared(code3, code4, argv[1]); + } else { + int status; + wait(&status); + return WEXITSTATUS(status); + } + } + } + + printf("Invalid arguments\n"); + printf("please specify one of %s\n", args); + + return -1; +} \ No newline at end of file diff --git a/unittests/POSIX/CMakeLists.txt b/unittests/POSIX/CMakeLists.txt index caaf90f4a..0b9489c65 100644 --- a/unittests/POSIX/CMakeLists.txt +++ b/unittests/POSIX/CMakeLists.txt @@ -16,6 +16,7 @@ foreach(POSIX_TEST ${POSIX_TESTS}) "${CMAKE_SOURCE_DIR}/unittests/POSIX/Expected_Output" "${CMAKE_SOURCE_DIR}/unittests/POSIX/Disabled_Tests" "${TEST_NAME}" + "guest" "${CMAKE_BINARY_DIR}/Bin/FEXLoader" "--no-silent" "-c" "irint" "-n" "500" "--" "${POSIX_TEST}") @@ -27,6 +28,7 @@ foreach(POSIX_TEST ${POSIX_TESTS}) "${CMAKE_SOURCE_DIR}/unittests/POSIX/Expected_Output" "${CMAKE_SOURCE_DIR}/unittests/POSIX/Disabled_Tests" "${TEST_NAME}" + "guest" "${CMAKE_BINARY_DIR}/Bin/FEXLoader" "--no-silent" "-c" "irjit" "-n" "500" "--" "${POSIX_TEST}") diff --git a/unittests/gcc-target-tests-32/CMakeLists.txt b/unittests/gcc-target-tests-32/CMakeLists.txt index 0f1ec285f..23c4b1772 100644 --- a/unittests/gcc-target-tests-32/CMakeLists.txt +++ b/unittests/gcc-target-tests-32/CMakeLists.txt @@ -17,6 +17,7 @@ foreach(TEST ${TESTS}) "${CMAKE_SOURCE_DIR}/unittests/gcc-target-tests-32/Expected_Output" "${CMAKE_SOURCE_DIR}/unittests/gcc-target-tests-32/Disabled_Tests" "${TEST_NAME}" + "guest" "${CMAKE_BINARY_DIR}/Bin/FEXLoader" "--no-silent" "-c" "irjit" "-n" "500" "--" "${TEST}") diff --git a/unittests/gcc-target-tests-64/CMakeLists.txt b/unittests/gcc-target-tests-64/CMakeLists.txt index 166de9a2a..eea06be96 100644 --- a/unittests/gcc-target-tests-64/CMakeLists.txt +++ b/unittests/gcc-target-tests-64/CMakeLists.txt @@ -17,6 +17,7 @@ foreach(TEST ${TESTS}) "${CMAKE_SOURCE_DIR}/unittests/gcc-target-tests-64/Expected_Output" "${CMAKE_SOURCE_DIR}/unittests/gcc-target-tests-64/Disabled_Tests" "${TEST_NAME}" + "guest" "${CMAKE_BINARY_DIR}/Bin/FEXLoader" "--no-silent" "-c" "irjit" "-n" "500" "--" "${TEST}") diff --git a/unittests/gvisor-tests/CMakeLists.txt b/unittests/gvisor-tests/CMakeLists.txt index 569c824ce..1e147d87b 100644 --- a/unittests/gvisor-tests/CMakeLists.txt +++ b/unittests/gvisor-tests/CMakeLists.txt @@ -17,6 +17,7 @@ foreach(TEST ${TESTS}) "${CMAKE_SOURCE_DIR}/unittests/gvisor-tests/Expected_Output" "${CMAKE_SOURCE_DIR}/unittests/gvisor-tests/Disabled_Tests" "${TEST_NAME}" + "guest" "${CMAKE_BINARY_DIR}/Bin/FEXLoader" "--no-silent" "-c" "irjit" "-n" "500" "--" "${TEST}")