From 07b171baffb6bca8be6799ef477713094ae8316f Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Wed, 29 Apr 2026 17:24:44 +0200 Subject: [PATCH] gdb: Fix register write from debugger --- src/core/gdbstub/gdbstub.cpp | 57 +++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 660168bc1..a2c4ff7ec 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -38,6 +38,9 @@ #include "core/hle/kernel/process.h" #include "core/memory.h" +// Uncomment to log all GDB traffic +// #define PRINT_GDB_TRAFFIC + namespace GDBStub { namespace { constexpr int GDB_BUFFER_SIZE = 10000; @@ -228,6 +231,13 @@ static void FpuWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) } } +// Clear instruction cache for all cores. +static void ClearAllInstructionCache() { + for (int i = 0; i < Core::GetNumCores(); i++) { + Core::GetCore(i).ClearInstructionCache(); + } +} + /** * Turns hex string character into the equivalent byte. * @@ -493,6 +503,15 @@ void SendReply(const char* reply) { std::memset(command_buffer, 0, sizeof(command_buffer)); command_length = static_cast(strlen(reply)); + +#ifdef PRINT_GDB_TRAFFIC + if (command_length > 0) { + LOG_INFO(Debug_GDBStub, "Req: {} {}", *reply, reply + 1); + } else { + LOG_INFO(Debug_GDBStub, "Req:"); + } +#endif + if (command_length + 4 > sizeof(command_buffer)) { LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); return; @@ -762,6 +781,17 @@ static void ReadRegisters() { SendReply(reinterpret_cast(buffer)); } +static void UpdateCPUThreadContext() { + u32 core_id = current_thread->core_id; + auto& system = Core::System::GetInstance(); + auto& thread_manager = system.Kernel().GetThreadManager(core_id); + if (thread_manager.GetCurrentThread() == current_thread) { + // Only update CPU context if current thread is active, + // otherwise it will be updated when the thread is selected + Core::GetCore(current_thread->core_id).LoadContext(current_thread->context); + } +} + /// Modify data of register specified by gdb client. static void WriteRegister() { const u8* buffer_ptr = command_buffer + 3; @@ -785,7 +815,7 @@ static void WriteRegister() { return SendReply("E01"); } - Core::GetRunningCore().LoadContext(current_thread->context); + UpdateCPUThreadContext(); SendReply("OK"); } @@ -799,23 +829,23 @@ static void WriteRegisters() { for (u32 i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { if (reg <= PC_REGISTER) { - RegWrite(reg, GdbHexToInt(buffer_ptr + i * 8)); + RegWrite(reg, GdbHexToInt(buffer_ptr + i * 8), current_thread); } else if (reg == CPSR_REGISTER) { - RegWrite(reg, GdbHexToInt(buffer_ptr + i * 8)); + RegWrite(reg, GdbHexToInt(buffer_ptr + i * 8), current_thread); } else if (reg == CPSR_REGISTER - 1) { // Dummy FPA register, ignore } else if (reg < CPSR_REGISTER) { // Dummy FPA registers, ignore i += 2; } else if (reg >= D0_REGISTER && reg < FPSCR_REGISTER) { - FpuWrite(reg, GdbHexToLong(buffer_ptr + i * 16)); + FpuWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); i++; // Skip padding } else if (reg == FPSCR_REGISTER) { - FpuWrite(reg, GdbHexToInt(buffer_ptr + i * 8)); + FpuWrite(reg, GdbHexToInt(buffer_ptr + i * 8), current_thread); } } - Core::GetRunningCore().LoadContext(current_thread->context); + UpdateCPUThreadContext(); SendReply("OK"); } @@ -876,7 +906,7 @@ static void WriteMemory() { GdbHexToMem(data.data(), len_pos + 1, len); memory.WriteBlock(addr, data.data(), len); - Core::GetRunningCore().ClearInstructionCache(); + ClearAllInstructionCache(); SendReply("OK"); } @@ -890,12 +920,12 @@ void Break(bool is_memory_break) { static void Step() { if (command_length > 1) { RegWrite(PC_REGISTER, GdbHexToInt(command_buffer + 1), current_thread); - Core::GetRunningCore().LoadContext(current_thread->context); + UpdateCPUThreadContext(); } step_loop = true; halt_loop = true; send_trap = true; - Core::GetRunningCore().ClearInstructionCache(); + ClearAllInstructionCache(); } bool IsMemoryBreak() { @@ -911,7 +941,7 @@ static void Continue() { memory_break = false; step_loop = false; halt_loop = false; - Core::GetRunningCore().ClearInstructionCache(); + ClearAllInstructionCache(); } /** @@ -937,7 +967,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u32 len) { Core::System::GetInstance().Memory().WriteBlock( *Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, btrap.data(), btrap.size()); - Core::GetRunningCore().ClearInstructionCache(); + ClearAllInstructionCache(); } p.insert({addr, breakpoint}); @@ -1057,6 +1087,11 @@ void HandlePacket(Core::System& system) { return; } +#ifdef PRINT_GDB_TRAFFIC + std::string cmd_str(command_buffer + 1, command_buffer + command_length); + LOG_INFO(Debug_GDBStub, "Res: {:c} {}", command_buffer[0], cmd_str); +#endif + LOG_DEBUG(Debug_GDBStub, "Packet: {0:d} ('{0:c}')", command_buffer[0]); switch (command_buffer[0]) {