| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- 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));
- }
- }
- }
|