dmnt: implement break/continue, static reg commands

This commit is contained in:
Michael Scire 2020-04-16 21:16:55 -07:00
parent 332dbdd497
commit 11b8a92458
6 changed files with 230 additions and 8 deletions

View file

@ -66,6 +66,14 @@ namespace ams::dmnt::cheat {
return dmnt::cheat::impl::QueryCheatProcessMemory(mapping.GetPointer(), address); return dmnt::cheat::impl::QueryCheatProcessMemory(mapping.GetPointer(), address);
} }
Result CheatService::BreakCheatProcess() {
return dmnt::cheat::impl::BreakCheatProcess();
}
Result CheatService::ContinueCheatProcess() {
return dmnt::cheat::impl::ContinueCheatProcess();
}
/* ========================================================================================= */ /* ========================================================================================= */
/* =================================== Cheat Commands ==================================== */ /* =================================== Cheat Commands ==================================== */
/* ========================================================================================= */ /* ========================================================================================= */
@ -95,6 +103,18 @@ namespace ams::dmnt::cheat {
return dmnt::cheat::impl::RemoveCheat(cheat_id); return dmnt::cheat::impl::RemoveCheat(cheat_id);
} }
Result CheatService::ReadStaticRegister(sf::Out<u64> out, u8 which) {
return dmnt::cheat::impl::ReadStaticRegister(out.GetPointer(), which);
}
Result CheatService::WriteStaticRegister(u8 which, u64 value) {
return dmnt::cheat::impl::WriteStaticRegister(which, value);
}
Result CheatService::ResetStaticRegisters() {
return dmnt::cheat::impl::ResetStaticRegisters();
}
/* ========================================================================================= */ /* ========================================================================================= */
/* =================================== Address Commands ================================== */ /* =================================== Address Commands ================================== */
/* ========================================================================================= */ /* ========================================================================================= */

View file

@ -33,6 +33,8 @@ namespace ams::dmnt::cheat {
ReadCheatProcessMemory = 65102, ReadCheatProcessMemory = 65102,
WriteCheatProcessMemory = 65103, WriteCheatProcessMemory = 65103,
QueryCheatProcessMemory = 65104, QueryCheatProcessMemory = 65104,
BreakCheatProcess = 65105,
ContinueCheatProcess = 65106,
/* Interact with Cheats */ /* Interact with Cheats */
GetCheatCount = 65200, GetCheatCount = 65200,
@ -41,6 +43,9 @@ namespace ams::dmnt::cheat {
ToggleCheat = 65203, ToggleCheat = 65203,
AddCheat = 65204, AddCheat = 65204,
RemoveCheat = 65205, RemoveCheat = 65205,
ReadStaticRegister = 65206,
WriteStaticRegister = 65207,
ResetStaticRegisters = 65208,
/* Interact with Frozen Addresses */ /* Interact with Frozen Addresses */
GetFrozenAddressCount = 65300, GetFrozenAddressCount = 65300,
@ -60,6 +65,8 @@ namespace ams::dmnt::cheat {
Result ReadCheatProcessMemory(const sf::OutBuffer &buffer, u64 address, u64 out_size); Result ReadCheatProcessMemory(const sf::OutBuffer &buffer, u64 address, u64 out_size);
Result WriteCheatProcessMemory(const sf::InBuffer &buffer, u64 address, u64 in_size); Result WriteCheatProcessMemory(const sf::InBuffer &buffer, u64 address, u64 in_size);
Result QueryCheatProcessMemory(sf::Out<MemoryInfo> mapping, u64 address); Result QueryCheatProcessMemory(sf::Out<MemoryInfo> mapping, u64 address);
Result BreakCheatProcess();
Result ContinueCheatProcess();
Result GetCheatCount(sf::Out<u64> out_count); Result GetCheatCount(sf::Out<u64> out_count);
Result GetCheats(const sf::OutArray<CheatEntry> &cheats, sf::Out<u64> out_count, u64 offset); Result GetCheats(const sf::OutArray<CheatEntry> &cheats, sf::Out<u64> out_count, u64 offset);
@ -67,6 +74,9 @@ namespace ams::dmnt::cheat {
Result ToggleCheat(u32 cheat_id); Result ToggleCheat(u32 cheat_id);
Result AddCheat(const CheatDefinition &cheat, sf::Out<u32> out_cheat_id, bool enabled); Result AddCheat(const CheatDefinition &cheat, sf::Out<u32> out_cheat_id, bool enabled);
Result RemoveCheat(u32 cheat_id); Result RemoveCheat(u32 cheat_id);
Result ReadStaticRegister(sf::Out<u64> out, u8 which);
Result WriteStaticRegister(u8 which, u64 value);
Result ResetStaticRegisters();
Result GetFrozenAddressCount(sf::Out<u64> out_count); Result GetFrozenAddressCount(sf::Out<u64> out_count);
Result GetFrozenAddresses(const sf::OutArray<FrozenAddressEntry> &addresses, sf::Out<u64> out_count, u64 offset); Result GetFrozenAddresses(const sf::OutArray<FrozenAddressEntry> &addresses, sf::Out<u64> out_count, u64 offset);
@ -86,6 +96,8 @@ namespace ams::dmnt::cheat {
MAKE_SERVICE_COMMAND_META(ReadCheatProcessMemory), MAKE_SERVICE_COMMAND_META(ReadCheatProcessMemory),
MAKE_SERVICE_COMMAND_META(WriteCheatProcessMemory), MAKE_SERVICE_COMMAND_META(WriteCheatProcessMemory),
MAKE_SERVICE_COMMAND_META(QueryCheatProcessMemory), MAKE_SERVICE_COMMAND_META(QueryCheatProcessMemory),
MAKE_SERVICE_COMMAND_META(BreakCheatProcess),
MAKE_SERVICE_COMMAND_META(ContinueCheatProcess),
MAKE_SERVICE_COMMAND_META(GetCheatCount), MAKE_SERVICE_COMMAND_META(GetCheatCount),
MAKE_SERVICE_COMMAND_META(GetCheats), MAKE_SERVICE_COMMAND_META(GetCheats),
@ -93,6 +105,9 @@ namespace ams::dmnt::cheat {
MAKE_SERVICE_COMMAND_META(ToggleCheat), MAKE_SERVICE_COMMAND_META(ToggleCheat),
MAKE_SERVICE_COMMAND_META(AddCheat), MAKE_SERVICE_COMMAND_META(AddCheat),
MAKE_SERVICE_COMMAND_META(RemoveCheat), MAKE_SERVICE_COMMAND_META(RemoveCheat),
MAKE_SERVICE_COMMAND_META(ReadStaticRegister),
MAKE_SERVICE_COMMAND_META(WriteStaticRegister),
MAKE_SERVICE_COMMAND_META(ResetStaticRegisters),
MAKE_SERVICE_COMMAND_META(GetFrozenAddressCount), MAKE_SERVICE_COMMAND_META(GetFrozenAddressCount),
MAKE_SERVICE_COMMAND_META(GetFrozenAddresses), MAKE_SERVICE_COMMAND_META(GetFrozenAddresses),

View file

@ -34,6 +34,7 @@ namespace ams::dmnt::cheat::impl {
static constexpr s32 DebugEventsThreadPriority = -1; static constexpr s32 DebugEventsThreadPriority = -1;
private: private:
os::Mutex cheat_lock; os::Mutex cheat_lock;
os::Event unsafe_break_event;
os::Event debug_events_event; /* Autoclear. */ os::Event debug_events_event; /* Autoclear. */
os::ThreadType detect_thread, debug_events_thread; os::ThreadType detect_thread, debug_events_thread;
os::SystemEvent cheat_process_event; os::SystemEvent cheat_process_event;
@ -41,6 +42,7 @@ namespace ams::dmnt::cheat::impl {
CheatProcessMetadata cheat_process_metadata = {}; CheatProcessMetadata cheat_process_metadata = {};
os::ThreadType vm_thread; os::ThreadType vm_thread;
bool broken_unsafe = false;
bool needs_reload_vm = false; bool needs_reload_vm = false;
CheatVirtualMachine cheat_vm; CheatVirtualMachine cheat_vm;
@ -88,6 +90,8 @@ namespace ams::dmnt::cheat::impl {
for (size_t i = 0; i < MaxCheatCount; i++) { for (size_t i = 0; i < MaxCheatCount; i++) {
this->ResetCheatEntry(i); this->ResetCheatEntry(i);
} }
this->cheat_vm.ResetStaticRegisters();
} }
CheatEntry *GetCheatEntryById(size_t i) { CheatEntry *GetCheatEntryById(size_t i) {
@ -122,6 +126,10 @@ namespace ams::dmnt::cheat::impl {
void CloseActiveCheatProcess() { void CloseActiveCheatProcess() {
if (this->cheat_process_debug_handle != svc::InvalidHandle) { if (this->cheat_process_debug_handle != svc::InvalidHandle) {
/* We don't need to do any unsafe brekaing. */
this->broken_unsafe = false;
this->unsafe_break_event.Signal();
/* Knock out the debug events thread. */ /* Knock out the debug events thread. */
os::CancelThreadSynchronization(std::addressof(this->debug_events_thread)); os::CancelThreadSynchronization(std::addressof(this->debug_events_thread));
@ -185,7 +193,7 @@ namespace ams::dmnt::cheat::impl {
} }
public: public:
CheatProcessManager() : cheat_lock(false), debug_events_event(os::EventClearMode_AutoClear), cheat_process_event(os::EventClearMode_AutoClear, true) { CheatProcessManager() : cheat_lock(false), unsafe_break_event(os::EventClearMode_ManualClear), debug_events_event(os::EventClearMode_AutoClear), cheat_process_event(os::EventClearMode_AutoClear, true) {
/* Learn whether we should enable cheats by default. */ /* Learn whether we should enable cheats by default. */
{ {
u8 en = 0; u8 en = 0;
@ -257,6 +265,19 @@ namespace ams::dmnt::cheat::impl {
return ResultSuccess(); return ResultSuccess();
} }
Result BreakCheatProcessUnsafe() {
this->broken_unsafe = true;
this->unsafe_break_event.Clear();
return svcBreakDebugProcess(this->GetCheatProcessHandle());
}
Result ContinueCheatProcessUnsafe() {
this->broken_unsafe = false;
this->unsafe_break_event.Signal();
dmnt::cheat::impl::ContinueCheatProcess(this->GetCheatProcessHandle());
return ResultSuccess();
}
Result GetCheatProcessMappingCount(u64 *out_count) { Result GetCheatProcessMappingCount(u64 *out_count) {
std::scoped_lock lk(this->cheat_lock); std::scoped_lock lk(this->cheat_lock);
@ -335,6 +356,22 @@ namespace ams::dmnt::cheat::impl {
return svcQueryDebugProcessMemory(mapping, &tmp, this->GetCheatProcessHandle(), address); return svcQueryDebugProcessMemory(mapping, &tmp, this->GetCheatProcessHandle(), address);
} }
Result BreakCheatProcess() {
std::scoped_lock lk(this->cheat_lock);
R_TRY(this->EnsureCheatProcess());
return this->BreakCheatProcessUnsafe();
}
Result ContinueCheatProcess() {
std::scoped_lock lk(this->cheat_lock);
R_TRY(this->EnsureCheatProcess());
return this->ContinueCheatProcessUnsafe();
}
Result GetCheatCount(u64 *out_count) { Result GetCheatCount(u64 *out_count) {
std::scoped_lock lk(this->cheat_lock); std::scoped_lock lk(this->cheat_lock);
@ -436,6 +473,35 @@ namespace ams::dmnt::cheat::impl {
return ResultSuccess(); return ResultSuccess();
} }
Result ReadStaticRegister(u64 *out, size_t which) {
std::scoped_lock lk(this->cheat_lock);
R_TRY(this->EnsureCheatProcess());
R_UNLESS(which < CheatVirtualMachine::NumStaticRegisters, ResultCheatInvalid());
*out = this->cheat_vm.GetStaticRegister(which);
return ResultSuccess();
}
Result WriteStaticRegister(size_t which, u64 value) {
std::scoped_lock lk(this->cheat_lock);
R_TRY(this->EnsureCheatProcess());
R_UNLESS(which < CheatVirtualMachine::NumStaticRegisters, ResultCheatInvalid());
this->cheat_vm.SetStaticRegister(which, value);
return ResultSuccess();
}
Result ResetStaticRegisters() {
std::scoped_lock lk(this->cheat_lock);
R_TRY(this->EnsureCheatProcess());
this->cheat_vm.ResetStaticRegisters();
return ResultSuccess();
}
Result GetFrozenAddressCount(u64 *out_count) { Result GetFrozenAddressCount(u64 *out_count) {
std::scoped_lock lk(this->cheat_lock); std::scoped_lock lk(this->cheat_lock);
@ -533,7 +599,20 @@ namespace ams::dmnt::cheat::impl {
this_ptr->debug_events_event.Wait(); this_ptr->debug_events_event.Wait();
while (true) { while (true) {
while (R_SUCCEEDED(svcWaitSynchronizationSingle(this_ptr->GetCheatProcessHandle(), std::numeric_limits<u64>::max()))) { while (R_SUCCEEDED(svcWaitSynchronizationSingle(this_ptr->GetCheatProcessHandle(), std::numeric_limits<u64>::max()))) {
std::scoped_lock lk(this_ptr->cheat_lock); this_ptr->cheat_lock.Lock();
ON_SCOPE_EXIT { this_ptr->cheat_lock.Unlock(); };
/* If we did an unsafe break, wait until we're not broken. */
if (this_ptr->broken_unsafe) {
this_ptr->cheat_lock.Unlock();
this_ptr->unsafe_break_event.Wait();
this_ptr->cheat_lock.Lock();
if (this_ptr->GetCheatProcessHandle() != svc::InvalidHandle) {
continue;
} else {
break;
}
}
/* Handle any pending debug events. */ /* Handle any pending debug events. */
if (this_ptr->HasActiveCheatProcess()) { if (this_ptr->HasActiveCheatProcess()) {
@ -680,6 +759,10 @@ namespace ams::dmnt::cheat::impl {
/* Cancel process guard. */ /* Cancel process guard. */
proc_guard.Cancel(); proc_guard.Cancel();
/* Reset broken state. */
this->broken_unsafe = false;
this->unsafe_break_event.Signal();
/* If new process, start the process. */ /* If new process, start the process. */
if (on_process_launch) { if (on_process_launch) {
this->StartProcess(this->cheat_process_metadata.process_id); this->StartProcess(this->cheat_process_metadata.process_id);
@ -1021,6 +1104,14 @@ namespace ams::dmnt::cheat::impl {
return GetReference(g_cheat_process_manager).WriteCheatProcessMemoryUnsafe(process_addr, data, size); return GetReference(g_cheat_process_manager).WriteCheatProcessMemoryUnsafe(process_addr, data, size);
} }
Result BreakCheatProcessUnsafe() {
return GetReference(g_cheat_process_manager).BreakCheatProcessUnsafe();
}
Result ContinueCheatProcessUnsafe() {
return GetReference(g_cheat_process_manager).ContinueCheatProcessUnsafe();
}
Result GetCheatProcessMappingCount(u64 *out_count) { Result GetCheatProcessMappingCount(u64 *out_count) {
return GetReference(g_cheat_process_manager).GetCheatProcessMappingCount(out_count); return GetReference(g_cheat_process_manager).GetCheatProcessMappingCount(out_count);
} }
@ -1041,6 +1132,14 @@ namespace ams::dmnt::cheat::impl {
return GetReference(g_cheat_process_manager).QueryCheatProcessMemory(mapping, address); return GetReference(g_cheat_process_manager).QueryCheatProcessMemory(mapping, address);
} }
Result BreakCheatProcess() {
return GetReference(g_cheat_process_manager).BreakCheatProcess();
}
Result ContinueCheatProcess() {
return GetReference(g_cheat_process_manager).ContinueCheatProcess();
}
Result GetCheatCount(u64 *out_count) { Result GetCheatCount(u64 *out_count) {
return GetReference(g_cheat_process_manager).GetCheatCount(out_count); return GetReference(g_cheat_process_manager).GetCheatCount(out_count);
} }
@ -1065,6 +1164,18 @@ namespace ams::dmnt::cheat::impl {
return GetReference(g_cheat_process_manager).RemoveCheat(cheat_id); return GetReference(g_cheat_process_manager).RemoveCheat(cheat_id);
} }
Result ReadStaticRegister(u64 *out, size_t which) {
return GetReference(g_cheat_process_manager).ReadStaticRegister(out, which);
}
Result WriteStaticRegister(size_t which, u64 value) {
return GetReference(g_cheat_process_manager).WriteStaticRegister(which, value);
}
Result ResetStaticRegisters() {
return GetReference(g_cheat_process_manager).ResetStaticRegisters();
}
Result GetFrozenAddressCount(u64 *out_count) { Result GetFrozenAddressCount(u64 *out_count) {
return GetReference(g_cheat_process_manager).GetFrozenAddressCount(out_count); return GetReference(g_cheat_process_manager).GetFrozenAddressCount(out_count);
} }

View file

@ -28,11 +28,16 @@ namespace ams::dmnt::cheat::impl {
Result ReadCheatProcessMemoryUnsafe(u64 process_addr, void *out_data, size_t size); Result ReadCheatProcessMemoryUnsafe(u64 process_addr, void *out_data, size_t size);
Result WriteCheatProcessMemoryUnsafe(u64 process_addr, void *data, size_t size); Result WriteCheatProcessMemoryUnsafe(u64 process_addr, void *data, size_t size);
Result BreakCheatProcessUnsafe();
Result ContinueCheatProcessUnsafe();
Result GetCheatProcessMappingCount(u64 *out_count); Result GetCheatProcessMappingCount(u64 *out_count);
Result GetCheatProcessMappings(MemoryInfo *mappings, size_t max_count, u64 *out_count, u64 offset); Result GetCheatProcessMappings(MemoryInfo *mappings, size_t max_count, u64 *out_count, u64 offset);
Result ReadCheatProcessMemory(u64 proc_addr, void *out_data, size_t size); Result ReadCheatProcessMemory(u64 proc_addr, void *out_data, size_t size);
Result WriteCheatProcessMemory(u64 proc_addr, const void *data, size_t size); Result WriteCheatProcessMemory(u64 proc_addr, const void *data, size_t size);
Result QueryCheatProcessMemory(MemoryInfo *mapping, u64 address); Result QueryCheatProcessMemory(MemoryInfo *mapping, u64 address);
Result BreakCheatProcess();
Result ContinueCheatProcess();
Result GetCheatCount(u64 *out_count); Result GetCheatCount(u64 *out_count);
Result GetCheats(CheatEntry *cheats, size_t max_count, u64 *out_count, u64 offset); Result GetCheats(CheatEntry *cheats, size_t max_count, u64 *out_count, u64 offset);
@ -40,6 +45,9 @@ namespace ams::dmnt::cheat::impl {
Result ToggleCheat(u32 cheat_id); Result ToggleCheat(u32 cheat_id);
Result AddCheat(u32 *out_id, const CheatDefinition &def, bool enabled); Result AddCheat(u32 *out_id, const CheatDefinition &def, bool enabled);
Result RemoveCheat(u32 cheat_id); Result RemoveCheat(u32 cheat_id);
Result ReadStaticRegister(u64 *out, size_t which);
Result WriteStaticRegister(size_t which, u64 value);
Result ResetStaticRegisters();
Result GetFrozenAddressCount(u64 *out_count); Result GetFrozenAddressCount(u64 *out_count);
Result GetFrozenAddresses(FrozenAddressEntry *frz_addrs, size_t max_count, u64 *out_count, u64 offset); Result GetFrozenAddresses(FrozenAddressEntry *frz_addrs, size_t max_count, u64 *out_count, u64 offset);

View file

@ -237,6 +237,17 @@ namespace ams::dmnt::cheat::impl {
this->LogToDebugFile("Act[%02x]: %d\n", i, opcode->save_restore_regmask.should_operate[i]); this->LogToDebugFile("Act[%02x]: %d\n", i, opcode->save_restore_regmask.should_operate[i]);
} }
break; break;
case CheatVmOpcodeType_LoadStaticRegister:
this->LogToDebugFile("Opcode: Load Static Register\n");
this->LogToDebugFile("Reg Idx: %x\n", opcode->load_static_reg.idx);
this->LogToDebugFile("Stc Idx: %x\n", opcode->load_static_reg.static_idx);
break;
case CheatVmOpcodeType_BreakProcess:
this->LogToDebugFile("Opcode: Break Cheat Process\n");
break;
case CheatVmOpcodeType_ContinueProcess:
this->LogToDebugFile("Opcode: Continue Cheat Process\n");
break;
case CheatVmOpcodeType_DebugLog: case CheatVmOpcodeType_DebugLog:
this->LogToDebugFile("Opcode: Debug Log\n"); this->LogToDebugFile("Opcode: Debug Log\n");
this->LogToDebugFile("Bit Width: %x\n", opcode->debug_log.bit_width); this->LogToDebugFile("Bit Width: %x\n", opcode->debug_log.bit_width);
@ -570,6 +581,30 @@ namespace ams::dmnt::cheat::impl {
} }
} }
break; break;
case CheatVmOpcodeType_LoadStaticRegister:
{
/* C3000XXx */
/* C3 = opcode 0xC3. */
/* XX = static register index. */
/* x = register index. */
opcode.load_static_reg.static_idx = ((first_dword >> 4) & 0xFF);
opcode.load_static_reg.idx = (first_dword & 0xF);
}
break;
case CheatVmOpcodeType_BreakProcess:
{
/* FF0????? */
/* FF0 = opcode 0xFF0 */
/* Breaks the current process. */
}
break;
case CheatVmOpcodeType_ContinueProcess:
{
/* FF1????? */
/* FF1 = opcode 0xFF1 */
/* Continues the current process. */
}
break;
case CheatVmOpcodeType_DebugLog: case CheatVmOpcodeType_DebugLog:
{ {
/* FFFTIX## */ /* FFFTIX## */
@ -1174,6 +1209,16 @@ namespace ams::dmnt::cheat::impl {
} }
} }
break; break;
case CheatVmOpcodeType_LoadStaticRegister:
/* Load a register with a static register. */
this->registers[cur_opcode.load_static_reg.idx] = this->static_registers[cur_opcode.load_static_reg.static_idx];
break;
case CheatVmOpcodeType_BreakProcess:
dmnt::cheat::impl::BreakCheatProcessUnsafe();
break;
case CheatVmOpcodeType_ContinueProcess:
dmnt::cheat::impl::ContinueCheatProcessUnsafe();
break;
case CheatVmOpcodeType_DebugLog: case CheatVmOpcodeType_DebugLog:
{ {
/* Read value from memory. */ /* Read value from memory. */

View file

@ -42,12 +42,15 @@ namespace ams::dmnt::cheat::impl {
CheatVmOpcodeType_BeginRegisterConditionalBlock = 0xC0, CheatVmOpcodeType_BeginRegisterConditionalBlock = 0xC0,
CheatVmOpcodeType_SaveRestoreRegister = 0xC1, CheatVmOpcodeType_SaveRestoreRegister = 0xC1,
CheatVmOpcodeType_SaveRestoreRegisterMask = 0xC2, CheatVmOpcodeType_SaveRestoreRegisterMask = 0xC2,
CheatVmOpcodeType_LoadStaticRegister = 0xC3,
/* This is a meta entry, and not a real opcode. */ /* This is a meta entry, and not a real opcode. */
/* This is to facilitate multi-nybble instruction decoding. */ /* This is to facilitate multi-nybble instruction decoding. */
CheatVmOpcodeType_DoubleExtendedWidth = 0xF0, CheatVmOpcodeType_DoubleExtendedWidth = 0xF0,
/* Double-extended width opcodes. */ /* Double-extended width opcodes. */
CheatVmOpcodeType_BreakProcess = 0xFF0,
CheatVmOpcodeType_ContinueProcess = 0xFF1,
CheatVmOpcodeType_DebugLog = 0xFFF, CheatVmOpcodeType_DebugLog = 0xFFF,
}; };
@ -223,6 +226,11 @@ namespace ams::dmnt::cheat::impl {
bool should_operate[0x10]; bool should_operate[0x10];
}; };
struct LoadStaticRegisterOpcode {
u32 static_idx;
u32 idx;
};
struct DebugLogOpcode { struct DebugLogOpcode {
u32 bit_width; u32 bit_width;
u32 log_id; u32 log_id;
@ -252,6 +260,7 @@ namespace ams::dmnt::cheat::impl {
BeginRegisterConditionalOpcode begin_reg_cond; BeginRegisterConditionalOpcode begin_reg_cond;
SaveRestoreRegisterOpcode save_restore_reg; SaveRestoreRegisterOpcode save_restore_reg;
SaveRestoreRegisterMaskOpcode save_restore_regmask; SaveRestoreRegisterMaskOpcode save_restore_regmask;
LoadStaticRegisterOpcode load_static_reg;
DebugLogOpcode debug_log; DebugLogOpcode debug_log;
}; };
}; };
@ -260,6 +269,7 @@ namespace ams::dmnt::cheat::impl {
public: public:
constexpr static size_t MaximumProgramOpcodeCount = 0x400; constexpr static size_t MaximumProgramOpcodeCount = 0x400;
constexpr static size_t NumRegisters = 0x10; constexpr static size_t NumRegisters = 0x10;
constexpr static size_t NumStaticRegisters = 0x100;
private: private:
size_t num_opcodes = 0; size_t num_opcodes = 0;
size_t instruction_ptr = 0; size_t instruction_ptr = 0;
@ -268,6 +278,7 @@ namespace ams::dmnt::cheat::impl {
u32 program[MaximumProgramOpcodeCount] = {0}; u32 program[MaximumProgramOpcodeCount] = {0};
u64 registers[NumRegisters] = {0}; u64 registers[NumRegisters] = {0};
u64 saved_values[NumRegisters] = {0}; u64 saved_values[NumRegisters] = {0};
u64 static_registers[NumStaticRegisters] = {0};
size_t loop_tops[NumRegisters] = {0}; size_t loop_tops[NumRegisters] = {0};
private: private:
bool DecodeNextOpcode(CheatVmOpcode *out); bool DecodeNextOpcode(CheatVmOpcode *out);
@ -294,6 +305,18 @@ namespace ams::dmnt::cheat::impl {
bool LoadProgram(const CheatEntry *cheats, size_t num_cheats); bool LoadProgram(const CheatEntry *cheats, size_t num_cheats);
void Execute(const CheatProcessMetadata *metadata); void Execute(const CheatProcessMetadata *metadata);
u64 GetStaticRegister(size_t which) const {
return this->static_registers[which];
}
void SetStaticRegister(size_t which, u64 value) {
this->static_registers[which] = value;
}
void ResetStaticRegisters() {
std::memset(this->static_registers, 0, sizeof(this->static_registers));
}
#ifdef DMNT_CHEAT_VM_DEBUG_LOG #ifdef DMNT_CHEAT_VM_DEBUG_LOG
private: private:
fs::FileHandle debug_log_file; fs::FileHandle debug_log_file;