diff --git a/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h b/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h index 7fac1d8e0..ad18d6765 100644 --- a/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h +++ b/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,13 @@ public: class const_iterator final { public: + // libstdc++'s algorithms need these. Input, not forward, because operator* returns a copy. + using iterator_category = std::input_iterator_tag; + using value_type = OwnerT; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = OwnerT; + [[nodiscard]] OwnerT operator*() const noexcept { return m_owners->At(m_index); } const_iterator& operator++() noexcept { ++m_index; diff --git a/tests/ImagePageTableTests.cpp b/tests/ImagePageTableTests.cpp index 44f82745a..435ae7bbc 100644 --- a/tests/ImagePageTableTests.cpp +++ b/tests/ImagePageTableTests.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -13,6 +15,11 @@ using Table = Libs::Graphics::MultiLevelPageTable; using PageOwners = Libs::Graphics::InlinePageOwnerList; using OwnerTable = Libs::Graphics::MultiLevelPageTable; +// MSVC's STL and libc++ don't need these traits for std::any_of, but libstdc++ does, so only a +// Linux build would notice them missing. +static_assert(std::is_same_v::iterator_category, + std::input_iterator_tag>); + void Check(bool value, const char* text) { if (!value) { std::fprintf(stderr, "ImagePageTableTests: failed: %s\n", text); diff --git a/tests/SrtWalkerTestMemory.h b/tests/SrtWalkerTestMemory.h index b792237d4..443256bc6 100644 --- a/tests/SrtWalkerTestMemory.h +++ b/tests/SrtWalkerTestMemory.h @@ -6,12 +6,16 @@ #include #include +#include #include +#include #include #include #if defined(__linux__) #include +#elif defined(__APPLE__) +#include #elif defined(_WIN32) #include #endif @@ -23,18 +27,20 @@ public: explicit FakeGuestMemory(Libs::Graphics::ShaderRecompiler::IR::SrtMemoryReader reader = nullptr, void *userdata = nullptr) { Current() = {reader, userdata}; -#if defined(__linux__) +#if defined(__linux__) || defined(__APPLE__) struct sigaction action {}; action.sa_sigaction = Handle; action.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &action, &m_previous); + for (size_t index = 0; index < std::size(kSignals); ++index) + sigaction(kSignals[index], &action, &m_previous[index]); #elif defined(_WIN32) m_handler = AddVectoredExceptionHandler(1, Handle); #endif } ~FakeGuestMemory() { -#if defined(__linux__) - sigaction(SIGSEGV, &m_previous, nullptr); +#if defined(__linux__) || defined(__APPLE__) + for (size_t index = 0; index < std::size(kSignals); ++index) + sigaction(kSignals[index], &m_previous[index], nullptr); #elif defined(_WIN32) RemoveVectoredExceptionHandler(m_handler); #endif @@ -54,16 +60,30 @@ private: const auto [reader, userdata] = Current(); return reader != nullptr && reader(userdata, address, {&word, 1}) ? word : 0u; } -#if defined(__linux__) +#if defined(__linux__) || defined(__APPLE__) +#if defined(__APPLE__) + // macOS raises SIGBUS for some protection faults and SIGSEGV for others. + static constexpr int kSignals[] = {SIGSEGV, SIGBUS}; +#else + static constexpr int kSignals[] = {SIGSEGV}; +#endif static void Handle(int, siginfo_t *, void *context) { - auto ®isters = static_cast(context)->uc_mcontext.gregs; - const auto length = - Libs::Graphics::ShaderRecompiler::IR::SrtWalkerLoadLength(registers[REG_RIP]); + auto *native = static_cast(context); +#if defined(__APPLE__) + auto &rip = native->uc_mcontext->__ss.__rip; + auto &rax = native->uc_mcontext->__ss.__rax; + const auto r10 = native->uc_mcontext->__ss.__r10; +#else + auto &rip = native->uc_mcontext.gregs[REG_RIP]; + auto &rax = native->uc_mcontext.gregs[REG_RAX]; + const auto r10 = native->uc_mcontext.gregs[REG_R10]; +#endif + const auto length = Libs::Graphics::ShaderRecompiler::IR::SrtWalkerLoadLength(rip); if (length == 0) std::abort(); - registers[REG_RAX] = Read(registers[REG_R10]); - registers[REG_RIP] += length; + rax = Read(r10); + rip += length; } - struct sigaction m_previous {}; + struct sigaction m_previous[std::size(kSignals)] {}; #elif defined(_WIN32) static LONG CALLBACK Handle(EXCEPTION_POINTERS *info) { auto &context = *info->ContextRecord;