using Ryujinx.Common.Logging; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Tamper.CodeEmitters; using Ryujinx.HLE.HOS.Tamper.Operations; using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Tamper { class AtmosphereCompiler { private ulong _exeAddress; private ulong _heapAddress; private ulong _aliasAddress; private ulong _aslrAddress; private ITamperedProcess _process; public AtmosphereCompiler(ulong exeAddress, ulong heapAddress, ulong aliasAddress, ulong aslrAddress, ITamperedProcess process) { _exeAddress = exeAddress; _heapAddress = heapAddress; _aliasAddress = aliasAddress; _aslrAddress = aslrAddress; _process = process; } public ITamperProgram Compile(string name, IEnumerable rawInstructions) { string[] addresses = new string[] { $" Executable address: 0x{_exeAddress:X16}", $" Heap address : 0x{_heapAddress:X16}", $" Alias address : 0x{_aliasAddress:X16}", $" Aslr address : 0x{_aslrAddress:X16}" }; Logger.Debug?.Print(LogClass.TamperMachine, $"Compiling Atmosphere cheat {name}...\n{string.Join('\n', addresses)}"); try { return CompileImpl(name, rawInstructions); } catch(TamperCompilationException exception) { // Just print the message without the stack trace. Logger.Error?.Print(LogClass.TamperMachine, exception.Message); } catch (Exception exception) { Logger.Error?.Print(LogClass.TamperMachine, exception.ToString()); } Logger.Error?.Print(LogClass.TamperMachine, "There was a problem while compiling the Atmosphere cheat"); return null; } private ITamperProgram CompileImpl(string name, IEnumerable rawInstructions) { CompilationContext context = new CompilationContext(_exeAddress, _heapAddress, _aliasAddress, _aslrAddress, _process); context.BlockStack.Push(new OperationBlock(null)); // Parse the instructions. foreach (string rawInstruction in rawInstructions) { Logger.Debug?.Print(LogClass.TamperMachine, $"Compiling instruction {rawInstruction}"); byte[] instruction = InstructionHelper.ParseRawInstruction(rawInstruction); CodeType codeType = InstructionHelper.GetCodeType(instruction); switch (codeType) { case CodeType.StoreConstantToAddress: StoreConstantToAddress.Emit(instruction, context); break; case CodeType.BeginMemoryConditionalBlock: BeginConditionalBlock.Emit(instruction, context); break; case CodeType.EndConditionalBlock: EndConditionalBlock.Emit(instruction, context); break; case CodeType.StartEndLoop: StartEndLoop.Emit(instruction, context); break; case CodeType.LoadRegisterWithContant: LoadRegisterWithConstant.Emit(instruction, context); break; case CodeType.LoadRegisterWithMemory: LoadRegisterWithMemory.Emit(instruction, context); break; case CodeType.StoreConstantToMemory: StoreConstantToMemory.Emit(instruction, context); break; case CodeType.LegacyArithmetic: LegacyArithmetic.Emit(instruction, context); break; case CodeType.BeginKeypressConditionalBlock: BeginConditionalBlock.Emit(instruction, context); break; case CodeType.Arithmetic: Arithmetic.Emit(instruction, context); break; case CodeType.StoreRegisterToMemory: StoreRegisterToMemory.Emit(instruction, context); break; case CodeType.BeginRegisterConditionalBlock: BeginConditionalBlock.Emit(instruction, context); break; case CodeType.SaveOrRestoreRegister: SaveOrRestoreRegister.Emit(instruction, context); break; case CodeType.SaveOrRestoreRegisterWithMask: SaveOrRestoreRegisterWithMask.Emit(instruction, context); break; case CodeType.ReadOrWriteStaticRegister: ReadOrWriteStaticRegister.Emit(instruction, context); break; case CodeType.PauseProcess: PauseProcess.Emit(instruction, context); break; case CodeType.ResumeProcess: ResumeProcess.Emit(instruction, context); break; case CodeType.DebugLog: DebugLog.Emit(instruction, context); break; default: throw new TamperCompilationException($"Code type {codeType} not implemented in Atmosphere cheat"); } } // Initialize only the registers used. Value zero = new Value(0UL); int position = 0; foreach (Register register in context.Registers.Values) { context.CurrentOperations.Insert(position, new OpMov(register, zero)); position++; } if (context.BlockStack.Count != 1) { throw new TamperCompilationException($"Reached end of compilation with unmatched conditional(s) or loop(s)"); } return new AtmosphereProgram(name, _process, context.PressedKeys, new Block(context.CurrentOperations)); } } }