/ src / Ryujinx.Cpu / Signal / UnixSignalHandlerRegistration.cs
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  }