From f90a022d3a20c86399f49a8154847b73bc1b8fd3 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 2 Jan 2024 17:12:16 -0500 Subject: kernel: fix debugger and process list lifetime --- src/core/debugger/debugger.cpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'src/core/debugger/debugger.cpp') diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 0e270eb50..e86aae846 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp @@ -114,7 +114,7 @@ public: } Kernel::KThread* GetActiveThread() override { - return state->active_thread; + return state->active_thread.GetPointerUnsafe(); } private: @@ -147,11 +147,14 @@ private: std::scoped_lock lk{connection_lock}; + // Find the process we are going to debug. + SetDebugProcess(); + // Ensure everything is stopped. PauseEmulation(); // Set up the new frontend. - frontend = std::make_unique(*this, system); + frontend = std::make_unique(*this, system, debug_process.GetPointerUnsafe()); // Set the new state. This will tear down any existing state. state = ConnectionState{ @@ -194,15 +197,20 @@ private: UpdateActiveThread(); if (state->info.type == SignalType::Watchpoint) { - frontend->Watchpoint(state->active_thread, *state->info.watchpoint); + frontend->Watchpoint(std::addressof(*state->active_thread), + *state->info.watchpoint); } else { - frontend->Stopped(state->active_thread); + frontend->Stopped(std::addressof(*state->active_thread)); } break; case SignalType::ShuttingDown: frontend->ShuttingDown(); + // Release members. + state->active_thread.Reset(nullptr); + debug_process.Reset(nullptr); + // Wait for emulation to shut down gracefully now. state->signal_pipe.close(); state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); @@ -222,7 +230,7 @@ private: stopped = true; PauseEmulation(); UpdateActiveThread(); - frontend->Stopped(state->active_thread); + frontend->Stopped(state->active_thread.GetPointerUnsafe()); break; } case DebuggerAction::Continue: @@ -232,7 +240,7 @@ private: MarkResumed([&] { state->active_thread->SetStepState(Kernel::StepState::StepPending); state->active_thread->Resume(Kernel::SuspendType::Debug); - ResumeEmulation(state->active_thread); + ResumeEmulation(state->active_thread.GetPointerUnsafe()); }); break; case DebuggerAction::StepThreadLocked: { @@ -255,6 +263,7 @@ private: } void PauseEmulation() { + Kernel::KScopedLightLock ll{debug_process->GetListLock()}; Kernel::KScopedSchedulerLock sl{system.Kernel()}; // Put all threads to sleep on next scheduler round. @@ -264,6 +273,9 @@ private: } void ResumeEmulation(Kernel::KThread* except = nullptr) { + Kernel::KScopedLightLock ll{debug_process->GetListLock()}; + Kernel::KScopedSchedulerLock sl{system.Kernel()}; + // Wake up all threads. for (auto& thread : ThreadList()) { if (std::addressof(thread) == except) { @@ -277,15 +289,16 @@ private: template void MarkResumed(Callback&& cb) { - Kernel::KScopedSchedulerLock sl{system.Kernel()}; stopped = false; cb(); } void UpdateActiveThread() { + Kernel::KScopedLightLock ll{debug_process->GetListLock()}; + auto& threads{ThreadList()}; for (auto& thread : threads) { - if (std::addressof(thread) == state->active_thread) { + if (std::addressof(thread) == state->active_thread.GetPointerUnsafe()) { // Thread is still alive, no need to update. return; } @@ -293,12 +306,18 @@ private: state->active_thread = std::addressof(threads.front()); } +private: + void SetDebugProcess() { + debug_process = std::move(system.Kernel().GetProcessList().back()); + } + Kernel::KProcess::ThreadList& ThreadList() { - return system.ApplicationProcess()->GetThreadList(); + return debug_process->GetThreadList(); } private: System& system; + Kernel::KScopedAutoObject debug_process; std::unique_ptr frontend; boost::asio::io_context io_context; @@ -310,7 +329,7 @@ private: boost::process::async_pipe signal_pipe; SignalInfo info; - Kernel::KThread* active_thread; + Kernel::KScopedAutoObject active_thread; std::array client_data; bool pipe_data; }; -- cgit v1.2.3