diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e216eb3dee..7107f4f789 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -166,6 +166,13 @@ if (WIN32) target_link_libraries(common PRIVATE ntdll) endif() +if (NOT WIN32) + target_sources(common PRIVATE + signal_chain.cpp + signal_chain.h + ) +endif() + if(ANDROID) target_sources(common PRIVATE diff --git a/src/common/signal_chain.cpp b/src/common/signal_chain.cpp new file mode 100644 index 0000000000..e0c6b9d4e3 --- /dev/null +++ b/src/common/signal_chain.cpp @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "common/assert.h" +#include "common/dynamic_library.h" +#include "common/scope_exit.h" +#include "common/signal_chain.h" + +namespace Common { + +template +T* LookupLibcSymbol(const char* name) { +#if defined(__BIONIC__) + Common::DynamicLibrary provider("libc.so"); + if (!provider.IsOpen()) { + UNREACHABLE_MSG("Failed to open libc!"); + } +#else + // For other operating environments, we assume the symbol is not overriden. + const char* base = nullptr; + Common::DynamicLibrary provider(base); +#endif + + void* sym = provider.GetSymbolAddress(name); + if (sym == nullptr) { + sym = dlsym(RTLD_DEFAULT, name); + } + if (sym == nullptr) { + UNREACHABLE_MSG("Unable to find symbol {}!", name); + } + + return reinterpret_cast(sym); +} + +int SigAction(int signum, const struct sigaction* act, struct sigaction* oldact) { + static auto libc_sigaction = LookupLibcSymbol("sigaction"); + return libc_sigaction(signum, act, oldact); +} + +} // namespace Common diff --git a/src/common/signal_chain.h b/src/common/signal_chain.h new file mode 100644 index 0000000000..e3bfe68826 --- /dev/null +++ b/src/common/signal_chain.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifndef _WIN32 + +#include + +namespace Common { + +// Android's ART overrides sigaction with its own wrapper. This is problematic for SIGSEGV +// in particular, because ARTs handler access TPIDR_EL0, so this extracts the libc version +// and calls it directly. +int SigAction(int signum, const struct sigaction* act, struct sigaction* oldact); + +} // namespace Common + +#endif