From e48fb1850e5e0ec1dc5ea2e1fbce782445d7b9ab Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 19:47:50 -0700 Subject: [PATCH 01/41] fextl: add unordered_multimap --- External/FEXCore/include/FEXCore/fextl/unordered_map.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/External/FEXCore/include/FEXCore/fextl/unordered_map.h b/External/FEXCore/include/FEXCore/fextl/unordered_map.h index 21429c27a..beab49837 100644 --- a/External/FEXCore/include/FEXCore/fextl/unordered_map.h +++ b/External/FEXCore/include/FEXCore/fextl/unordered_map.h @@ -6,4 +6,7 @@ namespace fextl { template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc>> using unordered_map = std::unordered_map; + + template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc>> + using unordered_multimap = std::unordered_multimap; } From 7150c532f3ba5b691402512851465eb237c62437 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 19:48:17 -0700 Subject: [PATCH 02/41] fextl: add robin_map --- External/FEXCore/include/FEXCore/fextl/robin_map.h | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 External/FEXCore/include/FEXCore/fextl/robin_map.h diff --git a/External/FEXCore/include/FEXCore/fextl/robin_map.h b/External/FEXCore/include/FEXCore/fextl/robin_map.h new file mode 100644 index 000000000..b705eed74 --- /dev/null +++ b/External/FEXCore/include/FEXCore/fextl/robin_map.h @@ -0,0 +1,9 @@ +#pragma once +#include + +#include + +namespace fextl { + template, class KeyEqual = std::equal_to, class Allocator = fextl::FEXAlloc>> + using robin_map = tsl::robin_map; +} From 79f7baffe31b42e7334daff0d909533ce8bbc4a9 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 19:51:01 -0700 Subject: [PATCH 03/41] fextl: Add pmr default resource --- External/FEXCore/Source/Utils/Allocator.cpp | 10 +- .../Source/Utils/AllocatorOverride.cpp | 140 ++++++++++++++++++ .../include/FEXCore/fextl/memory_resource.h | 77 ++++++++++ 3 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 External/FEXCore/Source/Utils/AllocatorOverride.cpp create mode 100644 External/FEXCore/include/FEXCore/fextl/memory_resource.h diff --git a/External/FEXCore/Source/Utils/Allocator.cpp b/External/FEXCore/Source/Utils/Allocator.cpp index ad6ca2da9..fab422c4e 100644 --- a/External/FEXCore/Source/Utils/Allocator.cpp +++ b/External/FEXCore/Source/Utils/Allocator.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,13 @@ extern "C" { #endif } +namespace fextl::pmr { + static fextl::pmr::default_resource FEXDefaultResource; + std::pmr::memory_resource* get_default_resource() { + return &FEXDefaultResource; + } +} + namespace FEXCore::Allocator { MMAP_Hook mmap {::mmap}; MUNMAP_Hook munmap {::munmap}; @@ -63,7 +71,7 @@ namespace FEXCore::Allocator { using GLIBC_REALLOC_Hook = void*(*)(void*, size_t, const void *caller); using GLIBC_FREE_Hook = void(*)(void*, const void *caller); - std::unique_ptr Alloc64{}; + fextl::unique_ptr Alloc64{}; void *FEX_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { void *Result = Alloc64->Mmap(addr, length, prot, flags, fd, offset); diff --git a/External/FEXCore/Source/Utils/AllocatorOverride.cpp b/External/FEXCore/Source/Utils/AllocatorOverride.cpp new file mode 100644 index 000000000..0e68b8ee3 --- /dev/null +++ b/External/FEXCore/Source/Utils/AllocatorOverride.cpp @@ -0,0 +1,140 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +extern "C" { +#ifdef GLIBC_ALLOCATOR_FAULT + // glibc allocator faulting. If anything uses a glibc allocator symbol then cause a fault. + // Ensures that FEX only ever allocates memory through its allocator routines. + // If thunks are enabled then this should crash immediately. Thunks should still go through glibc allocator. + // These need to be symbol definitions /only/, don't let their visibility to the rest of the source happen. +#define GLIBC_ALIAS_FUNCTION(func) __attribute__((alias(#func), visibility("default"))) + extern void *__libc_calloc(size_t, size_t); + void *calloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_calloc); + + extern void __libc_free(void*); + void free(void*) GLIBC_ALIAS_FUNCTION(fault_free); + + extern void *__libc_malloc(size_t); + void *malloc(size_t) GLIBC_ALIAS_FUNCTION(fault_malloc); + + extern void *__libc_memalign(size_t, size_t); + void *memalign(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_memalign); + + extern void *__libc_realloc(void*, size_t); + void *realloc(void*, size_t) GLIBC_ALIAS_FUNCTION(fault_realloc); + + extern void *__libc_valloc(size_t); + void *valloc(size_t) GLIBC_ALIAS_FUNCTION(fault_valloc); + + extern int __posix_memalign(void **, size_t, size_t); + int posix_memalign(void **, size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_posix_memalign); + + extern size_t __malloc_usable_size(void*); + size_t malloc_usable_size(void*) GLIBC_ALIAS_FUNCTION(fault_malloc_usable_size); + + // Reuse __libc_memalign + void *aligned_alloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_aligned_alloc); +} + +namespace FEXCore::Allocator { + static bool Evaluate{}; + thread_local uint64_t SkipEvalForThread{}; + + CALLOC_Hook calloc_ptr = __libc_calloc; + FREE_Hook free_ptr = __libc_free; + MALLOC_Hook malloc_ptr = __libc_malloc; + MEMALIGN_Hook memalign_ptr = __libc_memalign; + REALLOC_Hook realloc_ptr = __libc_realloc; + VALLOC_Hook valloc_ptr = __libc_valloc; + POSIX_MEMALIGN_Hook posix_memalign_ptr = ::posix_memalign; + MALLOC_USABLE_SIZE_Hook malloc_usable_size_ptr = ::malloc_usable_size; + ALIGNED_ALLOC_Hook aligned_alloc_ptr = __libc_memalign; + + YesIKnowImNotSupposedToUseTheGlibcAllocator::YesIKnowImNotSupposedToUseTheGlibcAllocator() { + ++SkipEvalForThread; + } + + YesIKnowImNotSupposedToUseTheGlibcAllocator::~YesIKnowImNotSupposedToUseTheGlibcAllocator() { + --SkipEvalForThread; + } + + FEX_DEFAULT_VISIBILITY void YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable() { + // Just set it to half of its maximum value so it never wraps back around. + SkipEvalForThread = std::numeric_limits::max() / 2; + } + + void SetupFaultEvaluate() { + Evaluate = true; + } + + void ClearFaultEvaluate() { + Evaluate = false; + } + + void EvaluateReturnAddress(void* Return) { + if (!Evaluate) { + return; + } + + if (SkipEvalForThread) { + return; + } + + // We don't know where we are when allocating. Make sure to be safe and generate the string on the stack. + char Tmp[512]; + auto Res = fmt::format_to_n(Tmp, 512, "Allocation from 0x{:x}\n", reinterpret_cast(Return)); + Tmp[Res.size] = 0; + write(STDERR_FILENO, Tmp, Res.size); + LogMan::Msg::AFmt(Tmp); + FEX_UNREACHABLE; + } +} + +extern "C" { + void *fault_calloc(size_t n, size_t size) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); + return FEXCore::Allocator::calloc_ptr(n, size); + } + void fault_free(void* ptr) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); + FEXCore::Allocator::free_ptr(ptr); + } + void *fault_malloc(size_t size) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); + return FEXCore::Allocator::malloc_ptr(size); + } + void *fault_memalign(size_t align, size_t s) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); + return FEXCore::Allocator::memalign_ptr(align, s); + } + void *fault_realloc(void* ptr, size_t size) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); + return FEXCore::Allocator::realloc_ptr(ptr, size); + } + void *fault_valloc(size_t size) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); + return FEXCore::Allocator::valloc_ptr(size); + } + int fault_posix_memalign(void ** r, size_t a, size_t s) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); + return FEXCore::Allocator::posix_memalign_ptr(r, a, s); + } + size_t fault_malloc_usable_size(void *ptr) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); + return FEXCore::Allocator::malloc_usable_size_ptr(ptr); + } + void *fault_aligned_alloc(size_t a, size_t s) { + FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); + return FEXCore::Allocator::aligned_alloc_ptr(a, s); + } +#endif +} diff --git a/External/FEXCore/include/FEXCore/fextl/memory_resource.h b/External/FEXCore/include/FEXCore/fextl/memory_resource.h new file mode 100644 index 000000000..5857979f5 --- /dev/null +++ b/External/FEXCore/include/FEXCore/fextl/memory_resource.h @@ -0,0 +1,77 @@ +#pragma once +#include +#include +#include + +#include +#include + +namespace fextl { + namespace pmr { + class default_resource : public std::pmr::memory_resource { + private: + void* do_allocate( std::size_t bytes, std::size_t alignment ) override { + return FEXCore::Allocator::memalign(alignment, bytes); + } + + void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) override { + return FEXCore::Allocator::free(p); + } + + bool do_is_equal( const std::pmr::memory_resource& other ) const noexcept override { + return this == &other; + } + }; + + FEX_DEFAULT_VISIBILITY std::pmr::memory_resource* get_default_resource(); + + /** + * @brief This is similar to the std::pmr::monotonic_buffer_resource. + * + * The difference is that class doesn't have ownership of the backing memory and + * it also doesn't have any growth factor. + * + * If the amount of memory allocated is overrun then this will overwrite memory unless assertions are enabled. + * + * Ensure that you know how much memory you're going to use before using this class. + */ + class fixed_size_monotonic_buffer_resource final : public std::pmr::memory_resource { + public: + fixed_size_monotonic_buffer_resource(void* Base, size_t Size) + : Ptr {reinterpret_cast(Base)} +#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED + , PtrEnd {reinterpret_cast(Base) + Size} + , Size {Size} +#endif + {} + void* do_allocate( std::size_t bytes, std::size_t alignment ) override { + uint64_t NewPtr = FEXCore::AlignUp((uint64_t)Ptr, alignment); + Ptr = NewPtr + bytes; +#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED + if (Ptr >= PtrEnd) { + LogMan::Msg::AFmt("Fail: Only allocated: {} ({} this time) bytes. Tried allocating at ptr offset: {}.\n", + Size, + bytes, + (uint64_t)(Ptr - (PtrEnd - Size))); + FEX_TRAP_EXECUTION; + } +#endif + return reinterpret_cast(NewPtr); + } + + void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) override { + // noop + } + + bool do_is_equal( const std::pmr::memory_resource& other ) const noexcept override { + return this == &other; + } + private: + uint64_t Ptr; +#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED + uint64_t PtrEnd; + size_t Size; +#endif + }; + } +} From f02a111d33ad98b32c0d572b31a32be1d7c61d0a Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 19:51:32 -0700 Subject: [PATCH 04/41] fextl: add memory for unique_ptr and make_unique --- .../FEXCore/include/FEXCore/fextl/memory.h | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 External/FEXCore/include/FEXCore/fextl/memory.h diff --git a/External/FEXCore/include/FEXCore/fextl/memory.h b/External/FEXCore/include/FEXCore/fextl/memory.h new file mode 100644 index 000000000..bf24fecce --- /dev/null +++ b/External/FEXCore/include/FEXCore/fextl/memory.h @@ -0,0 +1,33 @@ +#pragma once +#include + +#include +#include +#include + +namespace fextl { + template + struct default_delete : public std::default_delete { + void operator()(T* ptr) const { + std::destroy_at(ptr); + FEXCore::Allocator::free(ptr); + } + + template + requires (std::is_base_of_v) + operator fextl::default_delete() { + return fextl::default_delete(); + } + }; + + template> + using unique_ptr = std::unique_ptr; + + template + fextl::unique_ptr make_unique(Args&&... args) { + auto ptr = FEXCore::Allocator::aligned_alloc(std::alignment_of_v, sizeof(T)); + auto Result = ::new (ptr) T (std::forward(args)...); + return fextl::unique_ptr(Result); + } +} + From 64aa3bfabe958d70817ce0eceb51ad7d258123e4 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 19:52:41 -0700 Subject: [PATCH 05/41] Switch FEX to fextl::fmt --- External/FEXCore/Source/Utils/LogManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/External/FEXCore/Source/Utils/LogManager.cpp b/External/FEXCore/Source/Utils/LogManager.cpp index a82a52c7a..75cd33a85 100644 --- a/External/FEXCore/Source/Utils/LogManager.cpp +++ b/External/FEXCore/Source/Utils/LogManager.cpp @@ -6,10 +6,10 @@ $end_info$ #include #include +#include #include #include -#include #include #include @@ -21,7 +21,7 @@ void InstallHandler(ThrowHandler Handler) { Handlers.emplace_back(Handler); } void UnInstallHandlers() { Handlers.clear(); } void MFmt(const char *fmt, const fmt::format_args& args) { - auto msg = fmt::vformat(fmt, args); + auto msg = fextl::fmt::vformat(fmt, args); for (auto& Handler : Handlers) { Handler(msg.c_str()); @@ -69,7 +69,7 @@ void D(const char *fmt, ...) { } void MFmtImpl(DebugLevels level, const char* fmt, const fmt::format_args& args) { - const auto msg = fmt::vformat(fmt, args); + const auto msg = fextl::fmt::vformat(fmt, args); for (auto& Handler : Handlers) { Handler(level, msg.c_str()); From 141dddc83e841c187d1fa8c678e473388851983f Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 20:02:10 -0700 Subject: [PATCH 06/41] CMake: Adds glibc allocator fault option This will be used for CI to ensure FEX doesn't use the glibc allocator --- CMakeLists.txt | 5 ++++ External/FEXCore/Source/CMakeLists.txt | 5 ++++ .../FEXCore/include/FEXCore/Utils/Allocator.h | 26 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2195ac60..e61e72625 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ option(ENABLE_VIXL_DISASSEMBLER "Enables debug disassembler output with VIXL" FA option(COMPILE_VIXL_DISASSEMBLER "Compiles the vixl disassembler in to vixl" FALSE) option(ENABLE_FEXCORE_PROFILER "Enables use of the FEXCore timeline profiling capabilities" FALSE) set (FEXCORE_PROFILER_BACKEND "gpuvis" CACHE STRING "Set which backend you want to use for the FEXCore profiler") +option(ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT "Enables glibc memory allocation hooking with fault for CI testing") set (X86_32_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/toolchain_x86_32.cmake" CACHE FILEPATH "Toolchain file for the (cross-)compiler targeting i686") set (X86_64_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/toolchain_x86_64.cmake" CACHE FILEPATH "Toolchain file for the (cross-)compiler targeting x86_64") @@ -56,6 +57,10 @@ if (ENABLE_FEXCORE_PROFILER) endif() endif() +if (ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT) + add_definitions(-DGLIBC_ALLOCATOR_FAULT=1) +endif() + # uninstall target if(NOT TARGET uninstall) configure_file( diff --git a/External/FEXCore/Source/CMakeLists.txt b/External/FEXCore/Source/CMakeLists.txt index fb5db760c..882ffb5a8 100644 --- a/External/FEXCore/Source/CMakeLists.txt +++ b/External/FEXCore/Source/CMakeLists.txt @@ -146,6 +146,11 @@ set (SRCS Utils/Profiler.cpp ) +if (ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT) + list(APPEND FEXCORE_BASE_SRCS + Utils/AllocatorOverride.cpp) +endif() + if (ENABLE_INTERPRETER) list(APPEND SRCS Interface/Core/Interpreter/InterpreterCore.cpp diff --git a/External/FEXCore/include/FEXCore/Utils/Allocator.h b/External/FEXCore/include/FEXCore/Utils/Allocator.h index 426f222fd..58af7c325 100644 --- a/External/FEXCore/include/FEXCore/Utils/Allocator.h +++ b/External/FEXCore/include/FEXCore/Utils/Allocator.h @@ -13,6 +13,32 @@ namespace FEXCore::Allocator { FEX_DEFAULT_VISIBILITY size_t DetermineVASize(); +#ifdef GLIBC_ALLOCATOR_FAULT + // Glibc hooks should only fault once we are in main. + // Required since glibc allocator hooking will catch things before FEX has control. + FEX_DEFAULT_VISIBILITY void SetupFaultEvaluate(); + // Glibc hook faulting needs to be disabled when leaving main. + // Required since glibc does some state teardown after main. + FEX_DEFAULT_VISIBILITY void ClearFaultEvaluate(); + + class FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator final { + public: + FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator(); + FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator(); + FEX_DEFAULT_VISIBILITY static void HardDisable(); + }; +#else + FEX_DEFAULT_VISIBILITY inline void SetupFaultEvaluate() {} + FEX_DEFAULT_VISIBILITY inline void ClearFaultEvaluate() {} + + class FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator final { + public: + FEX_DEFAULT_VISIBILITY YesIKnowImNotSupposedToUseTheGlibcAllocator() {} + FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator() {} + FEX_DEFAULT_VISIBILITY static inline void HardDisable() {} + }; +#endif + struct MemoryRegion { void *Ptr; size_t Size; From 0d7c85677533e7b5d506dedc16da3e6aff1171fa Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 20:06:27 -0700 Subject: [PATCH 07/41] Update xbyak --- External/xbyak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/External/xbyak b/External/xbyak index b0f0c7805..5f8c0488b 160000 --- a/External/xbyak +++ b/External/xbyak @@ -1 +1 @@ -Subproject commit b0f0c7805ad16d9abbac0f8101cc226669983b57 +Subproject commit 5f8c0488bab7a5e1c8cee831c3b6a5a884e10df8 From 43e6d398b697ba1283bdffd8f96be05156f242ad Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 20:06:45 -0700 Subject: [PATCH 08/41] X86Dispatcher: Move xbyak to custom types --- .../Source/Interface/Core/Dispatcher/X86Dispatcher.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.h b/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.h index 46001fcc9..e4564dc9f 100644 --- a/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.h +++ b/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.h @@ -1,8 +1,20 @@ #pragma once +#include +#include + #include "Interface/Core/Dispatcher/Dispatcher.h" #define XBYAK64 +#define XBYAK_CUSTOM_ALLOC +#define XBYAK_CUSTOM_MALLOC FEXCore::Allocator::malloc +#define XBYAK_CUSTOM_FREE FEXCore::Allocator::free +#define XBYAK_CUSTOM_SETS +#define XBYAK_STD_UNORDERED_SET fextl::unordered_set +#define XBYAK_STD_UNORDERED_MAP fextl::unordered_map +#define XBYAK_STD_UNORDERED_MULTIMAP fextl::unordered_multimap +#define XBYAK_STD_LIST fextl::list + #include namespace FEXCore::Core { From 465ecd9b1917388e71e3202f26ff2793237816c4 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 20:12:25 -0700 Subject: [PATCH 09/41] Mark code regions that require glibc memory allocations. This ensures that when we enable glibc fault testing these sections won't break CI. --- External/FEXCore/Source/Common/Paths.cpp | 1 + .../Source/Interface/Config/Config.cpp | 19 ++++++-- .../FEXCore/Source/Interface/IR/AOTIR.cpp | 1 + External/FEXCore/Source/Utils/Telemetry.cpp | 2 + External/FEXCore/Source/Utils/Threads.cpp | 9 ++++ Source/Common/ArgumentLoader.cpp | 1 + Source/Common/Config.cpp | 3 ++ Source/Common/FDUtils.h | 2 + Source/Common/FEXServerClient.cpp | 1 + Source/Tests/FEXLoader.cpp | 47 ++++++++++++------- .../EmulatedFiles/EmulatedFiles.cpp | 1 + Source/Tests/LinuxSyscalls/FileManagement.cpp | 2 + 12 files changed, 70 insertions(+), 19 deletions(-) diff --git a/External/FEXCore/Source/Common/Paths.cpp b/External/FEXCore/Source/Common/Paths.cpp index 28011e4a5..d82a43a7f 100644 --- a/External/FEXCore/Source/Common/Paths.cpp +++ b/External/FEXCore/Source/Common/Paths.cpp @@ -70,6 +70,7 @@ namespace FEXCore::Paths { *EntryCache = *CachePath + "/EntryCache/"; std::error_code ec{}; + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; // Ensure the folder structure is created for our Data if (!std::filesystem::exists(*EntryCache, ec) && !std::filesystem::create_directories(*EntryCache, ec)) { diff --git a/External/FEXCore/Source/Interface/Config/Config.cpp b/External/FEXCore/Source/Interface/Config/Config.cpp index ae7f7f90d..844645266 100644 --- a/External/FEXCore/Source/Interface/Config/Config.cpp +++ b/External/FEXCore/Source/Interface/Config/Config.cpp @@ -4,6 +4,7 @@ #include "Utils/FileLoading.h" #include +#include #include #include #include @@ -144,6 +145,8 @@ namespace JSON { // Ensure the folder structure is created for our configuration std::error_code ec{}; + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + if (!std::filesystem::exists(ConfigDir, ec) && !std::filesystem::create_directories(ConfigDir, ec)) { // Let's go local in this case @@ -176,6 +179,8 @@ namespace JSON { fextl::string ConfigFile = GetConfigDirectory(Global); std::error_code ec{}; + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + if (!Global && !std::filesystem::exists(ConfigFile, ec) && !std::filesystem::create_directories(ConfigFile, ec)) { @@ -346,8 +351,11 @@ namespace JSON { return PathName; } - // Expand relative path to absolute - Path = std::filesystem::absolute(Path); + { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + // Expand relative path to absolute + Path = std::filesystem::absolute(Path); + } // Only return if it exists std::error_code ec{}; @@ -379,8 +387,9 @@ namespace JSON { return {}; } - fextl::string FindContainer() { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + // We only support pressure-vessel at the moment const static fextl::string ContainerManager = "/run/host/container-manager"; if (std::filesystem::exists(ContainerManager)) { @@ -396,6 +405,8 @@ namespace JSON { } fextl::string FindContainerPrefix() { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + // We only support pressure-vessel at the moment const static fextl::string ContainerManager = "/run/host/container-manager"; if (std::filesystem::exists(ContainerManager)) { @@ -459,6 +470,7 @@ namespace JSON { fextl::string ContainerPrefix { FindContainerPrefix() }; auto ExpandPathIfExists = [&ContainerPrefix](FEXCore::Config::ConfigOption Config, fextl::string PathName) { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; auto NewPath = ExpandPath(ContainerPrefix, PathName); if (!NewPath.empty()) { FEXCore::Config::EraseSet(Config, NewPath); @@ -722,6 +734,7 @@ namespace JSON { EnvMap[Key]=Value; } + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; std::function GetVar = [=](const std::string_view id) -> std::optional { if (EnvMap.find(id) != EnvMap.end()) return EnvMap.at(id); diff --git a/External/FEXCore/Source/Interface/IR/AOTIR.cpp b/External/FEXCore/Source/Interface/IR/AOTIR.cpp index 90228a492..ceb7f0e7f 100644 --- a/External/FEXCore/Source/Interface/IR/AOTIR.cpp +++ b/External/FEXCore/Source/Interface/IR/AOTIR.cpp @@ -371,6 +371,7 @@ namespace FEXCore::IR { } AOTIRCacheEntry *AOTIRCaptureCache::LoadAOTIRCacheEntry(const fextl::string &filename) { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; fextl::string base_filename = fextl::string_from_path(std::filesystem::path(filename).filename()); if (!base_filename.empty()) { diff --git a/External/FEXCore/Source/Utils/Telemetry.cpp b/External/FEXCore/Source/Utils/Telemetry.cpp index 40dd9e6ad..672b9823d 100644 --- a/External/FEXCore/Source/Utils/Telemetry.cpp +++ b/External/FEXCore/Source/Utils/Telemetry.cpp @@ -29,6 +29,7 @@ namespace FEXCore::Telemetry { // Ensure the folder structure is created for our configuration std::error_code ec{}; + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; if (!std::filesystem::exists(DataDirectory, ec) && !std::filesystem::create_directories(DataDirectory, ec)) { LogMan::Msg::IFmt("Couldn't create telemetry Folder"); @@ -40,6 +41,7 @@ namespace FEXCore::Telemetry { DataDirectory += "Telemetry/" + ApplicationName + ".telem"; std::error_code ec{}; + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; if (std::filesystem::exists(DataDirectory, ec)) { // If the file exists, retain a single backup auto Backup = DataDirectory + ".1"; diff --git a/External/FEXCore/Source/Utils/Threads.cpp b/External/FEXCore/Source/Utils/Threads.cpp index d24d284a8..9eb2223cc 100644 --- a/External/FEXCore/Source/Utils/Threads.cpp +++ b/External/FEXCore/Source/Utils/Threads.cpp @@ -97,9 +97,14 @@ namespace FEXCore::Threads { , UserArg {Arg} { pthread_attr_t Attr{}; Stack = AllocateStackObject(STACK_SIZE); + // pthreads allocates its dtv region behind our back and there is nothing we can do about it. + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; AddStackToLivePool(Stack, STACK_SIZE); pthread_attr_init(&Attr); pthread_attr_setstack(&Attr, Stack, STACK_SIZE); + // TODO: Thread creation should be using this instead. + // Causes Steam to crash early though. + // pthread_create(&Thread, &Attr, InitializeThread, this); pthread_create(&Thread, &Attr, Func, Arg); pthread_attr_destroy(&Attr); @@ -155,6 +160,10 @@ namespace FEXCore::Threads { // Put the stack back in to the stack pool Thread->FreeStack(); + + // TLS/DTV teardown is something FEX can't control. Disable glibc checking when we leave a pthread. + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable(); + return Result; } diff --git a/Source/Common/ArgumentLoader.cpp b/Source/Common/ArgumentLoader.cpp index 583a78650..ce011adca 100644 --- a/Source/Common/ArgumentLoader.cpp +++ b/Source/Common/ArgumentLoader.cpp @@ -14,6 +14,7 @@ namespace FEX::ArgLoader { static std::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") "; void FEX::ArgLoader::ArgLoader::Load() { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; optparse::OptionParser Parser{}; Parser.version(Version); optparse::OptionGroup CPUGroup(Parser, "CPU Core options"); diff --git a/Source/Common/Config.cpp b/Source/Common/Config.cpp index e914e0c29..7653f337f 100644 --- a/Source/Common/Config.cpp +++ b/Source/Common/Config.cpp @@ -44,6 +44,8 @@ namespace FEX::Config { } fextl::string RecoverGuestProgramFilename(fextl::string Program, bool ExecFDInterp, const std::string_view ProgramFDFromEnv) { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + // If executed with a FEX FD then the Program argument might be empty. // In this case we need to scan the FD node to recover the application binary that exists on disk. // Only do this if the Program argument is empty, since we would prefer the application's expectation @@ -137,6 +139,7 @@ namespace FEX::Config { Args[0] = RecoverGuestProgramFilename(std::move(Args[0]), ExecFDInterp, ProgramFDFromEnv); fextl::string& Program = Args[0]; + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; bool Wine = false; std::filesystem::path ProgramName; for (size_t CurrentProgramNameIndex = 0; CurrentProgramNameIndex < Args.size(); ++CurrentProgramNameIndex) { diff --git a/Source/Common/FDUtils.h b/Source/Common/FDUtils.h index 38e4be20f..d8b313b71 100644 --- a/Source/Common/FDUtils.h +++ b/Source/Common/FDUtils.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -13,6 +14,7 @@ namespace FEX { [[maybe_unused]] static std::optional get_fdpath(int fd) { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; char SymlinkPath[PATH_MAX]; std::filesystem::path Path = std::filesystem::path("/proc/self/fd") / std::to_string(fd); int Result = readlinkat(AT_FDCWD, Path.c_str(), SymlinkPath, sizeof(SymlinkPath)); diff --git a/Source/Common/FEXServerClient.cpp b/Source/Common/FEXServerClient.cpp index 35e28af6e..f9348338d 100644 --- a/Source/Common/FEXServerClient.cpp +++ b/Source/Common/FEXServerClient.cpp @@ -211,6 +211,7 @@ namespace FEXServerClient { return -1; } + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; fextl::string FEXServerPath = fextl::string_from_path(std::filesystem::path(InterpreterPath).parent_path()) + "/FEXServer"; // Check if a local FEXServer next to FEXInterpreter exists // If it does then it takes priority over the installed one diff --git a/Source/Tests/FEXLoader.cpp b/Source/Tests/FEXLoader.cpp index fb51d0c6d..44ac576ed 100644 --- a/Source/Tests/FEXLoader.cpp +++ b/Source/Tests/FEXLoader.cpp @@ -123,6 +123,7 @@ namespace FEXServerLogging { } void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fextl::vector *args) { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; // Open the file pointer to the filename and see if we need to find an interpreter std::fstream File(fextl::string_from_string(*Filename), std::fstream::in | std::fstream::binary); @@ -178,6 +179,7 @@ void RootFSRedirect(fextl::string *Filename, fextl::string const &RootFS) { auto RootFSLink = ELFCodeLoader::ResolveRootfsFile(*Filename, RootFS); std::error_code ec{}; + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; if (std::filesystem::exists(RootFSLink, ec)) { *Filename = RootFSLink; } @@ -293,11 +295,16 @@ int main(int argc, char **argv, char **const envp) { InterpreterHandler(&Program.ProgramPath, LDPath(), &Args); std::error_code ec{}; - if (!ExecutedWithFD && !FEXFD && !std::filesystem::exists(Program.ProgramPath, ec)) { - // Early exit if the program passed in doesn't exist - // Will prevent a crash later - fmt::print(stderr, "{}: command not found\n", Program.ProgramPath); - return -ENOEXEC; + + { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + if (!ExecutedWithFD && !FEXFD && !std::filesystem::exists(Program.ProgramPath, ec)) { + // Early exit if the program passed in doesn't exist + // Will prevent a crash later + fmt::print(stderr, "{}: command not found\n", Program.ProgramPath); + FEXCore::Allocator::ClearFaultEvaluate(); + return -ENOEXEC; + } } uint32_t KernelVersion = FEX::HLE::SyscallHandler::CalculateHostKernelVersion(); @@ -342,7 +349,10 @@ int main(int argc, char **argv, char **const envp) { FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_CONFIG_NAME, ""); } else { - FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_FILENAME, std::filesystem::canonical(Program.ProgramPath).string()); + { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_FILENAME, std::filesystem::canonical(Program.ProgramPath).string()); + } FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_CONFIG_NAME, Program.ProgramName); } FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode() ? "1" : "0"); @@ -402,18 +412,23 @@ int main(int argc, char **argv, char **const envp) { auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX, SignalDelegation.get()) : FEX::HLE::x32::CreateHandler(CTX, SignalDelegation.get(), std::move(Allocator)); - auto Mapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMmap, SyscallHandler.get()); - auto Unmapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMunmap, SyscallHandler.get()); + { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - // Load VDSO in to memory prior to mapping our ELFs. - void* VDSOBase = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), Mapper); - Loader.SetVDSOBase(VDSOBase); - Loader.CalculateHWCaps(CTX); + auto Mapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMmap, SyscallHandler.get()); + auto Unmapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMunmap, SyscallHandler.get()); - if (!Loader.MapMemory(Mapper, Unmapper)) { - // failed to map - LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32); - return -ENOEXEC; + // Load VDSO in to memory prior to mapping our ELFs. + void* VDSOBase = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), Mapper); + Loader.SetVDSOBase(VDSOBase); + Loader.CalculateHWCaps(CTX); + + if (!Loader.MapMemory(Mapper, Unmapper)) { + // failed to map + LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32); + FEXCore::Allocator::ClearFaultEvaluate(); + return -ENOEXEC; + } } SyscallHandler->SetCodeLoader(&Loader); diff --git a/Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp b/Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp index feb50c85b..ed9a5b45c 100644 --- a/Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp +++ b/Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp @@ -764,6 +764,7 @@ namespace FEX::EmulatedFile { } if (!RealPathExists) { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; Creator = FDReadCreators.find(fextl::string_from_path(std::filesystem::path(Path).lexically_normal())); } diff --git a/Source/Tests/LinuxSyscalls/FileManagement.cpp b/Source/Tests/LinuxSyscalls/FileManagement.cpp index 7e1d3d7e5..cecd48cbd 100644 --- a/Source/Tests/LinuxSyscalls/FileManagement.cpp +++ b/Source/Tests/LinuxSyscalls/FileManagement.cpp @@ -62,6 +62,7 @@ namespace FEX::HLE { struct open_how; static bool LoadFile(fextl::vector &Data, const fextl::string &Filename) { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; std::fstream File(fextl::string_from_string(Filename), std::ios::in); if (!File.is_open()) { @@ -216,6 +217,7 @@ static void LoadThunkDatabase(fextl::unordered_map FileManager::FileManager(FEXCore::Context::Context *ctx) : EmuFD {ctx} { + FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; auto ThunkConfigFile = ThunkConfig(); From 1eb36b8b31c6da19868a42d41b7f54cdb8388d45 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 20:20:28 -0700 Subject: [PATCH 10/41] Convert a ton of things over to fextl --- External/FEXCore/Source/Common/Paths.cpp | 10 +++-- .../Source/Interface/Config/Config.cpp | 33 +++++++++-------- .../Source/Interface/Context/Context.h | 19 +++++++--- .../FEXCore/Source/Interface/Core/Core.cpp | 16 ++++---- .../Core/Dispatcher/Arm64Dispatcher.cpp | 5 ++- .../Interface/Core/Dispatcher/Dispatcher.h | 5 ++- .../Core/Dispatcher/X86Dispatcher.cpp | 5 ++- .../Core/Interpreter/InterpreterCore.cpp | 6 +-- .../Core/Interpreter/InterpreterCore.h | 5 ++- .../Source/Interface/Core/JIT/Arm64/JIT.cpp | 4 +- .../Source/Interface/Core/JIT/JITCore.h | 7 ++-- .../Source/Interface/Core/JIT/x86_64/JIT.cpp | 4 +- .../Core/ObjectCache/ObjectCacheService.h | 4 +- .../Source/Interface/HLE/Thunks/Thunks.cpp | 4 +- .../Source/Interface/HLE/Thunks/Thunks.h | 11 +++--- .../FEXCore/Source/Interface/IR/PassManager.h | 10 ++--- External/FEXCore/Source/Interface/IR/Passes.h | 28 +++++++------- .../Source/Interface/IR/Passes/ConstProp.cpp | 8 ++-- .../IR/Passes/DeadCodeElimination.cpp | 4 +- .../IR/Passes/DeadContextStoreElimination.cpp | 6 +-- .../IR/Passes/DeadStoreElimination.cpp | 4 +- .../Interface/IR/Passes/IRCompaction.cpp | 4 +- .../Interface/IR/Passes/IRValidation.cpp | 4 +- .../IR/Passes/LongDivideRemovalPass.cpp | 4 +- .../Interface/IR/Passes/PhiValidation.cpp | 4 +- .../Interface/IR/Passes/RAValidation.cpp | 4 +- .../RedundantFlagCalculationElimination.cpp | 4 +- .../IR/Passes/RegisterAllocationPass.cpp | 12 +++++- .../IR/Passes/SyscallOptimization.cpp | 4 +- .../IR/Passes/ValueDominanceValidation.cpp | 4 +- .../Source/Utils/Allocator/64BitAllocator.cpp | 17 +++++++-- .../Source/Utils/Allocator/HostAllocator.h | 5 ++- External/FEXCore/Source/Utils/Threads.cpp | 8 ++-- .../FEXCore/include/FEXCore/Config/Config.h | 12 +++--- .../FEXCore/include/FEXCore/Core/Context.h | 4 +- .../FEXCore/Debug/InternalThreadState.h | 37 ++++++++++++++----- .../include/FEXCore/HLE/SourcecodeResolver.h | 3 +- .../include/FEXCore/IR/IntrusiveIRList.h | 12 +++++- .../include/FEXCore/Utils/BucketList.h | 6 +-- .../FEXCore/Utils/ThreadPoolAllocator.h | 8 ++++ .../FEXCore/include/FEXCore/Utils/Threads.h | 7 ++-- FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h | 7 ++-- Source/Common/Config.cpp | 2 +- Source/Tests/FEXLoader.cpp | 2 +- Source/Tests/IRLoader.cpp | 2 +- Source/Tests/LinuxSyscalls/LinuxAllocator.cpp | 10 +++-- Source/Tests/LinuxSyscalls/LinuxAllocator.h | 6 ++- Source/Tests/LinuxSyscalls/SignalDelegator.h | 8 ++++ Source/Tests/LinuxSyscalls/Syscalls.cpp | 6 +-- Source/Tests/LinuxSyscalls/Syscalls.h | 13 ++++++- Source/Tests/LinuxSyscalls/x32/Syscalls.cpp | 7 ++-- Source/Tests/LinuxSyscalls/x32/Syscalls.h | 9 +++-- Source/Tests/LinuxSyscalls/x64/Syscalls.cpp | 4 +- Source/Tests/LinuxSyscalls/x64/Syscalls.h | 3 +- Source/Tests/TestHarnessRunner.cpp | 6 +-- Source/Tools/Opt.cpp | 2 +- 56 files changed, 273 insertions(+), 175 deletions(-) diff --git a/External/FEXCore/Source/Common/Paths.cpp b/External/FEXCore/Source/Common/Paths.cpp index d82a43a7f..8722b1d14 100644 --- a/External/FEXCore/Source/Common/Paths.cpp +++ b/External/FEXCore/Source/Common/Paths.cpp @@ -1,5 +1,7 @@ #include "Common/Paths.h" +#include #include +#include #include #include @@ -10,8 +12,8 @@ #include namespace FEXCore::Paths { - std::unique_ptr CachePath; - std::unique_ptr EntryCache; + fextl::unique_ptr CachePath; + fextl::unique_ptr EntryCache; char const* FindUserHomeThroughUID() { auto passwd = getpwuid(geteuid()); @@ -43,8 +45,8 @@ namespace FEXCore::Paths { } void InitializePaths() { - CachePath = std::make_unique(); - EntryCache = std::make_unique(); + CachePath = fextl::make_unique(); + EntryCache = fextl::make_unique(); char const *HomeDir = getenv("HOME"); diff --git a/External/FEXCore/Source/Interface/Config/Config.cpp b/External/FEXCore/Source/Interface/Config/Config.cpp index 844645266..cd55b2920 100644 --- a/External/FEXCore/Source/Interface/Config/Config.cpp +++ b/External/FEXCore/Source/Interface/Config/Config.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -46,13 +46,13 @@ namespace DefaultValues { namespace JSON { struct JsonAllocator { jsonPool_t PoolObject; - std::unique_ptr> json_objects; + fextl::unique_ptr> json_objects; }; static_assert(offsetof(JsonAllocator, PoolObject) == 0, "This needs to be at offset zero"); json_t* PoolInit(jsonPool_t* Pool) { JsonAllocator* alloc = reinterpret_cast(Pool); - alloc->json_objects = std::make_unique>(); + alloc->json_objects = fextl::make_unique>(); return &*alloc->json_objects->emplace(alloc->json_objects->end()); } @@ -213,7 +213,7 @@ namespace JSON { return 0; } - static fextl::map> ConfigLayers; + static fextl::map> ConfigLayers; static FEXCore::Config::Layer *Meta{}; constexpr std::array LoadOrder = { @@ -316,7 +316,7 @@ namespace JSON { } void Initialize() { - AddLayer(std::make_unique(FEXCore::Config::LayerType::LAYER_TOP)); + AddLayer(fextl::make_unique(FEXCore::Config::LayerType::LAYER_TOP)); Meta = ConfigLayers.begin()->second.get(); } @@ -339,6 +339,7 @@ namespace JSON { return {}; } + std::filesystem::path Path{PathName}; // Expand home if it exists @@ -479,7 +480,7 @@ namespace JSON { if (FEXCore::Config::Exists(FEXCore::Config::CONFIG_ROOTFS)) { FEX_CONFIG_OPT(PathName, ROOTFS); - auto ExpandedString = ExpandPath(ContainerPrefix, PathName()); + auto ExpandedString = ExpandPath(ContainerPrefix,PathName()); if (!ExpandedString.empty()) { // Adjust the path if it ended up being relative FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_ROOTFS, ExpandedString); @@ -530,7 +531,7 @@ namespace JSON { } } - void AddLayer(std::unique_ptr _Layer) { + void AddLayer(fextl::unique_ptr _Layer) { ConfigLayers.emplace(_Layer->GetLayerType(), std::move(_Layer)); } @@ -758,25 +759,25 @@ namespace JSON { } } - std::unique_ptr CreateGlobalMainLayer() { - return std::make_unique(FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN); + fextl::unique_ptr CreateGlobalMainLayer() { + return fextl::make_unique(FEXCore::Config::LayerType::LAYER_GLOBAL_MAIN); } - std::unique_ptr CreateMainLayer(fextl::string const *File) { + fextl::unique_ptr CreateMainLayer(fextl::string const *File) { if (File) { - return std::make_unique(*File); + return fextl::make_unique(*File); } else { - return std::make_unique(FEXCore::Config::LayerType::LAYER_MAIN); + return fextl::make_unique(FEXCore::Config::LayerType::LAYER_MAIN); } } - std::unique_ptr CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type) { - return std::make_unique(Filename, Type); + fextl::unique_ptr CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type) { + return fextl::make_unique(Filename, Type); } - std::unique_ptr CreateEnvironmentLayer(char *const _envp[]) { - return std::make_unique(_envp); + fextl::unique_ptr CreateEnvironmentLayer(char *const _envp[]) { + return fextl::make_unique(_envp); } } diff --git a/External/FEXCore/Source/Interface/Context/Context.h b/External/FEXCore/Source/Interface/Context/Context.h index ff94343c1..ad35e6d87 100644 --- a/External/FEXCore/Source/Interface/Context/Context.h +++ b/External/FEXCore/Source/Interface/Context/Context.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,14 @@ namespace FEXCore::Context { class ContextImpl final : public FEXCore::Context::Context { public: + void *operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void operator delete(void *ptr) { + return FEXCore::Allocator::free(ptr); + } + // Context base class implementation. bool InitializeContext() override; @@ -261,14 +270,14 @@ namespace FEXCore::Context { FEXCore::CPUIDEmu CPUID; FEXCore::HLE::SyscallHandler *SyscallHandler{}; FEXCore::HLE::SourcecodeResolver *SourcecodeResolver{}; - std::unique_ptr ThunkHandler; - std::unique_ptr Dispatcher; + fextl::unique_ptr ThunkHandler; + fextl::unique_ptr Dispatcher; CustomCPUFactoryType CustomCPUFactory; FEXCore::Context::ExitHandler CustomExitHandler; #ifdef BLOCKSTATS - std::unique_ptr BlockData; + fextl::unique_ptr BlockData; #endif SignalDelegator *SignalDelegation{}; @@ -405,10 +414,10 @@ namespace FEXCore::Context { // Entry Cache std::mutex ExitMutex; - std::unique_ptr DebugServer; + fextl::unique_ptr DebugServer; IR::AOTIRCaptureCache IRCaptureCache; - std::unique_ptr CodeObjectCacheService; + fextl::unique_ptr CodeObjectCacheService; bool StartPaused = false; bool IsMemoryShared = false; diff --git a/External/FEXCore/Source/Interface/Core/Core.cpp b/External/FEXCore/Source/Interface/Core/Core.cpp index 95d0e5d39..4ddb6f096 100644 --- a/External/FEXCore/Source/Interface/Core/Core.cpp +++ b/External/FEXCore/Source/Interface/Core/Core.cpp @@ -45,6 +45,7 @@ $end_info$ #include #include #include +#include #include #include #include @@ -59,7 +60,6 @@ $end_info$ #include #include #include -#include #include #include #include @@ -151,7 +151,7 @@ namespace FEXCore::Context { BlockData = std::make_unique(); #endif if (Config.CacheObjectCodeCompilation() != FEXCore::Config::ConfigObjectCodeHandler::CONFIG_NONE) { - CodeObjectCacheService = std::make_unique(this); + CodeObjectCacheService = fextl::make_unique(this); } if (!Config.EnableAVX) { HostFeatures.SupportsAVX = false; @@ -275,7 +275,7 @@ namespace FEXCore::Context { StopGdbServer(); } - ThunkHandler.reset(FEXCore::ThunkHandler::Create()); + ThunkHandler = FEXCore::ThunkHandler::Create(); using namespace FEXCore::Core; @@ -295,7 +295,7 @@ namespace FEXCore::Context { void ContextImpl::StartGdbServer() { if (!DebugServer) { - DebugServer = std::make_unique(this); + DebugServer = fextl::make_unique(this); StartPaused = true; } } @@ -557,11 +557,11 @@ namespace FEXCore::Context { } void ContextImpl::InitializeCompiler(FEXCore::Core::InternalThreadState* Thread) { - Thread->OpDispatcher = std::make_unique(this); + Thread->OpDispatcher = fextl::make_unique(this); Thread->OpDispatcher->SetMultiblock(Config.Multiblock); - Thread->LookupCache = std::make_unique(this); - Thread->FrontendDecoder = std::make_unique(this); - Thread->PassManager = std::make_unique(); + Thread->LookupCache = fextl::make_unique(this); + Thread->FrontendDecoder = fextl::make_unique(this); + Thread->PassManager = fextl::make_unique(); Thread->PassManager->RegisterExitHandler([this]() { Stop(false /* Ignore current thread */); }); diff --git a/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp b/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp index b40db6dd6..95d28ede0 100644 --- a/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/Dispatcher/Arm64Dispatcher.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -672,8 +673,8 @@ void Arm64Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState *Thr } } -std::unique_ptr Dispatcher::CreateArm64(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config) { - return std::make_unique(CTX, Config); +fextl::unique_ptr Dispatcher::CreateArm64(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config) { + return fextl::make_unique(CTX, Config); } } diff --git a/External/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.h b/External/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.h index e6b3155de..279ee9970 100644 --- a/External/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.h +++ b/External/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "Interface/Core/ArchHelpers/MContext.h" #include @@ -73,8 +74,8 @@ public: virtual size_t GenerateGDBPauseCheck(uint8_t *CodeBuffer, uint64_t GuestRIP) = 0; virtual size_t GenerateInterpreterTrampoline(uint8_t *CodeBuffer) = 0; - static std::unique_ptr CreateX86(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config); - static std::unique_ptr CreateArm64(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config); + static fextl::unique_ptr CreateX86(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config); + static fextl::unique_ptr CreateArm64(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config); virtual void ExecuteDispatch(FEXCore::Core::CpuStateFrame *Frame) { DispatchPtr(Frame); diff --git a/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.cpp b/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.cpp index 79f13601c..a6238937a 100644 --- a/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -500,8 +501,8 @@ void X86Dispatcher::InitThreadPointers(FEXCore::Core::InternalThreadState *Threa } } -std::unique_ptr Dispatcher::CreateX86(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config) { - return std::make_unique(CTX, Config); +fextl::unique_ptr Dispatcher::CreateX86(FEXCore::Context::ContextImpl *CTX, const DispatcherConfig &Config) { + return fextl::make_unique(CTX, Config); } } diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp index 0b3d25ca3..2697a6568 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp @@ -10,8 +10,8 @@ #include #include #include +#include -#include #include #include #include @@ -103,8 +103,8 @@ void InterpreterCore::ClearCache() { BufferUsed = 0; } -std::unique_ptr CreateInterpreterCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) { - return std::make_unique(ctx->Dispatcher.get(), Thread); +fextl::unique_ptr CreateInterpreterCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) { + return fextl::make_unique(ctx->Dispatcher.get(), Thread); } void InitializeInterpreterSignalHandlers(FEXCore::Context::ContextImpl *CTX) { diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.h b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.h index a59731bd4..b97769014 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.h +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.h @@ -1,6 +1,7 @@ #pragma once -#include +#include +#include namespace FEXCore::Context { class ContextImpl; @@ -14,7 +15,7 @@ namespace FEXCore::CPU { class CPUBackend; struct DispatcherConfig; -[[nodiscard]] std::unique_ptr CreateInterpreterCore(FEXCore::Context::ContextImpl *ctx, +[[nodiscard]] fextl::unique_ptr CreateInterpreterCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread); void InitializeInterpreterSignalHandlers(FEXCore::Context::ContextImpl *CTX); CPUBackendFeatures GetInterpreterBackendFeatures(); diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index a327dd147..307670cd4 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -1087,8 +1087,8 @@ void Arm64JITCore::ResetStack() { } } -std::unique_ptr CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) { - return std::make_unique(ctx, Thread); +fextl::unique_ptr CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) { + return fextl::make_unique(ctx, Thread); } void InitializeArm64JITSignalHandlers(FEXCore::Context::ContextImpl *CTX) { diff --git a/External/FEXCore/Source/Interface/Core/JIT/JITCore.h b/External/FEXCore/Source/Interface/Core/JIT/JITCore.h index 0dcf8aa25..592dcabf0 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/JITCore.h +++ b/External/FEXCore/Source/Interface/Core/JIT/JITCore.h @@ -1,6 +1,7 @@ #pragma once -#include +#include +#include namespace FEXCore::Context { class ContextImpl; @@ -13,12 +14,12 @@ struct InternalThreadState; namespace FEXCore::CPU { class CPUBackend; -[[nodiscard]] std::unique_ptr CreateX86JITCore(FEXCore::Context::ContextImpl *ctx, +[[nodiscard]] fextl::unique_ptr CreateX86JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread); void InitializeX86JITSignalHandlers(FEXCore::Context::ContextImpl *CTX); CPUBackendFeatures GetX86JITBackendFeatures(); -[[nodiscard]] std::unique_ptr CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx, +[[nodiscard]] fextl::unique_ptr CreateArm64JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread); void InitializeArm64JITSignalHandlers(FEXCore::Context::ContextImpl *CTX); CPUBackendFeatures GetArm64JITBackendFeatures(); diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 46f097b17..7eb0e9339 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -788,8 +788,8 @@ CPUBackend::CompiledCode X86JITCore::CompileCode(uint64_t Entry, [[maybe_unused] return CodeData; } -std::unique_ptr CreateX86JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) { - return std::make_unique(ctx, Thread); +fextl::unique_ptr CreateX86JITCore(FEXCore::Context::ContextImpl *ctx, FEXCore::Core::InternalThreadState *Thread) { + return fextl::make_unique(ctx, Thread); } CPUBackendFeatures GetX86JITBackendFeatures() { diff --git a/External/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.h b/External/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.h index 074eefc56..61cb2be86 100644 --- a/External/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.h +++ b/External/FEXCore/Source/Interface/Core/ObjectCache/ObjectCacheService.h @@ -8,12 +8,12 @@ #include #include #include +#include #include #include #include #include -#include namespace FEXCore::CodeSerialize { // XXX: Does this need to be signal safe? @@ -111,7 +111,7 @@ namespace FEXCore::CodeSerialize { // This per section map takes the most time to load and needs to be quick // This is the map of all code segments for this entry - tsl::robin_map SectionLookupMap{}; + fextl::robin_map SectionLookupMap{}; /** @} */ // Default initialization diff --git a/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp b/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp index b66640f46..5ac89fdee 100644 --- a/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp +++ b/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.cpp @@ -355,8 +355,8 @@ namespace FEXCore { } }; - ThunkHandler* ThunkHandler::Create() { - return new ThunkHandler_impl(); + fextl::unique_ptr ThunkHandler::Create() { + return fextl::make_unique(); } /** diff --git a/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.h b/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.h index e8a03c5e5..bb368346b 100644 --- a/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.h +++ b/External/FEXCore/Source/Interface/HLE/Thunks/Thunks.h @@ -7,6 +7,7 @@ $end_info$ #pragma once #include +#include #include namespace FEXCore::Context { @@ -26,12 +27,12 @@ namespace FEXCore { class ThunkHandler { public: - virtual ThunkedFunction* LookupThunk(const IR::SHA256Sum &sha256) = 0; - virtual void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) = 0; - virtual ~ThunkHandler() { } + virtual ThunkedFunction* LookupThunk(const IR::SHA256Sum &sha256) = 0; + virtual void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) = 0; + virtual ~ThunkHandler() { } - static ThunkHandler* Create(); + static fextl::unique_ptr Create(); - virtual void AppendThunkDefinitions(fextl::vector const& Definitions) = 0; + virtual void AppendThunkDefinitions(fextl::vector const& Definitions) = 0; }; }; diff --git a/External/FEXCore/Source/Interface/IR/PassManager.h b/External/FEXCore/Source/Interface/IR/PassManager.h index e2b9da836..704f800f5 100644 --- a/External/FEXCore/Source/Interface/IR/PassManager.h +++ b/External/FEXCore/Source/Interface/IR/PassManager.h @@ -8,12 +8,12 @@ $end_info$ #include #include +#include #include #include #include #include -#include #include namespace FEXCore::Context { @@ -48,7 +48,7 @@ class PassManager final { public: void AddDefaultPasses(FEXCore::Context::ContextImpl *ctx, bool InlineConstants, bool StaticRegisterAllocation); void AddDefaultValidationPasses(); - Pass* InsertPass(std::unique_ptr Pass, fextl::string Name = "") { + Pass* InsertPass(fextl::unique_ptr Pass, fextl::string Name = "") { Pass->RegisterPassManager(this); auto PassPtr = Passes.emplace_back(std::move(Pass)).get(); @@ -88,12 +88,12 @@ protected: FEXCore::HLE::SyscallHandler *SyscallHandler; private: - fextl::vector> Passes; + fextl::vector> Passes; fextl::unordered_map NameToPassMaping; #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - fextl::vector> ValidationPasses; - void InsertValidationPass(std::unique_ptr Pass, fextl::string Name = "") { + fextl::vector> ValidationPasses; + void InsertValidationPass(fextl::unique_ptr Pass, fextl::string Name = "") { Pass->RegisterPassManager(this); auto PassPtr = ValidationPasses.emplace_back(std::move(Pass)).get(); diff --git a/External/FEXCore/Source/Interface/IR/Passes.h b/External/FEXCore/Source/Interface/IR/Passes.h index d40a9cdc1..d258b0fc3 100644 --- a/External/FEXCore/Source/Interface/IR/Passes.h +++ b/External/FEXCore/Source/Interface/IR/Passes.h @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace FEXCore::Utils { class IntrusivePooledAllocator; @@ -11,23 +11,23 @@ class Pass; class RegisterAllocationPass; class RegisterAllocationData; -std::unique_ptr CreateConstProp(bool InlineConstants, bool SupportsTSOImm9); -std::unique_ptr CreateContextLoadStoreElimination(bool SupportsAVX); -std::unique_ptr CreateSyscallOptimization(); -std::unique_ptr CreateDeadFlagCalculationEliminination(); -std::unique_ptr CreateDeadStoreElimination(bool SupportsAVX); -std::unique_ptr CreatePassDeadCodeElimination(); -std::unique_ptr CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator); -std::unique_ptr CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, +fextl::unique_ptr CreateConstProp(bool InlineConstants, bool SupportsTSOImm9); +fextl::unique_ptr CreateContextLoadStoreElimination(bool SupportsAVX); +fextl::unique_ptr CreateSyscallOptimization(); +fextl::unique_ptr CreateDeadFlagCalculationEliminination(); +fextl::unique_ptr CreateDeadStoreElimination(bool SupportsAVX); +fextl::unique_ptr CreatePassDeadCodeElimination(); +fextl::unique_ptr CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator); +fextl::unique_ptr CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool OptimizeSRA, bool SupportsAVX); -std::unique_ptr CreateLongDivideEliminationPass(); +fextl::unique_ptr CreateLongDivideEliminationPass(); namespace Validation { -std::unique_ptr CreateIRValidation(); -std::unique_ptr CreateRAValidation(); -std::unique_ptr CreatePhiValidation(); -std::unique_ptr CreateValueDominanceValidation(); +fextl::unique_ptr CreateIRValidation(); +fextl::unique_ptr CreateRAValidation(); +fextl::unique_ptr CreatePhiValidation(); +fextl::unique_ptr CreateValueDominanceValidation(); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp index 10699d044..c1156b441 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ConstProp.cpp @@ -22,6 +22,7 @@ $end_info$ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ $end_info$ #include #include #include -#include #include namespace FEXCore::IR { @@ -201,7 +201,7 @@ private: fextl::map AddressgenConsts; // Pool inline constant generation. These are typically very small and pool efficiently. - tsl::robin_map InlineConstantGen; + fextl::robin_map InlineConstantGen; OrderedNode *CreateInlineConstant(IREmitter *IREmit, uint64_t Constant) { const auto it = InlineConstantGen.find(Constant); if (it != InlineConstantGen.end()) { @@ -1073,8 +1073,8 @@ bool ConstProp::Run(IREmitter *IREmit) { return Changed; } -std::unique_ptr CreateConstProp(bool InlineConstants, bool SupportsTSOImm9) { - return std::make_unique(InlineConstants, SupportsTSOImm9); +fextl::unique_ptr CreateConstProp(bool InlineConstants, bool SupportsTSOImm9) { + return fextl::make_unique(InlineConstants, SupportsTSOImm9); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp index 3047c002f..cdba93b3e 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadCodeElimination.cpp @@ -80,8 +80,8 @@ void DeadCodeElimination::markUsed(OrderedNodeWrapper *CodeOp, IROp_Header *IROp } -std::unique_ptr CreatePassDeadCodeElimination() { - return std::make_unique(); +fextl::unique_ptr CreatePassDeadCodeElimination() { + return fextl::make_unique(); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp index 02bc35cdf..c740f491c 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadContextStoreElimination.cpp @@ -410,7 +410,7 @@ public: } bool Run(FEXCore::IR::IREmitter *IREmit) override; private: - std::unique_ptr DCE; + fextl::unique_ptr DCE; ContextInfo ClassifiedStruct; fextl::unordered_map OffsetToBlockMap; @@ -784,8 +784,8 @@ bool RCLSE::Run(FEXCore::IR::IREmitter *IREmit) { namespace FEXCore::IR { -std::unique_ptr CreateContextLoadStoreElimination(bool SupportsAVX) { - return std::make_unique(SupportsAVX); +fextl::unique_ptr CreateContextLoadStoreElimination(bool SupportsAVX) { + return fextl::make_unique(SupportsAVX); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp index 3f7f90aa9..284bcd97b 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/DeadStoreElimination.cpp @@ -358,8 +358,8 @@ bool DeadStoreElimination::Run(IREmitter *IREmit) { return Changed; } -std::unique_ptr CreateDeadStoreElimination(bool SupportsAVX) { - return std::make_unique(SupportsAVX); +fextl::unique_ptr CreateDeadStoreElimination(bool SupportsAVX) { + return fextl::make_unique(SupportsAVX); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp index 9497598fa..d53840802 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp @@ -220,8 +220,8 @@ bool IRCompaction::Run(IREmitter *IREmit) { return true; } -std::unique_ptr CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator) { - return std::make_unique(Allocator); +fextl::unique_ptr CreateIRCompaction(FEXCore::Utils::IntrusivePooledAllocator &Allocator) { + return fextl::make_unique(Allocator); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp index 939315e62..b2e6854fb 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRValidation.cpp @@ -271,7 +271,7 @@ bool IRValidation::Run(IREmitter *IREmit) { return false; } -std::unique_ptr CreateIRValidation() { - return std::make_unique(); +fextl::unique_ptr CreateIRValidation() { + return fextl::make_unique(); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/LongDivideRemovalPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/LongDivideRemovalPass.cpp index 46b958031..edc6a5cb6 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/LongDivideRemovalPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/LongDivideRemovalPass.cpp @@ -114,7 +114,7 @@ bool LongDivideEliminationPass::Run(IREmitter *IREmit) { return Changed; } -std::unique_ptr CreateLongDivideEliminationPass() { - return std::make_unique(); +fextl::unique_ptr CreateLongDivideEliminationPass() { + return fextl::make_unique(); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp index c24322831..41216f28c 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/PhiValidation.cpp @@ -70,8 +70,8 @@ bool PhiValidation::Run(IREmitter *IREmit) { return false; } -std::unique_ptr CreatePhiValidation() { - return std::make_unique(); +fextl::unique_ptr CreatePhiValidation() { + return fextl::make_unique(); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp index 351b26422..28c007d14 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RAValidation.cpp @@ -452,7 +452,7 @@ bool RAValidation::Run(IREmitter *IREmit) { return false; } -std::unique_ptr CreateRAValidation() { - return std::make_unique(); +fextl::unique_ptr CreateRAValidation() { + return fextl::make_unique(); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp b/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp index c58bf36ad..b5693a170 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RedundantFlagCalculationElimination.cpp @@ -68,8 +68,8 @@ bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) { return Changed; } -std::unique_ptr CreateDeadFlagCalculationEliminination() { - return std::make_unique(); +fextl::unique_ptr CreateDeadFlagCalculationEliminination() { + return fextl::make_unique(); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index fc00b4548..b57cf6119 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -98,6 +98,14 @@ namespace { fextl::vector SpillStack; fextl::unordered_map> BlockPredecessors; fextl::unordered_map> VisitedNodePredecessors; + + void *operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void operator delete(void *ptr) { + return FEXCore::Allocator::free(ptr); + } }; void ResetRegisterGraph(RegisterGraph *Graph, uint64_t NodeCount); @@ -1559,7 +1567,7 @@ namespace { return Changed; } - std::unique_ptr CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool OptimizeSRA, bool SupportsAVX) { - return std::make_unique(CompactionPass, OptimizeSRA, SupportsAVX); + fextl::unique_ptr CreateRegisterAllocationPass(FEXCore::IR::Pass* CompactionPass, bool OptimizeSRA, bool SupportsAVX) { + return fextl::make_unique(CompactionPass, OptimizeSRA, SupportsAVX); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp b/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp index 5d68eb7e1..eb5401107 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/SyscallOptimization.cpp @@ -82,8 +82,8 @@ bool SyscallOptimization::Run(IREmitter *IREmit) { return Changed; } -std::unique_ptr CreateSyscallOptimization() { - return std::make_unique(); +fextl::unique_ptr CreateSyscallOptimization() { + return fextl::make_unique(); } } diff --git a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp index 62466e0fc..46f734112 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp @@ -206,8 +206,8 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) { return false; } -std::unique_ptr CreateValueDominanceValidation() { - return std::make_unique(); +fextl::unique_ptr CreateValueDominanceValidation() { + return fextl::make_unique(); } } diff --git a/External/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp b/External/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp index cc42f8c30..8dfd07c79 100644 --- a/External/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp +++ b/External/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,14 @@ namespace Alloc::OSAllocator { class OSAllocator_64Bit final : public Alloc::HostAllocator { public: + void *operator new(size_t size) { + return ::malloc(size); + } + + void operator delete(void *ptr) { + return ::free(ptr); + } + OSAllocator_64Bit(); virtual ~OSAllocator_64Bit(); void *AllocateSlab(size_t Size) override { return nullptr; } @@ -142,7 +151,9 @@ namespace Alloc::OSAllocator { [[maybe_unused]] auto Res = mprotect(reinterpret_cast(ReservedRegion->Base), SizePlusManagedData, PROT_READ | PROT_WRITE); - LOGMAN_THROW_AA_FMT(Res == 0, "Couldn't mprotect region: {} '{}' Likely occurs when running out of memory or Maximum VMAs", errno, strerror(errno)); + if (Res == -1) { + LOGMAN_MSG_A_FMT("Couldn't mprotect region: {} '{}' Likely occurs when running out of memory or Maximum VMAs", errno, strerror(errno)); + } LiveVMARegion *LiveRange = new (reinterpret_cast(ReservedRegion->Base)) LiveVMARegion(); @@ -572,7 +583,7 @@ OSAllocator_64Bit::~OSAllocator_64Bit() { } } -std::unique_ptr Create64BitAllocator() { - return std::make_unique(); +fextl::unique_ptr Create64BitAllocator() { + return fextl::make_unique(); } } diff --git a/External/FEXCore/Source/Utils/Allocator/HostAllocator.h b/External/FEXCore/Source/Utils/Allocator/HostAllocator.h index 5e86f441c..83ebcd033 100644 --- a/External/FEXCore/Source/Utils/Allocator/HostAllocator.h +++ b/External/FEXCore/Source/Utils/Allocator/HostAllocator.h @@ -1,8 +1,9 @@ #pragma once +#include +#include #include #include -#include #include namespace Alloc { @@ -35,5 +36,5 @@ namespace Alloc { } namespace Alloc::OSAllocator { -std::unique_ptr Create64BitAllocator(); +fextl::unique_ptr Create64BitAllocator(); } diff --git a/External/FEXCore/Source/Utils/Threads.cpp b/External/FEXCore/Source/Utils/Threads.cpp index 9eb2223cc..0e9469421 100644 --- a/External/FEXCore/Source/Utils/Threads.cpp +++ b/External/FEXCore/Source/Utils/Threads.cpp @@ -1,12 +1,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -167,10 +167,10 @@ namespace FEXCore::Threads { return Result; } - std::unique_ptr CreateThread_PThread( + fextl::unique_ptr CreateThread_PThread( ThreadFunc Func, void* Arg) { - return std::make_unique(Func, Arg); + return fextl::make_unique(Func, Arg); } void CleanupAfterFork_PThread() { @@ -208,7 +208,7 @@ namespace FEXCore::Threads { .CleanupAfterFork = CleanupAfterFork_PThread, }; - std::unique_ptr FEXCore::Threads::Thread::Create( + fextl::unique_ptr FEXCore::Threads::Thread::Create( ThreadFunc Func, void* Arg) { return Ptrs.CreateThread(Func, Arg); diff --git a/External/FEXCore/include/FEXCore/Config/Config.h b/External/FEXCore/include/FEXCore/Config/Config.h index 60aa212e4..da665ece5 100644 --- a/External/FEXCore/include/FEXCore/Config/Config.h +++ b/External/FEXCore/include/FEXCore/Config/Config.h @@ -3,11 +3,11 @@ #include #include #include +#include #include #include #include -#include #include #include @@ -170,7 +170,7 @@ namespace Type { FEX_DEFAULT_VISIBILITY fextl::string FindContainer(); FEX_DEFAULT_VISIBILITY fextl::string FindContainerPrefix(); - FEX_DEFAULT_VISIBILITY void AddLayer(std::unique_ptr _Layer); + FEX_DEFAULT_VISIBILITY void AddLayer(fextl::unique_ptr _Layer); FEX_DEFAULT_VISIBILITY bool Exists(ConfigOption Option); FEX_DEFAULT_VISIBILITY std::optional All(ConfigOption Option); @@ -255,7 +255,7 @@ namespace Type { * * @return unique_ptr for that layer */ - FEX_DEFAULT_VISIBILITY std::unique_ptr CreateGlobalMainLayer(); + FEX_DEFAULT_VISIBILITY fextl::unique_ptr CreateGlobalMainLayer(); /** * @brief Loads the main application config @@ -265,7 +265,7 @@ namespace Type { * * @return unique_ptr for that layer */ - FEX_DEFAULT_VISIBILITY std::unique_ptr CreateMainLayer(fextl::string const *File = nullptr); + FEX_DEFAULT_VISIBILITY fextl::unique_ptr CreateMainLayer(fextl::string const *File = nullptr); /** * @brief Create an application configuration loader @@ -275,7 +275,7 @@ namespace Type { * * @return unique_ptr for that layer */ - FEX_DEFAULT_VISIBILITY std::unique_ptr CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type); + FEX_DEFAULT_VISIBILITY fextl::unique_ptr CreateAppLayer(const fextl::string& Filename, FEXCore::Config::LayerType Type); /** * @brief iCreate an environment configuration loader @@ -284,6 +284,6 @@ namespace Type { * * @return unique_ptr for that layer */ - FEX_DEFAULT_VISIBILITY std::unique_ptr CreateEnvironmentLayer(char *const _envp[]); + FEX_DEFAULT_VISIBILITY fextl::unique_ptr CreateEnvironmentLayer(char *const _envp[]); } diff --git a/External/FEXCore/include/FEXCore/Core/Context.h b/External/FEXCore/include/FEXCore/Core/Context.h index 93bbad21c..6ebc8dace 100644 --- a/External/FEXCore/include/FEXCore/Core/Context.h +++ b/External/FEXCore/include/FEXCore/Core/Context.h @@ -6,13 +6,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include @@ -75,7 +75,7 @@ namespace FEXCore::Context { void *VDSO_kernel_rt_sigreturn; }; - using CustomCPUFactoryType = std::function (FEXCore::Context::Context*, FEXCore::Core::InternalThreadState *Thread)>; + using CustomCPUFactoryType = std::function (FEXCore::Context::Context*, FEXCore::Core::InternalThreadState *Thread)>; using ExitHandler = std::function; diff --git a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h index f5e8cb556..41d30e87c 100644 --- a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h +++ b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h @@ -7,11 +7,12 @@ #include #include #include +#include +#include #include -#include - #include +#include namespace FEXCore { class LookupCache; @@ -62,6 +63,14 @@ namespace FEXCore::Core { fextl::vector Subblocks; fextl::vector GuestOpcodes; fextl::vector *Relocations; + + void *operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void operator delete(void *ptr) { + return FEXCore::Allocator::free(ptr); + } }; enum class SignalEvent { @@ -75,9 +84,9 @@ namespace FEXCore::Core { struct LocalIREntry { uint64_t StartAddr; uint64_t Length; - std::unique_ptr IR; + fextl::unique_ptr IR; FEXCore::IR::RegisterAllocationData::UniquePtr RAData; - std::unique_ptr DebugData; + fextl::unique_ptr DebugData; }; struct InternalThreadState { @@ -93,20 +102,20 @@ namespace FEXCore::Core { FEXCore::Context::Context *CTX; std::atomic SignalReason{SignalEvent::Nothing}; - std::unique_ptr ExecutionThread; + fextl::unique_ptr ExecutionThread; bool StartPaused {false}; InterruptableConditionVariable StartRunning; Event ThreadWaiting; - std::unique_ptr OpDispatcher; + fextl::unique_ptr OpDispatcher; - std::unique_ptr CPUBackend; - std::unique_ptr LookupCache; + fextl::unique_ptr CPUBackend; + fextl::unique_ptr LookupCache; tsl::robin_map DebugStore; - std::unique_ptr FrontendDecoder; - std::unique_ptr PassManager; + fextl::unique_ptr FrontendDecoder; + fextl::unique_ptr PassManager; FEXCore::HLE::ThreadManagement ThreadManager; RuntimeStats Stats{}; @@ -118,6 +127,14 @@ namespace FEXCore::Core { std::shared_mutex ObjectCacheRefCounter{}; bool DestroyedByParent{false}; // Should the parent destroy this thread, or it destory itself + void *operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void operator delete(void *ptr) { + return FEXCore::Allocator::free(ptr); + } + alignas(16) FEXCore::Core::CpuStateFrame BaseFrameState{}; }; diff --git a/External/FEXCore/include/FEXCore/HLE/SourcecodeResolver.h b/External/FEXCore/include/FEXCore/HLE/SourcecodeResolver.h index 89689d03c..f416501ca 100644 --- a/External/FEXCore/include/FEXCore/HLE/SourcecodeResolver.h +++ b/External/FEXCore/include/FEXCore/HLE/SourcecodeResolver.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include @@ -91,6 +92,6 @@ private: class SourcecodeResolver { public: - virtual std::unique_ptr GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) = 0; + virtual fextl::unique_ptr GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) = 0; }; } diff --git a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h index befe0d263..25241f80a 100644 --- a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h +++ b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h @@ -170,6 +170,14 @@ public: } } + void *operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void operator delete(void *ptr) { + return FEXCore::Allocator::free(ptr); + } + void Serialize(std::ostream& stream) const { void *nul = nullptr; //void *IRDataInternal; @@ -183,7 +191,7 @@ public: //uint64_t Flags; uint64_t WrittenFlags = FLAG_Shared; //on disk format always has the Shared flag stream.write((const char*)&WrittenFlags, sizeof(WrittenFlags)); - + // inline data stream.write((const char*)GetData(), DataSize); stream.write((const char*)GetListData(), ListSize); @@ -202,7 +210,7 @@ public: //uint64_t Flags; uint64_t WrittenFlags = FLAG_Shared; //on disk format always has the Shared flag memcpy(ptr, &WrittenFlags, sizeof(WrittenFlags)); ptr += sizeof(WrittenFlags); - + // inline data memcpy(ptr, (const void*)GetData(), DataSize); ptr += DataSize; memcpy(ptr, (const void*)GetListData(), ListSize); ptr += ListSize; diff --git a/External/FEXCore/include/FEXCore/Utils/BucketList.h b/External/FEXCore/include/FEXCore/Utils/BucketList.h index 656d8ad82..5bdf20f36 100644 --- a/External/FEXCore/include/FEXCore/Utils/BucketList.h +++ b/External/FEXCore/include/FEXCore/Utils/BucketList.h @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include namespace FEXCore { @@ -17,7 +17,7 @@ namespace FEXCore { static constexpr size_t Size = _Size; T Items[Size]; - std::unique_ptr> Next; + fextl::unique_ptr> Next; void Clear() { Items[0] = T{}; @@ -96,7 +96,7 @@ namespace FEXCore { if (i < (Size-1)) { that->Items[i+1] = T{}; } else { - that->Next = std::make_unique>(); + that->Next = fextl::make_unique>(); } } void Erase(T Val) { diff --git a/External/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h b/External/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h index 72fc648ae..9e8f6c8d7 100644 --- a/External/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h +++ b/External/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h @@ -68,6 +68,14 @@ namespace FEXCore::Utils { size_t Size; std::atomic> LastUsed; BufferOwnedFlag *CurrentClientOwnedFlag{}; + + void *operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void operator delete(void *ptr) { + return FEXCore::Allocator::free(ptr); + } }; // Ensure that the atomic objects of MemoryBuffer are lock free static_assert(decltype(MemoryBuffer::LastUsed){}.is_always_lock_free, "Oops, needs to be lock free"); diff --git a/External/FEXCore/include/FEXCore/Utils/Threads.h b/External/FEXCore/include/FEXCore/Utils/Threads.h index cfe082953..9adfc51b2 100644 --- a/External/FEXCore/include/FEXCore/Utils/Threads.h +++ b/External/FEXCore/include/FEXCore/Utils/Threads.h @@ -1,12 +1,13 @@ #pragma once +#include + #include -#include namespace FEXCore::Threads { using ThreadFunc = void*(*)(void* user_ptr); class Thread; - using CreateThreadFunc = std::function(ThreadFunc Func, void* Arg)>; + using CreateThreadFunc = std::function(ThreadFunc Func, void* Arg)>; using CleanupAfterForkFunc = std::function; struct Pointers { @@ -27,7 +28,7 @@ namespace FEXCore::Threads { * @name Calls provided API functions * @{ */ - static std::unique_ptr Create( + static fextl::unique_ptr Create( ThreadFunc Func, void* Arg); diff --git a/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h b/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h index 4540ad697..87e23b7b8 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h +++ b/FEXHeaderUtils/FEXHeaderUtils/SymlinkChecks.h @@ -1,13 +1,14 @@ #pragma once +#include + #include -#include #include #include #include namespace FHU::Symlinks { // Checks to see if a filepath is a symlink. -inline bool IsSymlink(const std::string &Filename) { +inline bool IsSymlink(const fextl::string &Filename) { struct stat Buffer{}; int Result = lstat(Filename.c_str(), &Buffer); return Result == 0 && S_ISLNK(Buffer.st_mode); @@ -17,7 +18,7 @@ inline bool IsSymlink(const std::string &Filename) { // Doesn't handle recursive symlinks. // Doesn't append null terminator character. // Returns a string_view of the resolved path, or an empty view on error. -inline std::string_view ResolveSymlink(const std::string &Filename, std::span ResultBuffer) { +inline std::string_view ResolveSymlink(const fextl::string &Filename, std::span ResultBuffer) { ssize_t Result = readlink(Filename.c_str(), ResultBuffer.data(), ResultBuffer.size()); if (Result == -1) { return {}; diff --git a/Source/Common/Config.cpp b/Source/Common/Config.cpp index 7653f337f..9e6f43579 100644 --- a/Source/Common/Config.cpp +++ b/Source/Common/Config.cpp @@ -122,7 +122,7 @@ namespace FEX::Config { FEX::ArgLoader::LoadWithoutArguments(argc, argv); } else { - FEXCore::Config::AddLayer(std::make_unique(argc, argv)); + FEXCore::Config::AddLayer(fextl::make_unique(argc, argv)); } FEXCore::Config::AddLayer(FEXCore::Config::CreateEnvironmentLayer(envp)); diff --git a/Source/Tests/FEXLoader.cpp b/Source/Tests/FEXLoader.cpp index 44ac576ed..4345eacbb 100644 --- a/Source/Tests/FEXLoader.cpp +++ b/Source/Tests/FEXLoader.cpp @@ -357,7 +357,7 @@ int main(int argc, char **argv, char **const envp) { } FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode() ? "1" : "0"); - std::unique_ptr Allocator; + fextl::unique_ptr Allocator; fextl::vector Base48Bit; if (Loader.Is64BitMode()) { diff --git a/Source/Tests/IRLoader.cpp b/Source/Tests/IRLoader.cpp index 6baada3de..16c8c620c 100644 --- a/Source/Tests/IRLoader.cpp +++ b/Source/Tests/IRLoader.cpp @@ -172,7 +172,7 @@ int main(int argc, char **argv, char **const envp) LogMan::Msg::InstallHandler(MsgHandler); FEXCore::Config::Initialize(); - FEXCore::Config::AddLayer(std::make_unique(argc, argv)); + FEXCore::Config::AddLayer(fextl::make_unique(argc, argv)); FEXCore::Config::AddLayer(FEXCore::Config::CreateEnvironmentLayer(envp)); FEXCore::Config::Load(); // Ensure the IRLoader runs in 64-bit mode. diff --git a/Source/Tests/LinuxSyscalls/LinuxAllocator.cpp b/Source/Tests/LinuxSyscalls/LinuxAllocator.cpp index f0305a826..df05b1a42 100644 --- a/Source/Tests/LinuxSyscalls/LinuxAllocator.cpp +++ b/Source/Tests/LinuxSyscalls/LinuxAllocator.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,7 @@ public: FindPageRangePtr = &MemAllocator32Bit::FindPageRange; } } + void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) override; int Munmap(void *addr, size_t length) override; void *Mremap(void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) override; @@ -603,12 +605,12 @@ public: } }; -std::unique_ptr Create32BitAllocator() { - return std::make_unique(); +fextl::unique_ptr Create32BitAllocator() { + return fextl::make_unique(); } -std::unique_ptr CreatePassthroughAllocator() { - return std::make_unique(); +fextl::unique_ptr CreatePassthroughAllocator() { + return fextl::make_unique(); } } diff --git a/Source/Tests/LinuxSyscalls/LinuxAllocator.h b/Source/Tests/LinuxSyscalls/LinuxAllocator.h index 62e546db7..dd47aecf3 100644 --- a/Source/Tests/LinuxSyscalls/LinuxAllocator.h +++ b/Source/Tests/LinuxSyscalls/LinuxAllocator.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -16,6 +18,6 @@ namespace FEX::HLE { virtual uint64_t Shmdt(const void* shmaddr) = 0; }; - std::unique_ptr Create32BitAllocator(); - std::unique_ptr CreatePassthroughAllocator(); + fextl::unique_ptr Create32BitAllocator(); + fextl::unique_ptr CreatePassthroughAllocator(); } diff --git a/Source/Tests/LinuxSyscalls/SignalDelegator.h b/Source/Tests/LinuxSyscalls/SignalDelegator.h index 6d5d4197c..8c20b2dcc 100644 --- a/Source/Tests/LinuxSyscalls/SignalDelegator.h +++ b/Source/Tests/LinuxSyscalls/SignalDelegator.h @@ -25,6 +25,14 @@ namespace Core { namespace FEX::HLE { class SignalDelegator final : public FEXCore::SignalDelegator { public: + void *operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void operator delete(void *ptr) { + return FEXCore::Allocator::free(ptr); + } + // Returns true if the host handled the signal // Arguments are the same as sigaction handler SignalDelegator(); diff --git a/Source/Tests/LinuxSyscalls/Syscalls.cpp b/Source/Tests/LinuxSyscalls/Syscalls.cpp index 7b0bf5934..c1b10b870 100644 --- a/Source/Tests/LinuxSyscalls/Syscalls.cpp +++ b/Source/Tests/LinuxSyscalls/Syscalls.cpp @@ -867,7 +867,7 @@ static bool isHEX(char c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); } -std::unique_ptr SyscallHandler::GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) { +fextl::unique_ptr SyscallHandler::GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) { ELFParser GuestELF; @@ -929,7 +929,7 @@ std::unique_ptr SyscallHandler::GenerateMap(const s goto DoGenerate; } - auto rv = std::make_unique(); + auto rv = fextl::make_unique(); { auto len = rv->SourceFile.size(); @@ -1006,7 +1006,7 @@ std::unique_ptr SyscallHandler::GenerateMap(const s uintptr_t CurrentOffset{}; int LastOffsetLine; - auto rv = std::make_unique(); + auto rv = fextl::make_unique(); rv->SourceFile = GuestSourceFile; diff --git a/Source/Tests/LinuxSyscalls/Syscalls.h b/Source/Tests/LinuxSyscalls/Syscalls.h index 0588ec32d..3b2181891 100644 --- a/Source/Tests/LinuxSyscalls/Syscalls.h +++ b/Source/Tests/LinuxSyscalls/Syscalls.h @@ -16,6 +16,7 @@ $end_info$ #include #include #include +#include #include #include @@ -94,6 +95,14 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env class SyscallHandler : public FEXCore::HLE::SyscallHandler, FEXCore::HLE::SourcecodeResolver { public: + void *operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void operator delete(void *ptr) { + return FEXCore::Allocator::free(ptr); + } + virtual ~SyscallHandler(); // In the case that the syscall doesn't hit the optimized path then we still need to go here @@ -252,9 +261,9 @@ private: void Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret); #endif - std::unique_ptr Alloc32Handler{}; + fextl::unique_ptr Alloc32Handler{}; - std::unique_ptr GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) override; + fextl::unique_ptr GenerateMap(const std::string_view& GuestBinaryFile, const std::string_view& GuestBinaryFileId) override; ///// VMA (Virtual Memory Area) tracking ///// diff --git a/Source/Tests/LinuxSyscalls/x32/Syscalls.cpp b/Source/Tests/LinuxSyscalls/x32/Syscalls.cpp index b8c561b9f..eb7cf367e 100644 --- a/Source/Tests/LinuxSyscalls/x32/Syscalls.cpp +++ b/Source/Tests/LinuxSyscalls/x32/Syscalls.cpp @@ -11,6 +11,7 @@ $end_info$ #include #include +#include #include #include @@ -39,7 +40,7 @@ namespace FEX::HLE::x32 { void RegisterTime(FEX::HLE::SyscallHandler *Handler); void RegisterTimer(FEX::HLE::SyscallHandler *Handler); - x32SyscallHandler::x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, std::unique_ptr Allocator) + x32SyscallHandler::x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr Allocator) : SyscallHandler{ctx, _SignalDelegation}, AllocHandler{std::move(Allocator)} { OSABI = FEXCore::HLE::SyscallOSABI::OS_LINUX32; RegisterSyscallHandlers(); @@ -110,8 +111,8 @@ namespace FEX::HLE::x32 { #endif } - std::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, std::unique_ptr Allocator) { - return std::make_unique(ctx, _SignalDelegation, std::move(Allocator)); + fextl::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr Allocator) { + return fextl::make_unique(ctx, _SignalDelegation, std::move(Allocator)); } } diff --git a/Source/Tests/LinuxSyscalls/x32/Syscalls.h b/Source/Tests/LinuxSyscalls/x32/Syscalls.h index 808904734..e501807b9 100644 --- a/Source/Tests/LinuxSyscalls/x32/Syscalls.h +++ b/Source/Tests/LinuxSyscalls/x32/Syscalls.h @@ -6,6 +6,7 @@ $end_info$ #pragma once +#include #include #include "Tests/LinuxSyscalls/Syscalls.h" @@ -33,7 +34,7 @@ namespace FEX::HLE::x32 { class x32SyscallHandler final : public FEX::HLE::SyscallHandler { public: - x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, std::unique_ptr Allocator); + x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr Allocator); FEX::HLE::MemAllocator *GetAllocator() { return AllocHandler.get(); } void *GuestMmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) override; @@ -69,12 +70,12 @@ public: private: void RegisterSyscallHandlers(); - std::unique_ptr AllocHandler{}; + fextl::unique_ptr AllocHandler{}; }; -std::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, +fextl::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, - std::unique_ptr Allocator); + fextl::unique_ptr Allocator); ////// // REGISTER_SYSCALL_IMPL implementation // Given a syscall name + a lambda, and it will generate an strace string, extract number of arguments diff --git a/Source/Tests/LinuxSyscalls/x64/Syscalls.cpp b/Source/Tests/LinuxSyscalls/x64/Syscalls.cpp index 95d9fcdb5..a1cebad68 100644 --- a/Source/Tests/LinuxSyscalls/x64/Syscalls.cpp +++ b/Source/Tests/LinuxSyscalls/x64/Syscalls.cpp @@ -113,7 +113,7 @@ namespace FEX::HLE::x64 { #endif } - std::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation) { - return std::make_unique(ctx, _SignalDelegation); + fextl::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation) { + return fextl::make_unique(ctx, _SignalDelegation); } } diff --git a/Source/Tests/LinuxSyscalls/x64/Syscalls.h b/Source/Tests/LinuxSyscalls/x64/Syscalls.h index 0bf865ed7..4ac7d5fb0 100644 --- a/Source/Tests/LinuxSyscalls/x64/Syscalls.h +++ b/Source/Tests/LinuxSyscalls/x64/Syscalls.h @@ -11,6 +11,7 @@ $end_info$ #include #include +#include #include #include @@ -70,7 +71,7 @@ class x64SyscallHandler final : public FEX::HLE::SyscallHandler { void RegisterSyscallHandlers(); }; -std::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation); +fextl::unique_ptr CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation); ////// // REGISTER_SYSCALL_IMPL implementation diff --git a/Source/Tests/TestHarnessRunner.cpp b/Source/Tests/TestHarnessRunner.cpp index 005b29b51..b3f3ad586 100644 --- a/Source/Tests/TestHarnessRunner.cpp +++ b/Source/Tests/TestHarnessRunner.cpp @@ -118,7 +118,7 @@ int main(int argc, char **argv, char **const envp) { LogMan::Throw::InstallHandler(AssertHandler); LogMan::Msg::InstallHandler(MsgHandler); FEXCore::Config::Initialize(); - FEXCore::Config::AddLayer(std::make_unique(argc, argv)); + FEXCore::Config::AddLayer(fextl::make_unique(argc, argv)); FEXCore::Config::AddLayer(FEXCore::Config::CreateEnvironmentLayer(envp)); FEXCore::Config::Load(); @@ -132,14 +132,14 @@ int main(int argc, char **argv, char **const envp) { FEX::HarnessHelper::HarnessCodeLoader Loader{Args[0], Args[1].c_str()}; // Adds in environment options from the test harness config - FEXCore::Config::AddLayer(std::make_unique(Loader.GetEnvironmentOptions())); + FEXCore::Config::AddLayer(fextl::make_unique(Loader.GetEnvironmentOptions())); FEXCore::Config::ReloadMetaLayer(); FEXCore::Config::Set(FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode() ? "1" : "0"); FEX_CONFIG_OPT(Core, CORE); - std::unique_ptr Allocator; + fextl::unique_ptr Allocator; if (!Loader.Is64BitMode()) { // Setup our userspace allocator diff --git a/Source/Tools/Opt.cpp b/Source/Tools/Opt.cpp index ffa41828e..1bff62c8f 100644 --- a/Source/Tools/Opt.cpp +++ b/Source/Tools/Opt.cpp @@ -13,7 +13,7 @@ $end_info$ int main(int argc, char **argv, char **const envp) { FEXCore::Config::Initialize(); FEXCore::Config::AddLayer(FEXCore::Config::CreateMainLayer()); - FEXCore::Config::AddLayer(std::make_unique(argc, argv)); + FEXCore::Config::AddLayer(fextl::make_unique(argc, argv)); FEXCore::Config::AddLayer(FEXCore::Config::CreateEnvironmentLayer(envp)); FEXCore::Config::Load(); From c77c2faaeab0af08f57a569bae7558a22b561e18 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 20:20:45 -0700 Subject: [PATCH 11/41] FEXLoader: Add glibc hook faulting setup --- Source/Tests/FEXLoader.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Tests/FEXLoader.cpp b/Source/Tests/FEXLoader.cpp index 4345eacbb..d2921f12a 100644 --- a/Source/Tests/FEXLoader.cpp +++ b/Source/Tests/FEXLoader.cpp @@ -199,6 +199,7 @@ bool IsInterpreterInstalled() { } int main(int argc, char **argv, char **const envp) { + FEXCore::Allocator::SetupFaultEvaluate(); const bool IsInterpreter = RanAsInterpreter(argv[0]); ExecutedWithFD = getauxval(AT_EXECFD) != 0; @@ -217,6 +218,7 @@ int main(int argc, char **argv, char **const envp) { if (Program.ProgramPath.empty() && !FEXFD) { // Early exit if we weren't passed an argument + FEXCore::Allocator::ClearFaultEvaluate(); return 0; } @@ -241,6 +243,7 @@ int main(int argc, char **argv, char **const envp) { // Ensure FEXServer is setup before config options try to pull CONFIG_ROOTFS if (!FEXServerClient::SetupClient(argv[0])) { LogMan::Msg::EFmt("FEXServerClient: Failure to setup client"); + FEXCore::Allocator::ClearFaultEvaluate(); return -1; } @@ -335,6 +338,7 @@ int main(int argc, char **argv, char **const envp) { fmt::print(stderr, "Use FEXRootFSFetcher to download a RootFS\n"); } #endif + FEXCore::Allocator::ClearFaultEvaluate(); return -ENOEXEC; } @@ -538,6 +542,8 @@ int main(int argc, char **argv, char **const envp) { // Allocator is now original system allocator FEXCore::Telemetry::Shutdown(Program.ProgramName); FEXCore::Profiler::Shutdown(); + FEXCore::Allocator::ClearFaultEvaluate(); + if (ShutdownReason == FEXCore::Context::ExitReason::EXIT_SHUTDOWN) { return ProgramStatus; } From 170c9ee9e46c5f59ff73c46cabcaf330cae8a460 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 20:21:29 -0700 Subject: [PATCH 12/41] LookupCache: Switch to fextl --- External/FEXCore/Source/Interface/Core/LookupCache.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/LookupCache.h b/External/FEXCore/Source/Interface/Core/LookupCache.h index 3a8e4ad13..f5054ddea 100644 --- a/External/FEXCore/Source/Interface/Core/LookupCache.h +++ b/External/FEXCore/Source/Interface/Core/LookupCache.h @@ -2,6 +2,7 @@ #include "Interface/Context/Context.h" #include #include +#include #include #include @@ -10,13 +11,11 @@ #include #include #include -#include namespace FEXCore { class LookupCache { public: - struct LookupCacheEntry { uintptr_t HostCode; uintptr_t GuestCode; @@ -248,7 +247,7 @@ private: std::pmr::polymorphic_allocator BlockLinks_pma {&BlockLinks_mbr}; BlockLinksMapType *BlockLinks; - tsl::robin_map BlockList; + fextl::robin_map BlockList; size_t TotalCacheSize; From b2ec28503d073a44a4ee62a2679f041801e97f16 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 17 Mar 2023 20:35:11 -0700 Subject: [PATCH 13/41] LookupCache: Move over to fextl::pmr --- External/FEXCore/Source/Interface/Core/LookupCache.cpp | 8 +++++--- External/FEXCore/Source/Interface/Core/LookupCache.h | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/LookupCache.cpp b/External/FEXCore/Source/Interface/Core/LookupCache.cpp index 16b32d65b..451e0780a 100644 --- a/External/FEXCore/Source/Interface/Core/LookupCache.cpp +++ b/External/FEXCore/Source/Interface/Core/LookupCache.cpp @@ -18,8 +18,10 @@ LookupCache::LookupCache(FEXCore::Context::ContextImpl *CTX) : ctx {CTX} { TotalCacheSize = ctx->Config.VirtualMemSize / 4096 * 8 + CODE_SIZE + L1_SIZE; + BlockLinks_mbr = fextl::make_unique(fextl::pmr::get_default_resource()); + BlockLinks_pma = fextl::make_unique>(BlockLinks_mbr.get()); // Setup our PMR map. - BlockLinks = BlockLinks_pma.new_object(); + BlockLinks = BlockLinks_pma->new_object(); // Block cache ends up looking like this // PageMemoryMap[VirtualMemoryRegion >> 12] @@ -72,9 +74,9 @@ void LookupCache::ClearCache() { // Clear L1 and L2 by clearing the full cache. madvise(reinterpret_cast(PagePointer), TotalCacheSize, MADV_DONTNEED); // Clear the BlockLinks allocator which frees the BlockLinks map implicitly. - BlockLinks_mbr.release(); + BlockLinks_mbr->release(); // Allocate a new pointer from the BlockLinks pma again. - BlockLinks = BlockLinks_pma.new_object(); + BlockLinks = BlockLinks_pma->new_object(); // All code is gone, clear the block list BlockList.clear(); } diff --git a/External/FEXCore/Source/Interface/Core/LookupCache.h b/External/FEXCore/Source/Interface/Core/LookupCache.h index f5054ddea..07e1ea7c4 100644 --- a/External/FEXCore/Source/Interface/Core/LookupCache.h +++ b/External/FEXCore/Source/Interface/Core/LookupCache.h @@ -2,12 +2,13 @@ #include "Interface/Context/Context.h" #include #include +#include #include #include +#include #include #include -#include #include #include #include @@ -242,9 +243,9 @@ private: // walking each block member and destructing objects. // // This makes `BlockLinks` look like a raw pointer that could memory leak, but since it is backed by the MBR, it won't. - std::pmr::monotonic_buffer_resource BlockLinks_mbr; + fextl::unique_ptr BlockLinks_mbr; using BlockLinksMapType = std::pmr::map>; - std::pmr::polymorphic_allocator BlockLinks_pma {&BlockLinks_mbr}; + fextl::unique_ptr> BlockLinks_pma; BlockLinksMapType *BlockLinks; fextl::robin_map BlockList; From 4cc14cf0e9c1b6a7ea3d36aa3d0738422da0dbe0 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:26:40 -0700 Subject: [PATCH 14/41] FHU: Add more utilities --- FEXHeaderUtils/FEXHeaderUtils/Filesystem.h | 270 +++++++++++++++++++++ 1 file changed, 270 insertions(+) diff --git a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h index 0c1018d99..2832ce8d5 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h +++ b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h @@ -1,6 +1,14 @@ #pragma once +#include +#include +#include + +#include #include +#include #include +#include +#include #include namespace FHU::Filesystem { @@ -14,4 +22,266 @@ namespace FHU::Filesystem { inline bool Exists(const char *Path) { return access(Path, F_OK) == 0; } + + /** + * @brief Creates a directory at the provided path. + * + * @param Path The path to create a directory at. + * + * @return True if the directory was created or already exists. + */ + inline bool CreateDirectory(const fextl::string &Path) { + auto Result = ::mkdir(Path.c_str(), 0777); + if (Result == 0) { + return true; + } + + if (Result == -1 && errno == EEXIST) { + // If it exists, we need to check if it is a file or folder. + struct stat buf; + if (stat(Path.c_str(), &buf) == 0) { + // Check to see if the path is a file or folder. Following symlinks. + return S_ISDIR(buf.st_mode); + } + } + + // Couldn't create, or the path that existed wasn't a folder. + return false; + } + + /** + * @brief Creates a directory tree with the provided path. + * + * @param Path The path to create a tree at. + * + * @return True if the directory tree was created or already exists. + */ + inline bool CreateDirectories(const fextl::string &Path) { + // Try to create the directory initially. + if (CreateDirectory(Path)) { + return true; + } + + // Walk the path in reverse and create paths as we go. + fextl::string TmpPath {Path.substr(0, Path.rfind('/', Path.size() - 1))}; + if (!TmpPath.empty() && CreateDirectories(TmpPath)) { + return CreateDirectory(Path); + } + return false; + } + + /** + * @brief Extracts the filename component from a file path. + * + * @param Path The path to create a directory at. + * + * @return The filename component of the path. + */ + inline fextl::string GetFilename(const fextl::string &Path) { + auto LastSeparator = Path.rfind('/'); + if (LastSeparator == fextl::string::npos) { + // No separator. Likely relative `.`, `..`, ``, or empty string. + return Path; + } + + return Path.substr(LastSeparator + 1); + } + + inline fextl::string ParentPath(const fextl::string &Path) { + auto LastSeparator = Path.rfind('/'); + if (LastSeparator == fextl::string::npos) { + // No separator. Likely relative `.`, `..`, ``, or empty string. + return Path; + } + + return Path.substr(0, LastSeparator); + } + + inline bool IsRelative(const fextl::string &Path) { + return Path.starts_with('/'); + } + + enum class CopyOptions { + NONE, + SKIP_EXISTING, + OVERWRITE_EXISTING, + }; + + inline bool CopyFile(const fextl::string &From, const fextl::string &To, CopyOptions Options = CopyOptions::NONE) { + bool DestTested = false; + bool DestExists = false; + if (Options == CopyOptions::SKIP_EXISTING && Exists(To.c_str())) { + DestTested = true; + DestExists = Exists(To.c_str()); + if (DestExists) { + // If the destination file exists already and the skip existing flag is set then + // return true without error. + return true; + } + } + + if (!DestTested) { + DestTested = true; + DestExists = Exists(To.c_str()); + } + + if (Options == CopyOptions::OVERWRITE_EXISTING && DestExists) { + // If we are overwriting and the file exists then we want to use `sendfile` to overwrite + int SourceFD = open(From.c_str(), O_RDONLY | O_CLOEXEC); + if (SourceFD == -1) { + return false; + } + + int DestinationFD = open(To.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0200); + if (DestinationFD == -1) { + close(SourceFD); + return false; + } + + struct stat buf; + if (fstat(SourceFD, &buf) != 0) { + close(DestinationFD); + close(SourceFD); + return false; + } + + // Set the destination permissions to the original source permissions. + if (fchmod(DestinationFD, buf.st_mode) != 0) { + close(DestinationFD); + close(SourceFD); + return false; + } + bool Result = sendfile(DestinationFD, SourceFD, nullptr, buf.st_size) == buf.st_size; + close(DestinationFD); + close(SourceFD); + return Result; + } + + if (!DestExists) { + // If the destination doesn't exist then just use rename. + return rename(From.c_str(), To.c_str()) == 0; + } + + return false; + } + + inline fextl::string LexicallyNormal(const fextl::string &Path) { + const auto PathSize = Path.size(); + + // Early exit on empty paths. + if (PathSize == 0) { + return {}; + } + + // Count the number of separators up front + const auto SeparatorCount = std::count(Path.begin(), Path.end(), '/'); + + // Needs to be a list so iterators aren't invalidated while erasing. + // Maximum number of list regions will be the counted separators plus 2. + // Multiplied by two since it allocates * 2 the size (32-bytes per element) + // Use a small stack allocator to be more optimal. + // Needs to be a list so iterators aren't invalidated while erasing. + size_t DataSize = sizeof(std::string_view) * (SeparatorCount + 2) * 2; + void *Data = alloca(DataSize); + fextl::pmr::fixed_size_monotonic_buffer_resource mbr(Data, DataSize); + std::pmr::polymorphic_allocator pa {&mbr}; + std::pmr::list Parts{pa}; + // Calculate the expected string size while parsing to reduce allocations. + size_t ExpectedStringSize{}; + + size_t CurrentOffset{}; + do { + auto FoundSeperator = Path.find('/', CurrentOffset); + if (FoundSeperator == Path.npos) { + FoundSeperator = PathSize; + } + + const auto Begin = Path.begin() + CurrentOffset; + const auto End = Path.begin() + FoundSeperator; + const auto Size = End - Begin; + ExpectedStringSize += Size; + + // If Size is zero then only insert if Parts is empty. + // Ensures that we don't remove an initial `/` by itself + if (Parts.empty() || Size != 0) { + Parts.emplace_back(std::string_view(Begin, End)); + } + + if (Size == 0) { + // If the view is empty, skip over the separator. + FoundSeperator += 1; + } + + CurrentOffset = FoundSeperator; + } while (CurrentOffset != PathSize); + + size_t CurrentIterDistance{}; + for (auto iter = Parts.begin(); iter != Parts.end();) { + if (*iter == ".") { + // Erase '.' directory parts if not at root. + if (CurrentIterDistance > 0) { + // Erasing this iterator, don't increase iter distances + iter = Parts.erase(iter); + --ExpectedStringSize; + continue; + } + } + + if (*iter == "..") { + auto Distance = std::distance(Parts.begin(), iter); + if (Distance > 0) { + // If not at root then remove both this iterator and the previous one. + // ONLY if the previous iterator is also not ".." + // + // If the previous iterator is '.' then /only/ erase the previous iterator. + auto PreviousIter = iter; + --PreviousIter; + + if (*PreviousIter == ".") { + // Erasing the previous iterator, iterator distance has subtracted by one + --CurrentIterDistance; + ExpectedStringSize -= PreviousIter->size(); + Parts.erase(PreviousIter); + } + else if (*PreviousIter != "..") { + // Erasing the previous iterator, iterator distance has subtracted by one + // Also erasing current iterator, which means iterator distance also doesn't increase by one. + --CurrentIterDistance; + ExpectedStringSize -= PreviousIter->size() + 2; + Parts.erase(PreviousIter); + iter = Parts.erase(iter); + continue; + } + } + } + + // Interator distance increased by one. + ++CurrentIterDistance; + ++iter; + } + + fextl::string OutputPath{}; + OutputPath.reserve(ExpectedStringSize + Parts.size()); + + auto iter = Parts.begin(); + for (size_t i = 0; i < Parts.size(); ++i, ++iter) { + auto &Part = *iter; + OutputPath += Part; + + const bool IsFinal = (i + 1) == Parts.size(); + // If the final element is ellipses then don't apply a separator. + // Otherwise if it is anything else, apply a separator. + const bool IsEllipses = Part == "." || Part == ".."; + + const bool NeedsSeparator = + !IsFinal || // Needs a separator if this isn't the final part. + (IsFinal && !IsEllipses); // Needs a separator if the final part doesn't end in `.` or `..` + + if (NeedsSeparator) { + OutputPath += '/'; + } + } + + return OutputPath; + } } From a3be4b77fa9254b4e6f3ce1f480747664117c2a5 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:28:27 -0700 Subject: [PATCH 15/41] Paths: Convert to FHU to remove glibc --- External/FEXCore/Source/Common/Paths.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/External/FEXCore/Source/Common/Paths.cpp b/External/FEXCore/Source/Common/Paths.cpp index 8722b1d14..fbb314680 100644 --- a/External/FEXCore/Source/Common/Paths.cpp +++ b/External/FEXCore/Source/Common/Paths.cpp @@ -3,12 +3,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include namespace FEXCore::Paths { @@ -71,11 +73,9 @@ namespace FEXCore::Paths { *CachePath += "/.fex-emu/"; *EntryCache = *CachePath + "/EntryCache/"; - std::error_code ec{}; - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; // Ensure the folder structure is created for our Data - if (!std::filesystem::exists(*EntryCache, ec) && - !std::filesystem::create_directories(*EntryCache, ec)) { + if (!FHU::Filesystem::Exists(EntryCache->c_str()) && + !FHU::Filesystem::CreateDirectories(*EntryCache)) { LogMan::Msg::DFmt("Couldn't create EntryCache directory: '{}'", *EntryCache); } } From 1f9458a3c3c61de68b886e1e089db2c9f5a3835c Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:28:56 -0700 Subject: [PATCH 16/41] Config: Convert to FHU to remove glibc --- .../Source/Interface/Config/Config.cpp | 61 ++++++++----------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/External/FEXCore/Source/Interface/Config/Config.cpp b/External/FEXCore/Source/Interface/Config/Config.cpp index cd55b2920..f240e60f9 100644 --- a/External/FEXCore/Source/Interface/Config/Config.cpp +++ b/External/FEXCore/Source/Interface/Config/Config.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -144,11 +146,8 @@ namespace JSON { } // Ensure the folder structure is created for our configuration - std::error_code ec{}; - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - - if (!std::filesystem::exists(ConfigDir, ec) && - !std::filesystem::create_directories(ConfigDir, ec)) { + if (!FHU::Filesystem::Exists(ConfigDir.c_str()) && + !FHU::Filesystem::CreateDirectories(ConfigDir)) { // Let's go local in this case return "./"; } @@ -178,12 +177,9 @@ namespace JSON { fextl::string GetApplicationConfig(const fextl::string &Filename, bool Global) { fextl::string ConfigFile = GetConfigDirectory(Global); - std::error_code ec{}; - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - if (!Global && - !std::filesystem::exists(ConfigFile, ec) && - !std::filesystem::create_directories(ConfigFile, ec)) { + !FHU::Filesystem::Exists(ConfigFile.c_str()) && + !FHU::Filesystem::CreateDirectories(ConfigFile)) { LogMan::Msg::DFmt("Couldn't create config directory: '{}'", ConfigFile); // Let's go local in this case return "./" + Filename + ".json"; @@ -193,8 +189,8 @@ namespace JSON { // Attempt to create the local folder if it doesn't exist if (!Global && - !std::filesystem::exists(ConfigFile, ec) && - !std::filesystem::create_directories(ConfigFile, ec)) { + !FHU::Filesystem::Exists(ConfigFile.c_str()) && + !FHU::Filesystem::CreateDirectories(ConfigFile)) { // Let's go local in this case return "./" + Filename + ".json"; } @@ -340,10 +336,8 @@ namespace JSON { } - std::filesystem::path Path{PathName}; - // Expand home if it exists - if (Path.is_relative()) { + if (FHU::Filesystem::IsRelative(PathName)) { fextl::string Home = getenv("HOME") ?: ""; // Home expansion only works if it is the first character // This matches bash behaviour @@ -352,16 +346,16 @@ namespace JSON { return PathName; } - { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - // Expand relative path to absolute - Path = std::filesystem::absolute(Path); + // Expand relative path to absolute + char ExistsTempPath[PATH_MAX]; + char *RealPath = realpath(PathName.c_str(), ExistsTempPath); + if (RealPath) { + PathName = RealPath; } // Only return if it exists - std::error_code ec{}; - if (std::filesystem::exists(Path, ec)) { - return fextl::string_from_path(Path); + if (FHU::Filesystem::Exists(PathName.c_str())) { + return PathName; } } else { @@ -377,9 +371,9 @@ namespace JSON { // HostThunks: $CMAKE_INSTALL_PREFIX/lib/fex-emu/HostThunks/ // GuestThunks: $CMAKE_INSTALL_PREFIX/share/fex-emu/GuestThunks/ if (!ContainerPrefix.empty() && !PathName.empty()) { - if (!std::filesystem::exists(PathName)) { + if (!FHU::Filesystem::Exists(PathName.c_str())) { auto ContainerPath = ContainerPrefix + PathName; - if (std::filesystem::exists(ContainerPath)) { + if (FHU::Filesystem::Exists(ContainerPath.c_str())) { return ContainerPath; } } @@ -389,11 +383,9 @@ namespace JSON { } fextl::string FindContainer() { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - // We only support pressure-vessel at the moment const static fextl::string ContainerManager = "/run/host/container-manager"; - if (std::filesystem::exists(ContainerManager)) { + if (FHU::Filesystem::Exists(ContainerManager.c_str())) { fextl::vector Manager{}; if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) { // Trim the whitespace, may contain a newline @@ -406,11 +398,9 @@ namespace JSON { } fextl::string FindContainerPrefix() { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - // We only support pressure-vessel at the moment const static fextl::string ContainerManager = "/run/host/container-manager"; - if (std::filesystem::exists(ContainerManager)) { + if (FHU::Filesystem::Exists(ContainerManager.c_str())) { fextl::vector Manager{}; if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) { // Trim the whitespace, may contain a newline @@ -471,7 +461,6 @@ namespace JSON { fextl::string ContainerPrefix { FindContainerPrefix() }; auto ExpandPathIfExists = [&ContainerPrefix](FEXCore::Config::ConfigOption Config, fextl::string PathName) { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; auto NewPath = ExpandPath(ContainerPrefix, PathName); if (!NewPath.empty()) { FEXCore::Config::EraseSet(Config, NewPath); @@ -718,7 +707,8 @@ namespace JSON { } void EnvLoader::Load() { - fextl::unordered_map EnvMap; + using EnvMapType = fextl::unordered_map; + EnvMapType EnvMap; for(const char *const *pvar=envp; pvar && *pvar; pvar++) { std::string_view Var(*pvar); @@ -732,11 +722,10 @@ namespace JSON { #define ENVLOADER #include - EnvMap[Key]=Value; + EnvMap[Key] = Value; } - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - std::function GetVar = [=](const std::string_view id) -> std::optional { + std::function GetVar = [](EnvMapType &EnvMap, const std::string_view id) -> std::optional { if (EnvMap.find(id) != EnvMap.end()) return EnvMap.at(id); @@ -753,7 +742,7 @@ namespace JSON { std::optional Value; for (auto &it : EnvConfigLookup) { - if ((Value = GetVar(it.first)).has_value()) { + if ((Value = GetVar(EnvMap, it.first)).has_value()) { Set(it.second, fextl::string(*Value)); } } From 1eac7e710568953de6c5918d612a224b580e6785 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:29:18 -0700 Subject: [PATCH 17/41] AOTIR: Convert to FHU to remove glibc --- .../FEXCore/Source/Interface/IR/AOTIR.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/External/FEXCore/Source/Interface/IR/AOTIR.cpp b/External/FEXCore/Source/Interface/IR/AOTIR.cpp index ceb7f0e7f..74e17f6f0 100644 --- a/External/FEXCore/Source/Interface/IR/AOTIR.cpp +++ b/External/FEXCore/Source/Interface/IR/AOTIR.cpp @@ -1,3 +1,4 @@ +#include "FEXHeaderUtils/Filesystem.h" #include "Interface/Context/Context.h" #include "Interface/IR/AOTIR.h" @@ -5,6 +6,7 @@ #include #include #include +#include #include #include @@ -371,20 +373,18 @@ namespace FEXCore::IR { } AOTIRCacheEntry *AOTIRCaptureCache::LoadAOTIRCacheEntry(const fextl::string &filename) { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - fextl::string base_filename = fextl::string_from_path(std::filesystem::path(filename).filename()); + fextl::string base_filename = FHU::Filesystem::GetFilename(filename); if (!base_filename.empty()) { auto filename_hash = XXH3_64bits(filename.c_str(), filename.size()); - auto fileid = base_filename + "-"; - fileid += std::to_string(filename_hash) + "-"; - - // append optimization flags to the fileid - fileid += (CTX->Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) ? "S" : "s"; - fileid += CTX->Config.TSOEnabled ? "T" : "t"; - fileid += CTX->Config.ABILocalFlags ? "L" : "l"; - fileid += CTX->Config.ABINoPF ? "p" : "P"; + auto fileid = fextl::fmt::format("{}-{}-{}{}{}{}", + base_filename, + filename_hash, + (CTX->Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) ? 'S' : 's', + CTX->Config.TSOEnabled ? 'T' : 't', + CTX->Config.ABILocalFlags ? 'L' : 'l', + CTX->Config.ABINoPF ? 'p' : 'P'); std::unique_lock lk(AOTIRCacheLock); From bbd0d26c16d22faa0fb4794b7a9ea651692158ad Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:29:36 -0700 Subject: [PATCH 18/41] Telemetry: Convert to FHU to remove glibc --- External/FEXCore/Source/Utils/Telemetry.cpp | 28 ++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/External/FEXCore/Source/Utils/Telemetry.cpp b/External/FEXCore/Source/Utils/Telemetry.cpp index 672b9823d..99cc65b6b 100644 --- a/External/FEXCore/Source/Utils/Telemetry.cpp +++ b/External/FEXCore/Source/Utils/Telemetry.cpp @@ -1,7 +1,9 @@ #include #include #include +#include #include +#include #include #include @@ -28,10 +30,8 @@ namespace FEXCore::Telemetry { DataDirectory += "Telemetry/"; // Ensure the folder structure is created for our configuration - std::error_code ec{}; - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - if (!std::filesystem::exists(DataDirectory, ec) && - !std::filesystem::create_directories(DataDirectory, ec)) { + if (!FHU::Filesystem::Exists(DataDirectory.c_str()) && + !FHU::Filesystem::CreateDirectories(DataDirectory)) { LogMan::Msg::IFmt("Couldn't create telemetry Folder"); } } @@ -40,24 +40,24 @@ namespace FEXCore::Telemetry { auto DataDirectory = Config::GetDataDirectory(); DataDirectory += "Telemetry/" + ApplicationName + ".telem"; - std::error_code ec{}; - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - if (std::filesystem::exists(DataDirectory, ec)) { + if (FHU::Filesystem::Exists(DataDirectory.c_str())) { // If the file exists, retain a single backup auto Backup = DataDirectory + ".1"; - std::filesystem::copy_file(DataDirectory, Backup, std::filesystem::copy_options::overwrite_existing, ec); + FHU::Filesystem::CopyFile(DataDirectory, Backup, FHU::Filesystem::CopyOptions::OVERWRITE_EXISTING); } - std::fstream fs(fextl::string_from_string(DataDirectory), std::ios_base::out | std::ios_base::trunc); - if (fs.is_open()) { + constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO; + int fd = open(DataDirectory.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, USER_PERMS); + + if (fd != -1) { for (size_t i = 0; i < TelemetryType::TYPE_LAST; ++i) { auto &Name = TelemetryNames.at(i); auto &Data = TelemetryValues.at(i); - fs << Name << ": " << *Data << std::endl; + auto Output = fextl::fmt::format("{}: {}\n", Name, *Data); + write(fd, Output.c_str(), Output.size()); } - - fs.flush(); - fs.close(); + fsync(fd); + close(fd); } } From 86f8ebf0ee4a1f60e993e27f960af63e9b20e1a1 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:30:01 -0700 Subject: [PATCH 19/41] FEX/Config: Convert to FHU to remove glibc --- Source/Common/Config.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Source/Common/Config.cpp b/Source/Common/Config.cpp index 9e6f43579..c1d238061 100644 --- a/Source/Common/Config.cpp +++ b/Source/Common/Config.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -44,8 +45,6 @@ namespace FEX::Config { } fextl::string RecoverGuestProgramFilename(fextl::string Program, bool ExecFDInterp, const std::string_view ProgramFDFromEnv) { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - // If executed with a FEX FD then the Program argument might be empty. // In this case we need to scan the FD node to recover the application binary that exists on disk. // Only do this if the Program argument is empty, since we would prefer the application's expectation @@ -60,7 +59,11 @@ namespace FEX::Config { // If the program name isn't resolved to an absolute path then glibc breaks inside it's `_dl_get_origin` function. // This is because we rewrite `/proc/self/exe` to the absolute program path calculated in here. if (!Program.starts_with('/')) { - Program = std::filesystem::canonical(std::move(Program)).string(); + char ExistsTempPath[PATH_MAX]; + char *RealPath = realpath(Program.c_str(), ExistsTempPath); + if (RealPath) { + Program = RealPath; + } } // If FEX was invoked through an FD path (either binfmt_misc or execveat) then we need to check the @@ -139,11 +142,10 @@ namespace FEX::Config { Args[0] = RecoverGuestProgramFilename(std::move(Args[0]), ExecFDInterp, ProgramFDFromEnv); fextl::string& Program = Args[0]; - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; bool Wine = false; - std::filesystem::path ProgramName; + fextl::string ProgramName; for (size_t CurrentProgramNameIndex = 0; CurrentProgramNameIndex < Args.size(); ++CurrentProgramNameIndex) { - auto CurrentProgramName = std::filesystem::path(Args[CurrentProgramNameIndex]).filename(); + auto CurrentProgramName = FHU::Filesystem::GetFilename(Args[CurrentProgramNameIndex]); if (CurrentProgramName == "wine-preloader" || CurrentProgramName == "wine64-preloader") { @@ -165,10 +167,10 @@ namespace FEX::Config { else { if (Wine == true) { // If this was path separated with '\' then we need to check that. - auto WinSeparator = CurrentProgramName.string().find_last_of('\\'); - if (WinSeparator != CurrentProgramName.string().npos) { + auto WinSeparator = CurrentProgramName.find_last_of('\\'); + if (WinSeparator != CurrentProgramName.npos) { // Used windows separators - CurrentProgramName = CurrentProgramName.string().substr(WinSeparator + 1); + CurrentProgramName = CurrentProgramName.substr(WinSeparator + 1); } } @@ -179,8 +181,8 @@ namespace FEX::Config { } } - FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(fextl::string_from_path(ProgramName), FEXCore::Config::LayerType::LAYER_GLOBAL_APP)); - FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(fextl::string_from_path(ProgramName), FEXCore::Config::LayerType::LAYER_LOCAL_APP)); + FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(ProgramName, FEXCore::Config::LayerType::LAYER_GLOBAL_APP)); + FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(ProgramName, FEXCore::Config::LayerType::LAYER_LOCAL_APP)); auto SteamID = getenv("SteamAppId"); if (SteamID) { @@ -191,8 +193,7 @@ namespace FEX::Config { FEXCore::Config::AddLayer(FEXCore::Config::CreateAppLayer(SteamAppName, FEXCore::Config::LayerType::LAYER_LOCAL_STEAM_APP)); } - // TODO: No need for conversion once Config uses fextl. - return ApplicationNames{std::move(Program), fextl::string_from_path(ProgramName)}; + return ApplicationNames{std::move(Program), std::move(ProgramName)}; } return {}; } From 1ec31c610c6a34046047836427baad8aabeb8f30 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:30:22 -0700 Subject: [PATCH 20/41] FEXServerClient: Convert to FHU to remove glibc --- Source/Common/FEXServerClient.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Common/FEXServerClient.cpp b/Source/Common/FEXServerClient.cpp index f9348338d..d77ea4db0 100644 --- a/Source/Common/FEXServerClient.cpp +++ b/Source/Common/FEXServerClient.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -211,11 +212,10 @@ namespace FEXServerClient { return -1; } - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - fextl::string FEXServerPath = fextl::string_from_path(std::filesystem::path(InterpreterPath).parent_path()) + "/FEXServer"; + fextl::string FEXServerPath = FHU::Filesystem::ParentPath(InterpreterPath) + "/FEXServer"; // Check if a local FEXServer next to FEXInterpreter exists // If it does then it takes priority over the installed one - if (!std::filesystem::exists(FEXServerPath)) { + if (!FHU::Filesystem::Exists(FEXServerPath.c_str())) { FEXServerPath = "FEXServer"; } From 9d04c4daee606a67cbc84dd450719c73507f1869 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:31:25 -0700 Subject: [PATCH 21/41] ELFCodeLoader: Convert to get_fdpath with temp to avoid glibc --- Source/Tests/ELFCodeLoader.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Tests/ELFCodeLoader.h b/Source/Tests/ELFCodeLoader.h index 5d239769d..aed9b960a 100644 --- a/Source/Tests/ELFCodeLoader.h +++ b/Source/Tests/ELFCodeLoader.h @@ -87,9 +87,10 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { LogMan::Msg::EFmt("MapFile: Some elf mapping failed, {}, fd: {}\n", errno, file.fd); return false; } else { - auto Filename = FEX::get_fdpath(file.fd); - if (Filename.has_value()) { - Sections.push_back({Base, (uintptr_t)rv, size, (off_t)off, Filename.value(), (prot & PROT_EXEC) != 0}); + char Tmp[PATH_MAX]; + auto PathLength = FEX::get_fdpath(file.fd, Tmp); + if (PathLength != -1) { + Sections.push_back({Base, (uintptr_t)rv, size, (off_t)off, fextl::string(Tmp, PathLength), (prot & PROT_EXEC) != 0}); } return true; From e8c1dfa03a9ac59d12d664f3b8898c59e3088b93 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:31:44 -0700 Subject: [PATCH 22/41] FEXLoader: Convert to FHU to avoid glibc --- Source/Tests/FEXLoader.cpp | 63 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/Source/Tests/FEXLoader.cpp b/Source/Tests/FEXLoader.cpp index d2921f12a..4d5029c82 100644 --- a/Source/Tests/FEXLoader.cpp +++ b/Source/Tests/FEXLoader.cpp @@ -28,6 +28,7 @@ $end_info$ #include #include #include +#include #include #include @@ -123,28 +124,31 @@ namespace FEXServerLogging { } void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fextl::vector *args) { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - // Open the file pointer to the filename and see if we need to find an interpreter - std::fstream File(fextl::string_from_string(*Filename), std::fstream::in | std::fstream::binary); - - if (!File.is_open()) { + // Open the Filename to determine if it is a shebang file. + int FD = open(Filename->c_str(), O_RDONLY | O_CLOEXEC); + if (FD == -1) { return; } - File.seekg(0, std::fstream::end); - const auto FileSize = File.tellg(); - File.seekg(0, std::fstream::beg); + std::array Header; + const auto ChunkSize = 257l; + const auto ReadSize = pread(FD, &Header.at(0), ChunkSize, 0); + + const auto Data = std::span(Header.data(), ReadSize); // Is the file large enough for shebang - if (FileSize <= 2) { + if (ReadSize <= 2) { + close(FD); return; } // Handle shebang files - if (File.get() == '#' && - File.get() == '!') { - fextl::string InterpreterLine; - std::getline(File, InterpreterLine); + if (Data[0] == '#' && + Data[1] == '!') { + fextl::string InterpreterLine { + Data.begin() + 2, // strip off "#!" prefix + std::find(Data.begin(), Data.end(), '\n') + }; fextl::vector ShebangArguments{}; // Shebang line can have a single argument @@ -169,18 +173,14 @@ void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fe // Insert all the arguments at the start args->insert(args->begin(), ShebangArguments.begin(), ShebangArguments.end()); - - // Done here - return; } + close(FD); } void RootFSRedirect(fextl::string *Filename, fextl::string const &RootFS) { auto RootFSLink = ELFCodeLoader::ResolveRootfsFile(*Filename, RootFS); - std::error_code ec{}; - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - if (std::filesystem::exists(RootFSLink, ec)) { + if (FHU::Filesystem::Exists(RootFSLink.c_str())) { *Filename = RootFSLink; } } @@ -297,17 +297,12 @@ int main(int argc, char **argv, char **const envp) { RootFSRedirect(&Program.ProgramPath, LDPath()); InterpreterHandler(&Program.ProgramPath, LDPath(), &Args); - std::error_code ec{}; - - { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - if (!ExecutedWithFD && !FEXFD && !std::filesystem::exists(Program.ProgramPath, ec)) { - // Early exit if the program passed in doesn't exist - // Will prevent a crash later - fmt::print(stderr, "{}: command not found\n", Program.ProgramPath); - FEXCore::Allocator::ClearFaultEvaluate(); - return -ENOEXEC; - } + if (!ExecutedWithFD && !FEXFD && !FHU::Filesystem::Exists(Program.ProgramPath.c_str())) { + // Early exit if the program passed in doesn't exist + // Will prevent a crash later + fmt::print(stderr, "{}: command not found\n", Program.ProgramPath); + FEXCore::Allocator::ClearFaultEvaluate(); + return -ENOEXEC; } uint32_t KernelVersion = FEX::HLE::SyscallHandler::CalculateHostKernelVersion(); @@ -354,8 +349,11 @@ int main(int argc, char **argv, char **const envp) { } else { { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_FILENAME, std::filesystem::canonical(Program.ProgramPath).string()); + char ExistsTempPath[PATH_MAX]; + char *RealPath = realpath(Program.ProgramPath.c_str(), ExistsTempPath); + if (RealPath) { + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_FILENAME, fextl::string(RealPath)); + } } FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_APP_CONFIG_NAME, Program.ProgramName); } @@ -503,6 +501,7 @@ int main(int argc, char **argv, char **const envp) { } if (AOTEnabled) { + std::error_code ec{}; std::filesystem::create_directories(std::filesystem::path(FEXCore::Config::GetDataDirectory()) / "aotir", ec); if (!ec) { CTX->WriteFilesWithCode([](const fextl::string& fileid, const fextl::string& filename) { From 4d35d550c1227365cae6219e83bbf75bae29d395 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:32:08 -0700 Subject: [PATCH 23/41] EmulatedFiles: Convert to FHU to avoid glibc --- Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp b/Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp index ed9a5b45c..788d3d241 100644 --- a/Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp +++ b/Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp @@ -17,6 +17,7 @@ $end_info$ #include #include #include +#include #include @@ -759,13 +760,12 @@ namespace FEX::EmulatedFile { char *RealPath = realpath(Path, ExistsTempPath); if (RealPath) { RealPathExists = true; - Creator = FDReadCreators.find(realpath(Path, Tmp)); + Creator = FDReadCreators.find(RealPath); } } if (!RealPathExists) { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - Creator = FDReadCreators.find(fextl::string_from_path(std::filesystem::path(Path).lexically_normal())); + Creator = FDReadCreators.find(FHU::Filesystem::LexicallyNormal(Path)); } if (Creator == FDReadCreators.end()) { From 114b626cff1171b93bf1e9e17a231648fa04b27e Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:32:40 -0700 Subject: [PATCH 24/41] FileManager: Convert to FHU to avoid glibc --- Source/Tests/LinuxSyscalls/FileManagement.cpp | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/Source/Tests/LinuxSyscalls/FileManagement.cpp b/Source/Tests/LinuxSyscalls/FileManagement.cpp index cecd48cbd..884cf70ea 100644 --- a/Source/Tests/LinuxSyscalls/FileManagement.cpp +++ b/Source/Tests/LinuxSyscalls/FileManagement.cpp @@ -19,6 +19,7 @@ $end_info$ #include #include #include +#include #include #include @@ -42,13 +43,13 @@ $end_info$ namespace JSON { struct JsonAllocator { jsonPool_t PoolObject; - std::unique_ptr> json_objects; + fextl::unique_ptr> json_objects; }; static_assert(offsetof(JsonAllocator, PoolObject) == 0, "This needs to be at offset zero"); json_t* PoolInit(jsonPool_t* Pool) { JsonAllocator* alloc = reinterpret_cast(Pool); - alloc->json_objects = std::make_unique>(); + alloc->json_objects = fextl::make_unique>(); return &*alloc->json_objects->emplace(alloc->json_objects->end()); } @@ -62,40 +63,31 @@ namespace FEX::HLE { struct open_how; static bool LoadFile(fextl::vector &Data, const fextl::string &Filename) { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - std::fstream File(fextl::string_from_string(Filename), std::ios::in); - - if (!File.is_open()) { + int fd = open(Filename.c_str(), O_RDONLY | O_CLOEXEC); + if (fd == -1) { return false; } - if (!File.seekg(0, std::fstream::end)) { - LogMan::Msg::DFmt("Couldn't load configuration file: Seek end"); + struct stat buf; + if (fstat(fd, &buf) != 0) { + LogMan::Msg::DFmt("Couldn't load configuration file: fstat"); + close(fd); return false; } - auto FileSize = File.tellg(); - if (File.fail()) { - LogMan::Msg::DFmt("Couldn't load configuration file: tellg"); - return false; - } - - if (!File.seekg(0, std::fstream::beg)) { - LogMan::Msg::DFmt("Couldn't load configuration file: Seek beginning"); - return false; - } + auto FileSize = buf.st_size; if (FileSize <= 0) { LogMan::Msg::DFmt("FileSize less than or equal to zero specified"); + close(fd); return false; } Data.resize(FileSize); - if (!File.read(Data.data(), FileSize)) { - // Probably means permissions aren't set. Just early exit - return false; - } - return true; + const auto ReadSize = pread(fd, Data.data(), FileSize, 0); + + close(fd); + return ReadSize == FileSize; } struct ThunkDBObject { @@ -217,8 +209,6 @@ static void LoadThunkDatabase(fextl::unordered_map FileManager::FileManager(FEXCore::Context::Context *ctx) : EmuFD {ctx} { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - auto ThunkConfigFile = ThunkConfig(); // We try to load ThunksDB from: @@ -289,7 +279,7 @@ FileManager::FileManager(FEXCore::Context::Context *ctx) } // Now that we loaded the thunks object, walk through and ensure dependencies are enabled as well - auto ThunkGuestPath = std::filesystem::path { Is64BitMode() ? ThunkGuestLibs() : ThunkGuestLibs32() }; + auto ThunkGuestPath = Is64BitMode() ? ThunkGuestLibs() : ThunkGuestLibs32() ; for (auto const &DBObject : ThunkDB) { if (!DBObject.second.Enabled) { continue; @@ -300,17 +290,17 @@ FileManager::FileManager(FEXCore::Context::Context *ctx) struct { decltype(FileManager::ThunkOverlays)& ThunkOverlays; decltype(ThunkDB)& ThunkDB; - const std::filesystem::path& ThunkGuestPath; + const fextl::string& ThunkGuestPath; bool Is64BitMode; void SetupOverlay(const ThunkDBObject& DBDepend) { - auto ThunkPath = ThunkGuestPath / DBDepend.LibraryName; - if (!std::filesystem::exists(ThunkPath)) { + auto ThunkPath = fextl::fmt::format("{}/{}", ThunkGuestPath, DBDepend.LibraryName); + if (!FHU::Filesystem::Exists(ThunkPath.c_str())) { if (!Is64BitMode) { // Guest libraries not existing is expected since not all libraries are thunked on 32-bit return; } - ERROR_AND_DIE_FMT("Requested thunking via guest library \"{}\" that does not exist", ThunkPath.string()); + ERROR_AND_DIE_FMT("Requested thunking via guest library \"{}\" that does not exist", ThunkPath); } for (const auto& Overlay : DBDepend.Overlays) { @@ -665,7 +655,14 @@ uint64_t FileManager::Readlinkat(int dirfd, const char *pathname, char *buf, siz dirfd != AT_FDCWD) { // Passed in a dirfd that isn't magic FDCWD // We need to get the path from the fd now - Path = FEX::get_fdpath(dirfd).value_or(""); + char Tmp[PATH_MAX]; + auto PathLength = FEX::get_fdpath(dirfd, Tmp); + if (PathLength != -1) { + Path = fextl::string(Tmp, PathLength); + } + else { + Path = ""; + } if (pathname) { if (!Path.empty()) { From e6a48ad7f342d384656ad6e3b8156b4c9f2b2a26 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:33:16 -0700 Subject: [PATCH 25/41] Syscalls: Convert to get_fdpath with temp to avoid glibc --- Source/Tests/LinuxSyscalls/Syscalls.cpp | 8 ++++---- Source/Tests/LinuxSyscalls/SyscallsSMCTracking.cpp | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Source/Tests/LinuxSyscalls/Syscalls.cpp b/Source/Tests/LinuxSyscalls/Syscalls.cpp index c1b10b870..c75ea6d95 100644 --- a/Source/Tests/LinuxSyscalls/Syscalls.cpp +++ b/Source/Tests/LinuxSyscalls/Syscalls.cpp @@ -6,6 +6,7 @@ desc: Glue logic, brk allocations $end_info$ */ +#include "FEXHeaderUtils/Filesystem.h" #include "Linux/Utils/ELFContainer.h" #include "Linux/Utils/ELFParser.h" @@ -237,7 +238,6 @@ static bool IsShebangFilename(fextl::string const &Filename) { uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* envp, ExecveAtArgs Args) { fextl::string Filename{}; - std::error_code ec; fextl::string RootFS = FEX::HLE::_SyscallHandler->RootFSPath(); ELFLoader::ELFContainer::ELFType Type{}; @@ -257,7 +257,7 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env // For absolute paths, check the rootfs first (if available) if (pathname[0] == '/') { auto Path = FEX::HLE::_SyscallHandler->FM.GetEmulatedPath(pathname, true); - if (!Path.empty() && std::filesystem::exists(Path, ec)) { + if (!Path.empty() && FHU::Filesystem::Exists(Path.c_str())) { Filename = Path; } else { @@ -268,8 +268,8 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env Filename = pathname; } - bool exists = std::filesystem::exists(Filename, ec); - if (ec || !exists) { + bool exists = FHU::Filesystem::Exists(Filename.c_str()); + if (!exists) { return -ENOENT; } diff --git a/Source/Tests/LinuxSyscalls/SyscallsSMCTracking.cpp b/Source/Tests/LinuxSyscalls/SyscallsSMCTracking.cpp index cd32a69bd..187d25482 100644 --- a/Source/Tests/LinuxSyscalls/SyscallsSMCTracking.cpp +++ b/Source/Tests/LinuxSyscalls/SyscallsSMCTracking.cpp @@ -199,14 +199,16 @@ void SyscallHandler::TrackMmap(uintptr_t Base, uintptr_t Size, int Prot, int Fla fstat64(fd, &buf); MRID mrid {buf.st_dev, buf.st_ino}; - auto filename = FEX::get_fdpath(fd); + char Tmp[PATH_MAX]; + auto PathLength = FEX::get_fdpath(fd, Tmp); - if (filename.has_value()) { + if (PathLength != -1) { + Tmp[PathLength] = '\0'; auto [Iter, Inserted] = VMATracking.MappedResources.emplace(mrid, MappedResource {nullptr, nullptr, 0}); Resource = &Iter->second; if (Inserted) { - Resource->AOTIRCacheEntry = CTX->LoadAOTIRCacheEntry(filename.value()); + Resource->AOTIRCacheEntry = CTX->LoadAOTIRCacheEntry(fextl::string(Tmp, PathLength)); Resource->Iterator = Iter; } } From ea275bbdcc62b74c621ade5a7a4e23b848a7bcf6 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:33:41 -0700 Subject: [PATCH 26/41] FDUtils: Remove std::fs get_fdpath, no longer used and avoids glibc --- Source/Common/FDUtils.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Source/Common/FDUtils.h b/Source/Common/FDUtils.h index d8b313b71..329f6b691 100644 --- a/Source/Common/FDUtils.h +++ b/Source/Common/FDUtils.h @@ -11,20 +11,6 @@ #include namespace FEX { -[[maybe_unused]] -static -std::optional get_fdpath(int fd) { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - char SymlinkPath[PATH_MAX]; - std::filesystem::path Path = std::filesystem::path("/proc/self/fd") / std::to_string(fd); - int Result = readlinkat(AT_FDCWD, Path.c_str(), SymlinkPath, sizeof(SymlinkPath)); - if (Result != -1) { - return fextl::string(SymlinkPath, Result); - } - - // Not fatal if an FD doesn't point to a file - return std::nullopt; -} inline int get_fdpath(int fd, char *SymlinkPath) { From 12b710ed16a826b32369df9a79ed250676ba4c00 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:34:10 -0700 Subject: [PATCH 27/41] APITests: Test FHU::LexicallyNormal --- unittests/APITests/CMakeLists.txt | 4 +++- unittests/APITests/LexicallyNormal.cpp | 30 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 unittests/APITests/LexicallyNormal.cpp diff --git a/unittests/APITests/CMakeLists.txt b/unittests/APITests/CMakeLists.txt index 2ee1473f9..f6d529915 100644 --- a/unittests/APITests/CMakeLists.txt +++ b/unittests/APITests/CMakeLists.txt @@ -1,5 +1,7 @@ set (TESTS - InterruptableConditionVariable) + InterruptableConditionVariable + LexicallyNormal + ) list(APPEND LIBS FEXCore) diff --git a/unittests/APITests/LexicallyNormal.cpp b/unittests/APITests/LexicallyNormal.cpp new file mode 100644 index 000000000..b9d3471c9 --- /dev/null +++ b/unittests/APITests/LexicallyNormal.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +#define TestPath(Path) \ + REQUIRE(std::string_view(FHU::Filesystem::LexicallyNormal(Path)) == std::string_view(std::filesystem::path(Path).lexically_normal().string())); + +TEST_CASE("LexicallyNormal") { + TestPath(""); + TestPath("/"); + TestPath("/./"); + TestPath("//."); + TestPath("//./"); + TestPath("//.//"); + + TestPath("."); + TestPath(".."); + TestPath(".//"); + TestPath("../../"); + TestPath("././"); + TestPath("./../"); + TestPath("./../"); + TestPath("./.././.././."); + TestPath("./.././.././.."); + + TestPath("./foo/../"); + TestPath("foo/./bar/.."); + TestPath("foo/.///bar/.."); + TestPath("foo/.///bar/../"); +} From 629e547e5fdc902894205f12a010d891e290e261 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 02:34:35 -0700 Subject: [PATCH 28/41] AllocatorOverride: Remove AFmt, it can try allocating memory and infinite loop. --- External/FEXCore/Source/Utils/AllocatorOverride.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/External/FEXCore/Source/Utils/AllocatorOverride.cpp b/External/FEXCore/Source/Utils/AllocatorOverride.cpp index 0e68b8ee3..316b0b8ff 100644 --- a/External/FEXCore/Source/Utils/AllocatorOverride.cpp +++ b/External/FEXCore/Source/Utils/AllocatorOverride.cpp @@ -94,8 +94,7 @@ namespace FEXCore::Allocator { auto Res = fmt::format_to_n(Tmp, 512, "Allocation from 0x{:x}\n", reinterpret_cast(Return)); Tmp[Res.size] = 0; write(STDERR_FILENO, Tmp, Res.size); - LogMan::Msg::AFmt(Tmp); - FEX_UNREACHABLE; + FEX_TRAP_EXECUTION; } } From a14353bc3c6e70c301848a2b035a7f3cb3dbdec0 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 17:48:29 -0700 Subject: [PATCH 29/41] FEXLoader: Convert remaining usages away from glibc --- .../FEXCore/include/FEXCore/Core/CodeLoader.h | 8 ------ Source/Tests/ELFCodeLoader.h | 28 +++++++++---------- Source/Tests/FEXLoader.cpp | 9 ++---- Source/Tests/HarnessHelpers.h | 4 ++- Source/Tests/VDSO_Emulation.cpp | 13 +++++---- Source/Tests/VDSO_Emulation.h | 4 ++- 6 files changed, 28 insertions(+), 38 deletions(-) diff --git a/External/FEXCore/include/FEXCore/Core/CodeLoader.h b/External/FEXCore/include/FEXCore/Core/CodeLoader.h index 2e76dac0a..dd8da17c4 100644 --- a/External/FEXCore/include/FEXCore/Core/CodeLoader.h +++ b/External/FEXCore/include/FEXCore/Core/CodeLoader.h @@ -17,9 +17,6 @@ class IREmitter; */ class CodeLoader { public: - using MapperFn = std::function; - using UnmapperFn = std::function; - virtual ~CodeLoader() = default; /** @@ -37,11 +34,6 @@ public: */ virtual uint64_t DefaultRIP() const = 0; - /** - * @brief Maps and copies the executable, also sets up stack - */ - virtual bool MapMemory(const MapperFn& Mapper, const UnmapperFn& Unmapper) { return false; } - virtual fextl::vector const *GetApplicationArguments() { return nullptr; } virtual void GetExecveArguments(fextl::vector *Args) {} diff --git a/Source/Tests/ELFCodeLoader.h b/Source/Tests/ELFCodeLoader.h index aed9b960a..686d07264 100644 --- a/Source/Tests/ELFCodeLoader.h +++ b/Source/Tests/ELFCodeLoader.h @@ -66,8 +66,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { return PAGE_ALIGN(last->p_vaddr + last->p_memsz); } - template - bool MapFile(const ELFParser& file, uintptr_t Base, const Elf64_Phdr &Header, int prot, int flags, T Mapper) { + bool MapFile(const ELFParser& file, uintptr_t Base, const Elf64_Phdr &Header, int prot, int flags, FEX::HLE::SyscallHandler *const Handler) { auto addr = Base + PAGE_START(Header.p_vaddr); auto size = Header.p_filesz + PAGE_OFFSET(Header.p_vaddr); @@ -80,7 +79,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { return true; } - void *rv = Mapper((void*)addr, size, prot, flags, file.fd, off); + void *rv = Handler->GuestMmap((void*)addr, size, prot, flags, file.fd, off); if (rv == MAP_FAILED) { // uhoh, something went wrong @@ -112,8 +111,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { return rv; } - template - std::optional LoadElfFile(ELFParser& Elf, uintptr_t *BrkBase, TMap Mapper, TUnmap Unmapper, uint64_t LoadHint = 0) { + std::optional LoadElfFile(ELFParser& Elf, uintptr_t *BrkBase, FEX::HLE::SyscallHandler *const Handler, uint64_t LoadHint = 0) { uintptr_t LoadBase = 0; @@ -124,7 +122,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { if (Elf.ehdr.e_type == ET_DYN) { // needs base address auto TotalSize = CalculateTotalElfSize(Elf.phdrs) + (BrkBase ? BRK_SIZE : 0); - LoadBase = (uintptr_t)Mapper(reinterpret_cast(LoadHint), TotalSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + LoadBase = (uintptr_t)Handler->GuestMmap(reinterpret_cast(LoadHint), TotalSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if ((void*)LoadBase == MAP_FAILED) { return {}; } @@ -142,7 +140,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { int MapProt = MapFlags(Header); int MapType = MAP_PRIVATE | MAP_DENYWRITE | MAP_FIXED; - if (!MapFile(Elf, LoadBase, Header, MapProt, MapType, Mapper)) { + if (!MapFile(Elf, LoadBase, Header, MapProt, MapType, Handler)) { return {}; } @@ -158,7 +156,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { } if (BSSPageStart != BSSPageEnd) { - auto bss = Mapper((void*)BSSPageStart, BSSPageEnd - BSSPageStart, MapProt, MapType | MAP_ANONYMOUS, -1, 0); + auto bss = Handler->GuestMmap((void*)BSSPageStart, BSSPageEnd - BSSPageStart, MapProt, MapType | MAP_ANONYMOUS, -1, 0); if ((void*)bss == MAP_FAILED) { LogMan::Msg::EFmt("Failed to allocate BSS @ {}, {}\n", fmt::ptr(bss), errno); return {}; @@ -354,7 +352,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { uint64_t val; }; - bool MapMemory(const MapperFn& Mapper, const UnmapperFn& Unmapper) override { + bool MapMemory(FEX::HLE::SyscallHandler *const Handler) { for (auto Header: MainElf.phdrs) { if (Header.p_type == PT_GNU_STACK) { if (Header.p_flags & PF_X) @@ -408,7 +406,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { uint64_t StackHint = Is64BitMode() ? STACK_HINT_64 : STACK_HINT_32; // Allocate the base of the full 128MB stack range. - StackPointerBase = Mapper(reinterpret_cast(StackHint), FULL_STACK_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN | MAP_NORESERVE, -1, 0); + StackPointerBase = Handler->GuestMmap(reinterpret_cast(StackHint), FULL_STACK_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN | MAP_NORESERVE, -1, 0); if (StackPointerBase == reinterpret_cast(~0ULL)) { LogMan::Msg::EFmt("Allocating stack failed"); @@ -416,7 +414,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { } // Allocate with permissions the 8MB of regular stack size. - StackPointer = reinterpret_cast(Mapper( + StackPointer = reinterpret_cast(Handler->GuestMmap( reinterpret_cast(reinterpret_cast(StackPointerBase) + FULL_STACK_SIZE - StackSize()), StackSize(), PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN, -1, 0)); @@ -465,7 +463,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { if (!MainElf.InterpreterElf.empty()) { uint64_t InterpLoadBase = 0; - if (auto elf = LoadElfFile(InterpElf, nullptr, Mapper, Unmapper)) { + if (auto elf = LoadElfFile(InterpElf, nullptr, Handler)) { InterpLoadBase = *elf; } else { LogMan::Msg::EFmt("Failed to load interpreter elf file"); @@ -531,7 +529,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { uintptr_t LoadBase = 0; - if (auto elf = LoadElfFile(MainElf, &BrkBase, Mapper, Unmapper, ELFLoadHint)) { + if (auto elf = LoadElfFile(MainElf, &BrkBase, Handler, ELFLoadHint)) { LoadBase = *elf; if (MainElf.ehdr.e_type == ET_DYN) { BaseOffset = LoadBase; @@ -543,7 +541,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { // XXX Randomise brk? - BrkStart = (uint64_t)Mapper((void*)BrkBase, BRK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + BrkStart = (uint64_t)Handler->GuestMmap((void*)BrkBase, BRK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); if ((void*)BrkStart == MAP_FAILED) { LogMan::Msg::EFmt("Failed to allocate BRK @ {:x}, {}\n", BrkBase, errno); @@ -586,7 +584,7 @@ class ELFCodeLoader final : public FEXCore::CodeLoader { if (!VSyscallEntry) [[unlikely]] { // If the VDSO thunk doesn't exist then we might not have a vsyscall entry. // Newer glibc requires vsyscall to exist now. So let's allocate a buffer and stick a vsyscall in to it. - auto VSyscallPage = Mapper(nullptr, FHU::FEX_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + auto VSyscallPage = Handler->GuestMmap(nullptr, FHU::FEX_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); constexpr static uint8_t VSyscallCode[] = { 0xcd, 0x80, // int 0x80 0xc3, // ret diff --git a/Source/Tests/FEXLoader.cpp b/Source/Tests/FEXLoader.cpp index 4d5029c82..94ebdee82 100644 --- a/Source/Tests/FEXLoader.cpp +++ b/Source/Tests/FEXLoader.cpp @@ -415,17 +415,12 @@ int main(int argc, char **argv, char **const envp) { : FEX::HLE::x32::CreateHandler(CTX, SignalDelegation.get(), std::move(Allocator)); { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; - - auto Mapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMmap, SyscallHandler.get()); - auto Unmapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMunmap, SyscallHandler.get()); - // Load VDSO in to memory prior to mapping our ELFs. - void* VDSOBase = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), Mapper); + void* VDSOBase = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), SyscallHandler.get()); Loader.SetVDSOBase(VDSOBase); Loader.CalculateHWCaps(CTX); - if (!Loader.MapMemory(Mapper, Unmapper)) { + if (!Loader.MapMemory(SyscallHandler.get())) { // failed to map LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32); FEXCore::Allocator::ClearFaultEvaluate(); diff --git a/Source/Tests/HarnessHelpers.h b/Source/Tests/HarnessHelpers.h index 54dc2c95c..56e380079 100644 --- a/Source/Tests/HarnessHelpers.h +++ b/Source/Tests/HarnessHelpers.h @@ -475,7 +475,9 @@ namespace FEX::HarnessHelper { return RIP; } - bool MapMemory(const MapperFn& Mapper, const UnmapperFn& Unmapper) override { + using MapperFn = std::function; + using UnmapperFn = std::function; + bool MapMemory(const MapperFn& Mapper, const UnmapperFn& Unmapper) { bool LimitedSize = true; auto DoMMap = [&Mapper](uint64_t Address, size_t Size) -> void* { void *Result = Mapper(reinterpret_cast(Address), Size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); diff --git a/Source/Tests/VDSO_Emulation.cpp b/Source/Tests/VDSO_Emulation.cpp index 3e76b8501..56b7ee789 100644 --- a/Source/Tests/VDSO_Emulation.cpp +++ b/Source/Tests/VDSO_Emulation.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -501,14 +502,14 @@ namespace FEX::VDSO { } } - void* LoadVDSOThunks(bool Is64Bit, MapperFn Mapper) { + void* LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler *const Handler) { void* VDSOBase{}; FEX_CONFIG_OPT(ThunkGuestLibs, THUNKGUESTLIBS); FEX_CONFIG_OPT(ThunkGuestLibs32, THUNKGUESTLIBS32); - std::filesystem::path ThunkGuestPath{}; + fextl::string ThunkGuestPath{}; if (Is64Bit) { - ThunkGuestPath = std::filesystem::path(ThunkGuestLibs()) / "libVDSO-guest.so"; + ThunkGuestPath = fextl::fmt::format("{}/libVDSO-guest.so", ThunkGuestLibs()); // Set the Thunk definition pointers for x86-64 VDSODefinitions[0].ThunkFunction = FEX::VDSO::x64::Handler_time; @@ -519,7 +520,7 @@ namespace FEX::VDSO { VDSODefinitions[5].ThunkFunction = FEX::VDSO::x64::Handler_getcpu; } else { - ThunkGuestPath = std::filesystem::path(ThunkGuestLibs32()) / "libVDSO-guest.so"; + ThunkGuestPath = fextl::fmt::format("{}/libVDSO-guest.so", ThunkGuestLibs32()); // Set the Thunk definition pointers for x86 VDSODefinitions[0].ThunkFunction = FEX::VDSO::x32::Handler_time; @@ -531,7 +532,7 @@ namespace FEX::VDSO { } // Load VDSO if we can - int VDSOFD = ::open(ThunkGuestPath.string().c_str(), O_RDONLY); + int VDSOFD = ::open(ThunkGuestPath.c_str(), O_RDONLY); if (VDSOFD != -1) { // Get file size @@ -543,7 +544,7 @@ namespace FEX::VDSO { VDSOSize = FEXCore::AlignUp(VDSOSize, 4096); // Map the VDSO file to memory - VDSOBase = Mapper(nullptr, VDSOSize, PROT_READ, MAP_PRIVATE, VDSOFD, 0); + VDSOBase = Handler->GuestMmap(nullptr, VDSOSize, PROT_READ, MAP_PRIVATE, VDSOFD, 0); // Since we found our VDSO thunk library, find our host VDSO function implementations. LoadHostVDSO(); diff --git a/Source/Tests/VDSO_Emulation.h b/Source/Tests/VDSO_Emulation.h index 4a8721829..e977c3404 100644 --- a/Source/Tests/VDSO_Emulation.h +++ b/Source/Tests/VDSO_Emulation.h @@ -2,13 +2,15 @@ #include #include +#include "Tests/LinuxSyscalls/Syscalls.h" + namespace FEXCore::Context { struct VDSOSigReturn; } namespace FEX::VDSO { using MapperFn = std::function; - void* LoadVDSOThunks(bool Is64Bit, MapperFn Mapper); + void* LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler *const Handler); uint64_t GetVSyscallEntry(const void* VDSOBase); From 3cfc1de410ebe33e4a36d581e814713489c50e9e Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sun, 19 Mar 2023 18:05:02 -0700 Subject: [PATCH 30/41] Common: Convert cpp-optparse over to fextl and use. --- .gitmodules | 2 +- CMakeLists.txt | 3 --- External/cpp-optparse | 1 - Source/Common/ArgumentLoader.cpp | 13 ++++--------- Source/Common/CMakeLists.txt | 2 ++ Source/Common/cpp-optparse | 1 + Source/Tools/FEXGetConfig/Main.cpp | 2 +- Source/Tools/FEXRootFSFetcher/Main.cpp | 9 +++------ Source/Tools/FEXServer/ArgumentLoader.cpp | 4 ++-- 9 files changed, 14 insertions(+), 23 deletions(-) delete mode 160000 External/cpp-optparse create mode 160000 Source/Common/cpp-optparse diff --git a/.gitmodules b/.gitmodules index b25ef3285..70e306411 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ path = External/vixl url = https://github.com/FEX-Emu/vixl.git [submodule "External/cpp-optparse"] - path = External/cpp-optparse + path = Source/Common/cpp-optparse url = https://github.com/Sonicadvance1/cpp-optparse [submodule "External/imgui"] path = External/imgui diff --git a/CMakeLists.txt b/CMakeLists.txt index e61e72625..9080872ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,9 +242,6 @@ if (BUILD_TESTS) include(Catch) endif() -add_subdirectory(External/cpp-optparse/) -include_directories(External/cpp-optparse/) - add_subdirectory(External/fmt/) add_subdirectory(External/imgui/) diff --git a/External/cpp-optparse b/External/cpp-optparse deleted file mode 160000 index 2e480985b..000000000 --- a/External/cpp-optparse +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2e480985bd5b024d4659988dc30c94ac24b4b14a diff --git a/Source/Common/ArgumentLoader.cpp b/Source/Common/ArgumentLoader.cpp index ce011adca..d96181f0e 100644 --- a/Source/Common/ArgumentLoader.cpp +++ b/Source/Common/ArgumentLoader.cpp @@ -3,7 +3,7 @@ #include #include -#include "OptionParser.h" +#include "cpp-optparse/OptionParser.h" #include "git_version.h" #include @@ -12,9 +12,8 @@ namespace FEX::ArgLoader { fextl::vector RemainingArgs; fextl::vector ProgramArguments; - static std::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") "; + static fextl::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") "; void FEX::ArgLoader::ArgLoader::Load() { - FEXCore::Allocator::YesIKnowImNotSupposedToUseTheGlibcAllocator glibc; optparse::OptionParser Parser{}; Parser.version(Version); optparse::OptionGroup CPUGroup(Parser, "CPU Core options"); @@ -40,12 +39,8 @@ namespace FEX::ArgLoader { using uint32 = uint32_t; #define AFTER_PARSE #include - // TODO: Convert cpp-optparse over to fextl::vector - auto ParserArgs = Parser.args(); - auto ParsedArgs = Parser.parsed_args(); - - RemainingArgs.insert(RemainingArgs.begin(), ParserArgs.begin(), ParserArgs.end()); - ProgramArguments.insert(ProgramArguments.begin(), ParsedArgs.begin(), ParsedArgs.end()); + RemainingArgs = Parser.args(); + ProgramArguments = Parser.parsed_args(); } void LoadWithoutArguments(int _argc, char **_argv) { diff --git a/Source/Common/CMakeLists.txt b/Source/Common/CMakeLists.txt index adae65422..6a8131e6b 100644 --- a/Source/Common/CMakeLists.txt +++ b/Source/Common/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(cpp-optparse/) + set(NAME Common) set(SRCS ArgumentLoader.cpp diff --git a/Source/Common/cpp-optparse b/Source/Common/cpp-optparse new file mode 160000 index 000000000..1f3b88a1b --- /dev/null +++ b/Source/Common/cpp-optparse @@ -0,0 +1 @@ +Subproject commit 1f3b88a1ba3c4c6302a096d7e9002982e8811cb7 diff --git a/Source/Tools/FEXGetConfig/Main.cpp b/Source/Tools/FEXGetConfig/Main.cpp index 8fbcf466e..e54ba1a48 100644 --- a/Source/Tools/FEXGetConfig/Main.cpp +++ b/Source/Tools/FEXGetConfig/Main.cpp @@ -1,5 +1,5 @@ #include "ConfigDefines.h" -#include "OptionParser.h" +#include "Common/cpp-optparse/OptionParser.h" #include "Common/FEXServerClient.h" #include "git_version.h" #include diff --git a/Source/Tools/FEXRootFSFetcher/Main.cpp b/Source/Tools/FEXRootFSFetcher/Main.cpp index 1af3f2fe3..60b6e5b76 100644 --- a/Source/Tools/FEXRootFSFetcher/Main.cpp +++ b/Source/Tools/FEXRootFSFetcher/Main.cpp @@ -1,7 +1,7 @@ #include #include -#include "OptionParser.h" +#include "Common/cpp-optparse/OptionParser.h" #include "XXFileHash.h" #include "Common/ArgumentLoader.h" @@ -37,7 +37,7 @@ namespace ArgOptions { ListQueryOption DistroListOption {ListQueryOption::OPTION_ASK}; - std::vector RemainingArgs; + fextl::vector RemainingArgs; std::string DistroName{}; std::string DistroVersion{}; @@ -95,10 +95,7 @@ namespace ArgOptions { DistroVersion = Options["distro_version"]; } - - // TODO: Convert cpp-optparse over to fextl::vector - auto ParserArgs = Parser.args(); - RemainingArgs.insert(RemainingArgs.begin(), ParserArgs.begin(), ParserArgs.end()); + RemainingArgs = Parser.args(); } } diff --git a/Source/Tools/FEXServer/ArgumentLoader.cpp b/Source/Tools/FEXServer/ArgumentLoader.cpp index 4c4ac3121..6815395e0 100644 --- a/Source/Tools/FEXServer/ArgumentLoader.cpp +++ b/Source/Tools/FEXServer/ArgumentLoader.cpp @@ -1,12 +1,12 @@ #include "ArgumentLoader.h" -#include "OptionParser.h" +#include "Common/cpp-optparse/OptionParser.h" #include "git_version.h" #include namespace FEXServer::Config { - static std::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") "; + static fextl::string Version = "FEX-Emu (" GIT_DESCRIBE_STRING ") "; FEXServerOptions Load(int argc, char **argv) { FEXServerOptions FEXOptions{}; From fc8bf9f0f64a7075f13f983bfd325f06f23170ff Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 20 Mar 2023 05:35:24 -0700 Subject: [PATCH 31/41] Config: Remove static which is allocated --- External/FEXCore/Source/Interface/Config/Config.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/External/FEXCore/Source/Interface/Config/Config.cpp b/External/FEXCore/Source/Interface/Config/Config.cpp index f240e60f9..c269c78a6 100644 --- a/External/FEXCore/Source/Interface/Config/Config.cpp +++ b/External/FEXCore/Source/Interface/Config/Config.cpp @@ -382,10 +382,11 @@ namespace JSON { return {}; } + constexpr char ContainerManager[] = "/run/host/container-manager"; + fextl::string FindContainer() { // We only support pressure-vessel at the moment - const static fextl::string ContainerManager = "/run/host/container-manager"; - if (FHU::Filesystem::Exists(ContainerManager.c_str())) { + if (FHU::Filesystem::Exists(ContainerManager)) { fextl::vector Manager{}; if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) { // Trim the whitespace, may contain a newline @@ -399,8 +400,7 @@ namespace JSON { fextl::string FindContainerPrefix() { // We only support pressure-vessel at the moment - const static fextl::string ContainerManager = "/run/host/container-manager"; - if (FHU::Filesystem::Exists(ContainerManager.c_str())) { + if (FHU::Filesystem::Exists(ContainerManager)) { fextl::vector Manager{}; if (FEXCore::FileLoading::LoadFile(Manager, ContainerManager)) { // Trim the whitespace, may contain a newline From 3eae668cec37dd5311ee4305aa4614fb69935f2d Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 20 Mar 2023 05:36:57 -0700 Subject: [PATCH 32/41] X86Jit: Fix xbyak allocating through glibc --- .../Source/Interface/Core/Dispatcher/X86Dispatcher.cpp | 6 ++---- .../Source/Interface/Core/Dispatcher/X86Dispatcher.h | 2 ++ External/FEXCore/Source/Interface/Core/HostFeatures.cpp | 2 +- .../FEXCore/Source/Interface/Core/JIT/x86_64/ALUOps.cpp | 2 +- .../FEXCore/Source/Interface/Core/JIT/x86_64/AtomicOps.cpp | 2 +- .../FEXCore/Source/Interface/Core/JIT/x86_64/BranchOps.cpp | 2 +- .../Source/Interface/Core/JIT/x86_64/ConversionOps.cpp | 3 +-- .../Source/Interface/Core/JIT/x86_64/EncryptionOps.cpp | 3 +-- .../FEXCore/Source/Interface/Core/JIT/x86_64/FlagOps.cpp | 2 +- External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp | 1 - .../FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h | 5 +---- .../FEXCore/Source/Interface/Core/JIT/x86_64/MemoryOps.cpp | 3 +-- .../FEXCore/Source/Interface/Core/JIT/x86_64/MiscOps.cpp | 2 +- .../FEXCore/Source/Interface/Core/JIT/x86_64/MoveOps.cpp | 2 +- .../FEXCore/Source/Interface/Core/JIT/x86_64/VectorOps.cpp | 3 +-- 15 files changed, 16 insertions(+), 24 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.cpp b/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.cpp index a6238937a..e71e378fc 100644 --- a/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #define STATE_PTR(STATE_TYPE, FIELD) \ [STATE + offsetof(FEXCore::Core::STATE_TYPE, FIELD)] @@ -418,13 +417,11 @@ X86Dispatcher::X86Dispatcher(FEXCore::Context::ContextImpl *ctx, const Dispatche } -// Used by GenerateGDBPauseCheck, GenerateInterpreterTrampoline -static thread_local Xbyak::CodeGenerator emit(1, &emit); // actual emit target set with setNewBuffer - size_t X86Dispatcher::GenerateGDBPauseCheck(uint8_t *CodeBuffer, uint64_t GuestRIP) { using namespace Xbyak; using namespace Xbyak::util; + Xbyak::CodeGenerator emit(1, &emit); // actual emit target set with setNewBuffer emit.setNewBuffer(CodeBuffer, MaxGDBPauseCheckSize); Label RunBlock; @@ -459,6 +456,7 @@ size_t X86Dispatcher::GenerateInterpreterTrampoline(uint8_t *CodeBuffer) { using namespace Xbyak; using namespace Xbyak::util; + Xbyak::CodeGenerator emit(1, &emit); // actual emit target set with setNewBuffer emit.setNewBuffer(CodeBuffer, MaxInterpreterTrampolineSize); Label InlineIRData; diff --git a/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.h b/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.h index e4564dc9f..98a38c07e 100644 --- a/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.h +++ b/External/FEXCore/Source/Interface/Core/Dispatcher/X86Dispatcher.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -16,6 +17,7 @@ #define XBYAK_STD_LIST fextl::list #include +#include namespace FEXCore::Core { struct InternalThreadState; diff --git a/External/FEXCore/Source/Interface/Core/HostFeatures.cpp b/External/FEXCore/Source/Interface/Core/HostFeatures.cpp index 0706278f4..315a7d3eb 100644 --- a/External/FEXCore/Source/Interface/Core/HostFeatures.cpp +++ b/External/FEXCore/Source/Interface/Core/HostFeatures.cpp @@ -9,7 +9,7 @@ #endif #ifdef _M_X86_64 -#include +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #endif namespace FEXCore { diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/ALUOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/ALUOps.cpp index 3de783c28..807e84e94 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/ALUOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/ALUOps.cpp @@ -5,6 +5,7 @@ $end_info$ */ #include "Interface/Core/JIT/x86_64/JITClass.h" +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include #include @@ -12,7 +13,6 @@ $end_info$ #include #include #include -#include namespace FEXCore::CPU { diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/AtomicOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/AtomicOps.cpp index 1b4d0e407..8a032f9f3 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/AtomicOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/AtomicOps.cpp @@ -5,6 +5,7 @@ $end_info$ */ #include "Interface/Core/JIT/x86_64/JITClass.h" +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include #include @@ -12,7 +13,6 @@ $end_info$ #include #include #include -#include namespace FEXCore::CPU { #define DEF_OP(x) void X86JITCore::Op_##x(IR::IROp_Header *IROp, IR::NodeID Node) diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/BranchOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/BranchOps.cpp index eed5cf270..c98d58ade 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/BranchOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/BranchOps.cpp @@ -7,6 +7,7 @@ $end_info$ #include "Interface/Context/Context.h" #include "Interface/Core/CPUID.h" #include "Interface/Core/Dispatcher/Dispatcher.h" +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include "Interface/Core/LookupCache.h" #include "Interface/Core/JIT/x86_64/JITClass.h" #include "Interface/HLE/Thunks/Thunks.h" @@ -25,7 +26,6 @@ $end_info$ #include #include #include -#include namespace FEXCore::CPU { #define DEF_OP(x) void X86JITCore::Op_##x(IR::IROp_Header *IROp, IR::NodeID Node) diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/ConversionOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/ConversionOps.cpp index 20a5c1da4..7d58cb97b 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/ConversionOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/ConversionOps.cpp @@ -5,13 +5,12 @@ $end_info$ */ #include "Interface/Core/JIT/x86_64/JITClass.h" - +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include #include #include #include -#include namespace FEXCore::CPU { diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/EncryptionOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/EncryptionOps.cpp index 4237760c6..4aa5c1204 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/EncryptionOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/EncryptionOps.cpp @@ -5,12 +5,11 @@ $end_info$ */ #include "Interface/Core/JIT/x86_64/JITClass.h" - +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include #include #include -#include namespace FEXCore::CPU { #define DEF_OP(x) void X86JITCore::Op_##x(IR::IROp_Header *IROp, IR::NodeID Node) diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/FlagOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/FlagOps.cpp index 9355debd7..4100c10cb 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/FlagOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/FlagOps.cpp @@ -5,12 +5,12 @@ $end_info$ */ #include "Interface/Core/JIT/x86_64/JITClass.h" +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include #include #include -#include namespace FEXCore::CPU { diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 7eb0e9339..5d7db2bc9 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -40,7 +40,6 @@ $end_info$ #include #include #include -#include // #define DEBUG_RA 1 // #define DEBUG_CYCLES diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h index 67f31698d..543d31fc3 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JITClass.h @@ -9,12 +9,9 @@ $end_info$ #include #include "Interface/Core/BlockSamplingData.h" #include "Interface/Core/Dispatcher/Dispatcher.h" +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include "Interface/Core/ObjectCache/Relocations.h" -#define XBYAK64 -#include -#include - using namespace Xbyak; #include diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/MemoryOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/MemoryOps.cpp index a60af13ab..98a7f3807 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/MemoryOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/MemoryOps.cpp @@ -6,7 +6,7 @@ $end_info$ #include "Interface/Core/CPUID.h" #include "Interface/Core/JIT/x86_64/JITClass.h" - +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include #include #include @@ -14,7 +14,6 @@ $end_info$ #include #include #include -#include namespace FEXCore::CPU { diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/MiscOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/MiscOps.cpp index 595309588..d47c4de4e 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/MiscOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/MiscOps.cpp @@ -6,6 +6,7 @@ $end_info$ #include "Interface/Context/Context.h" #include "Interface/Core/Dispatcher/Dispatcher.h" +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include "Interface/Core/JIT/x86_64/JITClass.h" #include "FEXCore/Debug/InternalThreadState.h" @@ -16,7 +17,6 @@ $end_info$ #include #include #include -#include namespace FEXCore::CPU { #define DEF_OP(x) void X86JITCore::Op_##x(IR::IROp_Header *IROp, IR::NodeID Node) diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/MoveOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/MoveOps.cpp index acb7d9b87..f912f5ae3 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/MoveOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/MoveOps.cpp @@ -5,7 +5,7 @@ $end_info$ */ #include "Interface/Core/JIT/x86_64/JITClass.h" - +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include #include diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/VectorOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/VectorOps.cpp index 50afd94cc..ce36187b2 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/VectorOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/VectorOps.cpp @@ -5,14 +5,13 @@ $end_info$ */ #include "Interface/Core/JIT/x86_64/JITClass.h" - +#include "Interface/Core/Dispatcher/X86Dispatcher.h" #include #include #include #include #include -#include namespace FEXCore::CPU { From 463b4b748c453fe8f5564fe1f51892f72cee1c2b Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 20 Mar 2023 05:37:29 -0700 Subject: [PATCH 33/41] fextl: Add fextl::fmt::print --- External/FEXCore/include/FEXCore/fextl/fmt.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/External/FEXCore/include/FEXCore/fextl/fmt.h b/External/FEXCore/include/FEXCore/fextl/fmt.h index 3c1b44f83..f53641cff 100644 --- a/External/FEXCore/include/FEXCore/fextl/fmt.h +++ b/External/FEXCore/include/FEXCore/fextl/fmt.h @@ -3,6 +3,7 @@ #include #include +#include namespace fextl::fmt { template fextl::string { return fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); } + + template + FMT_INLINE auto print(::fmt::format_string fmt, T&&... args) + -> void { + auto String = fextl::fmt::vformat(fmt, ::fmt::make_format_args(args...)); + write(STDERR_FILENO, String.c_str(), String.size()); + } } From 067f807405f1c7204249b7e788e267fb3a01e777 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 20 Mar 2023 05:37:53 -0700 Subject: [PATCH 34/41] InternalThreadState: Convert tsl to fextl --- External/FEXCore/include/FEXCore/Debug/InternalThreadState.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h index 41d30e87c..98253bdc1 100644 --- a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h +++ b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h @@ -112,7 +112,7 @@ namespace FEXCore::Core { fextl::unique_ptr CPUBackend; fextl::unique_ptr LookupCache; - tsl::robin_map DebugStore; + fextl::robin_map DebugStore; fextl::unique_ptr FrontendDecoder; fextl::unique_ptr PassManager; From e46dbf7b7eba9eae4bfe6510ec6b3b80ef5989a4 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 20 Mar 2023 05:38:49 -0700 Subject: [PATCH 35/41] TestHarnessRunner: Convert to fextl --- Source/Tests/HarnessHelpers.h | 106 ++++++++++++------ Source/Tests/TestHarnessRunner.cpp | 23 ++-- Source/Tests/TestHarnessRunner/HostRunner.cpp | 11 ++ 3 files changed, 96 insertions(+), 44 deletions(-) diff --git a/Source/Tests/HarnessHelpers.h b/Source/Tests/HarnessHelpers.h index 56e380079..87dd5dbe5 100644 --- a/Source/Tests/HarnessHelpers.h +++ b/Source/Tests/HarnessHelpers.h @@ -1,6 +1,7 @@ #pragma once #include "Common/Config.h" +#include "Tests/LinuxSyscalls/Syscalls.h" #include "Linux/Utils/ELFContainer.h" #include "Linux/Utils/ELFSymbolDatabase.h" @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +39,7 @@ namespace FEX::HarnessHelper { bool SupportsAVX) { bool Matches = true; - const auto DumpGPRs = [OutputGPRs](const std::string& Name, uint64_t A, uint64_t B) { + const auto DumpGPRs = [OutputGPRs](const fextl::string& Name, uint64_t A, uint64_t B) { if (!OutputGPRs) { return; } @@ -48,7 +50,7 @@ namespace FEX::HarnessHelper { fmt::print("{}: 0x{:016x} {} 0x{:016x}\n", Name, A, A==B ? "==" : "!=", B); }; - const auto DumpFLAGs = [OutputGPRs](const std::string& Name, uint64_t A, uint64_t B) { + const auto DumpFLAGs = [OutputGPRs](const fextl::string& Name, uint64_t A, uint64_t B) { if (!OutputGPRs) { return; } @@ -85,12 +87,12 @@ namespace FEX::HarnessHelper { } }; - const auto CheckGPRs = [&Matches, DumpGPRs](const std::string& Name, uint64_t A, uint64_t B){ + const auto CheckGPRs = [&Matches, DumpGPRs](const fextl::string& Name, uint64_t A, uint64_t B){ DumpGPRs(Name, A, B); Matches &= A == B; }; - const auto CheckFLAGS = [&Matches, DumpFLAGs](const std::string& Name, uint64_t A, uint64_t B){ + const auto CheckFLAGS = [&Matches, DumpFLAGs](const fextl::string& Name, uint64_t A, uint64_t B){ DumpFLAGs(Name, A, B); Matches &= A == B; }; @@ -106,7 +108,7 @@ namespace FEX::HarnessHelper { // GPRS for (unsigned i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; ++i, MatchMask >>= 1) { if (MatchMask & 1) { - CheckGPRs("GPR" + std::to_string(i), State1.gregs[i], State2.gregs[i]); + CheckGPRs(fextl::fmt::format("GPR{}", std::to_string(i)), State1.gregs[i], State2.gregs[i]); } } @@ -114,15 +116,15 @@ namespace FEX::HarnessHelper { if (SupportsAVX) { for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i, MatchMask >>= 1) { if (MatchMask & 1) { - CheckGPRs("XMM0_" + std::to_string(i), State1.xmm.avx.data[i][0], State2.xmm.avx.data[i][0]); - CheckGPRs("XMM1_" + std::to_string(i), State1.xmm.avx.data[i][1], State2.xmm.avx.data[i][1]); + CheckGPRs(fextl::fmt::format("XMM0_{}", std::to_string(i)), State1.xmm.avx.data[i][0], State2.xmm.avx.data[i][0]); + CheckGPRs(fextl::fmt::format("XMM1_{}", std::to_string(i)), State1.xmm.avx.data[i][1], State2.xmm.avx.data[i][1]); } } } else { for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; ++i, MatchMask >>= 1) { if (MatchMask & 1) { - CheckGPRs("XMM0_" + std::to_string(i), State1.xmm.sse.data[i][0], State2.xmm.sse.data[i][0]); - CheckGPRs("XMM1_" + std::to_string(i), State1.xmm.sse.data[i][1], State2.xmm.sse.data[i][1]); + CheckGPRs(fextl::fmt::format("XMM0_{}", std::to_string(i)), State1.xmm.sse.data[i][0], State2.xmm.sse.data[i][0]); + CheckGPRs(fextl::fmt::format("XMM1_{}", std::to_string(i)), State1.xmm.sse.data[i][1], State2.xmm.sse.data[i][1]); } } } @@ -159,16 +161,29 @@ namespace FEX::HarnessHelper { } inline void ReadFile(fextl::string const &Filename, fextl::vector *Data) { - std::fstream TestFile(fextl::string_from_string(Filename), std::fstream::in | std::fstream::binary); - LOGMAN_THROW_A_FMT(TestFile.is_open(), "Failed to open file"); + int fd = open(Filename.c_str(), O_RDONLY | O_CLOEXEC); + if (fd == -1) { + LogMan::Msg::AFmt("Failed to open file"); + } - TestFile.seekg(0, std::fstream::end); - const size_t FileSize = TestFile.tellg(); - TestFile.seekg(0, std::fstream::beg); + struct stat buf; + if (fstat(fd, &buf) != 0) { + close(fd); + LogMan::Msg::AFmt("Failed to open file"); + } + + auto FileSize = buf.st_size; + + if (FileSize <= 0) { + close(fd); + LogMan::Msg::AFmt("Failed to open file"); + } Data->resize(FileSize); + const auto ReadSize = pread(fd, Data->data(), FileSize, 0); - TestFile.read(Data->data(), FileSize); + close(fd); + LOGMAN_THROW_AA_FMT(ReadSize == FileSize, "Failed to open file"); } class ConfigLoader final { @@ -307,15 +322,15 @@ namespace FEX::HarnessHelper { uint64_t *State1Data = reinterpret_cast(reinterpret_cast(State1) + Offset); uint64_t *State2Data = reinterpret_cast(reinterpret_cast(State2) + Offset); - const auto DumpGPRs = [this](const std::string& Name, uint64_t A, uint64_t B) { + const auto DumpGPRs = [this](const fextl::string& Name, uint64_t A, uint64_t B) { if (!ConfigDumpGPRs()) { return; } - fmt::print("{}: 0x{:016x} {} 0x{:016x} (Expected)\n", Name, A, A==B ? "==" : "!=", B); + fextl::fmt::print("{}: 0x{:016x} {} 0x{:016x} (Expected)\n", Name, A, A==B ? "==" : "!=", B); }; - const auto CheckGPRs = [&Matches, DumpGPRs](const std::string& Name, uint64_t A, uint64_t B) { + const auto CheckGPRs = [&Matches, DumpGPRs](const fextl::string& Name, uint64_t A, uint64_t B) { DumpGPRs(Name, A, B); Matches &= A == B; }; @@ -325,9 +340,9 @@ namespace FEX::HarnessHelper { if (NameIndex == 0) // RIP Name = "RIP"; else if (NameIndex >= 1 && NameIndex < 17) - Name = fmt::format("GPR{}", NameIndex - 1); + Name = fextl::fmt::format("GPR{}", NameIndex - 1); else if (NameIndex >= 17 && NameIndex < 33) - Name = fmt::format("XMM[{}][{}]", NameIndex - 17, j); + Name = fextl::fmt::format("XMM[{}][{}]", NameIndex - 17, j); else if (NameIndex == 33) Name = "gs"; else if (NameIndex == 34) @@ -335,13 +350,13 @@ namespace FEX::HarnessHelper { else if (NameIndex == 35) Name = "rflags"; else if (NameIndex >= 36 && NameIndex < 45) - Name = fmt::format("MM[{}][{}]", NameIndex - 36, j); + Name = fextl::fmt::format("MM[{}][{}]", NameIndex - 36, j); if (State1) { - CheckGPRs(fmt::format("Core1: {}: ", Name), State1Data[j], RegData->RegValues[j]); + CheckGPRs(fextl::fmt::format("Core1: {}: ", Name), State1Data[j], RegData->RegValues[j]); } if (State2) { - CheckGPRs(fmt::format("Core2: {}: ", Name), State2Data[j], RegData->RegValues[j]); + CheckGPRs(fextl::fmt::format("Core2: {}: ", Name), State2Data[j], RegData->RegValues[j]); } } @@ -475,41 +490,39 @@ namespace FEX::HarnessHelper { return RIP; } - using MapperFn = std::function; - using UnmapperFn = std::function; - bool MapMemory(const MapperFn& Mapper, const UnmapperFn& Unmapper) { + bool MapMemoryInternal(auto Mapper, auto Munmap) { bool LimitedSize = true; - auto DoMMap = [&Mapper](uint64_t Address, size_t Size) -> void* { - void *Result = Mapper(reinterpret_cast(Address), Size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + auto DoMMap = [](auto This, auto Mapper, uint64_t Address, size_t Size) -> void* { + void *Result = (This->*Mapper)(reinterpret_cast(Address), Size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); LOGMAN_THROW_AA_FMT(Result == reinterpret_cast(Address), "Map Memory mmap failed"); return Result; }; if (LimitedSize) { - DoMMap(0xe000'0000, FHU::FEX_PAGE_SIZE * 10); + DoMMap(this, Mapper, 0xe000'0000, FHU::FEX_PAGE_SIZE * 10); // SIB8 // We test [-128, -126] (Bottom) // We test [-8, 8] (Middle) // We test [120, 127] (Top) // Can fit in two pages - DoMMap(0xe800'0000 - FHU::FEX_PAGE_SIZE, FHU::FEX_PAGE_SIZE * 2); + DoMMap(this, Mapper, 0xe800'0000 - FHU::FEX_PAGE_SIZE, FHU::FEX_PAGE_SIZE * 2); } else { // This is scratch memory location and SIB8 location - DoMMap(0xe000'0000, 0x1000'0000); + DoMMap(this, Mapper, 0xe000'0000, 0x1000'0000); // This is for large SIB 32bit displacement testing - DoMMap(0x2'0000'0000, 0x1'0000'1000); + DoMMap(this, Mapper, 0x2'0000'0000, 0x1'0000'1000); } // Map in the memory region for the test file size_t Length = FEXCore::AlignUp(TestFileSize, FHU::FEX_PAGE_SIZE); - Mapper(reinterpret_cast(Code_start_page), Length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, TestFD, 0); + (this->*Mapper)(reinterpret_cast(Code_start_page), Length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, TestFD, 0); RIP = Code_start_page; // Map the memory regions the test file asks for for (auto& [region, size] : Config.GetMemoryRegions()) { - DoMMap(region, size); + DoMMap(this, Mapper, region, size); } LoadMemory(); @@ -517,6 +530,15 @@ namespace FEX::HarnessHelper { return true; } + bool MapMemory(FEX::HLE::SyscallHandler *const Handler) { + SyscallHandler = Handler; + return MapMemoryInternal(&FEX::HarnessHelper::HarnessCodeLoader::SyscallMMap, &FEX::HarnessHelper::HarnessCodeLoader::SyscallMunmap); + } + + bool MapMemory() { + return MapMemoryInternal(&FEX::HarnessHelper::HarnessCodeLoader::MMap, &FEX::HarnessHelper::HarnessCodeLoader::Munmap); + } + void LoadMemory() { // Memory base here starts at the start location we passed back with GetLayout() // This will write at [CODE_START_RANGE + 0, RawFile.size() ) @@ -542,7 +564,23 @@ namespace FEX::HarnessHelper { bool RequiresBMI2() const { return Config.RequiresBMI2(); } bool RequiresCLWB() const { return Config.RequiresCLWB(); } + protected: + void *SyscallMMap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + return SyscallHandler->GuestMmap(addr, length, prot, flags, fd, offset); + } + int SyscallMunmap(void *addr, size_t length) { + return SyscallHandler->GuestMunmap(addr, length); + } + + void *MMap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + return mmap(addr, length, prot, flags, fd, offset); + } + int Munmap(void *addr, size_t length) { + return munmap(addr, length); + } private: + FEX::HLE::SyscallHandler *SyscallHandler{}; + constexpr static uint64_t STACK_SIZE = FHU::FEX_PAGE_SIZE; constexpr static uint64_t STACK_OFFSET = 0xc000'0000; // Zero is special case to know when we are done diff --git a/Source/Tests/TestHarnessRunner.cpp b/Source/Tests/TestHarnessRunner.cpp index b3f3ad586..53353b5fc 100644 --- a/Source/Tests/TestHarnessRunner.cpp +++ b/Source/Tests/TestHarnessRunner.cpp @@ -57,11 +57,11 @@ void MsgHandler(LogMan::DebugLevels Level, char const *Message) { CharLevel = "???"; break; } - fmt::print("[{}] {}\n", CharLevel, Message); + fextl::fmt::print("[{}] {}\n", CharLevel, Message); } void AssertHandler(char const *Message) { - fmt::print("[ASSERT] {}\n", Message); + fextl::fmt::print("[ASSERT] {}\n", Message); // make sure buffers are flushed fflush(nullptr); @@ -83,7 +83,7 @@ public: } void Load() override { - std::unordered_map EnvMap; + fextl::unordered_map EnvMap; for (auto &Option : Env) { std::string_view Key = Option.first; std::string_view Value = Option.second; @@ -115,6 +115,7 @@ private: } int main(int argc, char **argv, char **const envp) { + FEXCore::Allocator::SetupFaultEvaluate(); LogMan::Throw::InstallHandler(AssertHandler); LogMan::Msg::InstallHandler(MsgHandler); FEXCore::Config::Initialize(); @@ -126,6 +127,7 @@ int main(int argc, char **argv, char **const envp) { if (Args.size() < 2) { LogMan::Msg::EFmt("Not enough arguments"); + FEXCore::Allocator::ClearFaultEvaluate(); return -1; } @@ -184,6 +186,7 @@ int main(int argc, char **argv, char **const envp) { if (TestUnsupported) { FEXCore::Context::Context::DestroyContext(CTX); + FEXCore::Allocator::ClearFaultEvaluate(); return 0; } @@ -202,16 +205,14 @@ int main(int argc, char **argv, char **const envp) { return false; }, true); - // Run through FEX auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX, SignalDelegation.get()) : FEX::HLE::x32::CreateHandler(CTX, SignalDelegation.get(), std::move(Allocator)); - auto Mapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMmap, SyscallHandler.get()); - auto Unmapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMunmap, SyscallHandler.get()); - - if (!Loader.MapMemory(Mapper, Unmapper)) { + // Run through FEX + if (!Loader.MapMemory(SyscallHandler.get())) { // failed to map LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32); + FEXCore::Allocator::ClearFaultEvaluate(); return -ENOEXEC; } @@ -221,6 +222,7 @@ int main(int argc, char **argv, char **const envp) { bool Result1 = CTX->InitCore(Loader.DefaultRIP(), Loader.GetStackPointer()); if (!Result1) { + FEXCore::Allocator::ClearFaultEvaluate(); return 1; } @@ -237,9 +239,10 @@ int main(int argc, char **argv, char **const envp) { // Run as host SupportsAVX = true; SignalDelegation->RegisterTLSState((FEXCore::Core::InternalThreadState*)UINTPTR_MAX); - if (!Loader.MapMemory(mmap, munmap)) { + if (!Loader.MapMemory()) { // failed to map LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32); + FEXCore::Allocator::ClearFaultEvaluate(); return -ENOEXEC; } @@ -263,7 +266,7 @@ int main(int argc, char **argv, char **const envp) { LogMan::Msg::UnInstallHandlers(); FEXCore::Allocator::ClearHooks(); - + FEXCore::Allocator::ClearFaultEvaluate(); return Passed ? 0 : -1; } diff --git a/Source/Tests/TestHarnessRunner/HostRunner.cpp b/Source/Tests/TestHarnessRunner/HostRunner.cpp index 0aa61be68..b99864b69 100644 --- a/Source/Tests/TestHarnessRunner/HostRunner.cpp +++ b/Source/Tests/TestHarnessRunner/HostRunner.cpp @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include #ifdef _M_X86_64 @@ -21,6 +24,14 @@ #include #include +#define XBYAK_CUSTOM_ALLOC +#define XBYAK_CUSTOM_MALLOC FEXCore::Allocator::malloc +#define XBYAK_CUSTOM_FREE FEXCore::Allocator::free +#define XBYAK_CUSTOM_SETS +#define XBYAK_STD_UNORDERED_SET fextl::unordered_set +#define XBYAK_STD_UNORDERED_MAP fextl::unordered_map +#define XBYAK_STD_UNORDERED_MULTIMAP fextl::unordered_multimap +#define XBYAK_STD_LIST fextl::list #include using namespace Xbyak; From 4f66ff6ec4399a078e6a9d3cfb13c34f54df0d78 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 20 Mar 2023 19:29:16 -0700 Subject: [PATCH 36/41] Paths: Remove unique_ptr usage --- External/FEXCore/Source/Common/Paths.cpp | 30 +++++++------------ .../Source/Interface/Context/Context.cpp | 4 --- .../FEXCore/include/FEXCore/Core/Context.h | 1 - Source/Tests/FEXLoader.cpp | 1 - Source/Tests/TestHarnessRunner.cpp | 1 - 5 files changed, 11 insertions(+), 26 deletions(-) diff --git a/External/FEXCore/Source/Common/Paths.cpp b/External/FEXCore/Source/Common/Paths.cpp index fbb314680..4f6520a27 100644 --- a/External/FEXCore/Source/Common/Paths.cpp +++ b/External/FEXCore/Source/Common/Paths.cpp @@ -14,8 +14,8 @@ #include namespace FEXCore::Paths { - fextl::unique_ptr CachePath; - fextl::unique_ptr EntryCache; + fextl::string CachePath{}; + fextl::string EntryCache{}; char const* FindUserHomeThroughUID() { auto passwd = getpwuid(geteuid()); @@ -47,9 +47,6 @@ namespace FEXCore::Paths { } void InitializePaths() { - CachePath = fextl::make_unique(); - EntryCache = fextl::make_unique(); - char const *HomeDir = getenv("HOME"); if (!HomeDir) { @@ -62,34 +59,29 @@ namespace FEXCore::Paths { char *XDGDataDir = getenv("XDG_DATA_DIR"); if (XDGDataDir) { - *CachePath = XDGDataDir; + CachePath = XDGDataDir; } else { if (HomeDir) { - *CachePath = HomeDir; + CachePath = HomeDir; } } - *CachePath += "/.fex-emu/"; - *EntryCache = *CachePath + "/EntryCache/"; + CachePath += "/.fex-emu/"; + EntryCache = CachePath + "/EntryCache/"; // Ensure the folder structure is created for our Data - if (!FHU::Filesystem::Exists(EntryCache->c_str()) && - !FHU::Filesystem::CreateDirectories(*EntryCache)) { - LogMan::Msg::DFmt("Couldn't create EntryCache directory: '{}'", *EntryCache); + if (!FHU::Filesystem::Exists(EntryCache.c_str()) && + !FHU::Filesystem::CreateDirectories(EntryCache)) { + LogMan::Msg::DFmt("Couldn't create EntryCache directory: '{}'", EntryCache); } } - void ShutdownPaths() { - CachePath.reset(); - EntryCache.reset(); - } - fextl::string GetCachePath() { - return *CachePath; + return CachePath; } fextl::string GetEntryCachePath() { - return *EntryCache; + return EntryCache; } } diff --git a/External/FEXCore/Source/Interface/Context/Context.cpp b/External/FEXCore/Source/Interface/Context/Context.cpp index e1a1c6c4b..8cfba76fe 100644 --- a/External/FEXCore/Source/Interface/Context/Context.cpp +++ b/External/FEXCore/Source/Interface/Context/Context.cpp @@ -24,10 +24,6 @@ namespace FEXCore::Context { IR::InstallOpcodeHandlers(Mode); } - void ShutdownStaticTables() { - FEXCore::Paths::ShutdownPaths(); - } - FEXCore::Context::Context *FEXCore::Context::Context::CreateNewContext() { return new FEXCore::Context::ContextImpl{}; } diff --git a/External/FEXCore/include/FEXCore/Core/Context.h b/External/FEXCore/include/FEXCore/Core/Context.h index 6ebc8dace..1b56cc20d 100644 --- a/External/FEXCore/include/FEXCore/Core/Context.h +++ b/External/FEXCore/include/FEXCore/Core/Context.h @@ -291,5 +291,4 @@ namespace FEXCore::Context { * @brief This initializes internal FEXCore state that is shared between contexts and requires overhead to setup */ FEX_DEFAULT_VISIBILITY void InitializeStaticTables(OperatingMode Mode = MODE_64BIT); - FEX_DEFAULT_VISIBILITY void ShutdownStaticTables(); } diff --git a/Source/Tests/FEXLoader.cpp b/Source/Tests/FEXLoader.cpp index 94ebdee82..e8c0c18af 100644 --- a/Source/Tests/FEXLoader.cpp +++ b/Source/Tests/FEXLoader.cpp @@ -521,7 +521,6 @@ int main(int argc, char **argv, char **const envp) { SignalDelegation.reset(); FEXCore::Context::Context::DestroyContext(CTX); - FEXCore::Context::ShutdownStaticTables(); FEXCore::Threads::Shutdown(); Loader.FreeSections(); diff --git a/Source/Tests/TestHarnessRunner.cpp b/Source/Tests/TestHarnessRunner.cpp index 53353b5fc..9ae4cf1f9 100644 --- a/Source/Tests/TestHarnessRunner.cpp +++ b/Source/Tests/TestHarnessRunner.cpp @@ -250,7 +250,6 @@ int main(int argc, char **argv, char **const envp) { } FEXCore::Context::Context::DestroyContext(CTX); - FEXCore::Context::ShutdownStaticTables(); bool Passed = !DidFault && Loader.CompareStates(&State, nullptr, SupportsAVX); From 047dddb023b83c129ef7f269e9f0cb1e6d11e5a1 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 24 Mar 2023 05:03:59 -0700 Subject: [PATCH 37/41] Rebase patching --- External/FEXCore/Scripts/config_generator.py | 2 +- Source/Common/Config.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/External/FEXCore/Scripts/config_generator.py b/External/FEXCore/Scripts/config_generator.py index 17ba768e5..bb7af277a 100644 --- a/External/FEXCore/Scripts/config_generator.py +++ b/External/FEXCore/Scripts/config_generator.py @@ -387,7 +387,7 @@ def print_parse_argloader_options(options): output_argloader.write("\t}\n") else: if (NeedsString): - output_argloader.write("\tfextl::string UserValue = fextl::string_from_string(Options[\"{0}\"]);\n".format(op_key)) + output_argloader.write("\tfextl::string UserValue = Options[\"{0}\"];\n".format(op_key)) else: output_argloader.write("\t{0} UserValue = Options.get(\"{1}\");\n".format(value_type, op_key)) diff --git a/Source/Common/Config.cpp b/Source/Common/Config.cpp index c1d238061..96d84420f 100644 --- a/Source/Common/Config.cpp +++ b/Source/Common/Config.cpp @@ -94,9 +94,9 @@ namespace FEX::Config { // This symlink will be in the style of `/dev/fd/`. // // If the argument /is/ a symlink then resolve its path to get the original application name. - if (FHU::Symlinks::IsSymlink(fextl::string_from_string(Program))) { + if (FHU::Symlinks::IsSymlink(Program)) { char Filename[PATH_MAX]; - auto SymlinkPath = FHU::Symlinks::ResolveSymlink(fextl::string_from_string(Program), Filename); + auto SymlinkPath = FHU::Symlinks::ResolveSymlink(Program, Filename); if (SymlinkPath.starts_with('/')) { // This file was executed through an FD. // Remove the ` (deleted)` text if the file was deleted after the fact. From 53bbbd5a4fe7daf3918c2e53b13ab172dd022da7 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 24 Mar 2023 05:33:56 -0700 Subject: [PATCH 38/41] Review code --- External/FEXCore/Source/Common/Paths.cpp | 2 +- .../Source/Interface/Config/Config.cpp | 14 +++---- .../Source/Interface/Context/Context.h | 8 ---- .../Source/Interface/Core/LookupCache.cpp | 8 ++-- .../Source/Interface/Core/LookupCache.h | 2 +- .../Source/Utils/AllocatorOverride.cpp | 2 + External/FEXCore/Source/Utils/Telemetry.cpp | 4 +- .../FEXCore/include/FEXCore/Utils/Allocator.h | 20 +++++++++ .../include/FEXCore/fextl/memory_resource.h | 2 +- FEXHeaderUtils/FEXHeaderUtils/Filesystem.h | 4 ++ Source/Common/FEXServerClient.cpp | 2 +- Source/Tests/FEXLoader.cpp | 12 ++---- Source/Tests/LinuxSyscalls/FileManagement.cpp | 7 +--- Source/Tests/LinuxSyscalls/Syscalls.cpp | 4 +- Source/Tests/TestHarnessRunner.cpp | 8 +--- unittests/APITests/LexicallyNormal.cpp | 41 ++++++++++--------- 16 files changed, 71 insertions(+), 69 deletions(-) diff --git a/External/FEXCore/Source/Common/Paths.cpp b/External/FEXCore/Source/Common/Paths.cpp index 4f6520a27..5c648dc29 100644 --- a/External/FEXCore/Source/Common/Paths.cpp +++ b/External/FEXCore/Source/Common/Paths.cpp @@ -71,7 +71,7 @@ namespace FEXCore::Paths { EntryCache = CachePath + "/EntryCache/"; // Ensure the folder structure is created for our Data - if (!FHU::Filesystem::Exists(EntryCache.c_str()) && + if (!FHU::Filesystem::Exists(EntryCache) && !FHU::Filesystem::CreateDirectories(EntryCache)) { LogMan::Msg::DFmt("Couldn't create EntryCache directory: '{}'", EntryCache); } diff --git a/External/FEXCore/Source/Interface/Config/Config.cpp b/External/FEXCore/Source/Interface/Config/Config.cpp index c269c78a6..fc05a978d 100644 --- a/External/FEXCore/Source/Interface/Config/Config.cpp +++ b/External/FEXCore/Source/Interface/Config/Config.cpp @@ -146,7 +146,7 @@ namespace JSON { } // Ensure the folder structure is created for our configuration - if (!FHU::Filesystem::Exists(ConfigDir.c_str()) && + if (!FHU::Filesystem::Exists(ConfigDir) && !FHU::Filesystem::CreateDirectories(ConfigDir)) { // Let's go local in this case return "./"; @@ -178,7 +178,7 @@ namespace JSON { fextl::string ConfigFile = GetConfigDirectory(Global); if (!Global && - !FHU::Filesystem::Exists(ConfigFile.c_str()) && + !FHU::Filesystem::Exists(ConfigFile) && !FHU::Filesystem::CreateDirectories(ConfigFile)) { LogMan::Msg::DFmt("Couldn't create config directory: '{}'", ConfigFile); // Let's go local in this case @@ -189,7 +189,7 @@ namespace JSON { // Attempt to create the local folder if it doesn't exist if (!Global && - !FHU::Filesystem::Exists(ConfigFile.c_str()) && + !FHU::Filesystem::Exists(ConfigFile) && !FHU::Filesystem::CreateDirectories(ConfigFile)) { // Let's go local in this case return "./" + Filename + ".json"; @@ -354,7 +354,7 @@ namespace JSON { } // Only return if it exists - if (FHU::Filesystem::Exists(PathName.c_str())) { + if (FHU::Filesystem::Exists(PathName)) { return PathName; } } @@ -371,9 +371,9 @@ namespace JSON { // HostThunks: $CMAKE_INSTALL_PREFIX/lib/fex-emu/HostThunks/ // GuestThunks: $CMAKE_INSTALL_PREFIX/share/fex-emu/GuestThunks/ if (!ContainerPrefix.empty() && !PathName.empty()) { - if (!FHU::Filesystem::Exists(PathName.c_str())) { + if (!FHU::Filesystem::Exists(PathName)) { auto ContainerPath = ContainerPrefix + PathName; - if (FHU::Filesystem::Exists(ContainerPath.c_str())) { + if (FHU::Filesystem::Exists(ContainerPath)) { return ContainerPath; } } @@ -725,7 +725,7 @@ namespace JSON { EnvMap[Key] = Value; } - std::function GetVar = [](EnvMapType &EnvMap, const std::string_view id) -> std::optional { + auto GetVar = [](EnvMapType &EnvMap, const std::string_view id) -> std::optional { if (EnvMap.find(id) != EnvMap.end()) return EnvMap.at(id); diff --git a/External/FEXCore/Source/Interface/Context/Context.h b/External/FEXCore/Source/Interface/Context/Context.h index ad35e6d87..873dcaac7 100644 --- a/External/FEXCore/Source/Interface/Context/Context.h +++ b/External/FEXCore/Source/Interface/Context/Context.h @@ -72,14 +72,6 @@ namespace FEXCore::Context { class ContextImpl final : public FEXCore::Context::Context { public: - void *operator new(size_t size) { - return FEXCore::Allocator::malloc(size); - } - - void operator delete(void *ptr) { - return FEXCore::Allocator::free(ptr); - } - // Context base class implementation. bool InitializeContext() override; diff --git a/External/FEXCore/Source/Interface/Core/LookupCache.cpp b/External/FEXCore/Source/Interface/Core/LookupCache.cpp index 451e0780a..6fd47f3e5 100644 --- a/External/FEXCore/Source/Interface/Core/LookupCache.cpp +++ b/External/FEXCore/Source/Interface/Core/LookupCache.cpp @@ -15,11 +15,11 @@ $end_info$ namespace FEXCore { LookupCache::LookupCache(FEXCore::Context::ContextImpl *CTX) - : ctx {CTX} { + : BlockLinks_mbr { fextl::pmr::get_default_resource() } + , ctx {CTX} { TotalCacheSize = ctx->Config.VirtualMemSize / 4096 * 8 + CODE_SIZE + L1_SIZE; - BlockLinks_mbr = fextl::make_unique(fextl::pmr::get_default_resource()); - BlockLinks_pma = fextl::make_unique>(BlockLinks_mbr.get()); + BlockLinks_pma = fextl::make_unique>(&BlockLinks_mbr); // Setup our PMR map. BlockLinks = BlockLinks_pma->new_object(); @@ -73,8 +73,6 @@ void LookupCache::ClearCache() { // Clear L1 and L2 by clearing the full cache. madvise(reinterpret_cast(PagePointer), TotalCacheSize, MADV_DONTNEED); - // Clear the BlockLinks allocator which frees the BlockLinks map implicitly. - BlockLinks_mbr->release(); // Allocate a new pointer from the BlockLinks pma again. BlockLinks = BlockLinks_pma->new_object(); // All code is gone, clear the block list diff --git a/External/FEXCore/Source/Interface/Core/LookupCache.h b/External/FEXCore/Source/Interface/Core/LookupCache.h index 07e1ea7c4..819409e7f 100644 --- a/External/FEXCore/Source/Interface/Core/LookupCache.h +++ b/External/FEXCore/Source/Interface/Core/LookupCache.h @@ -243,7 +243,7 @@ private: // walking each block member and destructing objects. // // This makes `BlockLinks` look like a raw pointer that could memory leak, but since it is backed by the MBR, it won't. - fextl::unique_ptr BlockLinks_mbr; + std::pmr::monotonic_buffer_resource BlockLinks_mbr; using BlockLinksMapType = std::pmr::map>; fextl::unique_ptr> BlockLinks_pma; BlockLinksMapType *BlockLinks; diff --git a/External/FEXCore/Source/Utils/AllocatorOverride.cpp b/External/FEXCore/Source/Utils/AllocatorOverride.cpp index 316b0b8ff..f1f65cbaf 100644 --- a/External/FEXCore/Source/Utils/AllocatorOverride.cpp +++ b/External/FEXCore/Source/Utils/AllocatorOverride.cpp @@ -94,6 +94,8 @@ namespace FEXCore::Allocator { auto Res = fmt::format_to_n(Tmp, 512, "Allocation from 0x{:x}\n", reinterpret_cast(Return)); Tmp[Res.size] = 0; write(STDERR_FILENO, Tmp, Res.size); + + // Fault the execution to stop it in its tracks. FEX_TRAP_EXECUTION; } } diff --git a/External/FEXCore/Source/Utils/Telemetry.cpp b/External/FEXCore/Source/Utils/Telemetry.cpp index 99cc65b6b..015744052 100644 --- a/External/FEXCore/Source/Utils/Telemetry.cpp +++ b/External/FEXCore/Source/Utils/Telemetry.cpp @@ -30,7 +30,7 @@ namespace FEXCore::Telemetry { DataDirectory += "Telemetry/"; // Ensure the folder structure is created for our configuration - if (!FHU::Filesystem::Exists(DataDirectory.c_str()) && + if (!FHU::Filesystem::Exists(DataDirectory) && !FHU::Filesystem::CreateDirectories(DataDirectory)) { LogMan::Msg::IFmt("Couldn't create telemetry Folder"); } @@ -40,7 +40,7 @@ namespace FEXCore::Telemetry { auto DataDirectory = Config::GetDataDirectory(); DataDirectory += "Telemetry/" + ApplicationName + ".telem"; - if (FHU::Filesystem::Exists(DataDirectory.c_str())) { + if (FHU::Filesystem::Exists(DataDirectory)) { // If the file exists, retain a single backup auto Backup = DataDirectory + ".1"; FHU::Filesystem::CopyFile(DataDirectory, Backup, FHU::Filesystem::CopyOptions::OVERWRITE_EXISTING); diff --git a/External/FEXCore/include/FEXCore/Utils/Allocator.h b/External/FEXCore/include/FEXCore/Utils/Allocator.h index 58af7c325..5a817e9eb 100644 --- a/External/FEXCore/include/FEXCore/Utils/Allocator.h +++ b/External/FEXCore/include/FEXCore/Utils/Allocator.h @@ -27,6 +27,16 @@ namespace FEXCore::Allocator { FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator(); FEX_DEFAULT_VISIBILITY static void HardDisable(); }; + + class FEX_DEFAULT_VISIBILITY GLIBCScopedFault final { + public: + GLIBCScopedFault() { + FEXCore::Allocator::SetupFaultEvaluate(); + } + ~GLIBCScopedFault() { + FEXCore::Allocator::ClearFaultEvaluate(); + } + }; #else FEX_DEFAULT_VISIBILITY inline void SetupFaultEvaluate() {} FEX_DEFAULT_VISIBILITY inline void ClearFaultEvaluate() {} @@ -37,6 +47,16 @@ namespace FEXCore::Allocator { FEX_DEFAULT_VISIBILITY ~YesIKnowImNotSupposedToUseTheGlibcAllocator() {} FEX_DEFAULT_VISIBILITY static inline void HardDisable() {} }; + + class FEX_DEFAULT_VISIBILITY GLIBCScopedFault final { + public: + GLIBCScopedFault() { + // nop + } + ~GLIBCScopedFault() { + // nop + } + }; #endif struct MemoryRegion { diff --git a/External/FEXCore/include/FEXCore/fextl/memory_resource.h b/External/FEXCore/include/FEXCore/fextl/memory_resource.h index 5857979f5..7d6009bf9 100644 --- a/External/FEXCore/include/FEXCore/fextl/memory_resource.h +++ b/External/FEXCore/include/FEXCore/fextl/memory_resource.h @@ -37,7 +37,7 @@ namespace fextl { */ class fixed_size_monotonic_buffer_resource final : public std::pmr::memory_resource { public: - fixed_size_monotonic_buffer_resource(void* Base, size_t Size) + fixed_size_monotonic_buffer_resource(void* Base, [[maybe_unused]] size_t Size) : Ptr {reinterpret_cast(Base)} #if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED , PtrEnd {reinterpret_cast(Base) + Size} diff --git a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h index 2832ce8d5..c76978aca 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h +++ b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h @@ -23,6 +23,10 @@ namespace FHU::Filesystem { return access(Path, F_OK) == 0; } + inline bool Exists(const fextl::string &Path) { + return access(Path.c_str(), F_OK) == 0; + } + /** * @brief Creates a directory at the provided path. * diff --git a/Source/Common/FEXServerClient.cpp b/Source/Common/FEXServerClient.cpp index d77ea4db0..61441e9f5 100644 --- a/Source/Common/FEXServerClient.cpp +++ b/Source/Common/FEXServerClient.cpp @@ -215,7 +215,7 @@ namespace FEXServerClient { fextl::string FEXServerPath = FHU::Filesystem::ParentPath(InterpreterPath) + "/FEXServer"; // Check if a local FEXServer next to FEXInterpreter exists // If it does then it takes priority over the installed one - if (!FHU::Filesystem::Exists(FEXServerPath.c_str())) { + if (!FHU::Filesystem::Exists(FEXServerPath)) { FEXServerPath = "FEXServer"; } diff --git a/Source/Tests/FEXLoader.cpp b/Source/Tests/FEXLoader.cpp index e8c0c18af..b4f0770aa 100644 --- a/Source/Tests/FEXLoader.cpp +++ b/Source/Tests/FEXLoader.cpp @@ -180,7 +180,7 @@ void InterpreterHandler(fextl::string *Filename, fextl::string const &RootFS, fe void RootFSRedirect(fextl::string *Filename, fextl::string const &RootFS) { auto RootFSLink = ELFCodeLoader::ResolveRootfsFile(*Filename, RootFS); - if (FHU::Filesystem::Exists(RootFSLink.c_str())) { + if (FHU::Filesystem::Exists(RootFSLink)) { *Filename = RootFSLink; } } @@ -199,7 +199,7 @@ bool IsInterpreterInstalled() { } int main(int argc, char **argv, char **const envp) { - FEXCore::Allocator::SetupFaultEvaluate(); + FEXCore::Allocator::GLIBCScopedFault GLIBFaultScope; const bool IsInterpreter = RanAsInterpreter(argv[0]); ExecutedWithFD = getauxval(AT_EXECFD) != 0; @@ -218,7 +218,6 @@ int main(int argc, char **argv, char **const envp) { if (Program.ProgramPath.empty() && !FEXFD) { // Early exit if we weren't passed an argument - FEXCore::Allocator::ClearFaultEvaluate(); return 0; } @@ -243,7 +242,6 @@ int main(int argc, char **argv, char **const envp) { // Ensure FEXServer is setup before config options try to pull CONFIG_ROOTFS if (!FEXServerClient::SetupClient(argv[0])) { LogMan::Msg::EFmt("FEXServerClient: Failure to setup client"); - FEXCore::Allocator::ClearFaultEvaluate(); return -1; } @@ -297,11 +295,10 @@ int main(int argc, char **argv, char **const envp) { RootFSRedirect(&Program.ProgramPath, LDPath()); InterpreterHandler(&Program.ProgramPath, LDPath(), &Args); - if (!ExecutedWithFD && !FEXFD && !FHU::Filesystem::Exists(Program.ProgramPath.c_str())) { + if (!ExecutedWithFD && !FEXFD && !FHU::Filesystem::Exists(Program.ProgramPath)) { // Early exit if the program passed in doesn't exist // Will prevent a crash later fmt::print(stderr, "{}: command not found\n", Program.ProgramPath); - FEXCore::Allocator::ClearFaultEvaluate(); return -ENOEXEC; } @@ -333,7 +330,6 @@ int main(int argc, char **argv, char **const envp) { fmt::print(stderr, "Use FEXRootFSFetcher to download a RootFS\n"); } #endif - FEXCore::Allocator::ClearFaultEvaluate(); return -ENOEXEC; } @@ -423,7 +419,6 @@ int main(int argc, char **argv, char **const envp) { if (!Loader.MapMemory(SyscallHandler.get())) { // failed to map LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32); - FEXCore::Allocator::ClearFaultEvaluate(); return -ENOEXEC; } } @@ -535,7 +530,6 @@ int main(int argc, char **argv, char **const envp) { // Allocator is now original system allocator FEXCore::Telemetry::Shutdown(Program.ProgramName); FEXCore::Profiler::Shutdown(); - FEXCore::Allocator::ClearFaultEvaluate(); if (ShutdownReason == FEXCore::Context::ExitReason::EXIT_SHUTDOWN) { return ProgramStatus; diff --git a/Source/Tests/LinuxSyscalls/FileManagement.cpp b/Source/Tests/LinuxSyscalls/FileManagement.cpp index 884cf70ea..530a03515 100644 --- a/Source/Tests/LinuxSyscalls/FileManagement.cpp +++ b/Source/Tests/LinuxSyscalls/FileManagement.cpp @@ -295,7 +295,7 @@ FileManager::FileManager(FEXCore::Context::Context *ctx) void SetupOverlay(const ThunkDBObject& DBDepend) { auto ThunkPath = fextl::fmt::format("{}/{}", ThunkGuestPath, DBDepend.LibraryName); - if (!FHU::Filesystem::Exists(ThunkPath.c_str())) { + if (!FHU::Filesystem::Exists(ThunkPath)) { if (!Is64BitMode) { // Guest libraries not existing is expected since not all libraries are thunked on 32-bit return; @@ -655,14 +655,11 @@ uint64_t FileManager::Readlinkat(int dirfd, const char *pathname, char *buf, siz dirfd != AT_FDCWD) { // Passed in a dirfd that isn't magic FDCWD // We need to get the path from the fd now - char Tmp[PATH_MAX]; + char Tmp[PATH_MAX] = ""; auto PathLength = FEX::get_fdpath(dirfd, Tmp); if (PathLength != -1) { Path = fextl::string(Tmp, PathLength); } - else { - Path = ""; - } if (pathname) { if (!Path.empty()) { diff --git a/Source/Tests/LinuxSyscalls/Syscalls.cpp b/Source/Tests/LinuxSyscalls/Syscalls.cpp index c75ea6d95..395c8dc43 100644 --- a/Source/Tests/LinuxSyscalls/Syscalls.cpp +++ b/Source/Tests/LinuxSyscalls/Syscalls.cpp @@ -257,7 +257,7 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env // For absolute paths, check the rootfs first (if available) if (pathname[0] == '/') { auto Path = FEX::HLE::_SyscallHandler->FM.GetEmulatedPath(pathname, true); - if (!Path.empty() && FHU::Filesystem::Exists(Path.c_str())) { + if (!Path.empty() && FHU::Filesystem::Exists(Path)) { Filename = Path; } else { @@ -268,7 +268,7 @@ uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* env Filename = pathname; } - bool exists = FHU::Filesystem::Exists(Filename.c_str()); + bool exists = FHU::Filesystem::Exists(Filename); if (!exists) { return -ENOENT; } diff --git a/Source/Tests/TestHarnessRunner.cpp b/Source/Tests/TestHarnessRunner.cpp index 9ae4cf1f9..224a884ee 100644 --- a/Source/Tests/TestHarnessRunner.cpp +++ b/Source/Tests/TestHarnessRunner.cpp @@ -115,7 +115,7 @@ private: } int main(int argc, char **argv, char **const envp) { - FEXCore::Allocator::SetupFaultEvaluate(); + FEXCore::Allocator::GLIBCScopedFault GLIBFaultScope; LogMan::Throw::InstallHandler(AssertHandler); LogMan::Msg::InstallHandler(MsgHandler); FEXCore::Config::Initialize(); @@ -127,7 +127,6 @@ int main(int argc, char **argv, char **const envp) { if (Args.size() < 2) { LogMan::Msg::EFmt("Not enough arguments"); - FEXCore::Allocator::ClearFaultEvaluate(); return -1; } @@ -186,7 +185,6 @@ int main(int argc, char **argv, char **const envp) { if (TestUnsupported) { FEXCore::Context::Context::DestroyContext(CTX); - FEXCore::Allocator::ClearFaultEvaluate(); return 0; } @@ -212,7 +210,6 @@ int main(int argc, char **argv, char **const envp) { if (!Loader.MapMemory(SyscallHandler.get())) { // failed to map LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32); - FEXCore::Allocator::ClearFaultEvaluate(); return -ENOEXEC; } @@ -222,7 +219,6 @@ int main(int argc, char **argv, char **const envp) { bool Result1 = CTX->InitCore(Loader.DefaultRIP(), Loader.GetStackPointer()); if (!Result1) { - FEXCore::Allocator::ClearFaultEvaluate(); return 1; } @@ -242,7 +238,6 @@ int main(int argc, char **argv, char **const envp) { if (!Loader.MapMemory()) { // failed to map LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32); - FEXCore::Allocator::ClearFaultEvaluate(); return -ENOEXEC; } @@ -265,7 +260,6 @@ int main(int argc, char **argv, char **const envp) { LogMan::Msg::UnInstallHandlers(); FEXCore::Allocator::ClearHooks(); - FEXCore::Allocator::ClearFaultEvaluate(); return Passed ? 0 : -1; } diff --git a/unittests/APITests/LexicallyNormal.cpp b/unittests/APITests/LexicallyNormal.cpp index b9d3471c9..5ce4ed599 100644 --- a/unittests/APITests/LexicallyNormal.cpp +++ b/unittests/APITests/LexicallyNormal.cpp @@ -3,28 +3,29 @@ #include #define TestPath(Path) \ - REQUIRE(std::string_view(FHU::Filesystem::LexicallyNormal(Path)) == std::string_view(std::filesystem::path(Path).lexically_normal().string())); TEST_CASE("LexicallyNormal") { - TestPath(""); - TestPath("/"); - TestPath("/./"); - TestPath("//."); - TestPath("//./"); - TestPath("//.//"); + auto Path = GENERATE("", + "/", + "/./", + "//.", + "//./", + "//.//", - TestPath("."); - TestPath(".."); - TestPath(".//"); - TestPath("../../"); - TestPath("././"); - TestPath("./../"); - TestPath("./../"); - TestPath("./.././.././."); - TestPath("./.././.././.."); + ".", + "..", + ".//", + "../../", + "././", + "./../", + "./../", + "./.././.././.", + "./.././.././..", - TestPath("./foo/../"); - TestPath("foo/./bar/.."); - TestPath("foo/.///bar/.."); - TestPath("foo/.///bar/../"); + "./foo/../", + "foo/./bar/..", + "foo/.///bar/..", + "foo/.///bar/../"); + + REQUIRE(std::string_view(FHU::Filesystem::LexicallyNormal(Path)) == std::string_view(std::filesystem::path(Path).lexically_normal().string())); } From 2990a9d820051aa513db54e4b3e438a0d2c4e56c Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Fri, 24 Mar 2023 06:14:21 -0700 Subject: [PATCH 39/41] FaultingAllocator: Review comments --- .../Source/Utils/AllocatorOverride.cpp | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/External/FEXCore/Source/Utils/AllocatorOverride.cpp b/External/FEXCore/Source/Utils/AllocatorOverride.cpp index f1f65cbaf..a7b6faa4a 100644 --- a/External/FEXCore/Source/Utils/AllocatorOverride.cpp +++ b/External/FEXCore/Source/Utils/AllocatorOverride.cpp @@ -12,10 +12,12 @@ extern "C" { #ifdef GLIBC_ALLOCATOR_FAULT - // glibc allocator faulting. If anything uses a glibc allocator symbol then cause a fault. - // Ensures that FEX only ever allocates memory through its allocator routines. - // If thunks are enabled then this should crash immediately. Thunks should still go through glibc allocator. - // These need to be symbol definitions /only/, don't let their visibility to the rest of the source happen. + // The majority of FEX internal code should avoid using the glibc allocator. To ensure glibc allocations don't accidentally slip + // in, FEX overrides these glibc functions with faulting variants. + // + // A notable exception is thunks, which should still use glibc allocations and avoid using `fextl::` namespace. + // + // Other minor exceptions throughout FEX use the `YesIKnowImNotSupposedToUseTheGlibcAllocator` helper to temporarily disable faulting. #define GLIBC_ALIAS_FUNCTION(func) __attribute__((alias(#func), visibility("default"))) extern void *__libc_calloc(size_t, size_t); void *calloc(size_t, size_t) GLIBC_ALIAS_FUNCTION(fault_calloc); @@ -46,9 +48,13 @@ extern "C" { } namespace FEXCore::Allocator { - static bool Evaluate{}; + // Enable or disable allocation faulting globally. + static bool GlobalEvaluate{}; + + // Enable or disable allocation faulting per-thread. thread_local uint64_t SkipEvalForThread{}; + // Internal memory allocation hooks to allow non-faulting allocations through. CALLOC_Hook calloc_ptr = __libc_calloc; FREE_Hook free_ptr = __libc_free; MALLOC_Hook malloc_ptr = __libc_malloc; @@ -59,48 +65,60 @@ namespace FEXCore::Allocator { MALLOC_USABLE_SIZE_Hook malloc_usable_size_ptr = ::malloc_usable_size; ALIGNED_ALLOC_Hook aligned_alloc_ptr = __libc_memalign; + // Constructor for per-thread allocation faulting check. YesIKnowImNotSupposedToUseTheGlibcAllocator::YesIKnowImNotSupposedToUseTheGlibcAllocator() { ++SkipEvalForThread; } + // Destructor for per-thread allocation faulting check. YesIKnowImNotSupposedToUseTheGlibcAllocator::~YesIKnowImNotSupposedToUseTheGlibcAllocator() { --SkipEvalForThread; } + // Hard disabling of per-thread allocation fault checking. + // No coming back from this, used on thread destruction. FEX_DEFAULT_VISIBILITY void YesIKnowImNotSupposedToUseTheGlibcAllocator::HardDisable() { // Just set it to half of its maximum value so it never wraps back around. SkipEvalForThread = std::numeric_limits::max() / 2; } + // Enable global fault checking. void SetupFaultEvaluate() { - Evaluate = true; + GlobalEvaluate = true; } + // Disable global fault checking. void ClearFaultEvaluate() { - Evaluate = false; + GlobalEvaluate = false; } + // Evaluate if a glibc hooked allocation should fault. void EvaluateReturnAddress(void* Return) { - if (!Evaluate) { + if (!GlobalEvaluate) { + // Fault evaluation disabled globally. return; } if (SkipEvalForThread) { + // Fault evaluation disabled for this thread. return; } // We don't know where we are when allocating. Make sure to be safe and generate the string on the stack. + // Print an error message to let a developer know that an allocation faulted. char Tmp[512]; auto Res = fmt::format_to_n(Tmp, 512, "Allocation from 0x{:x}\n", reinterpret_cast(Return)); Tmp[Res.size] = 0; write(STDERR_FILENO, Tmp, Res.size); - // Fault the execution to stop it in its tracks. + // Trap the execution to stop FEX in its tracks. FEX_TRAP_EXECUTION; } } extern "C" { + // These are the glibc allocator override symbols. + // These will override the glibc allocators and then check if the allocation should fault. void *fault_calloc(size_t n, size_t size) { FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); return FEXCore::Allocator::calloc_ptr(n, size); From 97daec3dba1a7b7ae92725812e4ceac58c82ab38 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 30 Mar 2023 12:16:41 -0700 Subject: [PATCH 40/41] Review comments --- .../IR/Passes/RegisterAllocationPass.cpp | 1 + .../Source/Utils/Allocator/64BitAllocator.cpp | 8 - .../Source/Utils/AllocatorOverride.cpp | 6 +- .../FEXCore/Debug/InternalThreadState.h | 2 + .../include/FEXCore/IR/IntrusiveIRList.h | 1 + FEXHeaderUtils/FEXHeaderUtils/Filesystem.h | 139 ++++++++++-------- unittests/APITests/CMakeLists.txt | 2 +- unittests/APITests/Filesystem.cpp | 85 +++++++++++ unittests/APITests/LexicallyNormal.cpp | 31 ---- 9 files changed, 172 insertions(+), 103 deletions(-) create mode 100644 unittests/APITests/Filesystem.cpp delete mode 100644 unittests/APITests/LexicallyNormal.cpp diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index b57cf6119..6c1e1ae21 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -99,6 +99,7 @@ namespace { fextl::unordered_map> BlockPredecessors; fextl::unordered_map> VisitedNodePredecessors; + // Required due to raw new usage. void *operator new(size_t size) { return FEXCore::Allocator::malloc(size); } diff --git a/External/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp b/External/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp index 8dfd07c79..12f38edaa 100644 --- a/External/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp +++ b/External/FEXCore/Source/Utils/Allocator/64BitAllocator.cpp @@ -31,14 +31,6 @@ namespace Alloc::OSAllocator { class OSAllocator_64Bit final : public Alloc::HostAllocator { public: - void *operator new(size_t size) { - return ::malloc(size); - } - - void operator delete(void *ptr) { - return ::free(ptr); - } - OSAllocator_64Bit(); virtual ~OSAllocator_64Bit(); void *AllocateSlab(size_t Size) override { return nullptr; } diff --git a/External/FEXCore/Source/Utils/AllocatorOverride.cpp b/External/FEXCore/Source/Utils/AllocatorOverride.cpp index a7b6faa4a..4c7f4c190 100644 --- a/External/FEXCore/Source/Utils/AllocatorOverride.cpp +++ b/External/FEXCore/Source/Utils/AllocatorOverride.cpp @@ -11,7 +11,6 @@ #include extern "C" { -#ifdef GLIBC_ALLOCATOR_FAULT // The majority of FEX internal code should avoid using the glibc allocator. To ensure glibc allocations don't accidentally slip // in, FEX overrides these glibc functions with faulting variants. // @@ -52,7 +51,7 @@ namespace FEXCore::Allocator { static bool GlobalEvaluate{}; // Enable or disable allocation faulting per-thread. - thread_local uint64_t SkipEvalForThread{}; + static thread_local uint64_t SkipEvalForThread{}; // Internal memory allocation hooks to allow non-faulting allocations through. CALLOC_Hook calloc_ptr = __libc_calloc; @@ -100,7 +99,7 @@ namespace FEXCore::Allocator { } if (SkipEvalForThread) { - // Fault evaluation disabled for this thread. + // Fault evaluation currently disabled for this thread. return; } @@ -155,5 +154,4 @@ extern "C" { FEXCore::Allocator::EvaluateReturnAddress(__builtin_extract_return_addr (__builtin_return_address (0))); return FEXCore::Allocator::aligned_alloc_ptr(a, s); } -#endif } diff --git a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h index 98253bdc1..47395bd7c 100644 --- a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h +++ b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h @@ -64,6 +64,7 @@ namespace FEXCore::Core { fextl::vector GuestOpcodes; fextl::vector *Relocations; + // Required due to raw new usage. void *operator new(size_t size) { return FEXCore::Allocator::malloc(size); } @@ -127,6 +128,7 @@ namespace FEXCore::Core { std::shared_mutex ObjectCacheRefCounter{}; bool DestroyedByParent{false}; // Should the parent destroy this thread, or it destory itself + // Required due to raw new usage. void *operator new(size_t size) { return FEXCore::Allocator::malloc(size); } diff --git a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h index 25241f80a..f9cc621a6 100644 --- a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h +++ b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h @@ -170,6 +170,7 @@ public: } } + // Required due to raw new usage. void *operator new(size_t size) { return FEXCore::Allocator::malloc(size); } diff --git a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h index c76978aca..e22bc6b18 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h +++ b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -27,17 +28,22 @@ namespace FHU::Filesystem { return access(Path.c_str(), F_OK) == 0; } + enum class CreateDirectoryResult { + CREATED, + EXISTS, + ERROR, + }; /** * @brief Creates a directory at the provided path. * * @param Path The path to create a directory at. * - * @return True if the directory was created or already exists. + * @return Result enum depending. */ - inline bool CreateDirectory(const fextl::string &Path) { + inline CreateDirectoryResult CreateDirectory(const fextl::string &Path) { auto Result = ::mkdir(Path.c_str(), 0777); if (Result == 0) { - return true; + return CreateDirectoryResult::CREATED; } if (Result == -1 && errno == EEXIST) { @@ -45,12 +51,14 @@ namespace FHU::Filesystem { struct stat buf; if (stat(Path.c_str(), &buf) == 0) { // Check to see if the path is a file or folder. Following symlinks. - return S_ISDIR(buf.st_mode); + return S_ISDIR(buf.st_mode) ? + CreateDirectoryResult::EXISTS : + CreateDirectoryResult::ERROR; } } // Couldn't create, or the path that existed wasn't a folder. - return false; + return CreateDirectoryResult::ERROR; } /** @@ -62,14 +70,14 @@ namespace FHU::Filesystem { */ inline bool CreateDirectories(const fextl::string &Path) { // Try to create the directory initially. - if (CreateDirectory(Path)) { + if (CreateDirectory(Path) != CreateDirectoryResult::ERROR) { return true; } // Walk the path in reverse and create paths as we go. fextl::string TmpPath {Path.substr(0, Path.rfind('/', Path.size() - 1))}; if (!TmpPath.empty() && CreateDirectories(TmpPath)) { - return CreateDirectory(Path); + return CreateDirectory(Path) != CreateDirectoryResult::ERROR; } return false; } @@ -93,15 +101,37 @@ namespace FHU::Filesystem { inline fextl::string ParentPath(const fextl::string &Path) { auto LastSeparator = Path.rfind('/'); + if (LastSeparator == fextl::string::npos) { // No separator. Likely relative `.`, `..`, ``, or empty string. + if (Path == "." || Path == "..") { + // In this edge-case, return nothing to match std::filesystem::path::parent_path behaviour. + return {}; + } return Path; } - return Path.substr(0, LastSeparator); + if (LastSeparator == 0) { + // In the case of root, just return. + return "/"; + } + + auto SubString = Path.substr(0, LastSeparator); + + while (SubString.size() > 1 && SubString.ends_with("/")) { + // If the substring still ended with `/` then we need to string that off as well. + --LastSeparator; + SubString = Path.substr(0, LastSeparator); + } + + return SubString; } inline bool IsRelative(const fextl::string &Path) { + return !Path.starts_with('/'); + } + + inline bool IsAbsolute(const fextl::string &Path) { return Path.starts_with('/'); } @@ -111,22 +141,23 @@ namespace FHU::Filesystem { OVERWRITE_EXISTING, }; + /** + * @brief Copy a file from a location to another + * + * Behaves similarly to std::filesystem::copy_file but with less copy options. + * + * @param From Source file location. + * @param To Destination file location. + * @param Options Copy options. + * + * @return True if the copy succeeded, false otherwise. + */ inline bool CopyFile(const fextl::string &From, const fextl::string &To, CopyOptions Options = CopyOptions::NONE) { - bool DestTested = false; - bool DestExists = false; - if (Options == CopyOptions::SKIP_EXISTING && Exists(To.c_str())) { - DestTested = true; - DestExists = Exists(To.c_str()); - if (DestExists) { - // If the destination file exists already and the skip existing flag is set then - // return true without error. - return true; - } - } - - if (!DestTested) { - DestTested = true; - DestExists = Exists(To.c_str()); + const bool DestExists = Exists(To); + if (Options == CopyOptions::SKIP_EXISTING && DestExists) { + // If the destination file exists already and the skip existing flag is set then + // return true without error. + return true; } if (Options == CopyOptions::OVERWRITE_EXISTING && DestExists) { @@ -177,15 +208,16 @@ namespace FHU::Filesystem { return {}; } + const auto IsAbsolutePath = IsAbsolute(Path); + const auto EndsWithSeparator = Path.ends_with('/'); // Count the number of separators up front const auto SeparatorCount = std::count(Path.begin(), Path.end(), '/'); - // Needs to be a list so iterators aren't invalidated while erasing. - // Maximum number of list regions will be the counted separators plus 2. - // Multiplied by two since it allocates * 2 the size (32-bytes per element) - // Use a small stack allocator to be more optimal. - // Needs to be a list so iterators aren't invalidated while erasing. - size_t DataSize = sizeof(std::string_view) * (SeparatorCount + 2) * 2; + // Use std::list to store path elements to avoid iterator invalidation on insert/erase. + // The list is allocated on stack to be more optimal. The size is determined by the + // maximum number of list objects (separator count plus 2) multiplied by the list + // element size (32-bytes per element: the string_view itself and the prev/next pointers). + size_t DataSize = (sizeof(std::string_view) + sizeof(void*) * 2) * (SeparatorCount + 2); void *Data = alloca(DataSize); fextl::pmr::fixed_size_monotonic_buffer_resource mbr(Data, DataSize); std::pmr::polymorphic_allocator pa {&mbr}; @@ -205,9 +237,8 @@ namespace FHU::Filesystem { const auto Size = End - Begin; ExpectedStringSize += Size; - // If Size is zero then only insert if Parts is empty. - // Ensures that we don't remove an initial `/` by itself - if (Parts.empty() || Size != 0) { + // Only insert parts that contain data. + if (Size != 0) { Parts.emplace_back(std::string_view(Begin, End)); } @@ -221,9 +252,10 @@ namespace FHU::Filesystem { size_t CurrentIterDistance{}; for (auto iter = Parts.begin(); iter != Parts.end();) { - if (*iter == ".") { + auto &Part = *iter; + if (Part == ".") { // Erase '.' directory parts if not at root. - if (CurrentIterDistance > 0) { + if (CurrentIterDistance > 0 || IsAbsolutePath) { // Erasing this iterator, don't increase iter distances iter = Parts.erase(iter); --ExpectedStringSize; @@ -231,9 +263,8 @@ namespace FHU::Filesystem { } } - if (*iter == "..") { - auto Distance = std::distance(Parts.begin(), iter); - if (Distance > 0) { + if (Part == "..") { + if (CurrentIterDistance > 0) { // If not at root then remove both this iterator and the previous one. // ONLY if the previous iterator is also not ".." // @@ -257,6 +288,12 @@ namespace FHU::Filesystem { continue; } } + else if (IsAbsolutePath) { + // `..` at the base. Just remove this + ExpectedStringSize -= 2; + iter = Parts.erase(iter); + continue; + } } // Interator distance increased by one. @@ -264,28 +301,12 @@ namespace FHU::Filesystem { ++iter; } - fextl::string OutputPath{}; - OutputPath.reserve(ExpectedStringSize + Parts.size()); - auto iter = Parts.begin(); - for (size_t i = 0; i < Parts.size(); ++i, ++iter) { - auto &Part = *iter; - OutputPath += Part; - - const bool IsFinal = (i + 1) == Parts.size(); - // If the final element is ellipses then don't apply a separator. - // Otherwise if it is anything else, apply a separator. - const bool IsEllipses = Part == "." || Part == ".."; - - const bool NeedsSeparator = - !IsFinal || // Needs a separator if this isn't the final part. - (IsFinal && !IsEllipses); // Needs a separator if the final part doesn't end in `.` or `..` - - if (NeedsSeparator) { - OutputPath += '/'; - } - } - - return OutputPath; + // Add a final separator unless the last element is ellipses. + const bool NeedsFinalSeparator = EndsWithSeparator && (!Parts.empty() && Parts.back() != "." && Parts.back() != ".."); + return fextl::fmt::format("{}{}{}", + IsAbsolutePath ? "/" : "", + fmt::join(Parts, "/"), + NeedsFinalSeparator ? "/" : ""); } } diff --git a/unittests/APITests/CMakeLists.txt b/unittests/APITests/CMakeLists.txt index f6d529915..bfe8fcdf3 100644 --- a/unittests/APITests/CMakeLists.txt +++ b/unittests/APITests/CMakeLists.txt @@ -1,6 +1,6 @@ set (TESTS InterruptableConditionVariable - LexicallyNormal + Filesystem ) list(APPEND LIBS FEXCore) diff --git a/unittests/APITests/Filesystem.cpp b/unittests/APITests/Filesystem.cpp new file mode 100644 index 000000000..6ebadf39d --- /dev/null +++ b/unittests/APITests/Filesystem.cpp @@ -0,0 +1,85 @@ +#include +#include +#include + +TEST_CASE("LexicallyNormal") { + auto Path = GENERATE("", + "/", + "/./", + "//.", + "//./", + "//.//", + + ".", + "..", + ".//", + "../../", + "././", + "./../", + "./../", + "./.././.././.", + "./.././.././..", + + "./foo1/../", + "foo4/.///bar/../", + "foo5/././", + + "foo6/", + "foo7/test", + "foo8/test/", + "foo9/./../test/", + + "/../..", + "...", + "/...", + "foo10/...", + "/..", + "/foo11/../../bar" + ); + + REQUIRE(std::string_view(FHU::Filesystem::LexicallyNormal(Path)) == std::string_view(std::filesystem::path(Path).lexically_normal().string())); +} + +TEST_CASE("LexicallyNormalDifferences", "[!shouldfail]") { + auto Path = GENERATE("", + // std::fs here keeps the `/` after `foo2/` + // FEX algorithm doesn't keep behaviour here. + "foo2/./bar/..", // std::fs -> "foo2/" + "foo2/.///bar/.." // std::fs -> "foo3/" + ); + + REQUIRE(std::string_view(FHU::Filesystem::LexicallyNormal(Path)) == std::string_view(std::filesystem::path(Path).lexically_normal().string())); +} + +TEST_CASE("ParentPath") { + auto Path = GENERATE("", + "/", + "/./", + "//.", + "//./", + "//.//", + + ".", + "..", + ".//", + "../../", + "././", + "./../", + "./../", + "./.././.././.", + "./.././.././..", + + "./foo/../", + "foo/./bar/..", + "foo/.///bar/..", + "foo/.///bar/../", + "foo/././" + "...", + "/...", + "foo/...", + "/..", + "/foo/../../bar" + ); + + REQUIRE(std::string_view(FHU::Filesystem::ParentPath(Path)) == std::string_view(std::filesystem::path(Path).parent_path().string())); +} diff --git a/unittests/APITests/LexicallyNormal.cpp b/unittests/APITests/LexicallyNormal.cpp deleted file mode 100644 index 5ce4ed599..000000000 --- a/unittests/APITests/LexicallyNormal.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include - -#define TestPath(Path) \ - -TEST_CASE("LexicallyNormal") { - auto Path = GENERATE("", - "/", - "/./", - "//.", - "//./", - "//.//", - - ".", - "..", - ".//", - "../../", - "././", - "./../", - "./../", - "./.././.././.", - "./.././.././..", - - "./foo/../", - "foo/./bar/..", - "foo/.///bar/..", - "foo/.///bar/../"); - - REQUIRE(std::string_view(FHU::Filesystem::LexicallyNormal(Path)) == std::string_view(std::filesystem::path(Path).lexically_normal().string())); -} From 546a1edb551bf126ef4e98702cc47c9527a5ad9b Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Sat, 1 Apr 2023 09:27:01 -0700 Subject: [PATCH 41/41] CodeReview --- .../IR/Passes/RegisterAllocationPass.cpp | 11 +--------- .../FEXCore/Debug/InternalThreadState.h | 22 ++----------------- .../include/FEXCore/IR/IntrusiveIRList.h | 11 +--------- .../include/FEXCore/Utils/AllocatorHooks.h | 12 ++++++++++ .../FEXCore/Utils/ThreadPoolAllocator.h | 15 +++++-------- FEXHeaderUtils/FEXHeaderUtils/Filesystem.h | 7 ------ Source/Tests/LinuxSyscalls/SignalDelegator.h | 10 +-------- Source/Tests/LinuxSyscalls/Syscalls.h | 10 +-------- 8 files changed, 24 insertions(+), 74 deletions(-) diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index 6c1e1ae21..7fa145000 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -90,7 +90,7 @@ namespace { IR::OrderedNode *SpilledNode; }; - struct RegisterGraph { + struct RegisterGraph : public FEXCore::Allocator::FEXAllocOperators { IR::RegisterAllocationData::UniquePtr AllocData; RegisterSet Set; fextl::vector Nodes{}; @@ -98,15 +98,6 @@ namespace { fextl::vector SpillStack; fextl::unordered_map> BlockPredecessors; fextl::unordered_map> VisitedNodePredecessors; - - // Required due to raw new usage. - void *operator new(size_t size) { - return FEXCore::Allocator::malloc(size); - } - - void operator delete(void *ptr) { - return FEXCore::Allocator::free(ptr); - } }; void ResetRegisterGraph(RegisterGraph *Graph, uint64_t NodeCount); diff --git a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h index 47395bd7c..c5b2fdbe9 100644 --- a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h +++ b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h @@ -58,20 +58,11 @@ namespace FEXCore::Core { * * Needs to remain around for as long as the code could be executed at least */ - struct DebugData { + struct DebugData : public FEXCore::Allocator::FEXAllocOperators { uint64_t HostCodeSize; ///< The size of the code generated in the host JIT fextl::vector Subblocks; fextl::vector GuestOpcodes; fextl::vector *Relocations; - - // Required due to raw new usage. - void *operator new(size_t size) { - return FEXCore::Allocator::malloc(size); - } - - void operator delete(void *ptr) { - return FEXCore::Allocator::free(ptr); - } }; enum class SignalEvent { @@ -90,7 +81,7 @@ namespace FEXCore::Core { fextl::unique_ptr DebugData; }; - struct InternalThreadState { + struct InternalThreadState : public FEXCore::Allocator::FEXAllocOperators { FEXCore::Core::CpuStateFrame* const CurrentFrame = &BaseFrameState; struct { @@ -128,15 +119,6 @@ namespace FEXCore::Core { std::shared_mutex ObjectCacheRefCounter{}; bool DestroyedByParent{false}; // Should the parent destroy this thread, or it destory itself - // Required due to raw new usage. - void *operator new(size_t size) { - return FEXCore::Allocator::malloc(size); - } - - void operator delete(void *ptr) { - return FEXCore::Allocator::free(ptr); - } - alignas(16) FEXCore::Core::CpuStateFrame BaseFrameState{}; }; diff --git a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h index f9cc621a6..e2c46f299 100644 --- a/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h +++ b/External/FEXCore/include/FEXCore/IR/IntrusiveIRList.h @@ -120,7 +120,7 @@ class DualIntrusiveAllocatorThreadPool final : public DualIntrusiveAllocator { Utils::FixedSizePooledAllocation PoolObject; }; -class IRListView final { +class IRListView final : public FEXCore::Allocator::FEXAllocOperators { enum Flags { FLAG_IsCopy = 1, FLAG_Shared = 2, @@ -170,15 +170,6 @@ public: } } - // Required due to raw new usage. - void *operator new(size_t size) { - return FEXCore::Allocator::malloc(size); - } - - void operator delete(void *ptr) { - return FEXCore::Allocator::free(ptr); - } - void Serialize(std::ostream& stream) const { void *nul = nullptr; //void *IRDataInternal; diff --git a/External/FEXCore/include/FEXCore/Utils/AllocatorHooks.h b/External/FEXCore/include/FEXCore/Utils/AllocatorHooks.h index 57a2baeff..d8ef2974f 100644 --- a/External/FEXCore/include/FEXCore/Utils/AllocatorHooks.h +++ b/External/FEXCore/include/FEXCore/Utils/AllocatorHooks.h @@ -30,4 +30,16 @@ namespace FEXCore::Allocator { FEX_DEFAULT_VISIBILITY extern FREE_Hook free; FEX_DEFAULT_VISIBILITY extern MALLOC_USABLE_SIZE_Hook malloc_usable_size; FEX_DEFAULT_VISIBILITY extern ALIGNED_ALLOC_Hook aligned_alloc; + + struct FEXAllocOperators { + FEXAllocOperators() = default; + + void *operator new(size_t size) { + return FEXCore::Allocator::malloc(size); + } + + void operator delete(void *ptr) { + return FEXCore::Allocator::free(ptr); + } + }; } diff --git a/External/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h b/External/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h index 9e8f6c8d7..da9666b69 100644 --- a/External/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h +++ b/External/FEXCore/include/FEXCore/Utils/ThreadPoolAllocator.h @@ -63,19 +63,16 @@ namespace FEXCore::Utils { using BufferOwnedFlag = std::atomic; - struct MemoryBuffer { + struct MemoryBuffer : public FEXCore::Allocator::FEXAllocOperators { + MemoryBuffer(void* Ptr, size_t Size, std::chrono::time_point LastUsed) + : Ptr {Ptr} + , Size {Size} + , LastUsed {LastUsed} {} + void* Ptr; size_t Size; std::atomic> LastUsed; BufferOwnedFlag *CurrentClientOwnedFlag{}; - - void *operator new(size_t size) { - return FEXCore::Allocator::malloc(size); - } - - void operator delete(void *ptr) { - return FEXCore::Allocator::free(ptr); - } }; // Ensure that the atomic objects of MemoryBuffer are lock free static_assert(decltype(MemoryBuffer::LastUsed){}.is_always_lock_free, "Oops, needs to be lock free"); diff --git a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h index e22bc6b18..d249f0415 100644 --- a/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h +++ b/FEXHeaderUtils/FEXHeaderUtils/Filesystem.h @@ -222,8 +222,6 @@ namespace FHU::Filesystem { fextl::pmr::fixed_size_monotonic_buffer_resource mbr(Data, DataSize); std::pmr::polymorphic_allocator pa {&mbr}; std::pmr::list Parts{pa}; - // Calculate the expected string size while parsing to reduce allocations. - size_t ExpectedStringSize{}; size_t CurrentOffset{}; do { @@ -235,7 +233,6 @@ namespace FHU::Filesystem { const auto Begin = Path.begin() + CurrentOffset; const auto End = Path.begin() + FoundSeperator; const auto Size = End - Begin; - ExpectedStringSize += Size; // Only insert parts that contain data. if (Size != 0) { @@ -258,7 +255,6 @@ namespace FHU::Filesystem { if (CurrentIterDistance > 0 || IsAbsolutePath) { // Erasing this iterator, don't increase iter distances iter = Parts.erase(iter); - --ExpectedStringSize; continue; } } @@ -275,14 +271,12 @@ namespace FHU::Filesystem { if (*PreviousIter == ".") { // Erasing the previous iterator, iterator distance has subtracted by one --CurrentIterDistance; - ExpectedStringSize -= PreviousIter->size(); Parts.erase(PreviousIter); } else if (*PreviousIter != "..") { // Erasing the previous iterator, iterator distance has subtracted by one // Also erasing current iterator, which means iterator distance also doesn't increase by one. --CurrentIterDistance; - ExpectedStringSize -= PreviousIter->size() + 2; Parts.erase(PreviousIter); iter = Parts.erase(iter); continue; @@ -290,7 +284,6 @@ namespace FHU::Filesystem { } else if (IsAbsolutePath) { // `..` at the base. Just remove this - ExpectedStringSize -= 2; iter = Parts.erase(iter); continue; } diff --git a/Source/Tests/LinuxSyscalls/SignalDelegator.h b/Source/Tests/LinuxSyscalls/SignalDelegator.h index 8c20b2dcc..eca37be08 100644 --- a/Source/Tests/LinuxSyscalls/SignalDelegator.h +++ b/Source/Tests/LinuxSyscalls/SignalDelegator.h @@ -23,16 +23,8 @@ namespace Core { } namespace FEX::HLE { - class SignalDelegator final : public FEXCore::SignalDelegator { + class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::Allocator::FEXAllocOperators { public: - void *operator new(size_t size) { - return FEXCore::Allocator::malloc(size); - } - - void operator delete(void *ptr) { - return FEXCore::Allocator::free(ptr); - } - // Returns true if the host handled the signal // Arguments are the same as sigaction handler SignalDelegator(); diff --git a/Source/Tests/LinuxSyscalls/Syscalls.h b/Source/Tests/LinuxSyscalls/Syscalls.h index 3b2181891..c09d6bbf1 100644 --- a/Source/Tests/LinuxSyscalls/Syscalls.h +++ b/Source/Tests/LinuxSyscalls/Syscalls.h @@ -93,16 +93,8 @@ struct ExecveAtArgs { uint64_t ExecveHandler(const char *pathname, char* const* argv, char* const* envp, ExecveAtArgs Args); -class SyscallHandler : public FEXCore::HLE::SyscallHandler, FEXCore::HLE::SourcecodeResolver { +class SyscallHandler : public FEXCore::HLE::SyscallHandler, FEXCore::HLE::SourcecodeResolver, public FEXCore::Allocator::FEXAllocOperators { public: - void *operator new(size_t size) { - return FEXCore::Allocator::malloc(size); - } - - void operator delete(void *ptr) { - return FEXCore::Allocator::free(ptr); - } - virtual ~SyscallHandler(); // In the case that the syscall doesn't hit the optimized path then we still need to go here