DebugLog.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. using Ryujinx.HLE.Exceptions;
  2. using Ryujinx.HLE.HOS.Tamper.Operations;
  3. namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
  4. {
  5. /// <summary>
  6. /// Code type 0xFFF writes a debug log.
  7. /// </summary>
  8. class DebugLog
  9. {
  10. private const int OperationWidthIndex = 3;
  11. private const int LogIdIndex = 4;
  12. private const int OperandTypeIndex = 5;
  13. private const int RegisterOrMemoryRegionIndex = 6;
  14. private const int OffsetRegisterOrImmediateIndex = 7;
  15. private const int MemoryRegionWithOffsetImmediate = 0;
  16. private const int MemoryRegionWithOffsetRegister = 1;
  17. private const int AddressRegisterWithOffsetImmediate = 2;
  18. private const int AddressRegisterWithOffsetRegister = 3;
  19. private const int ValueRegister = 4;
  20. private const int OffsetImmediateSize = 9;
  21. public static void Emit(byte[] instruction, CompilationContext context)
  22. {
  23. // FFFTIX##
  24. // FFFTI0Ma aaaaaaaa
  25. // FFFTI1Mr
  26. // FFFTI2Ra aaaaaaaa
  27. // FFFTI3Rr
  28. // FFFTI4V0
  29. // T: Width of memory write (1, 2, 4, or 8 bytes).
  30. // I: Log id.
  31. // X: Operand Type, see below.
  32. // M: Memory Type (operand types 0 and 1).
  33. // R: Address Register (operand types 2 and 3).
  34. // a: Relative Address (operand types 0 and 2).
  35. // r: Offset Register (operand types 1 and 3).
  36. // V: Value Register (operand type 4).
  37. byte operationWidth = instruction[OperationWidthIndex];
  38. byte logId = instruction[LogIdIndex];
  39. byte operandType = instruction[OperandTypeIndex];
  40. byte registerOrMemoryRegion = instruction[RegisterOrMemoryRegionIndex];
  41. byte offsetRegisterIndex = instruction[OffsetRegisterOrImmediateIndex];
  42. ulong immediate;
  43. Register addressRegister;
  44. Register offsetRegister;
  45. IOperand sourceOperand;
  46. switch (operandType)
  47. {
  48. case MemoryRegionWithOffsetImmediate:
  49. // *(?x + #a)
  50. immediate = InstructionHelper.GetImmediate(instruction, OffsetRegisterOrImmediateIndex, OffsetImmediateSize);
  51. sourceOperand = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, immediate, context);
  52. break;
  53. case MemoryRegionWithOffsetRegister:
  54. // *(?x + $r)
  55. offsetRegister = context.GetRegister(offsetRegisterIndex);
  56. sourceOperand = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, offsetRegister, context);
  57. break;
  58. case AddressRegisterWithOffsetImmediate:
  59. // *($R + #a)
  60. addressRegister = context.GetRegister(registerOrMemoryRegion);
  61. immediate = InstructionHelper.GetImmediate(instruction, OffsetRegisterOrImmediateIndex, OffsetImmediateSize);
  62. sourceOperand = MemoryHelper.EmitPointer(addressRegister, immediate, context);
  63. break;
  64. case AddressRegisterWithOffsetRegister:
  65. // *($R + $r)
  66. addressRegister = context.GetRegister(registerOrMemoryRegion);
  67. offsetRegister = context.GetRegister(offsetRegisterIndex);
  68. sourceOperand = MemoryHelper.EmitPointer(addressRegister, offsetRegister, context);
  69. break;
  70. case ValueRegister:
  71. // $V
  72. sourceOperand = context.GetRegister(registerOrMemoryRegion);
  73. break;
  74. default:
  75. throw new TamperCompilationException($"Invalid operand type {operandType} in Atmosphere cheat");
  76. }
  77. InstructionHelper.Emit(typeof(OpLog<>), operationWidth, context, logId, sourceOperand);
  78. }
  79. }
  80. }