aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Translation/JitUnwindWindows.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/Translation/JitUnwindWindows.cs')
-rw-r--r--ARMeilleure/Translation/JitUnwindWindows.cs164
1 files changed, 164 insertions, 0 deletions
diff --git a/ARMeilleure/Translation/JitUnwindWindows.cs b/ARMeilleure/Translation/JitUnwindWindows.cs
new file mode 100644
index 00000000..108dc2c5
--- /dev/null
+++ b/ARMeilleure/Translation/JitUnwindWindows.cs
@@ -0,0 +1,164 @@
+using ARMeilleure.IntermediateRepresentation;
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Translation
+{
+ static class JitUnwindWindows
+ {
+ private const int MaxUnwindCodesArraySize = 9 + 10 * 2 + 3;
+
+ private struct RuntimeFunction
+ {
+ public uint BeginAddress;
+ public uint EndAddress;
+ public uint UnwindData;
+ }
+
+ private struct UnwindInfo
+ {
+ public byte VersionAndFlags;
+ public byte SizeOfProlog;
+ public byte CountOfUnwindCodes;
+ public byte FrameRegister;
+ public unsafe fixed ushort UnwindCodes[MaxUnwindCodesArraySize];
+ }
+
+ private enum UnwindOperation
+ {
+ PushNonvol = 0,
+ AllocLarge = 1,
+ AllocSmall = 2,
+ SetFpreg = 3,
+ SaveNonvol = 4,
+ SaveNonvolFar = 5,
+ SaveXmm128 = 8,
+ SaveXmm128Far = 9,
+ PushMachframe = 10
+ }
+
+ private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, IntPtr context);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
+ private static unsafe extern bool RtlInstallFunctionTableCallback(
+ ulong tableIdentifier,
+ ulong baseAddress,
+ uint length,
+ GetRuntimeFunctionCallback callback,
+ IntPtr context,
+ string outOfProcessCallbackDll);
+
+ private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
+
+ private static int _sizeOfRuntimeFunction;
+
+ private unsafe static RuntimeFunction* _runtimeFunction;
+
+ private unsafe static UnwindInfo* _unwindInfo;
+
+ public static void InstallFunctionTableHandler(IntPtr codeCachePointer, uint codeCacheLength)
+ {
+ ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
+
+ _sizeOfRuntimeFunction = Marshal.SizeOf<RuntimeFunction>();
+
+ bool result;
+
+ unsafe
+ {
+ _runtimeFunction = (RuntimeFunction*)codeCachePointer;
+
+ _unwindInfo = (UnwindInfo*)(codeCachePointer + _sizeOfRuntimeFunction);
+
+ _getRuntimeFunctionCallback = new GetRuntimeFunctionCallback(FunctionTableHandler);
+
+ result = RtlInstallFunctionTableCallback(
+ codeCachePtr | 3,
+ codeCachePtr,
+ codeCacheLength,
+ _getRuntimeFunctionCallback,
+ codeCachePointer,
+ null);
+ }
+
+ if (!result)
+ {
+ throw new InvalidOperationException("Failure installing function table callback.");
+ }
+ }
+
+ private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, IntPtr context)
+ {
+ int offset = (int)((long)controlPc - context.ToInt64());
+
+ if (!JitCache.TryFind(offset, out JitCacheEntry funcEntry))
+ {
+ // Not found.
+ return null;
+ }
+
+ var unwindInfo = funcEntry.UnwindInfo;
+
+ int codeIndex = 0;
+
+ int spOffset = unwindInfo.FixedAllocSize;
+
+ foreach (var entry in unwindInfo.PushEntries)
+ {
+ if (entry.Type == RegisterType.Vector)
+ {
+ spOffset -= 16;
+ }
+ }
+
+ for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
+ {
+ var entry = unwindInfo.PushEntries[index];
+
+ if (entry.Type == RegisterType.Vector)
+ {
+ ushort uwop = PackUwop(UnwindOperation.SaveXmm128, entry.StreamEndOffset, entry.Index);
+
+ _unwindInfo->UnwindCodes[codeIndex++] = uwop;
+ _unwindInfo->UnwindCodes[codeIndex++] = (ushort)spOffset;
+
+ spOffset += 16;
+ }
+ }
+
+ _unwindInfo->UnwindCodes[0] = PackUwop(UnwindOperation.AllocLarge, unwindInfo.PrologueSize, 1);
+ _unwindInfo->UnwindCodes[1] = (ushort)(unwindInfo.FixedAllocSize >> 0);
+ _unwindInfo->UnwindCodes[2] = (ushort)(unwindInfo.FixedAllocSize >> 16);
+
+ codeIndex += 3;
+
+ for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
+ {
+ var entry = unwindInfo.PushEntries[index];
+
+ if (entry.Type == RegisterType.Integer)
+ {
+ ushort uwop = PackUwop(UnwindOperation.PushNonvol, entry.StreamEndOffset, entry.Index);
+
+ _unwindInfo->UnwindCodes[codeIndex++] = uwop;
+ }
+ }
+
+ _unwindInfo->VersionAndFlags = 1;
+ _unwindInfo->SizeOfProlog = (byte)unwindInfo.PrologueSize;
+ _unwindInfo->CountOfUnwindCodes = (byte)codeIndex;
+ _unwindInfo->FrameRegister = 0;
+
+ _runtimeFunction->BeginAddress = (uint)funcEntry.Offset;
+ _runtimeFunction->EndAddress = (uint)(funcEntry.Offset + funcEntry.Size);
+ _runtimeFunction->UnwindData = (uint)_sizeOfRuntimeFunction;
+
+ return _runtimeFunction;
+ }
+
+ private static ushort PackUwop(UnwindOperation uwop, int prologOffset, int opInfo)
+ {
+ return (ushort)(prologOffset | ((int)uwop << 8) | (opInfo << 12));
+ }
+ }
+} \ No newline at end of file