AtmosphereCompiler.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.HLE.Exceptions;
  3. using Ryujinx.HLE.HOS.Tamper.CodeEmitters;
  4. using Ryujinx.HLE.HOS.Tamper.Operations;
  5. using System;
  6. using System.Collections.Generic;
  7. namespace Ryujinx.HLE.HOS.Tamper
  8. {
  9. class AtmosphereCompiler
  10. {
  11. private ulong _exeAddress;
  12. private ulong _heapAddress;
  13. private ulong _aliasAddress;
  14. private ulong _aslrAddress;
  15. private ITamperedProcess _process;
  16. public AtmosphereCompiler(ulong exeAddress, ulong heapAddress, ulong aliasAddress, ulong aslrAddress, ITamperedProcess process)
  17. {
  18. _exeAddress = exeAddress;
  19. _heapAddress = heapAddress;
  20. _aliasAddress = aliasAddress;
  21. _aslrAddress = aslrAddress;
  22. _process = process;
  23. }
  24. public ITamperProgram Compile(string name, IEnumerable<string> rawInstructions)
  25. {
  26. string[] addresses = new string[]
  27. {
  28. $" Executable address: 0x{_exeAddress:X16}",
  29. $" Heap address : 0x{_heapAddress:X16}",
  30. $" Alias address : 0x{_aliasAddress:X16}",
  31. $" Aslr address : 0x{_aslrAddress:X16}"
  32. };
  33. Logger.Debug?.Print(LogClass.TamperMachine, $"Compiling Atmosphere cheat {name}...\n{string.Join('\n', addresses)}");
  34. try
  35. {
  36. return CompileImpl(name, rawInstructions);
  37. }
  38. catch(TamperCompilationException exception)
  39. {
  40. // Just print the message without the stack trace.
  41. Logger.Error?.Print(LogClass.TamperMachine, exception.Message);
  42. }
  43. catch (Exception exception)
  44. {
  45. Logger.Error?.Print(LogClass.TamperMachine, exception.ToString());
  46. }
  47. Logger.Error?.Print(LogClass.TamperMachine, "There was a problem while compiling the Atmosphere cheat");
  48. return null;
  49. }
  50. private ITamperProgram CompileImpl(string name, IEnumerable<string> rawInstructions)
  51. {
  52. CompilationContext context = new CompilationContext(_exeAddress, _heapAddress, _aliasAddress, _aslrAddress, _process);
  53. context.BlockStack.Push(new OperationBlock(null));
  54. // Parse the instructions.
  55. foreach (string rawInstruction in rawInstructions)
  56. {
  57. Logger.Debug?.Print(LogClass.TamperMachine, $"Compiling instruction {rawInstruction}");
  58. byte[] instruction = InstructionHelper.ParseRawInstruction(rawInstruction);
  59. CodeType codeType = InstructionHelper.GetCodeType(instruction);
  60. switch (codeType)
  61. {
  62. case CodeType.StoreConstantToAddress:
  63. StoreConstantToAddress.Emit(instruction, context);
  64. break;
  65. case CodeType.BeginMemoryConditionalBlock:
  66. BeginConditionalBlock.Emit(instruction, context);
  67. break;
  68. case CodeType.EndConditionalBlock:
  69. EndConditionalBlock.Emit(instruction, context);
  70. break;
  71. case CodeType.StartEndLoop:
  72. StartEndLoop.Emit(instruction, context);
  73. break;
  74. case CodeType.LoadRegisterWithContant:
  75. LoadRegisterWithConstant.Emit(instruction, context);
  76. break;
  77. case CodeType.LoadRegisterWithMemory:
  78. LoadRegisterWithMemory.Emit(instruction, context);
  79. break;
  80. case CodeType.StoreConstantToMemory:
  81. StoreConstantToMemory.Emit(instruction, context);
  82. break;
  83. case CodeType.LegacyArithmetic:
  84. LegacyArithmetic.Emit(instruction, context);
  85. break;
  86. case CodeType.BeginKeypressConditionalBlock:
  87. BeginConditionalBlock.Emit(instruction, context);
  88. break;
  89. case CodeType.Arithmetic:
  90. Arithmetic.Emit(instruction, context);
  91. break;
  92. case CodeType.StoreRegisterToMemory:
  93. StoreRegisterToMemory.Emit(instruction, context);
  94. break;
  95. case CodeType.BeginRegisterConditionalBlock:
  96. BeginConditionalBlock.Emit(instruction, context);
  97. break;
  98. case CodeType.SaveOrRestoreRegister:
  99. SaveOrRestoreRegister.Emit(instruction, context);
  100. break;
  101. case CodeType.SaveOrRestoreRegisterWithMask:
  102. SaveOrRestoreRegisterWithMask.Emit(instruction, context);
  103. break;
  104. case CodeType.ReadOrWriteStaticRegister:
  105. ReadOrWriteStaticRegister.Emit(instruction, context);
  106. break;
  107. case CodeType.PauseProcess:
  108. PauseProcess.Emit(instruction, context);
  109. break;
  110. case CodeType.ResumeProcess:
  111. ResumeProcess.Emit(instruction, context);
  112. break;
  113. case CodeType.DebugLog:
  114. DebugLog.Emit(instruction, context);
  115. break;
  116. default:
  117. throw new TamperCompilationException($"Code type {codeType} not implemented in Atmosphere cheat");
  118. }
  119. }
  120. // Initialize only the registers used.
  121. Value<ulong> zero = new Value<ulong>(0UL);
  122. int position = 0;
  123. foreach (Register register in context.Registers.Values)
  124. {
  125. context.CurrentOperations.Insert(position, new OpMov<ulong>(register, zero));
  126. position++;
  127. }
  128. if (context.BlockStack.Count != 1)
  129. {
  130. throw new TamperCompilationException($"Reached end of compilation with unmatched conditional(s) or loop(s)");
  131. }
  132. return new AtmosphereProgram(name, _process, context.PressedKeys, new Block(context.CurrentOperations));
  133. }
  134. }
  135. }