e777e3f93b
- downgrade unicorn to last working version
- update to new cp reg struct system
- remove nonexistent register (used to silently continue)
- fix partial unmap tests
- InitializeSignalHandler() was moved out of the translator (almost 2.5 years ago), but the test code was never updated to manually call the function as it was changed to do in the real cpu context, so the tests just started failing.
- by manually initializing the handler we no longer cause tests to fail.
Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/140
186 lines
5.9 KiB
C#
186 lines
5.9 KiB
C#
using ARMeilleure.Signal;
|
|
using Ryujinx.Common;
|
|
using Ryujinx.Memory;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
|
|
namespace Ryujinx.Cpu.Signal
|
|
{
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
struct SignalHandlerRange
|
|
{
|
|
public int IsActive;
|
|
public nuint RangeAddress;
|
|
public nuint RangeEndAddress;
|
|
public nint ActionPointer;
|
|
}
|
|
|
|
[InlineArray(NativeSignalHandlerGenerator.MaxTrackedRanges)]
|
|
struct SignalHandlerRangeArray
|
|
{
|
|
public SignalHandlerRange Range0;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
struct SignalHandlerConfig
|
|
{
|
|
/// <summary>
|
|
/// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct.
|
|
/// </summary>
|
|
public int StructAddressOffset;
|
|
|
|
/// <summary>
|
|
/// The byte offset of the write flag in the SigInfo or ExceptionRecord struct.
|
|
/// </summary>
|
|
public int StructWriteOffset;
|
|
|
|
/// <summary>
|
|
/// The sigaction handler that was registered before this one. (unix only)
|
|
/// </summary>
|
|
public nuint UnixOldSigaction;
|
|
|
|
/// <summary>
|
|
/// The type of the previous sigaction. True for the 3 argument variant. (unix only)
|
|
/// </summary>
|
|
public int UnixOldSigaction3Arg;
|
|
|
|
/// <summary>
|
|
/// Fixed size array of tracked ranges.
|
|
/// </summary>
|
|
public SignalHandlerRangeArray Ranges;
|
|
}
|
|
|
|
public static class NativeSignalHandler
|
|
{
|
|
private static readonly nint _handlerConfig;
|
|
private static nint _signalHandlerPtr;
|
|
|
|
private static MemoryBlock _codeBlock;
|
|
|
|
private static readonly Lock _lock = new();
|
|
private static bool _initialized;
|
|
|
|
static NativeSignalHandler()
|
|
{
|
|
_handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf<SignalHandlerConfig>());
|
|
ref SignalHandlerConfig config = ref GetConfigRef();
|
|
|
|
config = new SignalHandlerConfig();
|
|
}
|
|
|
|
public static void InitializeSignalHandler(Func<nint, nint, nint> customSignalHandlerFactory = null)
|
|
{
|
|
if (_initialized)
|
|
{
|
|
return;
|
|
}
|
|
|
|
lock (_lock)
|
|
{
|
|
if (_initialized)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int rangeStructSize = Unsafe.SizeOf<SignalHandlerRange>();
|
|
|
|
ref SignalHandlerConfig config = ref GetConfigRef();
|
|
|
|
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
|
{
|
|
_signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateUnixSignalHandler(_handlerConfig, rangeStructSize));
|
|
|
|
if (customSignalHandlerFactory != null)
|
|
{
|
|
_signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr);
|
|
}
|
|
|
|
UnixSignalHandlerRegistration.SigAction old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
|
|
|
|
config.UnixOldSigaction = (nuint)(ulong)old.sa_handler;
|
|
config.UnixOldSigaction3Arg = old.sa_flags & 4;
|
|
}
|
|
else
|
|
{
|
|
config.StructAddressOffset = 40; // ExceptionInformation1
|
|
config.StructWriteOffset = 32; // ExceptionInformation0
|
|
|
|
_signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateWindowsSignalHandler(_handlerConfig, rangeStructSize));
|
|
|
|
if (customSignalHandlerFactory != null)
|
|
{
|
|
_signalHandlerPtr = customSignalHandlerFactory(nint.Zero, _signalHandlerPtr);
|
|
}
|
|
|
|
WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
|
|
}
|
|
|
|
_initialized = true;
|
|
}
|
|
}
|
|
|
|
private static nint MapCode(ReadOnlySpan<byte> code)
|
|
{
|
|
Debug.Assert(_codeBlock == null);
|
|
|
|
ulong codeSizeAligned = BitUtils.AlignUp((ulong)code.Length, MemoryBlock.GetPageSize());
|
|
|
|
_codeBlock = new MemoryBlock(codeSizeAligned);
|
|
_codeBlock.Write(0, code);
|
|
_codeBlock.Reprotect(0, codeSizeAligned, MemoryPermission.ReadAndExecute);
|
|
|
|
return _codeBlock.Pointer;
|
|
}
|
|
|
|
private static unsafe ref SignalHandlerConfig GetConfigRef()
|
|
{
|
|
return ref Unsafe.AsRef<SignalHandlerConfig>((void*)_handlerConfig);
|
|
}
|
|
|
|
public static bool AddTrackedRegion(nuint address, nuint endAddress, nint action)
|
|
{
|
|
Span<SignalHandlerRange> ranges = GetConfigRef().Ranges;
|
|
|
|
for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++)
|
|
{
|
|
if (ranges[i].IsActive == 0)
|
|
{
|
|
ranges[i].RangeAddress = address;
|
|
ranges[i].RangeEndAddress = endAddress;
|
|
ranges[i].ActionPointer = action;
|
|
ranges[i].IsActive = 1;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static bool RemoveTrackedRegion(nuint address)
|
|
{
|
|
Span<SignalHandlerRange> ranges = GetConfigRef().Ranges;
|
|
|
|
for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++)
|
|
{
|
|
if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address)
|
|
{
|
|
ranges[i].IsActive = 0;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static bool SupportsFaultAddressPatching()
|
|
{
|
|
return NativeSignalHandlerGenerator.SupportsFaultAddressPatchingForHost();
|
|
}
|
|
}
|
|
}
|