kernel: fix debugger and process list lifetime
This commit is contained in:
parent
f2fed21c11
commit
f90a022d3a
|
@ -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