From 20011dfeb8d1fa00a862e9b31ce10ceca8015fa2 Mon Sep 17 00:00:00 2001
From: GPUCode <geoster3d@gmail.com>
Date: Fri, 17 Nov 2023 20:22:38 +0200
Subject: [PATCH] common: Add libc sigaction hook

---
 src/common/CMakeLists.txt   |  7 +++++++
 src/common/signal_chain.cpp | 42 +++++++++++++++++++++++++++++++++++++
 src/common/signal_chain.h   | 19 +++++++++++++++++
 3 files changed, 68 insertions(+)
 create mode 100644 src/common/signal_chain.cpp
 create mode 100644 src/common/signal_chain.h

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 <dlfcn.h>
+
+#include "common/assert.h"
+#include "common/dynamic_library.h"
+#include "common/scope_exit.h"
+#include "common/signal_chain.h"
+
+namespace Common {
+
+template <typename T>
+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<T*>(sym);
+}
+
+int SigAction(int signum, const struct sigaction* act, struct sigaction* oldact) {
+    static auto libc_sigaction = LookupLibcSymbol<decltype(sigaction)>("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 <signal.h>
+
+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