mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-18 17:14:28 -04:00
Dmnt: Add break/continue commands, add static register api. (#899)
* dmnt: implement break/continue, static reg commands * dmnt: revise per WerWolv's feedback.
This commit is contained in:
parent
b7c4dae899
commit
be07035954
6 changed files with 242 additions and 8 deletions
|
@ -31,6 +31,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
static constexpr size_t ThreadStackSize = 0x4000;
|
||||
private:
|
||||
os::Mutex cheat_lock;
|
||||
os::Event unsafe_break_event;
|
||||
os::Event debug_events_event; /* Autoclear. */
|
||||
os::ThreadType detect_thread, debug_events_thread;
|
||||
os::SystemEvent cheat_process_event;
|
||||
|
@ -38,6 +39,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
CheatProcessMetadata cheat_process_metadata = {};
|
||||
|
||||
os::ThreadType vm_thread;
|
||||
bool broken_unsafe = false;
|
||||
bool needs_reload_vm = false;
|
||||
CheatVirtualMachine cheat_vm;
|
||||
|
||||
|
@ -85,6 +87,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
for (size_t i = 0; i < MaxCheatCount; i++) {
|
||||
this->ResetCheatEntry(i);
|
||||
}
|
||||
|
||||
this->cheat_vm.ResetStaticRegisters();
|
||||
}
|
||||
|
||||
CheatEntry *GetCheatEntryById(size_t i) {
|
||||
|
@ -119,6 +123,10 @@ namespace ams::dmnt::cheat::impl {
|
|||
|
||||
void CloseActiveCheatProcess() {
|
||||
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. */
|
||||
os::CancelThreadSynchronization(std::addressof(this->debug_events_thread));
|
||||
|
||||
|
@ -182,7 +190,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
}
|
||||
|
||||
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. */
|
||||
{
|
||||
u8 en = 0;
|
||||
|
@ -257,6 +265,19 @@ namespace ams::dmnt::cheat::impl {
|
|||
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) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
|
||||
|
@ -335,6 +356,22 @@ namespace ams::dmnt::cheat::impl {
|
|||
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) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
|
||||
|
@ -436,6 +473,35 @@ namespace ams::dmnt::cheat::impl {
|
|||
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) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
|
||||
|
@ -533,7 +599,20 @@ namespace ams::dmnt::cheat::impl {
|
|||
this_ptr->debug_events_event.Wait();
|
||||
while (true) {
|
||||
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. */
|
||||
if (this_ptr->HasActiveCheatProcess()) {
|
||||
|
@ -680,6 +759,10 @@ namespace ams::dmnt::cheat::impl {
|
|||
/* Cancel process guard. */
|
||||
proc_guard.Cancel();
|
||||
|
||||
/* Reset broken state. */
|
||||
this->broken_unsafe = false;
|
||||
this->unsafe_break_event.Signal();
|
||||
|
||||
/* If new process, start the process. */
|
||||
if (on_process_launch) {
|
||||
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);
|
||||
}
|
||||
|
||||
Result BreakCheatProcessUnsafe() {
|
||||
return GetReference(g_cheat_process_manager).BreakCheatProcessUnsafe();
|
||||
}
|
||||
|
||||
Result ContinueCheatProcessUnsafe() {
|
||||
return GetReference(g_cheat_process_manager).ContinueCheatProcessUnsafe();
|
||||
}
|
||||
|
||||
Result GetCheatProcessMappingCount(u64 *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);
|
||||
}
|
||||
|
||||
Result BreakCheatProcess() {
|
||||
return GetReference(g_cheat_process_manager).BreakCheatProcess();
|
||||
}
|
||||
|
||||
Result ContinueCheatProcess() {
|
||||
return GetReference(g_cheat_process_manager).ContinueCheatProcess();
|
||||
}
|
||||
|
||||
Result GetCheatCount(u64 *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);
|
||||
}
|
||||
|
||||
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) {
|
||||
return GetReference(g_cheat_process_manager).GetFrozenAddressCount(out_count);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue