kernel: fix debugger and process list lifetime
This commit is contained in:
		| @@ -114,7 +114,7 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     Kernel::KThread* GetActiveThread() override { |     Kernel::KThread* GetActiveThread() override { | ||||||
|         return state->active_thread; |         return state->active_thread.GetPointerUnsafe(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| private: | private: | ||||||
| @@ -147,11 +147,14 @@ private: | |||||||
|  |  | ||||||
|         std::scoped_lock lk{connection_lock}; |         std::scoped_lock lk{connection_lock}; | ||||||
|  |  | ||||||
|  |         // Find the process we are going to debug. | ||||||
|  |         SetDebugProcess(); | ||||||
|  |  | ||||||
|         // Ensure everything is stopped. |         // Ensure everything is stopped. | ||||||
|         PauseEmulation(); |         PauseEmulation(); | ||||||
|  |  | ||||||
|         // Set up the new frontend. |         // Set up the new frontend. | ||||||
|         frontend = std::make_unique<GDBStub>(*this, system); |         frontend = std::make_unique<GDBStub>(*this, system, debug_process.GetPointerUnsafe()); | ||||||
|  |  | ||||||
|         // Set the new state. This will tear down any existing state. |         // Set the new state. This will tear down any existing state. | ||||||
|         state = ConnectionState{ |         state = ConnectionState{ | ||||||
| @@ -194,15 +197,20 @@ private: | |||||||
|             UpdateActiveThread(); |             UpdateActiveThread(); | ||||||
|  |  | ||||||
|             if (state->info.type == SignalType::Watchpoint) { |             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 { |             } else { | ||||||
|                 frontend->Stopped(state->active_thread); |                 frontend->Stopped(std::addressof(*state->active_thread)); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             break; |             break; | ||||||
|         case SignalType::ShuttingDown: |         case SignalType::ShuttingDown: | ||||||
|             frontend->ShuttingDown(); |             frontend->ShuttingDown(); | ||||||
|  |  | ||||||
|  |             // Release members. | ||||||
|  |             state->active_thread.Reset(nullptr); | ||||||
|  |             debug_process.Reset(nullptr); | ||||||
|  |  | ||||||
|             // Wait for emulation to shut down gracefully now. |             // Wait for emulation to shut down gracefully now. | ||||||
|             state->signal_pipe.close(); |             state->signal_pipe.close(); | ||||||
|             state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); |             state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); | ||||||
| @@ -222,7 +230,7 @@ private: | |||||||
|                 stopped = true; |                 stopped = true; | ||||||
|                 PauseEmulation(); |                 PauseEmulation(); | ||||||
|                 UpdateActiveThread(); |                 UpdateActiveThread(); | ||||||
|                 frontend->Stopped(state->active_thread); |                 frontend->Stopped(state->active_thread.GetPointerUnsafe()); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             case DebuggerAction::Continue: |             case DebuggerAction::Continue: | ||||||
| @@ -232,7 +240,7 @@ private: | |||||||
|                 MarkResumed([&] { |                 MarkResumed([&] { | ||||||
|                     state->active_thread->SetStepState(Kernel::StepState::StepPending); |                     state->active_thread->SetStepState(Kernel::StepState::StepPending); | ||||||
|                     state->active_thread->Resume(Kernel::SuspendType::Debug); |                     state->active_thread->Resume(Kernel::SuspendType::Debug); | ||||||
|                     ResumeEmulation(state->active_thread); |                     ResumeEmulation(state->active_thread.GetPointerUnsafe()); | ||||||
|                 }); |                 }); | ||||||
|                 break; |                 break; | ||||||
|             case DebuggerAction::StepThreadLocked: { |             case DebuggerAction::StepThreadLocked: { | ||||||
| @@ -255,6 +263,7 @@ private: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void PauseEmulation() { |     void PauseEmulation() { | ||||||
|  |         Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||||||
|         Kernel::KScopedSchedulerLock sl{system.Kernel()}; |         Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||||||
|  |  | ||||||
|         // Put all threads to sleep on next scheduler round. |         // Put all threads to sleep on next scheduler round. | ||||||
| @@ -264,6 +273,9 @@ private: | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void ResumeEmulation(Kernel::KThread* except = nullptr) { |     void ResumeEmulation(Kernel::KThread* except = nullptr) { | ||||||
|  |         Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||||||
|  |         Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||||||
|  |  | ||||||
|         // Wake up all threads. |         // Wake up all threads. | ||||||
|         for (auto& thread : ThreadList()) { |         for (auto& thread : ThreadList()) { | ||||||
|             if (std::addressof(thread) == except) { |             if (std::addressof(thread) == except) { | ||||||
| @@ -277,15 +289,16 @@ private: | |||||||
|  |  | ||||||
|     template <typename Callback> |     template <typename Callback> | ||||||
|     void MarkResumed(Callback&& cb) { |     void MarkResumed(Callback&& cb) { | ||||||
|         Kernel::KScopedSchedulerLock sl{system.Kernel()}; |  | ||||||
|         stopped = false; |         stopped = false; | ||||||
|         cb(); |         cb(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void UpdateActiveThread() { |     void UpdateActiveThread() { | ||||||
|  |         Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||||||
|  |  | ||||||
|         auto& threads{ThreadList()}; |         auto& threads{ThreadList()}; | ||||||
|         for (auto& thread : threads) { |         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. |                 // Thread is still alive, no need to update. | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| @@ -293,12 +306,18 @@ private: | |||||||
|         state->active_thread = std::addressof(threads.front()); |         state->active_thread = std::addressof(threads.front()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void SetDebugProcess() { | ||||||
|  |         debug_process = std::move(system.Kernel().GetProcessList().back()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     Kernel::KProcess::ThreadList& ThreadList() { |     Kernel::KProcess::ThreadList& ThreadList() { | ||||||
|         return system.ApplicationProcess()->GetThreadList(); |         return debug_process->GetThreadList(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     System& system; |     System& system; | ||||||
|  |     Kernel::KScopedAutoObject<Kernel::KProcess> debug_process; | ||||||
|     std::unique_ptr<DebuggerFrontend> frontend; |     std::unique_ptr<DebuggerFrontend> frontend; | ||||||
|  |  | ||||||
|     boost::asio::io_context io_context; |     boost::asio::io_context io_context; | ||||||
| @@ -310,7 +329,7 @@ private: | |||||||
|         boost::process::async_pipe signal_pipe; |         boost::process::async_pipe signal_pipe; | ||||||
|  |  | ||||||
|         SignalInfo info; |         SignalInfo info; | ||||||
|         Kernel::KThread* active_thread; |         Kernel::KScopedAutoObject<Kernel::KThread> active_thread; | ||||||
|         std::array<u8, 4096> client_data; |         std::array<u8, 4096> client_data; | ||||||
|         bool pipe_data; |         bool pipe_data; | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -108,9 +108,9 @@ static std::string EscapeXML(std::string_view data) { | |||||||
|     return escaped; |     return escaped; | ||||||
| } | } | ||||||
|  |  | ||||||
| GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_) | GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_, Kernel::KProcess* debug_process_) | ||||||
|     : DebuggerFrontend(backend_), system{system_} { |     : DebuggerFrontend(backend_), system{system_}, debug_process{debug_process_} { | ||||||
|     if (system.ApplicationProcess()->Is64Bit()) { |     if (GetProcess()->Is64Bit()) { | ||||||
|         arch = std::make_unique<GDBStubA64>(); |         arch = std::make_unique<GDBStubA64>(); | ||||||
|     } else { |     } else { | ||||||
|         arch = std::make_unique<GDBStubA32>(); |         arch = std::make_unique<GDBStubA32>(); | ||||||
| @@ -276,7 +276,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||||||
|         const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; |         const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; | ||||||
|  |  | ||||||
|         std::vector<u8> mem(size); |         std::vector<u8> mem(size); | ||||||
|         if (system.ApplicationMemory().ReadBlock(addr, mem.data(), size)) { |         if (GetMemory().ReadBlock(addr, mem.data(), size)) { | ||||||
|             // Restore any bytes belonging to replaced instructions. |             // Restore any bytes belonging to replaced instructions. | ||||||
|             auto it = replaced_instructions.lower_bound(addr); |             auto it = replaced_instructions.lower_bound(addr); | ||||||
|             for (; it != replaced_instructions.end() && it->first < addr + size; it++) { |             for (; it != replaced_instructions.end() && it->first < addr + size; it++) { | ||||||
| @@ -310,8 +310,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||||||
|         const auto mem_substr{std::string_view(command).substr(mem_sep)}; |         const auto mem_substr{std::string_view(command).substr(mem_sep)}; | ||||||
|         const auto mem{Common::HexStringToVector(mem_substr, false)}; |         const auto mem{Common::HexStringToVector(mem_substr, false)}; | ||||||
|  |  | ||||||
|         if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) { |         if (GetMemory().WriteBlock(addr, mem.data(), size)) { | ||||||
|             Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, size); |             Core::InvalidateInstructionCacheRange(GetProcess(), addr, size); | ||||||
|             SendReply(GDB_STUB_REPLY_OK); |             SendReply(GDB_STUB_REPLY_OK); | ||||||
|         } else { |         } else { | ||||||
|             SendReply(GDB_STUB_REPLY_ERR); |             SendReply(GDB_STUB_REPLY_ERR); | ||||||
| @@ -353,7 +353,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { | |||||||
|     const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; |     const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | ||||||
|     const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; |     const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; | ||||||
|  |  | ||||||
|     if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { |     if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { | ||||||
|         SendReply(GDB_STUB_REPLY_ERR); |         SendReply(GDB_STUB_REPLY_ERR); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| @@ -362,22 +362,20 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { | |||||||
|  |  | ||||||
|     switch (type) { |     switch (type) { | ||||||
|     case BreakpointType::Software: |     case BreakpointType::Software: | ||||||
|         replaced_instructions[addr] = system.ApplicationMemory().Read32(addr); |         replaced_instructions[addr] = GetMemory().Read32(addr); | ||||||
|         system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction()); |         GetMemory().Write32(addr, arch->BreakpointInstruction()); | ||||||
|         Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); |         Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); | ||||||
|         success = true; |         success = true; | ||||||
|         break; |         break; | ||||||
|     case BreakpointType::WriteWatch: |     case BreakpointType::WriteWatch: | ||||||
|         success = system.ApplicationProcess()->InsertWatchpoint(addr, size, |         success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); | ||||||
|                                                                 Kernel::DebugWatchpointType::Write); |  | ||||||
|         break; |         break; | ||||||
|     case BreakpointType::ReadWatch: |     case BreakpointType::ReadWatch: | ||||||
|         success = system.ApplicationProcess()->InsertWatchpoint(addr, size, |         success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); | ||||||
|                                                                 Kernel::DebugWatchpointType::Read); |  | ||||||
|         break; |         break; | ||||||
|     case BreakpointType::AccessWatch: |     case BreakpointType::AccessWatch: | ||||||
|         success = system.ApplicationProcess()->InsertWatchpoint( |         success = | ||||||
|             addr, size, Kernel::DebugWatchpointType::ReadOrWrite); |             GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | ||||||
|         break; |         break; | ||||||
|     case BreakpointType::Hardware: |     case BreakpointType::Hardware: | ||||||
|     default: |     default: | ||||||
| @@ -400,7 +398,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | |||||||
|     const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; |     const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | ||||||
|     const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; |     const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; | ||||||
|  |  | ||||||
|     if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { |     if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { | ||||||
|         SendReply(GDB_STUB_REPLY_ERR); |         SendReply(GDB_STUB_REPLY_ERR); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| @@ -411,24 +409,22 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | |||||||
|     case BreakpointType::Software: { |     case BreakpointType::Software: { | ||||||
|         const auto orig_insn{replaced_instructions.find(addr)}; |         const auto orig_insn{replaced_instructions.find(addr)}; | ||||||
|         if (orig_insn != replaced_instructions.end()) { |         if (orig_insn != replaced_instructions.end()) { | ||||||
|             system.ApplicationMemory().Write32(addr, orig_insn->second); |             GetMemory().Write32(addr, orig_insn->second); | ||||||
|             Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); |             Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); | ||||||
|             replaced_instructions.erase(addr); |             replaced_instructions.erase(addr); | ||||||
|             success = true; |             success = true; | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case BreakpointType::WriteWatch: |     case BreakpointType::WriteWatch: | ||||||
|         success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, |         success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); | ||||||
|                                                                 Kernel::DebugWatchpointType::Write); |  | ||||||
|         break; |         break; | ||||||
|     case BreakpointType::ReadWatch: |     case BreakpointType::ReadWatch: | ||||||
|         success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, |         success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); | ||||||
|                                                                 Kernel::DebugWatchpointType::Read); |  | ||||||
|         break; |         break; | ||||||
|     case BreakpointType::AccessWatch: |     case BreakpointType::AccessWatch: | ||||||
|         success = system.ApplicationProcess()->RemoveWatchpoint( |         success = | ||||||
|             addr, size, Kernel::DebugWatchpointType::ReadOrWrite); |             GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | ||||||
|         break; |         break; | ||||||
|     case BreakpointType::Hardware: |     case BreakpointType::Hardware: | ||||||
|     default: |     default: | ||||||
| @@ -466,10 +462,10 @@ void GDBStub::HandleQuery(std::string_view command) { | |||||||
|         const auto target_xml{arch->GetTargetXML()}; |         const auto target_xml{arch->GetTargetXML()}; | ||||||
|         SendReply(PaginateBuffer(target_xml, command.substr(30))); |         SendReply(PaginateBuffer(target_xml, command.substr(30))); | ||||||
|     } else if (command.starts_with("Offsets")) { |     } else if (command.starts_with("Offsets")) { | ||||||
|         const auto main_offset = Core::FindMainModuleEntrypoint(system.ApplicationProcess()); |         const auto main_offset = Core::FindMainModuleEntrypoint(GetProcess()); | ||||||
|         SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); |         SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); | ||||||
|     } else if (command.starts_with("Xfer:libraries:read::")) { |     } else if (command.starts_with("Xfer:libraries:read::")) { | ||||||
|         auto modules = Core::FindModules(system.ApplicationProcess()); |         auto modules = Core::FindModules(GetProcess()); | ||||||
|  |  | ||||||
|         std::string buffer; |         std::string buffer; | ||||||
|         buffer += R"(<?xml version="1.0"?>)"; |         buffer += R"(<?xml version="1.0"?>)"; | ||||||
| @@ -483,7 +479,7 @@ void GDBStub::HandleQuery(std::string_view command) { | |||||||
|         SendReply(PaginateBuffer(buffer, command.substr(21))); |         SendReply(PaginateBuffer(buffer, command.substr(21))); | ||||||
|     } else if (command.starts_with("fThreadInfo")) { |     } else if (command.starts_with("fThreadInfo")) { | ||||||
|         // beginning of list |         // beginning of list | ||||||
|         const auto& threads = system.ApplicationProcess()->GetThreadList(); |         const auto& threads = GetProcess()->GetThreadList(); | ||||||
|         std::vector<std::string> thread_ids; |         std::vector<std::string> thread_ids; | ||||||
|         for (const auto& thread : threads) { |         for (const auto& thread : threads) { | ||||||
|             thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId())); |             thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId())); | ||||||
| @@ -497,7 +493,7 @@ void GDBStub::HandleQuery(std::string_view command) { | |||||||
|         buffer += R"(<?xml version="1.0"?>)"; |         buffer += R"(<?xml version="1.0"?>)"; | ||||||
|         buffer += "<threads>"; |         buffer += "<threads>"; | ||||||
|  |  | ||||||
|         const auto& threads = system.ApplicationProcess()->GetThreadList(); |         const auto& threads = GetProcess()->GetThreadList(); | ||||||
|         for (const auto& thread : threads) { |         for (const auto& thread : threads) { | ||||||
|             auto thread_name{Core::GetThreadName(&thread)}; |             auto thread_name{Core::GetThreadName(&thread)}; | ||||||
|             if (!thread_name) { |             if (!thread_name) { | ||||||
| @@ -613,7 +609,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | |||||||
|     std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; |     std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; | ||||||
|     std::string reply; |     std::string reply; | ||||||
|  |  | ||||||
|     auto* process = system.ApplicationProcess(); |     auto* process = GetProcess(); | ||||||
|     auto& page_table = process->GetPageTable(); |     auto& page_table = process->GetPageTable(); | ||||||
|  |  | ||||||
|     const char* commands = "Commands:\n" |     const char* commands = "Commands:\n" | ||||||
| @@ -714,7 +710,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | |||||||
| } | } | ||||||
|  |  | ||||||
| Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | ||||||
|     auto& threads{system.ApplicationProcess()->GetThreadList()}; |     auto& threads{GetProcess()->GetThreadList()}; | ||||||
|     for (auto& thread : threads) { |     for (auto& thread : threads) { | ||||||
|         if (thread.GetThreadId() == thread_id) { |         if (thread.GetThreadId() == thread_id) { | ||||||
|             return std::addressof(thread); |             return std::addressof(thread); | ||||||
| @@ -783,4 +779,12 @@ void GDBStub::SendStatus(char status) { | |||||||
|     backend.WriteToClient(buf); |     backend.WriteToClient(buf); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | Kernel::KProcess* GDBStub::GetProcess() { | ||||||
|  |     return debug_process; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Core::Memory::Memory& GDBStub::GetMemory() { | ||||||
|  |     return GetProcess()->GetMemory(); | ||||||
|  | } | ||||||
|  |  | ||||||
| } // namespace Core | } // namespace Core | ||||||
|   | |||||||
| @@ -12,13 +12,22 @@ | |||||||
| #include "core/debugger/debugger_interface.h" | #include "core/debugger/debugger_interface.h" | ||||||
| #include "core/debugger/gdbstub_arch.h" | #include "core/debugger/gdbstub_arch.h" | ||||||
|  |  | ||||||
|  | namespace Kernel { | ||||||
|  | class KProcess; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | namespace Core::Memory { | ||||||
|  | class Memory; | ||||||
|  | } | ||||||
|  |  | ||||||
| namespace Core { | namespace Core { | ||||||
|  |  | ||||||
| class System; | class System; | ||||||
|  |  | ||||||
| class GDBStub : public DebuggerFrontend { | class GDBStub : public DebuggerFrontend { | ||||||
| public: | public: | ||||||
|     explicit GDBStub(DebuggerBackend& backend, Core::System& system); |     explicit GDBStub(DebuggerBackend& backend, Core::System& system, | ||||||
|  |                      Kernel::KProcess* debug_process); | ||||||
|     ~GDBStub() override; |     ~GDBStub() override; | ||||||
|  |  | ||||||
|     void Connected() override; |     void Connected() override; | ||||||
| @@ -42,8 +51,12 @@ private: | |||||||
|     void SendReply(std::string_view data); |     void SendReply(std::string_view data); | ||||||
|     void SendStatus(char status); |     void SendStatus(char status); | ||||||
|  |  | ||||||
|  |     Kernel::KProcess* GetProcess(); | ||||||
|  |     Core::Memory::Memory& GetMemory(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     Core::System& system; |     Core::System& system; | ||||||
|  |     Kernel::KProcess* debug_process; | ||||||
|     std::unique_ptr<GDBStubArch> arch; |     std::unique_ptr<GDBStubArch> arch; | ||||||
|     std::vector<char> current_command; |     std::vector<char> current_command; | ||||||
|     std::map<VAddr, u32> replaced_instructions; |     std::map<VAddr, u32> replaced_instructions; | ||||||
|   | |||||||
| @@ -112,7 +112,14 @@ struct KernelCore::Impl { | |||||||
|             old_process->Close(); |             old_process->Close(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         { | ||||||
|  |             std::scoped_lock lk{process_list_lock}; | ||||||
|  |             for (auto* const process : process_list) { | ||||||
|  |                 process->Terminate(); | ||||||
|  |                 process->Close(); | ||||||
|  |             } | ||||||
|             process_list.clear(); |             process_list.clear(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         next_object_id = 0; |         next_object_id = 0; | ||||||
|         next_kernel_process_id = KProcess::InitialProcessIdMin; |         next_kernel_process_id = KProcess::InitialProcessIdMin; | ||||||
| @@ -770,6 +777,7 @@ struct KernelCore::Impl { | |||||||
|     std::atomic<u64> next_thread_id{1}; |     std::atomic<u64> next_thread_id{1}; | ||||||
|  |  | ||||||
|     // Lists all processes that exist in the current session. |     // Lists all processes that exist in the current session. | ||||||
|  |     std::mutex process_list_lock; | ||||||
|     std::vector<KProcess*> process_list; |     std::vector<KProcess*> process_list; | ||||||
|     std::atomic<KProcess*> application_process{}; |     std::atomic<KProcess*> application_process{}; | ||||||
|     std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; |     std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; | ||||||
| @@ -869,9 +877,19 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void KernelCore::AppendNewProcess(KProcess* process) { | void KernelCore::AppendNewProcess(KProcess* process) { | ||||||
|  |     process->Open(); | ||||||
|  |  | ||||||
|  |     std::scoped_lock lk{impl->process_list_lock}; | ||||||
|     impl->process_list.push_back(process); |     impl->process_list.push_back(process); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void KernelCore::RemoveProcess(KProcess* process) { | ||||||
|  |     std::scoped_lock lk{impl->process_list_lock}; | ||||||
|  |     if (std::erase(impl->process_list, process)) { | ||||||
|  |         process->Close(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| void KernelCore::MakeApplicationProcess(KProcess* process) { | void KernelCore::MakeApplicationProcess(KProcess* process) { | ||||||
|     impl->MakeApplicationProcess(process); |     impl->MakeApplicationProcess(process); | ||||||
| } | } | ||||||
| @@ -884,8 +902,15 @@ const KProcess* KernelCore::ApplicationProcess() const { | |||||||
|     return impl->application_process; |     return impl->application_process; | ||||||
| } | } | ||||||
|  |  | ||||||
| const std::vector<KProcess*>& KernelCore::GetProcessList() const { | std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() { | ||||||
|     return impl->process_list; |     std::list<KScopedAutoObject<KProcess>> processes; | ||||||
|  |     std::scoped_lock lk{impl->process_list_lock}; | ||||||
|  |  | ||||||
|  |     for (auto* const process : impl->process_list) { | ||||||
|  |         processes.emplace_back(process); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return processes; | ||||||
| } | } | ||||||
|  |  | ||||||
| Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { | Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
|  |  | ||||||
| #include <array> | #include <array> | ||||||
| #include <functional> | #include <functional> | ||||||
|  | #include <list> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| @@ -116,8 +117,9 @@ public: | |||||||
|     /// Retrieves a shared pointer to the system resource limit instance. |     /// Retrieves a shared pointer to the system resource limit instance. | ||||||
|     KResourceLimit* GetSystemResourceLimit(); |     KResourceLimit* GetSystemResourceLimit(); | ||||||
|  |  | ||||||
|     /// Adds the given shared pointer to an internal list of active processes. |     /// Adds/removes the given pointer to an internal list of active processes. | ||||||
|     void AppendNewProcess(KProcess* process); |     void AppendNewProcess(KProcess* process); | ||||||
|  |     void RemoveProcess(KProcess* process); | ||||||
|  |  | ||||||
|     /// Makes the given process the new application process. |     /// Makes the given process the new application process. | ||||||
|     void MakeApplicationProcess(KProcess* process); |     void MakeApplicationProcess(KProcess* process); | ||||||
| @@ -129,7 +131,7 @@ public: | |||||||
|     const KProcess* ApplicationProcess() const; |     const KProcess* ApplicationProcess() const; | ||||||
|  |  | ||||||
|     /// Retrieves the list of processes. |     /// Retrieves the list of processes. | ||||||
|     const std::vector<KProcess*>& GetProcessList() const; |     std::list<KScopedAutoObject<KProcess>> GetProcessList(); | ||||||
|  |  | ||||||
|     /// Gets the sole instance of the global scheduler |     /// Gets the sole instance of the global scheduler | ||||||
|     Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); |     Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); | ||||||
|   | |||||||
| @@ -74,13 +74,15 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     auto& memory = GetCurrentMemory(kernel); |     auto& memory = GetCurrentMemory(kernel); | ||||||
|     const auto& process_list = kernel.GetProcessList(); |     auto process_list = kernel.GetProcessList(); | ||||||
|  |     auto it = process_list.begin(); | ||||||
|  |  | ||||||
|     const auto num_processes = process_list.size(); |     const auto num_processes = process_list.size(); | ||||||
|     const auto copy_amount = |     const auto copy_amount = | ||||||
|         std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); |         std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); | ||||||
|  |  | ||||||
|     for (std::size_t i = 0; i < copy_amount; ++i) { |     for (std::size_t i = 0; i < copy_amount && it != process_list.end(); ++i, ++it) { | ||||||
|         memory.Write64(out_process_ids, process_list[i]->GetProcessId()); |         memory.Write64(out_process_ids, (*it)->GetProcessId()); | ||||||
|         out_process_ids += sizeof(u64); |         out_process_ids += sizeof(u64); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,9 +15,10 @@ | |||||||
| namespace Service::Glue { | namespace Service::Glue { | ||||||
|  |  | ||||||
| namespace { | namespace { | ||||||
| std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) { | std::optional<u64> GetTitleIDForProcessID(Core::System& system, u64 process_id) { | ||||||
|     const auto& list = system.Kernel().GetProcessList(); |     auto list = system.Kernel().GetProcessList(); | ||||||
|     const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) { |  | ||||||
|  |     const auto iter = std::find_if(list.begin(), list.end(), [&process_id](auto& process) { | ||||||
|         return process->GetProcessId() == process_id; |         return process->GetProcessId() == process_id; | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,12 +22,10 @@ void LoopProcess(Core::System& system) { | |||||||
|     std::shared_ptr<HidFirmwareSettings> firmware_settings = |     std::shared_ptr<HidFirmwareSettings> firmware_settings = | ||||||
|         std::make_shared<HidFirmwareSettings>(); |         std::make_shared<HidFirmwareSettings>(); | ||||||
|  |  | ||||||
|     // TODO: Remove this hack until this service is emulated properly. |     // TODO: Remove this hack when am is emulated properly. | ||||||
|     const auto process_list = system.Kernel().GetProcessList(); |  | ||||||
|     if (!process_list.empty()) { |  | ||||||
|     resource_manager->Initialize(); |     resource_manager->Initialize(); | ||||||
|         resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); |     resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(), | ||||||
|     } |                                                    true); | ||||||
|  |  | ||||||
|     server_manager->RegisterNamedService( |     server_manager->RegisterNamedService( | ||||||
|         "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); |         "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); | ||||||
|   | |||||||
| @@ -22,27 +22,26 @@ constexpr Result ResultProcessNotFound{ErrorModule::PM, 1}; | |||||||
|  |  | ||||||
| constexpr u64 NO_PROCESS_FOUND_PID{0}; | constexpr u64 NO_PROCESS_FOUND_PID{0}; | ||||||
|  |  | ||||||
| std::optional<Kernel::KProcess*> SearchProcessList( | using ProcessList = std::list<Kernel::KScopedAutoObject<Kernel::KProcess>>; | ||||||
|     const std::vector<Kernel::KProcess*>& process_list, |  | ||||||
|     std::function<bool(Kernel::KProcess*)> predicate) { | template <typename F> | ||||||
|  | Kernel::KScopedAutoObject<Kernel::KProcess> SearchProcessList(ProcessList& process_list, | ||||||
|  |                                                               F&& predicate) { | ||||||
|     const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); |     const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); | ||||||
|  |  | ||||||
|     if (iter == process_list.end()) { |     if (iter == process_list.end()) { | ||||||
|         return std::nullopt; |         return nullptr; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return *iter; |     return iter->GetPointerUnsafe(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void GetApplicationPidGeneric(HLERequestContext& ctx, | void GetApplicationPidGeneric(HLERequestContext& ctx, ProcessList& process_list) { | ||||||
|                               const std::vector<Kernel::KProcess*>& process_list) { |     auto process = SearchProcessList(process_list, [](auto& p) { return p->IsApplication(); }); | ||||||
|     const auto process = SearchProcessList(process_list, [](const auto& proc) { |  | ||||||
|         return proc->GetProcessId() == Kernel::KProcess::ProcessIdMin; |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     IPC::ResponseBuilder rb{ctx, 4}; |     IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|     rb.Push(ResultSuccess); |     rb.Push(ResultSuccess); | ||||||
|     rb.Push(process.has_value() ? (*process)->GetProcessId() : NO_PROCESS_FOUND_PID); |     rb.Push(process.IsNull() ? NO_PROCESS_FOUND_PID : process->GetProcessId()); | ||||||
| } | } | ||||||
|  |  | ||||||
| } // Anonymous namespace | } // Anonymous namespace | ||||||
| @@ -80,8 +79,7 @@ private: | |||||||
|  |  | ||||||
| class DebugMonitor final : public ServiceFramework<DebugMonitor> { | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | ||||||
| public: | public: | ||||||
|     explicit DebugMonitor(Core::System& system_) |     explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "pm:dmnt"} { | ||||||
|         : ServiceFramework{system_, "pm:dmnt"}, kernel{system_.Kernel()} { |  | ||||||
|         // clang-format off |         // clang-format off | ||||||
|         static const FunctionInfo functions[] = { |         static const FunctionInfo functions[] = { | ||||||
|             {0, nullptr, "GetJitDebugProcessIdList"}, |             {0, nullptr, "GetJitDebugProcessIdList"}, | ||||||
| @@ -106,12 +104,11 @@ private: | |||||||
|  |  | ||||||
|         LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); |         LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | ||||||
|  |  | ||||||
|         const auto process = |         auto list = kernel.GetProcessList(); | ||||||
|             SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) { |         auto process = SearchProcessList( | ||||||
|                 return proc->GetProgramId() == program_id; |             list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); | ||||||
|             }); |  | ||||||
|  |  | ||||||
|         if (!process.has_value()) { |         if (process.IsNull()) { | ||||||
|             IPC::ResponseBuilder rb{ctx, 2}; |             IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|             rb.Push(ResultProcessNotFound); |             rb.Push(ResultProcessNotFound); | ||||||
|             return; |             return; | ||||||
| @@ -119,12 +116,13 @@ private: | |||||||
|  |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 4}; |         IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|         rb.Push(ResultSuccess); |         rb.Push(ResultSuccess); | ||||||
|         rb.Push((*process)->GetProcessId()); |         rb.Push(process->GetProcessId()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void GetApplicationProcessId(HLERequestContext& ctx) { |     void GetApplicationProcessId(HLERequestContext& ctx) { | ||||||
|         LOG_DEBUG(Service_PM, "called"); |         LOG_DEBUG(Service_PM, "called"); | ||||||
|         GetApplicationPidGeneric(ctx, kernel.GetProcessList()); |         auto list = kernel.GetProcessList(); | ||||||
|  |         GetApplicationPidGeneric(ctx, list); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void AtmosphereGetProcessInfo(HLERequestContext& ctx) { |     void AtmosphereGetProcessInfo(HLERequestContext& ctx) { | ||||||
| @@ -135,11 +133,10 @@ private: | |||||||
|  |  | ||||||
|         LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid); |         LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid); | ||||||
|  |  | ||||||
|         const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) { |         auto list = kernel.GetProcessList(); | ||||||
|             return proc->GetProcessId() == pid; |         auto process = SearchProcessList(list, [pid](auto& p) { return p->GetProcessId() == pid; }); | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         if (!process.has_value()) { |         if (process.IsNull()) { | ||||||
|             IPC::ResponseBuilder rb{ctx, 2}; |             IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|             rb.Push(ResultProcessNotFound); |             rb.Push(ResultProcessNotFound); | ||||||
|             return; |             return; | ||||||
| @@ -159,7 +156,7 @@ private: | |||||||
|  |  | ||||||
|         OverrideStatus override_status{}; |         OverrideStatus override_status{}; | ||||||
|         ProgramLocation program_location{ |         ProgramLocation program_location{ | ||||||
|             .program_id = (*process)->GetProgramId(), |             .program_id = process->GetProgramId(), | ||||||
|             .storage_id = 0, |             .storage_id = 0, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
| @@ -169,14 +166,11 @@ private: | |||||||
|         rb.PushRaw(program_location); |         rb.PushRaw(program_location); | ||||||
|         rb.PushRaw(override_status); |         rb.PushRaw(override_status); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const Kernel::KernelCore& kernel; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class Info final : public ServiceFramework<Info> { | class Info final : public ServiceFramework<Info> { | ||||||
| public: | public: | ||||||
|     explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) |     explicit Info(Core::System& system_) : ServiceFramework{system_, "pm:info"} { | ||||||
|         : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { |  | ||||||
|         static const FunctionInfo functions[] = { |         static const FunctionInfo functions[] = { | ||||||
|             {0, &Info::GetProgramId, "GetProgramId"}, |             {0, &Info::GetProgramId, "GetProgramId"}, | ||||||
|             {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, |             {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, | ||||||
| @@ -193,11 +187,11 @@ private: | |||||||
|  |  | ||||||
|         LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); |         LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); | ||||||
|  |  | ||||||
|         const auto process = SearchProcessList(process_list, [process_id](const auto& proc) { |         auto list = kernel.GetProcessList(); | ||||||
|             return proc->GetProcessId() == process_id; |         auto process = SearchProcessList( | ||||||
|         }); |             list, [process_id](auto& p) { return p->GetProcessId() == process_id; }); | ||||||
|  |  | ||||||
|         if (!process.has_value()) { |         if (process.IsNull()) { | ||||||
|             IPC::ResponseBuilder rb{ctx, 2}; |             IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|             rb.Push(ResultProcessNotFound); |             rb.Push(ResultProcessNotFound); | ||||||
|             return; |             return; | ||||||
| @@ -205,7 +199,7 @@ private: | |||||||
|  |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 4}; |         IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|         rb.Push(ResultSuccess); |         rb.Push(ResultSuccess); | ||||||
|         rb.Push((*process)->GetProgramId()); |         rb.Push(process->GetProgramId()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void AtmosphereGetProcessId(HLERequestContext& ctx) { |     void AtmosphereGetProcessId(HLERequestContext& ctx) { | ||||||
| @@ -214,11 +208,11 @@ private: | |||||||
|  |  | ||||||
|         LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); |         LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | ||||||
|  |  | ||||||
|         const auto process = SearchProcessList(process_list, [program_id](const auto& proc) { |         auto list = system.Kernel().GetProcessList(); | ||||||
|             return proc->GetProgramId() == program_id; |         auto process = SearchProcessList( | ||||||
|         }); |             list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); | ||||||
|  |  | ||||||
|         if (!process.has_value()) { |         if (process.IsNull()) { | ||||||
|             IPC::ResponseBuilder rb{ctx, 2}; |             IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|             rb.Push(ResultProcessNotFound); |             rb.Push(ResultProcessNotFound); | ||||||
|             return; |             return; | ||||||
| @@ -226,16 +220,13 @@ private: | |||||||
|  |  | ||||||
|         IPC::ResponseBuilder rb{ctx, 4}; |         IPC::ResponseBuilder rb{ctx, 4}; | ||||||
|         rb.Push(ResultSuccess); |         rb.Push(ResultSuccess); | ||||||
|         rb.Push((*process)->GetProcessId()); |         rb.Push(process->GetProcessId()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const std::vector<Kernel::KProcess*>& process_list; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class Shell final : public ServiceFramework<Shell> { | class Shell final : public ServiceFramework<Shell> { | ||||||
| public: | public: | ||||||
|     explicit Shell(Core::System& system_) |     explicit Shell(Core::System& system_) : ServiceFramework{system_, "pm:shell"} { | ||||||
|         : ServiceFramework{system_, "pm:shell"}, kernel{system_.Kernel()} { |  | ||||||
|         // clang-format off |         // clang-format off | ||||||
|         static const FunctionInfo functions[] = { |         static const FunctionInfo functions[] = { | ||||||
|             {0, nullptr, "LaunchProgram"}, |             {0, nullptr, "LaunchProgram"}, | ||||||
| @@ -257,10 +248,9 @@ public: | |||||||
| private: | private: | ||||||
|     void GetApplicationProcessIdForShell(HLERequestContext& ctx) { |     void GetApplicationProcessIdForShell(HLERequestContext& ctx) { | ||||||
|         LOG_DEBUG(Service_PM, "called"); |         LOG_DEBUG(Service_PM, "called"); | ||||||
|         GetApplicationPidGeneric(ctx, kernel.GetProcessList()); |         auto list = kernel.GetProcessList(); | ||||||
|  |         GetApplicationPidGeneric(ctx, list); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const Kernel::KernelCore& kernel; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| void LoopProcess(Core::System& system) { | void LoopProcess(Core::System& system) { | ||||||
| @@ -268,8 +258,7 @@ void LoopProcess(Core::System& system) { | |||||||
|  |  | ||||||
|     server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system)); |     server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system)); | ||||||
|     server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system)); |     server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system)); | ||||||
|     server_manager->RegisterNamedService( |     server_manager->RegisterNamedService("pm:info", std::make_shared<Info>(system)); | ||||||
|         "pm:info", std::make_shared<Info>(system, system.Kernel().GetProcessList())); |  | ||||||
|     server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system)); |     server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system)); | ||||||
|     ServerManager::RunServer(std::move(server_manager)); |     ServerManager::RunServer(std::move(server_manager)); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user