dmnt: make debug event result handling more robust (closes #938)

This commit is contained in:
Michael Scire 2020-05-16 15:05:36 -07:00
parent 9598da0a0b
commit 9baf096a10
4 changed files with 64 additions and 43 deletions

View file

@ -599,25 +599,34 @@ namespace ams::dmnt::cheat::impl {
/* Atomically wait (and clear) signal for new process. */ /* Atomically wait (and clear) signal for new process. */
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()))) { Handle cheat_process_handle = this_ptr->GetCheatProcessHandle();
while (cheat_process_handle != svc::InvalidHandle && R_SUCCEEDED(svcWaitSynchronizationSingle(this_ptr->GetCheatProcessHandle(), std::numeric_limits<u64>::max()))) {
this_ptr->cheat_lock.Lock(); this_ptr->cheat_lock.Lock();
ON_SCOPE_EXIT { this_ptr->cheat_lock.Unlock(); }; ON_SCOPE_EXIT { this_ptr->cheat_lock.Unlock(); };
{
ON_SCOPE_EXIT { cheat_process_handle = this_ptr->GetCheatProcessHandle(); };
/* If we did an unsafe break, wait until we're not broken. */ /* If we did an unsafe break, wait until we're not broken. */
if (this_ptr->broken_unsafe) { if (this_ptr->broken_unsafe) {
this_ptr->cheat_lock.Unlock(); this_ptr->cheat_lock.Unlock();
this_ptr->unsafe_break_event.Wait(); this_ptr->unsafe_break_event.Wait();
this_ptr->cheat_lock.Lock(); this_ptr->cheat_lock.Lock();
if (this_ptr->GetCheatProcessHandle() != svc::InvalidHandle) { if (this_ptr->GetCheatProcessHandle() != svc::InvalidHandle) {
continue; continue;
} else { } else {
break; break;
}
} }
}
/* Handle any pending debug events. */ /* Handle any pending debug events. */
if (this_ptr->HasActiveCheatProcess()) { if (this_ptr->HasActiveCheatProcess()) {
dmnt::cheat::impl::ContinueCheatProcess(this_ptr->GetCheatProcessHandle()); R_TRY_CATCH(dmnt::cheat::impl::ContinueCheatProcess(this_ptr->GetCheatProcessHandle())) {
R_CATCH(svc::ResultProcessTerminated) {
this_ptr->CloseActiveCheatProcess();
break;
}
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
}
} }
} }

View file

@ -27,10 +27,11 @@ namespace ams::dmnt::cheat::impl {
static constexpr size_t NumCores = 4; static constexpr size_t NumCores = 4;
static constexpr size_t ThreadStackSize = os::MemoryPageSize; static constexpr size_t ThreadStackSize = os::MemoryPageSize;
private: private:
std::array<uintptr_t, NumCores> message_queue_buffers; std::array<uintptr_t, NumCores> handle_message_queue_buffers;
std::array<os::MessageQueue, NumCores> message_queues; std::array<uintptr_t, NumCores> result_message_queue_buffers;
std::array<os::MessageQueue, NumCores> handle_message_queues;
std::array<os::MessageQueue, NumCores> result_message_queues;
std::array<os::ThreadType, NumCores> threads; std::array<os::ThreadType, NumCores> threads;
os::Event continued_event;
alignas(os::MemoryPageSize) u8 thread_stacks[NumCores][ThreadStackSize]; alignas(os::MemoryPageSize) u8 thread_stacks[NumCores][ThreadStackSize];
private: private:
@ -43,14 +44,14 @@ namespace ams::dmnt::cheat::impl {
Handle debug_handle = this_ptr->WaitReceiveHandle(current_core); Handle debug_handle = this_ptr->WaitReceiveHandle(current_core);
/* Continue events on the correct core. */ /* Continue events on the correct core. */
R_ABORT_UNLESS(this_ptr->ContinueDebugEvent(debug_handle)); Result result = this_ptr->ContinueDebugEvent(debug_handle);
/* Signal that we've continued. */ /* Return our result. */
this_ptr->SignalContinued(); this_ptr->SendContinueResult(current_core, result);
} }
} }
size_t GetTargetCore(const svc::DebugEventInfo &dbg_event, Handle debug_handle) { Result GetTargetCore(size_t *out, const svc::DebugEventInfo &dbg_event, Handle debug_handle) {
/* If we don't need to continue on a specific core, use the system core. */ /* If we don't need to continue on a specific core, use the system core. */
size_t target_core = NumCores - 1; size_t target_core = NumCores - 1;
@ -58,20 +59,26 @@ namespace ams::dmnt::cheat::impl {
if (dbg_event.type == svc::DebugEvent_AttachThread) { if (dbg_event.type == svc::DebugEvent_AttachThread) {
u64 out64 = 0; u64 out64 = 0;
u32 out32 = 0; u32 out32 = 0;
R_ABORT_UNLESS(svcGetDebugThreadParam(&out64, &out32, debug_handle, dbg_event.info.attach_thread.thread_id, DebugThreadParam_CurrentCore));
R_TRY_CATCH(svcGetDebugThreadParam(&out64, &out32, debug_handle, dbg_event.info.attach_thread.thread_id, DebugThreadParam_CurrentCore)) {
R_CATCH_RETHROW(svc::ResultProcessTerminated)
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
target_core = out32; target_core = out32;
} }
return target_core; /* Set the target core. */
*out = target_core;
return ResultSuccess();
} }
void SendHandle(size_t target_core, Handle debug_handle) { void SendHandle(size_t target_core, Handle debug_handle) {
this->message_queues[target_core].Send(static_cast<uintptr_t>(debug_handle)); this->handle_message_queues[target_core].Send(static_cast<uintptr_t>(debug_handle));
} }
Handle WaitReceiveHandle(size_t core_id) { Handle WaitReceiveHandle(size_t core_id) {
uintptr_t x = 0; uintptr_t x = 0;
this->message_queues[core_id].Receive(&x); this->handle_message_queues[core_id].Receive(&x);
return static_cast<Handle>(x); return static_cast<Handle>(x);
} }
@ -83,22 +90,27 @@ namespace ams::dmnt::cheat::impl {
} }
} }
void WaitContinued() { void SendContinueResult(size_t target_core, Result result) {
this->continued_event.Wait(); this->result_message_queues[target_core].Send(static_cast<uintptr_t>(result.GetValue()));
} }
void SignalContinued() { Result GetContinueResult(size_t core_id) {
this->continued_event.Signal(); uintptr_t x = 0;
this->result_message_queues[core_id].Receive(&x);
return static_cast<Result>(x);
} }
public: public:
DebugEventsManager() DebugEventsManager()
: message_queues{ : handle_message_queues{
os::MessageQueue(std::addressof(message_queue_buffers[0]), 1), os::MessageQueue(std::addressof(handle_message_queue_buffers[0]), 1),
os::MessageQueue(std::addressof(message_queue_buffers[1]), 1), os::MessageQueue(std::addressof(handle_message_queue_buffers[1]), 1),
os::MessageQueue(std::addressof(message_queue_buffers[2]), 1), os::MessageQueue(std::addressof(handle_message_queue_buffers[2]), 1),
os::MessageQueue(std::addressof(message_queue_buffers[3]), 1)}, os::MessageQueue(std::addressof(handle_message_queue_buffers[3]), 1)},
continued_event(os::EventClearMode_AutoClear), result_message_queues{
os::MessageQueue(std::addressof(result_message_queue_buffers[0]), 1),
os::MessageQueue(std::addressof(result_message_queue_buffers[1]), 1),
os::MessageQueue(std::addressof(result_message_queue_buffers[2]), 1),
os::MessageQueue(std::addressof(result_message_queue_buffers[3]), 1)},
thread_stacks{} thread_stacks{}
{ {
for (size_t i = 0; i < NumCores; i++) { for (size_t i = 0; i < NumCores; i++) {
@ -114,19 +126,19 @@ namespace ams::dmnt::cheat::impl {
} }
} }
void ContinueCheatProcess(Handle cheat_dbg_hnd) { Result ContinueCheatProcess(Handle cheat_dbg_hnd) {
/* Loop getting all debug events. */ /* Loop getting all debug events. */
svc::DebugEventInfo d; svc::DebugEventInfo d;
size_t target_core = NumCores - 1; size_t target_core = NumCores - 1;
while (R_SUCCEEDED(svc::GetDebugEvent(std::addressof(d), cheat_dbg_hnd))) { while (R_SUCCEEDED(svc::GetDebugEvent(std::addressof(d), cheat_dbg_hnd))) {
if (d.type == svc::DebugEvent_AttachThread) { if (d.type == svc::DebugEvent_AttachThread) {
target_core = GetTargetCore(d, cheat_dbg_hnd); R_TRY(GetTargetCore(std::addressof(target_core), d, cheat_dbg_hnd));
} }
} }
/* Send handle to correct core, wait for continue to finish. */ /* Send handle to correct core, wait for continue to finish. */
this->SendHandle(target_core, cheat_dbg_hnd); this->SendHandle(target_core, cheat_dbg_hnd);
this->WaitContinued(); return this->GetContinueResult(target_core);
} }
}; };
@ -139,8 +151,8 @@ namespace ams::dmnt::cheat::impl {
new (GetPointer(g_events_manager)) DebugEventsManager; new (GetPointer(g_events_manager)) DebugEventsManager;
} }
void ContinueCheatProcess(Handle cheat_dbg_hnd) { Result ContinueCheatProcess(Handle cheat_dbg_hnd) {
GetReference(g_events_manager).ContinueCheatProcess(cheat_dbg_hnd); return GetReference(g_events_manager).ContinueCheatProcess(cheat_dbg_hnd);
} }
} }

View file

@ -20,6 +20,6 @@ namespace ams::dmnt::cheat::impl {
void InitializeDebugEventsManager(); void InitializeDebugEventsManager();
void ContinueCheatProcess(Handle cheat_dbg_hnd); Result ContinueCheatProcess(Handle cheat_dbg_hnd);
} }

View file

@ -40,7 +40,7 @@ namespace ams {
namespace result { namespace result {
bool CallFatalOnResultAssertion = true; bool CallFatalOnResultAssertion = false;
} }