From 4d0ab41e6e60734a06ab3c6b7eec762296341e5d Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 5 Mar 2019 23:58:36 -0800 Subject: [PATCH] dmnt-cheat: Fix debug event management --- .../dmnt/source/dmnt_cheat_manager.cpp | 99 ++++++++++++------- .../dmnt/source/dmnt_cheat_manager.hpp | 3 + stratosphere/libstratosphere | 2 +- 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/stratosphere/dmnt/source/dmnt_cheat_manager.cpp b/stratosphere/dmnt/source/dmnt_cheat_manager.cpp index 07349e104..926f9087e 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_manager.cpp +++ b/stratosphere/dmnt/source/dmnt_cheat_manager.cpp @@ -30,8 +30,9 @@ static DmntCheatVm *g_cheat_vm; static CheatProcessMetadata g_cheat_process_metadata = {0}; static Handle g_cheat_process_debug_hnd = 0; -/* For signalling the debug events thread. */ -static HosSignal g_has_cheat_process_signal; +/* For debug event thread management. */ +static HosMutex g_debug_event_thread_lock; +static bool g_has_debug_events_thread = false; /* To save some copying. */ static bool g_needs_reload_vm_program = false; @@ -42,11 +43,39 @@ static CheatEntry g_cheat_entries[DmntCheatManager::MaxCheatCount]; /* Global frozen address storage. */ static std::map g_frozen_addresses_map; -void DmntCheatManager::CloseActiveCheatProcess() { - if (g_cheat_process_debug_hnd != 0) { - /* We're no longer in possession of a debug process. */ - g_has_cheat_process_signal.Reset(); +void DmntCheatManager::StartDebugEventsThread() { + std::scoped_lock lk(g_debug_event_thread_lock); + + /* Spawn the debug events thread. */ + if (!g_has_debug_events_thread) { + Result rc; + if (R_FAILED((rc = g_debug_events_thread.Initialize(&DmntCheatManager::DebugEventsThread, nullptr, 0x4000, 48)))) { + return fatalSimple(rc); + } + + if (R_FAILED((rc = g_debug_events_thread.Start()))) { + return fatalSimple(rc); + } + + g_has_debug_events_thread = true; + } +} + +void DmntCheatManager::WaitDebugEventsThread() { + std::scoped_lock lk(g_debug_event_thread_lock); + + /* Wait for the thread to exit. */ + if (g_has_debug_events_thread) { + g_debug_events_thread.CancelSynchronization(); + g_debug_events_thread.Join(); + + g_has_debug_events_thread = false; + } +} + +void DmntCheatManager::CloseActiveCheatProcess() { + if (g_cheat_process_debug_hnd != 0) { /* Close process resources. */ svcCloseHandle(g_cheat_process_debug_hnd); g_cheat_process_debug_hnd = 0; @@ -71,6 +100,10 @@ bool DmntCheatManager::HasActiveCheatProcess() { has_cheat_process &= R_SUCCEEDED(svcGetProcessId(&tmp, g_cheat_process_debug_hnd)); } + if (has_cheat_process) { + has_cheat_process &= R_SUCCEEDED(pmdmntGetApplicationPid(&tmp)); + } + if (has_cheat_process) { has_cheat_process &= tmp == g_cheat_process_metadata.process_id; } @@ -89,7 +122,7 @@ void DmntCheatManager::ContinueCheatProcess() { while (R_SUCCEEDED(svcGetDebugEvent((u8 *)debug_event_buf, g_cheat_process_debug_hnd))) { /* ... */ } - + /* Continue the process. */ if (kernelAbove300()) { svcContinueDebugEvent(g_cheat_process_debug_hnd, 5, nullptr, 0); @@ -652,6 +685,11 @@ Result DmntCheatManager::ForceOpenCheatProcess() { return 0; } + /* Close the current application, if it's open. */ + CloseActiveCheatProcess(); + /* Wait to not have debug events thread. */ + WaitDebugEventsThread(); + /* Get the current application process ID. */ if (R_FAILED((rc = pmdmntGetApplicationPid(&g_cheat_process_metadata.process_id)))) { return rc; @@ -712,13 +750,10 @@ Result DmntCheatManager::ForceOpenCheatProcess() { if (R_FAILED((rc = svcDebugActiveProcess(&g_cheat_process_debug_hnd, g_cheat_process_metadata.process_id)))) { return rc; } + + /* Start debug events thread. */ + StartDebugEventsThread(); - /* Continue debug events, etc. */ - ContinueCheatProcess(); - - /* Signal to debug event swallower. */ - g_has_cheat_process_signal.Signal(); - /* Signal to our fans. */ g_cheat_process_event->Signal(); @@ -732,6 +767,9 @@ void DmntCheatManager::OnNewApplicationLaunch() { /* Close the current application, if it's open. */ CloseActiveCheatProcess(); + /* Wait to not have debug events thread. */ + WaitDebugEventsThread(); + /* Get the new application's process ID. */ if (R_FAILED((rc = pmdmntGetApplicationPid(&g_cheat_process_metadata.process_id)))) { fatalSimple(rc); @@ -801,13 +839,10 @@ void DmntCheatManager::OnNewApplicationLaunch() { /* Start the process. */ StartDebugProcess(g_cheat_process_metadata.process_id); - - /* Continue debug events, etc. */ - ContinueCheatProcess(); - - /* Signal to debug event swallower. */ - g_has_cheat_process_signal.Signal(); - + + /* Start debug events thread. */ + StartDebugEventsThread(); + /* Signal to our fans. */ g_cheat_process_event->Signal(); } @@ -862,20 +897,12 @@ void DmntCheatManager::VmThread(void *arg) { } void DmntCheatManager::DebugEventsThread(void *arg) { - while (true) { - /* Wait to have a cheat process. */ - g_has_cheat_process_signal.Wait(); + while (R_SUCCEEDED(svcWaitSynchronizationSingle(g_cheat_process_debug_hnd, U64_MAX))) { + std::scoped_lock lk(g_cheat_lock); - while (g_cheat_process_debug_hnd != 0 && R_SUCCEEDED(svcWaitSynchronizationSingle(g_cheat_process_debug_hnd, U64_MAX))) { - { - std::scoped_lock lk(g_cheat_lock); - /* Handle any pending debug events. */ - if (HasActiveCheatProcess()) { - ContinueCheatProcess(); - } - } - - svcSleepThread(1000000ull); + /* Handle any pending debug events. */ + if (HasActiveCheatProcess()) { + ContinueCheatProcess(); } } } @@ -917,12 +944,8 @@ void DmntCheatManager::InitializeCheatManager() { std::abort(); } - if (R_FAILED(g_debug_events_thread.Initialize(&DmntCheatManager::DebugEventsThread, nullptr, 0x4000, 48))) { - std::abort(); - } - /* Start threads. */ - if (R_FAILED(g_detect_thread.Start()) || R_FAILED(g_vm_thread.Start()) || R_FAILED(g_debug_events_thread.Start())) { + if (R_FAILED(g_detect_thread.Start()) || R_FAILED(g_vm_thread.Start())) { std::abort(); } } diff --git a/stratosphere/dmnt/source/dmnt_cheat_manager.hpp b/stratosphere/dmnt/source/dmnt_cheat_manager.hpp index 1a07360cd..dc8bff712 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_manager.hpp +++ b/stratosphere/dmnt/source/dmnt_cheat_manager.hpp @@ -31,6 +31,9 @@ class DmntCheatManager { static void VmThread(void *arg); static void DebugEventsThread(void *arg); + static void StartDebugEventsThread(); + static void WaitDebugEventsThread(); + static bool HasActiveCheatProcess(); static void CloseActiveCheatProcess(); static void ContinueCheatProcess(); diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index 0fbc0e2f4..49d2188f6 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit 0fbc0e2f468762de62d2b14d6495247d04e80bc3 +Subproject commit 49d2188f6fb71b54532f089a2c9439665a327ccd