mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-23 04:41:12 +00:00
dmnt: implement break/continue, static reg commands
This commit is contained in:
parent
332dbdd497
commit
11b8a92458
6 changed files with 230 additions and 8 deletions
|
@ -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 ================================== */
|
||||||
/* ========================================================================================= */
|
/* ========================================================================================= */
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue