UnicornAArch64.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. using System;
  2. using System.Diagnostics.Contracts;
  3. using System.Runtime.Intrinsics;
  4. using System.Runtime.Intrinsics.X86;
  5. namespace Ryujinx.Tests.Unicorn
  6. {
  7. public class UnicornAArch64
  8. {
  9. internal readonly IntPtr uc;
  10. public IndexedProperty<int, ulong> X
  11. {
  12. get
  13. {
  14. return new IndexedProperty<int, ulong>(
  15. (int i) => GetX(i),
  16. (int i, ulong value) => SetX(i, value));
  17. }
  18. }
  19. public IndexedProperty<int, Vector128<float>> Q
  20. {
  21. get
  22. {
  23. return new IndexedProperty<int, Vector128<float>>(
  24. (int i) => GetQ(i),
  25. (int i, Vector128<float> value) => SetQ(i, value));
  26. }
  27. }
  28. public ulong LR
  29. {
  30. get { return GetRegister(Native.ArmRegister.LR); }
  31. set { SetRegister(Native.ArmRegister.LR, value); }
  32. }
  33. public ulong SP
  34. {
  35. get { return GetRegister(Native.ArmRegister.SP); }
  36. set { SetRegister(Native.ArmRegister.SP, value); }
  37. }
  38. public ulong PC
  39. {
  40. get { return GetRegister(Native.ArmRegister.PC); }
  41. set { SetRegister(Native.ArmRegister.PC, value); }
  42. }
  43. public uint Pstate
  44. {
  45. get { return (uint)GetRegister(Native.ArmRegister.PSTATE); }
  46. set { SetRegister(Native.ArmRegister.PSTATE, (uint)value); }
  47. }
  48. public int Fpcr
  49. {
  50. get { return (int)GetRegister(Native.ArmRegister.FPCR); }
  51. set { SetRegister(Native.ArmRegister.FPCR, (uint)value); }
  52. }
  53. public int Fpsr
  54. {
  55. get { return (int)GetRegister(Native.ArmRegister.FPSR); }
  56. set { SetRegister(Native.ArmRegister.FPSR, (uint)value); }
  57. }
  58. public bool OverflowFlag
  59. {
  60. get { return (Pstate & 0x10000000u) != 0; }
  61. set { Pstate = (Pstate & ~0x10000000u) | (value ? 0x10000000u : 0u); }
  62. }
  63. public bool CarryFlag
  64. {
  65. get { return (Pstate & 0x20000000u) != 0; }
  66. set { Pstate = (Pstate & ~0x20000000u) | (value ? 0x20000000u : 0u); }
  67. }
  68. public bool ZeroFlag
  69. {
  70. get { return (Pstate & 0x40000000u) != 0; }
  71. set { Pstate = (Pstate & ~0x40000000u) | (value ? 0x40000000u : 0u); }
  72. }
  73. public bool NegativeFlag
  74. {
  75. get { return (Pstate & 0x80000000u) != 0; }
  76. set { Pstate = (Pstate & ~0x80000000u) | (value ? 0x80000000u : 0u); }
  77. }
  78. public UnicornAArch64()
  79. {
  80. Native.Interface.Checked(Native.Interface.uc_open((uint)Native.UnicornArch.UC_ARCH_ARM64, (uint)Native.UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc));
  81. SetRegister(Native.ArmRegister.CPACR_EL1, 0x00300000);
  82. }
  83. ~UnicornAArch64()
  84. {
  85. Native.Interface.Checked(Native.Interface.uc_close(uc));
  86. }
  87. public void RunForCount(ulong count)
  88. {
  89. Native.Interface.Checked(Native.Interface.uc_emu_start(uc, this.PC, 0xFFFFFFFFFFFFFFFFu, 0, count));
  90. }
  91. public void Step()
  92. {
  93. RunForCount(1);
  94. }
  95. internal static Native.ArmRegister[] X_registers = new Native.ArmRegister[31]
  96. {
  97. Native.ArmRegister.X0,
  98. Native.ArmRegister.X1,
  99. Native.ArmRegister.X2,
  100. Native.ArmRegister.X3,
  101. Native.ArmRegister.X4,
  102. Native.ArmRegister.X5,
  103. Native.ArmRegister.X6,
  104. Native.ArmRegister.X7,
  105. Native.ArmRegister.X8,
  106. Native.ArmRegister.X9,
  107. Native.ArmRegister.X10,
  108. Native.ArmRegister.X11,
  109. Native.ArmRegister.X12,
  110. Native.ArmRegister.X13,
  111. Native.ArmRegister.X14,
  112. Native.ArmRegister.X15,
  113. Native.ArmRegister.X16,
  114. Native.ArmRegister.X17,
  115. Native.ArmRegister.X18,
  116. Native.ArmRegister.X19,
  117. Native.ArmRegister.X20,
  118. Native.ArmRegister.X21,
  119. Native.ArmRegister.X22,
  120. Native.ArmRegister.X23,
  121. Native.ArmRegister.X24,
  122. Native.ArmRegister.X25,
  123. Native.ArmRegister.X26,
  124. Native.ArmRegister.X27,
  125. Native.ArmRegister.X28,
  126. Native.ArmRegister.X29,
  127. Native.ArmRegister.X30,
  128. };
  129. internal static Native.ArmRegister[] Q_registers = new Native.ArmRegister[32]
  130. {
  131. Native.ArmRegister.Q0,
  132. Native.ArmRegister.Q1,
  133. Native.ArmRegister.Q2,
  134. Native.ArmRegister.Q3,
  135. Native.ArmRegister.Q4,
  136. Native.ArmRegister.Q5,
  137. Native.ArmRegister.Q6,
  138. Native.ArmRegister.Q7,
  139. Native.ArmRegister.Q8,
  140. Native.ArmRegister.Q9,
  141. Native.ArmRegister.Q10,
  142. Native.ArmRegister.Q11,
  143. Native.ArmRegister.Q12,
  144. Native.ArmRegister.Q13,
  145. Native.ArmRegister.Q14,
  146. Native.ArmRegister.Q15,
  147. Native.ArmRegister.Q16,
  148. Native.ArmRegister.Q17,
  149. Native.ArmRegister.Q18,
  150. Native.ArmRegister.Q19,
  151. Native.ArmRegister.Q20,
  152. Native.ArmRegister.Q21,
  153. Native.ArmRegister.Q22,
  154. Native.ArmRegister.Q23,
  155. Native.ArmRegister.Q24,
  156. Native.ArmRegister.Q25,
  157. Native.ArmRegister.Q26,
  158. Native.ArmRegister.Q27,
  159. Native.ArmRegister.Q28,
  160. Native.ArmRegister.Q29,
  161. Native.ArmRegister.Q30,
  162. Native.ArmRegister.Q31,
  163. };
  164. internal ulong GetRegister(Native.ArmRegister register)
  165. {
  166. byte[] value_bytes = new byte[8];
  167. Native.Interface.Checked(Native.Interface.uc_reg_read(uc, (int)register, value_bytes));
  168. return (ulong)BitConverter.ToInt64(value_bytes, 0);
  169. }
  170. internal void SetRegister(Native.ArmRegister register, ulong value)
  171. {
  172. byte[] value_bytes = BitConverter.GetBytes(value);
  173. Native.Interface.Checked(Native.Interface.uc_reg_write(uc, (int)register, value_bytes));
  174. }
  175. internal Vector128<float> GetVector(Native.ArmRegister register)
  176. {
  177. byte[] value_bytes = new byte[16];
  178. Native.Interface.Checked(Native.Interface.uc_reg_read(uc, (int)register, value_bytes));
  179. unsafe
  180. {
  181. fixed (byte* p = &value_bytes[0])
  182. {
  183. return Sse.LoadVector128((float*)p);
  184. }
  185. }
  186. }
  187. internal void SetVector(Native.ArmRegister register, Vector128<float> value)
  188. {
  189. byte[] value_bytes = new byte[16];
  190. unsafe
  191. {
  192. fixed (byte* p = &value_bytes[0])
  193. {
  194. Sse.Store((float*)p, value);
  195. }
  196. }
  197. Native.Interface.Checked(Native.Interface.uc_reg_write(uc, (int)register, value_bytes));
  198. }
  199. public ulong GetX(int index)
  200. {
  201. Contract.Requires(index <= 30, "invalid register");
  202. return GetRegister(X_registers[index]);
  203. }
  204. public void SetX(int index, ulong value)
  205. {
  206. Contract.Requires(index <= 30, "invalid register");
  207. SetRegister(X_registers[index], value);
  208. }
  209. public Vector128<float> GetQ(int index)
  210. {
  211. Contract.Requires(index <= 31, "invalid vector");
  212. return GetVector(Q_registers[index]);
  213. }
  214. public void SetQ(int index, Vector128<float> value)
  215. {
  216. Contract.Requires(index <= 31, "invalid vector");
  217. SetVector(Q_registers[index], value);
  218. }
  219. public byte[] MemoryRead(ulong address, ulong size)
  220. {
  221. byte[] value = new byte[size];
  222. Native.Interface.Checked(Native.Interface.uc_mem_read(uc, address, value, size));
  223. return value;
  224. }
  225. public byte MemoryRead8 (ulong address) { return MemoryRead(address, 1)[0]; }
  226. public UInt16 MemoryRead16(ulong address) { return (UInt16)BitConverter.ToInt16(MemoryRead(address, 2), 0); }
  227. public UInt32 MemoryRead32(ulong address) { return (UInt32)BitConverter.ToInt32(MemoryRead(address, 4), 0); }
  228. public UInt64 MemoryRead64(ulong address) { return (UInt64)BitConverter.ToInt64(MemoryRead(address, 8), 0); }
  229. public void MemoryWrite(ulong address, byte[] value)
  230. {
  231. Native.Interface.Checked(Native.Interface.uc_mem_write(uc, address, value, (ulong)value.Length));
  232. }
  233. public void MemoryWrite8 (ulong address, byte value) { MemoryWrite(address, new byte[]{value}); }
  234. public void MemoryWrite16(ulong address, Int16 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
  235. public void MemoryWrite16(ulong address, UInt16 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
  236. public void MemoryWrite32(ulong address, Int32 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
  237. public void MemoryWrite32(ulong address, UInt32 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
  238. public void MemoryWrite64(ulong address, Int64 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
  239. public void MemoryWrite64(ulong address, UInt64 value) { MemoryWrite(address, BitConverter.GetBytes(value)); }
  240. public void MemoryMap(ulong address, ulong size, MemoryPermission permissions)
  241. {
  242. Native.Interface.Checked(Native.Interface.uc_mem_map(uc, address, size, (uint)permissions));
  243. }
  244. public void MemoryUnmap(ulong address, ulong size)
  245. {
  246. Native.Interface.Checked(Native.Interface.uc_mem_unmap(uc, address, size));
  247. }
  248. public void MemoryProtect(ulong address, ulong size, MemoryPermission permissions)
  249. {
  250. Native.Interface.Checked(Native.Interface.uc_mem_protect(uc, address, size, (uint)permissions));
  251. }
  252. public void DumpMemoryInformation()
  253. {
  254. Native.Interface.Checked(Native.Interface.uc_mem_regions(uc, out IntPtr regions_raw, out uint length));
  255. Native.Interface.MarshalArrayOf<Native.UnicornMemoryRegion>(regions_raw, (int)length, out var regions);
  256. foreach (var region in regions)
  257. {
  258. Console.WriteLine("region: begin {0:X16} end {1:X16} perms {2:X8}", region.begin, region.end, region.perms);
  259. }
  260. }
  261. public static bool IsAvailable()
  262. {
  263. try
  264. {
  265. Native.Interface.uc_version(out uint major, out uint minor);
  266. return true;
  267. }
  268. catch (DllNotFoundException)
  269. {
  270. return false;
  271. }
  272. }
  273. }
  274. }