From b7d08e5050da31304541c2d5bf6158fbcfe87c6d Mon Sep 17 00:00:00 2001 From: Mary Date: Mon, 8 May 2023 15:52:14 +0200 Subject: [PATCH] armeilleure: Add Android signal handler --- .../Signal/NativeSignalHandlerGenerator.cs | 2 +- src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs | 8 +- .../Signal/UnixSignalHandlerRegistration.cs | 130 ++++++++++++++++-- 3 files changed, 123 insertions(+), 17 deletions(-) diff --git a/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs index c5e708e16..838448bd9 100644 --- a/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs +++ b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs @@ -111,7 +111,7 @@ namespace ARMeilleure.Signal return context.BitwiseAnd(err, Const(2ul)); } } - else if (OperatingSystem.IsLinux()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsAndroid()) { if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) { diff --git a/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs index 5a9d92cc4..15d404554 100644 --- a/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs +++ b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs @@ -88,10 +88,16 @@ namespace Ryujinx.Cpu.Signal ref SignalHandlerConfig config = ref GetConfigRef(); - if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsAndroid()) { _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateUnixSignalHandler(_handlerConfig, rangeStructSize, pageSize)); + if (OperatingSystem.IsAndroid()) + { + config.StructAddressOffset = 16; // si_addr + config.StructWriteOffset = 8; // si_code + } + if (customSignalHandlerFactory != null) { _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr); diff --git a/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs index e88a6c0f6..065558d27 100644 --- a/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs +++ b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.Runtime.Versioning; namespace Ryujinx.Cpu.Signal { @@ -20,6 +21,16 @@ namespace Ryujinx.Cpu.Signal public IntPtr sa_restorer; } + [SupportedOSPlatform("android")] + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct SigActionBionic + { + public int sa_flags; + public IntPtr sa_handler; + public SigSet sa_mask; + public IntPtr sa_restorer; + } + private const int SIGSEGV = 11; private const int SIGBUS = 10; private const int SA_SIGINFO = 0x00000004; @@ -27,15 +38,41 @@ namespace Ryujinx.Cpu.Signal [LibraryImport("libc", SetLastError = true)] private static partial int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction); + [SupportedOSPlatform("android")] + [LibraryImport("libc", SetLastError = true)] + private static partial int sigaction(int signum, ref SigActionBionic sigAction, out SigActionBionic oldAction); + [LibraryImport("libc", SetLastError = true)] private static partial int sigaction(int signum, IntPtr sigAction, out SigAction oldAction); + [SupportedOSPlatform("android")] + [LibraryImport("libc", SetLastError = true)] + private static partial int sigaction(int signum, IntPtr sigAction, out SigActionBionic oldAction); + [LibraryImport("libc", SetLastError = true)] private static partial int sigemptyset(ref SigSet set); public static SigAction GetSegfaultExceptionHandler() { - int result = sigaction(SIGSEGV, IntPtr.Zero, out SigAction old); + int result; + SigAction old; + + if (OperatingSystem.IsAndroid()) + { + result = sigaction(SIGSEGV, IntPtr.Zero, out SigActionBionic tmp); + + old = new SigAction + { + sa_handler = tmp.sa_handler, + sa_mask = tmp.sa_mask, + sa_flags = tmp.sa_flags, + sa_restorer = tmp.sa_restorer + }; + } + else + { + result = sigaction(SIGSEGV, IntPtr.Zero, out old); + } if (result != 0) { @@ -47,28 +84,69 @@ namespace Ryujinx.Cpu.Signal public static SigAction RegisterExceptionHandler(IntPtr action) { - SigAction sig = new() + int result; + SigAction old; + + if (Ryujinx.Common.SystemInfo.SystemInfo.IsAndroid()) { - sa_handler = action, - sa_flags = SA_SIGINFO, - }; + SigActionBionic sig = new() + { + sa_handler = action, + sa_flags = SA_SIGINFO + }; - sigemptyset(ref sig.sa_mask); + sigemptyset(ref sig.sa_mask); - int result = sigaction(SIGSEGV, ref sig, out SigAction old); + result = sigaction(SIGSEGV, ref sig, out SigActionBionic tmp); - if (result != 0) - { - throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}"); + old = new SigAction + { + sa_handler = tmp.sa_handler, + sa_mask = tmp.sa_mask, + sa_flags = tmp.sa_flags, + sa_restorer = tmp.sa_restorer + }; + + if (userSignal != -1) + { + result = sigaction(userSignal, ref sig, out SigActionBionic oldu); + + if (oldu.sa_handler != IntPtr.Zero) + { + throw new InvalidOperationException($"SIG{userSignal} is already in use."); + } + + if (result != 0) + { + throw new InvalidOperationException($"Could not register SIG{userSignal} sigaction. Error: {result}"); + } + } } - - if (OperatingSystem.IsMacOS()) + else { - result = sigaction(SIGBUS, ref sig, out _); + SigAction sig = new SigAction + { + sa_handler = action, + sa_flags = SA_SIGINFO + }; + + sigemptyset(ref sig.sa_mask); + + result = sigaction(SIGSEGV, ref sig, out old); if (result != 0) { - throw new InvalidOperationException($"Could not register SIGBUS sigaction. Error: {result}"); + throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}"); + } + + if (OperatingSystem.IsMacOS()) + { + result = sigaction(SIGBUS, ref sig, out _); + + if (result != 0) + { + throw new InvalidOperationException($"Could not register SIGBUS sigaction. Error: {result}"); + } } } @@ -77,7 +155,29 @@ namespace Ryujinx.Cpu.Signal public static bool RestoreExceptionHandler(SigAction oldAction) { - return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0 && (!OperatingSystem.IsMacOS() || sigaction(SIGBUS, ref oldAction, out SigAction _) == 0); + if (OperatingSystem.IsAndroid()) + { + SigActionBionic tmp = new SigActionBionic + { + sa_handler = oldAction.sa_handler, + sa_mask = oldAction.sa_mask, + sa_flags = oldAction.sa_flags, + sa_restorer = oldAction.sa_restorer + }; + + return sigaction(SIGSEGV, ref tmp, out SigActionBionic _) == 0; + } + else + { + bool success = sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0; + + if (success && OperatingSystem.IsMacOS()) + { + success = sigaction(SIGBUS, ref oldAction, out SigAction _) == 0; + } + + return success; + } } } }