JitUnwindWindows.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. using ARMeilleure.IntermediateRepresentation;
  2. using System;
  3. using System.Runtime.InteropServices;
  4. namespace ARMeilleure.Translation
  5. {
  6. static class JitUnwindWindows
  7. {
  8. private const int MaxUnwindCodesArraySize = 9 + 10 * 2 + 3;
  9. private struct RuntimeFunction
  10. {
  11. public uint BeginAddress;
  12. public uint EndAddress;
  13. public uint UnwindData;
  14. }
  15. private struct UnwindInfo
  16. {
  17. public byte VersionAndFlags;
  18. public byte SizeOfProlog;
  19. public byte CountOfUnwindCodes;
  20. public byte FrameRegister;
  21. public unsafe fixed ushort UnwindCodes[MaxUnwindCodesArraySize];
  22. }
  23. private enum UnwindOperation
  24. {
  25. PushNonvol = 0,
  26. AllocLarge = 1,
  27. AllocSmall = 2,
  28. SetFpreg = 3,
  29. SaveNonvol = 4,
  30. SaveNonvolFar = 5,
  31. SaveXmm128 = 8,
  32. SaveXmm128Far = 9,
  33. PushMachframe = 10
  34. }
  35. private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, IntPtr context);
  36. [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
  37. private static unsafe extern bool RtlInstallFunctionTableCallback(
  38. ulong tableIdentifier,
  39. ulong baseAddress,
  40. uint length,
  41. GetRuntimeFunctionCallback callback,
  42. IntPtr context,
  43. string outOfProcessCallbackDll);
  44. private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
  45. private static int _sizeOfRuntimeFunction;
  46. private unsafe static RuntimeFunction* _runtimeFunction;
  47. private unsafe static UnwindInfo* _unwindInfo;
  48. public static void InstallFunctionTableHandler(IntPtr codeCachePointer, uint codeCacheLength)
  49. {
  50. ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
  51. _sizeOfRuntimeFunction = Marshal.SizeOf<RuntimeFunction>();
  52. bool result;
  53. unsafe
  54. {
  55. _runtimeFunction = (RuntimeFunction*)codeCachePointer;
  56. _unwindInfo = (UnwindInfo*)(codeCachePointer + _sizeOfRuntimeFunction);
  57. _getRuntimeFunctionCallback = new GetRuntimeFunctionCallback(FunctionTableHandler);
  58. result = RtlInstallFunctionTableCallback(
  59. codeCachePtr | 3,
  60. codeCachePtr,
  61. codeCacheLength,
  62. _getRuntimeFunctionCallback,
  63. codeCachePointer,
  64. null);
  65. }
  66. if (!result)
  67. {
  68. throw new InvalidOperationException("Failure installing function table callback.");
  69. }
  70. }
  71. private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, IntPtr context)
  72. {
  73. int offset = (int)((long)controlPc - context.ToInt64());
  74. if (!JitCache.TryFind(offset, out JitCacheEntry funcEntry))
  75. {
  76. // Not found.
  77. return null;
  78. }
  79. var unwindInfo = funcEntry.UnwindInfo;
  80. int codeIndex = 0;
  81. int spOffset = unwindInfo.FixedAllocSize;
  82. foreach (var entry in unwindInfo.PushEntries)
  83. {
  84. if (entry.Type == RegisterType.Vector)
  85. {
  86. spOffset -= 16;
  87. }
  88. }
  89. for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
  90. {
  91. var entry = unwindInfo.PushEntries[index];
  92. if (entry.Type == RegisterType.Vector)
  93. {
  94. ushort uwop = PackUwop(UnwindOperation.SaveXmm128, entry.StreamEndOffset, entry.Index);
  95. _unwindInfo->UnwindCodes[codeIndex++] = uwop;
  96. _unwindInfo->UnwindCodes[codeIndex++] = (ushort)spOffset;
  97. spOffset += 16;
  98. }
  99. }
  100. _unwindInfo->UnwindCodes[0] = PackUwop(UnwindOperation.AllocLarge, unwindInfo.PrologueSize, 1);
  101. _unwindInfo->UnwindCodes[1] = (ushort)(unwindInfo.FixedAllocSize >> 0);
  102. _unwindInfo->UnwindCodes[2] = (ushort)(unwindInfo.FixedAllocSize >> 16);
  103. codeIndex += 3;
  104. for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
  105. {
  106. var entry = unwindInfo.PushEntries[index];
  107. if (entry.Type == RegisterType.Integer)
  108. {
  109. ushort uwop = PackUwop(UnwindOperation.PushNonvol, entry.StreamEndOffset, entry.Index);
  110. _unwindInfo->UnwindCodes[codeIndex++] = uwop;
  111. }
  112. }
  113. _unwindInfo->VersionAndFlags = 1;
  114. _unwindInfo->SizeOfProlog = (byte)unwindInfo.PrologueSize;
  115. _unwindInfo->CountOfUnwindCodes = (byte)codeIndex;
  116. _unwindInfo->FrameRegister = 0;
  117. _runtimeFunction->BeginAddress = (uint)funcEntry.Offset;
  118. _runtimeFunction->EndAddress = (uint)(funcEntry.Offset + funcEntry.Size);
  119. _runtimeFunction->UnwindData = (uint)_sizeOfRuntimeFunction;
  120. return _runtimeFunction;
  121. }
  122. private static ushort PackUwop(UnwindOperation uwop, int prologOffset, int opInfo)
  123. {
  124. return (ushort)(prologOffset | ((int)uwop << 8) | (opInfo << 12));
  125. }
  126. }
  127. }