|
|
@@ -1,63 +1,14 @@
|
|
|
using ARMeilleure.IntermediateRepresentation;
|
|
|
-using ARMeilleure.Memory;
|
|
|
using ARMeilleure.Translation;
|
|
|
-using ARMeilleure.Translation.Cache;
|
|
|
using System;
|
|
|
-using System.Runtime.CompilerServices;
|
|
|
using System.Runtime.InteropServices;
|
|
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
|
|
|
|
|
namespace ARMeilleure.Signal
|
|
|
{
|
|
|
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
|
- struct SignalHandlerRange
|
|
|
+ public static class NativeSignalHandlerGenerator
|
|
|
{
|
|
|
- public int IsActive;
|
|
|
- public nuint RangeAddress;
|
|
|
- public nuint RangeEndAddress;
|
|
|
- public IntPtr ActionPointer;
|
|
|
- }
|
|
|
-
|
|
|
- [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;
|
|
|
-
|
|
|
- public SignalHandlerRange Range0;
|
|
|
- public SignalHandlerRange Range1;
|
|
|
- public SignalHandlerRange Range2;
|
|
|
- public SignalHandlerRange Range3;
|
|
|
- public SignalHandlerRange Range4;
|
|
|
- public SignalHandlerRange Range5;
|
|
|
- public SignalHandlerRange Range6;
|
|
|
- public SignalHandlerRange Range7;
|
|
|
- }
|
|
|
-
|
|
|
- public static class NativeSignalHandler
|
|
|
- {
|
|
|
- private delegate void UnixExceptionHandler(int sig, IntPtr info, IntPtr ucontext);
|
|
|
- [UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
|
|
- private delegate int VectoredExceptionHandler(IntPtr exceptionInfo);
|
|
|
-
|
|
|
- private const int MaxTrackedRanges = 8;
|
|
|
+ public const int MaxTrackedRanges = 8;
|
|
|
|
|
|
private const int StructAddressOffset = 0;
|
|
|
private const int StructWriteOffset = 4;
|
|
|
@@ -70,125 +21,10 @@ namespace ARMeilleure.Signal
|
|
|
|
|
|
private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
|
|
|
|
|
|
- private static ulong _pageSize;
|
|
|
- private static ulong _pageMask;
|
|
|
-
|
|
|
- private static readonly IntPtr _handlerConfig;
|
|
|
- private static IntPtr _signalHandlerPtr;
|
|
|
- private static IntPtr _signalHandlerHandle;
|
|
|
-
|
|
|
- private static readonly object _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 Initialize(IJitMemoryAllocator allocator)
|
|
|
- {
|
|
|
- JitCache.Initialize(allocator);
|
|
|
- }
|
|
|
-
|
|
|
- public static void InitializeSignalHandler(ulong pageSize, Func<IntPtr, IntPtr, IntPtr> customSignalHandlerFactory = null)
|
|
|
+ private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize, ulong pageSize)
|
|
|
{
|
|
|
- if (_initialized)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- lock (_lock)
|
|
|
- {
|
|
|
- if (_initialized)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- _pageSize = pageSize;
|
|
|
- _pageMask = pageSize - 1;
|
|
|
-
|
|
|
- ref SignalHandlerConfig config = ref GetConfigRef();
|
|
|
-
|
|
|
- if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
|
|
- {
|
|
|
- _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig));
|
|
|
-
|
|
|
- if (customSignalHandlerFactory != null)
|
|
|
- {
|
|
|
- _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr);
|
|
|
- }
|
|
|
-
|
|
|
- var 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 = Marshal.GetFunctionPointerForDelegate(GenerateWindowsSignalHandler(_handlerConfig));
|
|
|
-
|
|
|
- if (customSignalHandlerFactory != null)
|
|
|
- {
|
|
|
- _signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr);
|
|
|
- }
|
|
|
+ ulong pageMask = pageSize - 1;
|
|
|
|
|
|
- _signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
|
|
|
- }
|
|
|
-
|
|
|
- _initialized = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private static unsafe ref SignalHandlerConfig GetConfigRef()
|
|
|
- {
|
|
|
- return ref Unsafe.AsRef<SignalHandlerConfig>((void*)_handlerConfig);
|
|
|
- }
|
|
|
-
|
|
|
- public static unsafe bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action)
|
|
|
- {
|
|
|
- var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0;
|
|
|
-
|
|
|
- for (int i = 0; i < 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 unsafe bool RemoveTrackedRegion(nuint address)
|
|
|
- {
|
|
|
- var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0;
|
|
|
-
|
|
|
- for (int i = 0; i < MaxTrackedRanges; i++)
|
|
|
- {
|
|
|
- if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address)
|
|
|
- {
|
|
|
- ranges[i].IsActive = 0;
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite)
|
|
|
- {
|
|
|
Operand inRegionLocal = context.AllocateLocal(OperandType.I32);
|
|
|
context.Copy(inRegionLocal, Const(0));
|
|
|
|
|
|
@@ -196,7 +32,7 @@ namespace ARMeilleure.Signal
|
|
|
|
|
|
for (int i = 0; i < MaxTrackedRanges; i++)
|
|
|
{
|
|
|
- ulong rangeBaseOffset = (ulong)(RangeOffset + i * Unsafe.SizeOf<SignalHandlerRange>());
|
|
|
+ ulong rangeBaseOffset = (ulong)(RangeOffset + i * rangeStructSize);
|
|
|
|
|
|
Operand nextLabel = Label();
|
|
|
|
|
|
@@ -210,13 +46,12 @@ namespace ARMeilleure.Signal
|
|
|
// Is the fault address within this tracked region?
|
|
|
Operand inRange = context.BitwiseAnd(
|
|
|
context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI),
|
|
|
- context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI)
|
|
|
- );
|
|
|
+ context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI));
|
|
|
|
|
|
// Only call tracking if in range.
|
|
|
context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold);
|
|
|
|
|
|
- Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~_pageMask));
|
|
|
+ Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~pageMask));
|
|
|
|
|
|
// Call the tracking action, with the pointer's relative offset to the base address.
|
|
|
Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20));
|
|
|
@@ -227,7 +62,7 @@ namespace ARMeilleure.Signal
|
|
|
|
|
|
// Tracking action should be non-null to call it, otherwise assume false return.
|
|
|
context.BranchIfFalse(skipActionLabel, trackingActionPtr);
|
|
|
- Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(_pageSize), isWrite);
|
|
|
+ Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(pageSize), isWrite);
|
|
|
context.Copy(inRegionLocal, result);
|
|
|
|
|
|
context.MarkLabel(skipActionLabel);
|
|
|
@@ -269,8 +104,7 @@ namespace ARMeilleure.Signal
|
|
|
Operand esr = context.Load(OperandType.I64, context.Add(ctxPtr, Const(EsrOffset)));
|
|
|
return context.BitwiseAnd(esr, Const(0x40ul));
|
|
|
}
|
|
|
-
|
|
|
- if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
|
|
+ else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
|
|
{
|
|
|
const ulong ErrOffset = 4; // __es.__err
|
|
|
Operand err = context.Load(OperandType.I64, context.Add(ctxPtr, Const(ErrOffset)));
|
|
|
@@ -310,8 +144,7 @@ namespace ARMeilleure.Signal
|
|
|
Operand esr = context.Load(OperandType.I64, context.Add(auxPtr, Const(8ul)));
|
|
|
return context.BitwiseAnd(esr, Const(0x40ul));
|
|
|
}
|
|
|
-
|
|
|
- if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
|
|
+ else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
|
|
|
{
|
|
|
const int ErrOffset = 192; // uc_mcontext.gregs[REG_ERR]
|
|
|
Operand err = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(ErrOffset)));
|
|
|
@@ -322,7 +155,7 @@ namespace ARMeilleure.Signal
|
|
|
throw new PlatformNotSupportedException();
|
|
|
}
|
|
|
|
|
|
- private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr)
|
|
|
+ public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
|
|
|
{
|
|
|
EmitterContext context = new();
|
|
|
|
|
|
@@ -335,7 +168,7 @@ namespace ARMeilleure.Signal
|
|
|
|
|
|
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
|
|
|
|
|
|
- Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite);
|
|
|
+ Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
|
|
|
|
|
|
Operand endLabel = Label();
|
|
|
|
|
|
@@ -367,10 +200,10 @@ namespace ARMeilleure.Signal
|
|
|
|
|
|
OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 };
|
|
|
|
|
|
- return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<UnixExceptionHandler>();
|
|
|
+ return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
|
|
|
}
|
|
|
|
|
|
- private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr)
|
|
|
+ public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
|
|
|
{
|
|
|
EmitterContext context = new();
|
|
|
|
|
|
@@ -399,7 +232,7 @@ namespace ARMeilleure.Signal
|
|
|
|
|
|
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
|
|
|
|
|
|
- Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite);
|
|
|
+ Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
|
|
|
|
|
|
Operand endLabel = Label();
|
|
|
|
|
|
@@ -421,7 +254,7 @@ namespace ARMeilleure.Signal
|
|
|
|
|
|
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
|
|
|
|
|
- return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<VectoredExceptionHandler>();
|
|
|
+ return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
|
|
|
}
|
|
|
}
|
|
|
}
|