UnixSignalHandlerRegistration.cs
1 using System; 2 using System.Runtime.InteropServices; 3 4 namespace Ryujinx.Cpu.Signal 5 { 6 static partial class UnixSignalHandlerRegistration 7 { 8 [StructLayout(LayoutKind.Sequential, Pack = 1)] 9 public unsafe struct SigSet 10 { 11 fixed long sa_mask[16]; 12 } 13 14 [StructLayout(LayoutKind.Sequential, Pack = 1)] 15 public struct SigAction 16 { 17 public IntPtr sa_handler; 18 public SigSet sa_mask; 19 public int sa_flags; 20 public IntPtr sa_restorer; 21 } 22 23 private const int SIGSEGV = 11; 24 private const int SIGBUS = 10; 25 private const int SA_SIGINFO = 0x00000004; 26 27 [LibraryImport("libc", SetLastError = true)] 28 private static partial int sigaction(int signum, ref SigAction sigAction, out SigAction oldAction); 29 30 [LibraryImport("libc", SetLastError = true)] 31 private static partial int sigaction(int signum, IntPtr sigAction, out SigAction oldAction); 32 33 [LibraryImport("libc", SetLastError = true)] 34 private static partial int sigemptyset(ref SigSet set); 35 36 public static SigAction GetSegfaultExceptionHandler() 37 { 38 int result = sigaction(SIGSEGV, IntPtr.Zero, out SigAction old); 39 40 if (result != 0) 41 { 42 throw new InvalidOperationException($"Could not get SIGSEGV sigaction. Error: {result}"); 43 } 44 45 return old; 46 } 47 48 public static SigAction RegisterExceptionHandler(IntPtr action) 49 { 50 SigAction sig = new() 51 { 52 sa_handler = action, 53 sa_flags = SA_SIGINFO, 54 }; 55 56 sigemptyset(ref sig.sa_mask); 57 58 int result = sigaction(SIGSEGV, ref sig, out SigAction old); 59 60 if (result != 0) 61 { 62 throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}"); 63 } 64 65 if (OperatingSystem.IsMacOS()) 66 { 67 result = sigaction(SIGBUS, ref sig, out _); 68 69 if (result != 0) 70 { 71 throw new InvalidOperationException($"Could not register SIGBUS sigaction. Error: {result}"); 72 } 73 } 74 75 return old; 76 } 77 78 public static bool RestoreExceptionHandler(SigAction oldAction) 79 { 80 return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0 && (!OperatingSystem.IsMacOS() || sigaction(SIGBUS, ref oldAction, out SigAction _) == 0); 81 } 82 } 83 }