From 39569ed1f860c8233a5eecb67852c8fb630b1ff2 Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Wed, 29 Sep 2021 12:54:18 -0400 Subject: [PATCH 01/13] Remove unecessary include of the gdb stub --- Source/Core/Core/PowerPC/MMU.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index a567c60047..c9fc043e7d 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -24,10 +24,6 @@ #include "VideoCommon/VideoBackendBase.h" -#ifdef USE_GDBSTUB -#include "Core/PowerPC/GDBStub.h" -#endif - namespace PowerPC { // EFB RE From e03ddc2116193a2b16f4264aedadba000a0496fa Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Wed, 29 Sep 2021 12:57:46 -0400 Subject: [PATCH 02/13] Let the GDB stub listen for commands while running This is needed to send ctrl+C signals while the CPU thread is running. --- Source/Core/Core/PowerPC/GDBStub.cpp | 22 +++++++++++++++++-- Source/Core/Core/PowerPC/GDBStub.h | 10 ++++++++- .../Core/PowerPC/Interpreter/Interpreter.cpp | 2 +- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 39fc4e5e79..cdf9de19e0 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -55,6 +55,8 @@ static u32 sig = 0; static u32 send_signal = 0; static u32 step_break = 0; +static CoreTiming::EventType* m_gdbStubUpdateEvent; + typedef struct { u32 active; @@ -114,6 +116,12 @@ static void hex2mem(u8* dst, u8* src, u32 len) } } +void GDBStubUpdateCallback(u64 userdata, s64 cycles_late) +{ + gdb_handle_exception(false); + CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, m_gdbStubUpdateEvent); +} + static u8 gdb_read_byte() { u8 c = '+'; @@ -732,13 +740,20 @@ static void gdb_remove_bp() gdb_reply("OK"); } -void gdb_handle_exception() + +void gdb_handle_exception(bool loop_until_continue) { while (gdb_active()) { if (!gdb_data_available()) - continue; + { + if (loop_until_continue) + continue; + else + return; + } gdb_read_command(); + // No more commands if (cmd_len == 0) continue; @@ -868,6 +883,9 @@ static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t close(tmpsock); #endif tmpsock = -1; + + m_gdbStubUpdateEvent = CoreTiming::RegisterEvent("GDBStubUpdate", GDBStubUpdateCallback); + CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, m_gdbStubUpdateEvent); } void gdb_deinit() diff --git a/Source/Core/Core/PowerPC/GDBStub.h b/Source/Core/Core/PowerPC/GDBStub.h index deb0133a77..9cbea6a50c 100644 --- a/Source/Core/Core/PowerPC/GDBStub.h +++ b/Source/Core/Core/PowerPC/GDBStub.h @@ -6,6 +6,7 @@ #pragma once #include "Common/CommonTypes.h" +#include "Core/CoreTiming.h" #ifndef MSG_WAITALL #define MSG_WAITALL (8) @@ -26,13 +27,17 @@ typedef enum GDB_BP_TYPE_A } gdb_bp_type; +const s64 GDB_UPDATE_CYCLES = 100000; + +void GDBStubUpdateCallback(u64 userdata, s64 cycles_late); + void gdb_init(u32 port); void gdb_init_local(const char* socket); void gdb_deinit(); bool gdb_active(); void gdb_break(); -void gdb_handle_exception(); +void gdb_handle_exception(bool loopUntilContinue); int gdb_signal(u32 signal); int gdb_bp_x(u32 addr); @@ -41,3 +46,6 @@ int gdb_bp_w(u32 addr); int gdb_bp_a(u32 addr); bool gdb_add_bp(u32 type, u32 addr, u32 len); +void gdb_handle_exception(bool loop_until_continue); +void SendSignal(u32 signal); +} // namespace GDBStub diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 32b4eb09cc..029a8f35d7 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -158,7 +158,7 @@ int Interpreter::SingleStepInner() Host_UpdateDisasmDialog(); gdb_signal(GDB_SIGTRAP); - gdb_handle_exception(); + gdb_handle_exception(true); } #endif From e3b978cf20587c5c06fd8fe0077827c0197ad798 Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Thu, 30 Sep 2021 23:33:40 -0400 Subject: [PATCH 03/13] GDBStub: boot to pause --- Source/Core/Core/Core.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index c88b16fc9d..f32e814616 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -316,12 +316,12 @@ void UndeclareAsCPUThread() } // For the CPU Thread only. -static void CPUSetInitialExecutionState() +static void CPUSetInitialExecutionState(bool force_paused = false) { // The CPU starts in stepping state, and will wait until a new state is set before executing. // SetState must be called on the host thread, so we defer it for later. - QueueHostJob([]() { - SetState(SConfig::GetInstance().bBootToPause ? State::Paused : State::Running); + QueueHostJob([force_paused]() { + SetState(SConfig::GetInstance().bBootToPause || force_paused ? State::Paused : State::Running); Host_UpdateDisasmDialog(); Host_UpdateMainFrame(); Host_Message(HostMessageID::WMUserCreate); @@ -363,22 +363,22 @@ static void CpuThread(const std::optional& savestate_path, bool del } s_is_started = true; - CPUSetInitialExecutionState(); - -#ifdef USE_GDBSTUB #ifndef _WIN32 if (!_CoreParameter.gdb_socket.empty()) { - gdb_init_local(_CoreParameter.gdb_socket.data()); - gdb_break(); + GDBStub::InitLocal(_CoreParameter.gdb_socket.data()); + CPUSetInitialExecutionState(true); } else #endif if (_CoreParameter.iGDBPort > 0) { - gdb_init(_CoreParameter.iGDBPort); - // break at next instruction (the first instruction) - gdb_break(); + GDBStub::Init(_CoreParameter.iGDBPort); + CPUSetInitialExecutionState(true); + } + else + { + CPUSetInitialExecutionState(); } #endif From 994847f09c18da9757d512cac9bbff0020d5199f Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Thu, 30 Sep 2021 23:35:11 -0400 Subject: [PATCH 04/13] GDBStub: move the stalling logic to CPU::Run --- Source/Core/Core/HW/CPU.cpp | 13 +++++++++++++ .../Core/Core/PowerPC/Interpreter/Interpreter.cpp | 10 ---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp index 32ced9f6ac..5e62cb428f 100644 --- a/Source/Core/Core/HW/CPU.cpp +++ b/Source/Core/Core/HW/CPU.cpp @@ -15,6 +15,10 @@ #include "Core/PowerPC/PowerPC.h" #include "VideoCommon/Fifo.h" +#ifdef USE_GDBSTUB +#include "Core/PowerPC/GDBStub.h" +#endif + namespace CPU { // CPU Thread execution state. @@ -131,6 +135,15 @@ void Run() // Wait for step command. s_state_cpu_cvar.wait(state_lock, [&state_lock] { ExecutePendingJobs(state_lock); +#ifdef USE_GDBSTUB + state_lock.unlock(); + if (gdb_active() && gdb_hasControl()) + { + gdb_signal(GDB_SIGTRAP); + gdb_handle_exception(true); + } + state_lock.lock(); +#endif return s_state_cpu_step_instruction || !IsStepping(); }); if (!IsStepping()) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 029a8f35d7..8487fd1c30 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -152,16 +152,6 @@ int Interpreter::SingleStepInner() return PPCTables::GetOpInfo(m_prev_inst)->numCycles; } -#ifdef USE_GDBSTUB - if (gdb_active() && gdb_bp_x(PC)) - { - Host_UpdateDisasmDialog(); - - gdb_signal(GDB_SIGTRAP); - gdb_handle_exception(true); - } -#endif - NPC = PC + sizeof(UGeckoInstruction); m_prev_inst.hex = PowerPC::Read_Opcode(PC); From 7d3ea4c3a1b6242dc5da8eaca569deab49300690 Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Thu, 30 Sep 2021 23:36:11 -0400 Subject: [PATCH 05/13] GDBStub: rework the breakpoint and the control logic --- Source/Core/Core/PowerPC/GDBStub.cpp | 207 +++++------------- Source/Core/Core/PowerPC/GDBStub.h | 2 + .../Core/PowerPC/Interpreter/Interpreter.cpp | 3 + Source/Core/Core/PowerPC/MMU.cpp | 8 + Source/Core/Core/PowerPC/PowerPC.cpp | 9 + 5 files changed, 82 insertions(+), 147 deletions(-) diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index cdf9de19e0..6686b4722b 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -22,11 +22,14 @@ typedef SSIZE_T ssize_t; #include #endif +#include "Common/Event.h" #include "Common/Logging/Log.h" #include "Common/SocketContext.h" +#include "Core/Core.h" #include "Core/HW/CPU.h" #include "Core/HW/Memmap.h" #include "Core/Host.h" +#include "Core/PowerPC/BreakPoints.h" #include "Core/PowerPC/GDBStub.h" #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/PPCCache.h" @@ -38,13 +41,14 @@ std::optional s_socket_context; } // namespace #define GDB_BFR_MAX 10000 -#define GDB_MAX_BP 10 #define GDB_STUB_START '$' #define GDB_STUB_END '#' #define GDB_STUB_ACK '+' #define GDB_STUB_NAK '-' +static bool hasControl = false; + static int tmpsock = -1; static int sock = -1; @@ -57,18 +61,6 @@ static u32 step_break = 0; static CoreTiming::EventType* m_gdbStubUpdateEvent; -typedef struct -{ - u32 active; - u32 addr; - u32 len; -} gdb_bp_t; - -static gdb_bp_t bp_x[GDB_MAX_BP]; -static gdb_bp_t bp_r[GDB_MAX_BP]; -static gdb_bp_t bp_w[GDB_MAX_BP]; -static gdb_bp_t bp_a[GDB_MAX_BP]; - static const char* CommandBufferAsString() { return reinterpret_cast(cmd_bfr); @@ -148,91 +140,24 @@ static u8 gdb_calc_chksum() return c; } -static gdb_bp_t* gdb_bp_ptr(u32 type) -{ - switch (type) - { - case GDB_BP_TYPE_X: - return bp_x; - case GDB_BP_TYPE_R: - return bp_x; - case GDB_BP_TYPE_W: - return bp_x; - case GDB_BP_TYPE_A: - return bp_x; - default: - return nullptr; - } -} - -static gdb_bp_t* gdb_bp_empty_slot(u32 type) -{ - gdb_bp_t* p; - u32 i; - - p = gdb_bp_ptr(type); - if (p == nullptr) - return nullptr; - - for (i = 0; i < GDB_MAX_BP; i++) - { - if (p[i].active == 0) - return &p[i]; - } - - return nullptr; -} - -static gdb_bp_t* gdb_bp_find(u32 type, u32 addr, u32 len) -{ - gdb_bp_t* p; - u32 i; - - p = gdb_bp_ptr(type); - if (p == nullptr) - return nullptr; - - for (i = 0; i < GDB_MAX_BP; i++) - { - if (p[i].active == 1 && p[i].addr == addr && p[i].len == len) - return &p[i]; - } - - return nullptr; -} - static void gdb_bp_remove(u32 type, u32 addr, u32 len) { - gdb_bp_t* p; - - do + if (type == GDB_BP_TYPE_X) { - p = gdb_bp_find(type, addr, len); - if (p != nullptr) + while (PowerPC::breakpoints.IsAddressBreakPoint(addr)) { + PowerPC::breakpoints.Remove(addr); DEBUG_LOG_FMT(GDB_STUB, "gdb: removed a breakpoint: {:08x} bytes at {:08x}", len, addr); - p->active = 0; - memset(p, 0, sizeof(gdb_bp_t)); } - } while (p != nullptr); -} - -static int gdb_bp_check(u32 addr, u32 type) -{ - gdb_bp_t* p; - u32 i; - - p = gdb_bp_ptr(type); - if (p == nullptr) - return 0; - - for (i = 0; i < GDB_MAX_BP; i++) - { - if (p[i].active == 1 && (addr >= p[i].addr && addr < p[i].addr + p[i].len)) - return 1; } - - return 0; + else + { + while (PowerPC::memchecks.GetMemCheck(addr, len) != nullptr) + { + PowerPC::memchecks.Remove(addr); + DEBUG_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr); + } + } } static void gdb_nak() @@ -268,6 +193,7 @@ static void gdb_read_command() { CPU::Break(); gdb_signal(GDB_SIGTRAP); + hasControl = true; return; } else if (c != GDB_STUB_START) @@ -639,27 +565,45 @@ void gdb_break() static void gdb_step() { - gdb_break(); + Common::Event sync_event; + + PowerPC::CoreMode old_mode = PowerPC::GetMode(); + PowerPC::SetMode(PowerPC::CoreMode::Interpreter); + PowerPC::breakpoints.ClearAllTemporary(); + CPU::StepOpcode(&sync_event); + sync_event.WaitFor(std::chrono::milliseconds(20)); + PowerPC::SetMode(old_mode); + send_signal = 1; } static void gdb_continue() { send_signal = 1; + CPU::EnableStepping(false); + Core::CallOnStateChangedCallbacks(Core::State::Running); } bool gdb_add_bp(u32 type, u32 addr, u32 len) { - gdb_bp_t* bp; - bp = gdb_bp_empty_slot(type); - if (bp == nullptr) - return false; - - bp->active = 1; - bp->addr = addr; - bp->len = len; - - DEBUG_LOG_FMT(GDB_STUB, "gdb: added {} breakpoint: {:08x} bytes at {:08x}", type, bp->len, - bp->addr); + if (type == GDB_BP_TYPE_X) + { + PowerPC::breakpoints.Add(addr); + DEBUG_LOG_FMT(GDB_STUB, "gdb: added {} breakpoint: {:08x} bytes at {:08x}", type, len, addr); + } + else + { + TMemCheck new_memcheck; + new_memcheck.start_address = addr; + new_memcheck.end_address = addr + len - 1; + new_memcheck.is_ranged = (len > 1); + new_memcheck.is_break_on_read = (type == GDB_BP_TYPE_R || type == GDB_BP_TYPE_A); + new_memcheck.is_break_on_write = (type == GDB_BP_TYPE_W || type == GDB_BP_TYPE_A); + new_memcheck.break_on_hit = true; + new_memcheck.log_on_hit = false; + new_memcheck.is_enabled = true; + PowerPC::memchecks.Add(new_memcheck); + INFO_LOG_FMT(GDB_STUB, "gdb: added {} memcheck: {:08x} bytes at {:08x}", type, len, addr); + } return true; } @@ -798,6 +742,7 @@ void gdb_handle_exception(bool loop_until_continue) case 'C': case 'c': gdb_continue(); + hasControl = false; return; case 'z': gdb_remove_bp(); @@ -851,10 +796,6 @@ static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t sockaddr* client_addr, socklen_t* client_addrlen) { s_socket_context.emplace(); - memset(bp_x, 0, sizeof bp_x); - memset(bp_r, 0, sizeof bp_r); - memset(bp_w, 0, sizeof bp_w); - memset(bp_a, 0, sizeof bp_a); tmpsock = socket(domain, SOCK_STREAM, 0); if (tmpsock == -1) @@ -886,6 +827,7 @@ static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t m_gdbStubUpdateEvent = CoreTiming::RegisterEvent("GDBStubUpdate", GDBStubUpdateCallback); CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, m_gdbStubUpdateEvent); + hasControl = true; } void gdb_deinit() @@ -902,6 +844,7 @@ void gdb_deinit() } s_socket_context.reset(); + hasControl = false; } bool gdb_active() @@ -909,6 +852,16 @@ bool gdb_active() return tmpsock != -1 || sock != -1; } +bool gdb_hasControl() +{ + return hasControl; +} + +void gdb_takeControl() +{ + hasControl = true; +} + int gdb_signal(u32 s) { if (sock == -1) @@ -924,43 +877,3 @@ int gdb_signal(u32 s) return 0; } - -int gdb_bp_x(u32 addr) -{ - if (sock == -1) - return 0; - - if (step_break) - { - step_break = 0; - - DEBUG_LOG_FMT(GDB_STUB, "Step was successful."); - return 1; - } - - return gdb_bp_check(addr, GDB_BP_TYPE_X); -} - -int gdb_bp_r(u32 addr) -{ - if (sock == -1) - return 0; - - return gdb_bp_check(addr, GDB_BP_TYPE_R); -} - -int gdb_bp_w(u32 addr) -{ - if (sock == -1) - return 0; - - return gdb_bp_check(addr, GDB_BP_TYPE_W); -} - -int gdb_bp_a(u32 addr) -{ - if (sock == -1) - return 0; - - return gdb_bp_check(addr, GDB_BP_TYPE_A); -} diff --git a/Source/Core/Core/PowerPC/GDBStub.h b/Source/Core/Core/PowerPC/GDBStub.h index 9cbea6a50c..db7212422e 100644 --- a/Source/Core/Core/PowerPC/GDBStub.h +++ b/Source/Core/Core/PowerPC/GDBStub.h @@ -35,6 +35,8 @@ void gdb_init(u32 port); void gdb_init_local(const char* socket); void gdb_deinit(); bool gdb_active(); +bool gdb_hasControl(); +void gdb_takeControl(); void gdb_break(); void gdb_handle_exception(bool loopUntilContinue); diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 8487fd1c30..2ff486566f 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -296,6 +296,9 @@ void Interpreter::Run() #endif INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PC); CPU::Break(); +#ifdef USE_GDBSTUB + gdb_takeControl(); +#endif if (PowerPC::breakpoints.IsTempBreakPoint(PC)) PowerPC::breakpoints.Remove(PC); diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index c9fc043e7d..028bdef9a9 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -24,6 +24,10 @@ #include "VideoCommon/VideoBackendBase.h" +#ifdef USE_GDBSTUB +#include "Core/PowerPC/GDBStub.h" +#endif + namespace PowerPC { // EFB RE @@ -518,6 +522,10 @@ static void Memcheck(u32 address, u64 var, bool write, size_t size) CPU::Break(); +#ifdef USE_GDBSTUB + gdb_takeControl(); +#endif + // Fake a DSI so that all the code that tests for it in order to skip // the rest of the instruction will apply. (This means that // watchpoints will stop the emulator before the offending load/store, diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index f838911927..ab3fde08c3 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -30,6 +30,10 @@ #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PPCSymbolDB.h" +#ifdef USE_GDBSTUB +#include "Core/PowerPC/GDBStub.h" +#endif + namespace PowerPC { // STATE_TO_SAVE @@ -611,7 +615,12 @@ void CheckBreakPoints() return; if (PowerPC::breakpoints.IsBreakPointBreakOnHit(PC)) + { CPU::Break(); +#ifdef USE_GDBSTUB + gdb_takeControl(); +#endif + } if (PowerPC::breakpoints.IsBreakPointLogOnHit(PC)) { NOTICE_LOG_FMT(MEMMAP, From b9b7c4ac809c24e9683d964fd9c0af9e66f784cc Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Fri, 1 Oct 2021 00:56:17 -0400 Subject: [PATCH 06/13] GDBStub: Add support for the T command --- Source/Core/Core/PowerPC/GDBStub.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 6686b4722b..5752e53217 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -309,7 +309,15 @@ static void gdb_handle_query() static void gdb_handle_set_thread() { if (memcmp(cmd_bfr, "Hg0", 3) == 0 || memcmp(cmd_bfr, "Hc-1", 4) == 0 || - memcmp(cmd_bfr, "Hc0", 4) == 0 || memcmp(cmd_bfr, "Hc1", 4) == 0) + memcmp(cmd_bfr, "Hc0", 3) == 0 || memcmp(cmd_bfr, "Hc1", 3) == 0) + return gdb_reply("OK"); + gdb_reply("E01"); +} + +static void gdb_handle_thread_alive() +{ + if (memcmp(cmd_bfr, "T0", 2) == 0 || memcmp(cmd_bfr, "T1", 4) == 0 || + memcmp(cmd_bfr, "T-1", 3) == 0) return gdb_reply("OK"); gdb_reply("E01"); } @@ -709,6 +717,9 @@ void gdb_handle_exception(bool loop_until_continue) case 'H': gdb_handle_set_thread(); break; + case 'T': + gdb_handle_thread_alive(); + break; case '?': gdb_handle_signal(); break; From b8395280d3fb90dc166bdad940c2d2404834104a Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Fri, 1 Oct 2021 01:33:40 -0400 Subject: [PATCH 07/13] GDBStub: Correctly inform the CPU thread if we are stepping --- Source/Core/Core/HW/CPU.cpp | 3 +++ Source/Core/Core/PowerPC/GDBStub.cpp | 8 -------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp index 5e62cb428f..3e09340046 100644 --- a/Source/Core/Core/HW/CPU.cpp +++ b/Source/Core/Core/HW/CPU.cpp @@ -141,6 +141,9 @@ void Run() { gdb_signal(GDB_SIGTRAP); gdb_handle_exception(true); + // If we are still going to step, emulate the fact we just sent a step command + if (gdb_hasControl()) + s_state_cpu_step_instruction = true; } state_lock.lock(); #endif diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 5752e53217..f588696276 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -573,14 +573,6 @@ void gdb_break() static void gdb_step() { - Common::Event sync_event; - - PowerPC::CoreMode old_mode = PowerPC::GetMode(); - PowerPC::SetMode(PowerPC::CoreMode::Interpreter); - PowerPC::breakpoints.ClearAllTemporary(); - CPU::StepOpcode(&sync_event); - sync_event.WaitFor(std::chrono::milliseconds(20)); - PowerPC::SetMode(old_mode); send_signal = 1; } From 657bb00c0153a754fe120abc4f499f95bdc35816 Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Fri, 1 Oct 2021 01:57:40 -0400 Subject: [PATCH 08/13] GDBStub: Cleanly shut down on stop --- Source/Core/Core/Core.cpp | 9 +++++++++ Source/Core/Core/PowerPC/GDBStub.cpp | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index f32e814616..444e1bb0ba 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -393,6 +393,15 @@ static void CpuThread(const std::optional& savestate_path, bool del if (_CoreParameter.bFastmem) EMM::UninstallExceptionHandler(); + +#ifdef USE_GDBSTUB + if (gdb_active()) + { + gdb_deinit(); + INFO_LOG_FMT(GDB_STUB, "Killed by CPU shutdown"); + return; + } +#endif } static void FifoPlayerThread(const std::optional& savestate_path, diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index f588696276..7e947fccf2 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -689,6 +689,13 @@ void gdb_handle_exception(bool loop_until_continue) { while (gdb_active()) { + if (CPU::GetState() == CPU::State::PowerDown) + { + gdb_deinit(); + INFO_LOG_FMT(GDB_STUB, "killed by power down"); + return; + } + if (!gdb_data_available()) { if (loop_until_continue) @@ -822,7 +829,7 @@ static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t INFO_LOG_FMT(GDB_STUB, "Client connected."); #ifdef _WIN32 - closesocket(tmpsock); + closesocket(s_tmpsock); #else close(tmpsock); #endif From 94a0f416ebf654c97169c0e20805dd2c738d7bc4 Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Fri, 1 Oct 2021 09:56:26 -0400 Subject: [PATCH 09/13] GDBStub: remove the cmake option and the ifdefs --- CMakeLists.txt | 5 ----- Source/Core/Core/CMakeLists.txt | 9 ++------- Source/Core/Core/ConfigManager.cpp | 6 ------ Source/Core/Core/ConfigManager.h | 2 -- Source/Core/Core/Core.cpp | 10 +--------- Source/Core/Core/HW/CPU.cpp | 7 +------ Source/Core/Core/PowerPC/GDBStub.h | 4 ---- Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp | 10 +++------- Source/Core/Core/PowerPC/MMU.cpp | 10 +++------- Source/Core/Core/PowerPC/PowerPC.cpp | 10 +++------- 10 files changed, 13 insertions(+), 60 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b9f8ae348d..fa45b3fc7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,6 @@ option(ENCODE_FRAMEDUMPS "Encode framedumps in AVI format" ON) option(ENABLE_GPROF "Enable gprof profiling (must be using Debug build)" OFF) option(FASTLOG "Enable all logs" OFF) -option(GDBSTUB "Enable gdb stub for remote debugging." ON) option(OPROFILING "Enable profiling" OFF) # TODO: Add DSPSpy @@ -389,10 +388,6 @@ if(FASTLOG) add_definitions(-DDEBUGFAST) endif() -if(GDBSTUB) - add_definitions(-DUSE_GDBSTUB) -endif() - if(ENABLE_VTUNE) set(VTUNE_DIR "/opt/intel/vtune_amplifier") add_definitions(-DUSE_VTUNE) diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index b22f523811..a06a391c06 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -452,6 +452,8 @@ add_library(core PowerPC/JitCommon/JitCache.h PowerPC/JitInterface.cpp PowerPC/JitInterface.h + PowerPC/GDBStub.cpp + PowerPC/GDBStub.h PowerPC/MMU.cpp PowerPC/MMU.h PowerPC/PowerPC.cpp @@ -698,13 +700,6 @@ if(TARGET Hidapi::Hidapi) target_compile_definitions(core PRIVATE -DHAVE_HIDAPI=1) endif() -if(GDBSTUB) - target_sources(core PRIVATE - PowerPC/GDBStub.cpp - PowerPC/GDBStub.h - ) -endif() - if(UNIX) target_sources(core PRIVATE MemoryWatcher.cpp diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 9eeba47706..9baa710821 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -132,12 +132,10 @@ void SConfig::SaveGeneralSettings(IniFile& ini) general->Set("WirelessMac", m_WirelessMac); -#ifdef USE_GDBSTUB #ifndef _WIN32 general->Set("GDBSocket", gdb_socket); #endif general->Set("GDBPort", iGDBPort); -#endif } void SConfig::SaveInterfaceSettings(IniFile& ini) @@ -371,12 +369,10 @@ void SConfig::LoadGeneralSettings(IniFile& ini) general->Get("ShowLag", &m_ShowLag, false); general->Get("ShowFrameCount", &m_ShowFrameCount, false); -#ifdef USE_GDBSTUB #ifndef _WIN32 general->Get("GDBSocket", &gdb_socket, ""); #endif general->Get("GDBPort", &(iGDBPort), -1); -#endif m_ISOFolder.clear(); int numISOPaths; @@ -733,11 +729,9 @@ void SConfig::LoadDefaults() bAutomaticStart = false; bBootToPause = false; -#ifdef USE_GDBSTUB iGDBPort = -1; #ifndef _WIN32 gdb_socket = ""; -#endif #endif cpu_core = PowerPC::DefaultCPUCore(); diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index c6d954a398..319cb1b701 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -79,11 +79,9 @@ struct SConfig // Settings bool bEnableDebugging = false; -#ifdef USE_GDBSTUB int iGDBPort; #ifndef _WIN32 std::string gdb_socket; -#endif #endif bool bAutomaticStart = false; bool bBootToPause = false; diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 444e1bb0ba..1537272571 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -62,15 +62,12 @@ #include "Core/NetPlayClient.h" #include "Core/NetPlayProto.h" #include "Core/PatchEngine.h" +#include "Core/PowerPC/GDBStub.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" #include "Core/State.h" #include "Core/WiiRoot.h" -#ifdef USE_GDBSTUB -#include "Core/PowerPC/GDBStub.h" -#endif - #ifdef USE_MEMORYWATCHER #include "Core/MemoryWatcher.h" #endif @@ -380,7 +377,6 @@ static void CpuThread(const std::optional& savestate_path, bool del { CPUSetInitialExecutionState(); } -#endif // Enter CPU run loop. When we leave it - we are done. CPU::Run(); @@ -394,14 +390,12 @@ static void CpuThread(const std::optional& savestate_path, bool del if (_CoreParameter.bFastmem) EMM::UninstallExceptionHandler(); -#ifdef USE_GDBSTUB if (gdb_active()) { gdb_deinit(); INFO_LOG_FMT(GDB_STUB, "Killed by CPU shutdown"); return; } -#endif } static void FifoPlayerThread(const std::optional& savestate_path, @@ -662,11 +656,9 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi cpuThreadFunc(savestate_path, delete_savestate); } -#ifdef USE_GDBSTUB INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Stopping GDB ...")); gdb_deinit(); INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "GDB stopped.")); -#endif } // Set or get the running state diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp index 3e09340046..d64c1e5c90 100644 --- a/Source/Core/Core/HW/CPU.cpp +++ b/Source/Core/Core/HW/CPU.cpp @@ -12,13 +12,10 @@ #include "Common/Event.h" #include "Core/Core.h" #include "Core/Host.h" +#include "Core/PowerPC/GDBStub.h" #include "Core/PowerPC/PowerPC.h" #include "VideoCommon/Fifo.h" -#ifdef USE_GDBSTUB -#include "Core/PowerPC/GDBStub.h" -#endif - namespace CPU { // CPU Thread execution state. @@ -135,7 +132,6 @@ void Run() // Wait for step command. s_state_cpu_cvar.wait(state_lock, [&state_lock] { ExecutePendingJobs(state_lock); -#ifdef USE_GDBSTUB state_lock.unlock(); if (gdb_active() && gdb_hasControl()) { @@ -146,7 +142,6 @@ void Run() s_state_cpu_step_instruction = true; } state_lock.lock(); -#endif return s_state_cpu_step_instruction || !IsStepping(); }); if (!IsStepping()) diff --git a/Source/Core/Core/PowerPC/GDBStub.h b/Source/Core/Core/PowerPC/GDBStub.h index db7212422e..56bfa35d14 100644 --- a/Source/Core/Core/PowerPC/GDBStub.h +++ b/Source/Core/Core/PowerPC/GDBStub.h @@ -8,10 +8,6 @@ #include "Common/CommonTypes.h" #include "Core/CoreTiming.h" -#ifndef MSG_WAITALL -#define MSG_WAITALL (8) -#endif - typedef enum { GDB_SIGTRAP = 5, diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 2ff486566f..453097f016 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -20,15 +20,12 @@ #include "Core/HLE/HLE.h" #include "Core/HW/CPU.h" #include "Core/Host.h" +#include "Core/PowerPC/GDBStub.h" #include "Core/PowerPC/Interpreter/ExceptionUtils.h" #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/PowerPC.h" -#ifdef USE_GDBSTUB -#include "Core/PowerPC/GDBStub.h" -#endif - namespace { u32 last_pc; @@ -296,9 +293,8 @@ void Interpreter::Run() #endif INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PC); CPU::Break(); -#ifdef USE_GDBSTUB - gdb_takeControl(); -#endif + if (gdb_active()) + gdb_takeControl(); if (PowerPC::breakpoints.IsTempBreakPoint(PC)) PowerPC::breakpoints.Remove(PC); diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index 028bdef9a9..a027720a4f 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -19,15 +19,12 @@ #include "Core/HW/MMIO.h" #include "Core/HW/Memmap.h" #include "Core/HW/ProcessorInterface.h" +#include "Core/PowerPC/GDBStub.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" #include "VideoCommon/VideoBackendBase.h" -#ifdef USE_GDBSTUB -#include "Core/PowerPC/GDBStub.h" -#endif - namespace PowerPC { // EFB RE @@ -522,9 +519,8 @@ static void Memcheck(u32 address, u64 var, bool write, size_t size) CPU::Break(); -#ifdef USE_GDBSTUB - gdb_takeControl(); -#endif + if (gdb_active()) + gdb_takeControl(); // Fake a DSI so that all the code that tests for it in order to skip // the rest of the instruction will apply. (This means that diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index ab3fde08c3..d124643560 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -25,15 +25,12 @@ #include "Core/HW/SystemTimers.h" #include "Core/Host.h" #include "Core/PowerPC/CPUCoreBase.h" +#include "Core/PowerPC/GDBStub.h" #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PPCSymbolDB.h" -#ifdef USE_GDBSTUB -#include "Core/PowerPC/GDBStub.h" -#endif - namespace PowerPC { // STATE_TO_SAVE @@ -617,9 +614,8 @@ void CheckBreakPoints() if (PowerPC::breakpoints.IsBreakPointBreakOnHit(PC)) { CPU::Break(); -#ifdef USE_GDBSTUB - gdb_takeControl(); -#endif + if (gdb_active()) + gdb_takeControl(); } if (PowerPC::breakpoints.IsBreakPointLogOnHit(PC)) { From 1b92f813793be11a7276360566f72ab268463486 Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Fri, 1 Oct 2021 11:15:30 -0400 Subject: [PATCH 10/13] GDBStub: Refactor the whole code --- Source/Core/Core/Core.cpp | 9 +- Source/Core/Core/HW/CPU.cpp | 25 +- Source/Core/Core/HW/CPU.h | 3 + Source/Core/Core/PowerPC/GDBStub.cpp | 516 ++++++++---------- Source/Core/Core/PowerPC/GDBStub.h | 47 +- .../Core/PowerPC/Interpreter/Interpreter.cpp | 4 +- Source/Core/Core/PowerPC/MMU.cpp | 4 +- Source/Core/Core/PowerPC/PowerPC.cpp | 4 +- 8 files changed, 279 insertions(+), 333 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 1537272571..b9a3b60d1d 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -318,7 +318,8 @@ static void CPUSetInitialExecutionState(bool force_paused = false) // The CPU starts in stepping state, and will wait until a new state is set before executing. // SetState must be called on the host thread, so we defer it for later. QueueHostJob([force_paused]() { - SetState(SConfig::GetInstance().bBootToPause || force_paused ? State::Paused : State::Running); + bool paused = SConfig::GetInstance().bBootToPause || force_paused; + SetState(paused ? State::Paused : State::Running); Host_UpdateDisasmDialog(); Host_UpdateMainFrame(); Host_Message(HostMessageID::WMUserCreate); @@ -390,9 +391,9 @@ static void CpuThread(const std::optional& savestate_path, bool del if (_CoreParameter.bFastmem) EMM::UninstallExceptionHandler(); - if (gdb_active()) + if (GDBStub::IsActive()) { - gdb_deinit(); + GDBStub::Deinit(); INFO_LOG_FMT(GDB_STUB, "Killed by CPU shutdown"); return; } @@ -657,7 +658,7 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi } INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Stopping GDB ...")); - gdb_deinit(); + GDBStub::Deinit(); INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "GDB stopped.")); } diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp index d64c1e5c90..766eb01f7b 100644 --- a/Source/Core/Core/HW/CPU.cpp +++ b/Source/Core/Core/HW/CPU.cpp @@ -97,6 +97,7 @@ void Run() s_state_cpu_cvar.wait(state_lock, [] { return !s_state_paused_and_locked; }); ExecutePendingJobs(state_lock); + Common::Event gdb_step_sync_event; switch (s_state) { case State::Running: @@ -130,16 +131,24 @@ void Run() case State::Stepping: // Wait for step command. - s_state_cpu_cvar.wait(state_lock, [&state_lock] { + s_state_cpu_cvar.wait(state_lock, [&state_lock, &gdb_step_sync_event] { ExecutePendingJobs(state_lock); state_lock.unlock(); - if (gdb_active() && gdb_hasControl()) + if (GDBStub::IsActive() && GDBStub::HasControl()) { - gdb_signal(GDB_SIGTRAP); - gdb_handle_exception(true); + GDBStub::SendSignal(GDBStub::Signal::Sigtrap); + GDBStub::ProcessCommands(true); // If we are still going to step, emulate the fact we just sent a step command - if (gdb_hasControl()) + if (GDBStub::HasControl()) + { + // Make sure the previous step by gdb was serviced + if (s_state_cpu_step_instruction_sync && + s_state_cpu_step_instruction_sync != &gdb_step_sync_event) + s_state_cpu_step_instruction_sync->Set(); + s_state_cpu_step_instruction = true; + s_state_cpu_step_instruction_sync = &gdb_step_sync_event; + } } state_lock.lock(); return s_state_cpu_step_instruction || !IsStepping(); @@ -293,6 +302,12 @@ void Break() RunAdjacentSystems(false); } +void Continue() +{ + CPU::EnableStepping(false); + Core::CallOnStateChangedCallbacks(Core::State::Running); +} + bool PauseAndLock(bool do_lock, bool unpause_on_unlock, bool control_adjacent) { // NOTE: This is protected by s_stepping_lock. diff --git a/Source/Core/Core/HW/CPU.h b/Source/Core/Core/HW/CPU.h index c797583c6a..d69206c64b 100644 --- a/Source/Core/Core/HW/CPU.h +++ b/Source/Core/Core/HW/CPU.h @@ -53,6 +53,9 @@ void EnableStepping(bool stepping); // should not be used by the Host. void Break(); +// This should only be called from the CPU thread +void Continue(); + // Shorthand for GetState() == State::Stepping. // WARNING: State::PowerDown will return false, not just State::Running. bool IsStepping(); diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 7e947fccf2..bbf61f8111 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -3,6 +3,7 @@ // Originally written by Sven Peter for anergistic. +#include #include #include #include @@ -35,10 +36,9 @@ typedef SSIZE_T ssize_t; #include "Core/PowerPC/PPCCache.h" #include "Core/PowerPC/PowerPC.h" -namespace +namespace GDBStub { std::optional s_socket_context; -} // namespace #define GDB_BFR_MAX 10000 @@ -47,27 +47,35 @@ std::optional s_socket_context; #define GDB_STUB_ACK '+' #define GDB_STUB_NAK '-' -static bool hasControl = false; +// We are treating software breakpoints and hardware breakpoints the same way +enum class BreakpointType +{ + ExecuteSoft = 0, + ExecuteHard, + Read, + Write, + Access, +}; -static int tmpsock = -1; -static int sock = -1; +const s64 GDB_UPDATE_CYCLES = 100000; -static u8 cmd_bfr[GDB_BFR_MAX]; -static u32 cmd_len; +static bool s_has_control = false; -static u32 sig = 0; -static u32 send_signal = 0; -static u32 step_break = 0; +static int s_tmpsock = -1; +static int s_sock = -1; -static CoreTiming::EventType* m_gdbStubUpdateEvent; +static u8 s_cmd_bfr[GDB_BFR_MAX]; +static u32 s_cmd_len; + +static CoreTiming::EventType* s_update_event; static const char* CommandBufferAsString() { - return reinterpret_cast(cmd_bfr); + return reinterpret_cast(s_cmd_bfr); } // private helpers -static u8 hex2char(u8 hex) +static u8 Hex2char(u8 hex) { if (hex >= '0' && hex <= '9') return hex - '0'; @@ -80,7 +88,7 @@ static u8 hex2char(u8 hex) return 0; } -static u8 nibble2hex(u8 n) +static u8 Nibble2hex(u8 n) { n &= 0xf; if (n < 0xa) @@ -89,49 +97,50 @@ static u8 nibble2hex(u8 n) return 'A' + n - 0xa; } -static void mem2hex(u8* dst, u8* src, u32 len) +static void Mem2hex(u8* dst, u8* src, u32 len) { while (len-- > 0) { const u8 tmp = *src++; - *dst++ = nibble2hex(tmp >> 4); - *dst++ = nibble2hex(tmp); + *dst++ = Nibble2hex(tmp >> 4); + *dst++ = Nibble2hex(tmp); } } -static void hex2mem(u8* dst, u8* src, u32 len) +static void Hex2mem(u8* dst, u8* src, u32 len) { while (len-- > 0) { - *dst++ = (hex2char(*src) << 4) | hex2char(*(src + 1)); + *dst++ = (Hex2char(*src) << 4) | Hex2char(*(src + 1)); src += 2; } } -void GDBStubUpdateCallback(u64 userdata, s64 cycles_late) +static void UpdateCallback(u64 userdata, s64 cycles_late) { - gdb_handle_exception(false); - CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, m_gdbStubUpdateEvent); + ProcessCommands(false); + if (IsActive()) + CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event); } -static u8 gdb_read_byte() +static u8 ReadByte() { u8 c = '+'; - const ssize_t res = recv(sock, (char*)&c, 1, MSG_WAITALL); + const ssize_t res = recv(s_sock, (char*)&c, 1, MSG_WAITALL); if (res != 1) { ERROR_LOG_FMT(GDB_STUB, "recv failed : {}", res); - gdb_deinit(); + Deinit(); } return c; } -static u8 gdb_calc_chksum() +static u8 CalculateChecksum() { - u32 len = cmd_len; - u8* ptr = cmd_bfr; + u32 len = s_cmd_len; + u8* ptr = s_cmd_bfr; u8 c = 0; while (len-- > 0) @@ -140,9 +149,9 @@ static u8 gdb_calc_chksum() return c; } -static void gdb_bp_remove(u32 type, u32 addr, u32 len) +static void RemoveBreakpoint(BreakpointType type, u32 addr, u32 len) { - if (type == GDB_BP_TYPE_X) + if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft) { while (PowerPC::breakpoints.IsAddressBreakPoint(addr)) { @@ -160,30 +169,30 @@ static void gdb_bp_remove(u32 type, u32 addr, u32 len) } } -static void gdb_nak() +static void Nack() { const char nak = GDB_STUB_NAK; - const ssize_t res = send(sock, &nak, 1, 0); + const ssize_t res = send(s_sock, &nak, 1, 0); if (res != 1) ERROR_LOG_FMT(GDB_STUB, "send failed"); } -static void gdb_ack() +static void Ack() { const char ack = GDB_STUB_ACK; - const ssize_t res = send(sock, &ack, 1, 0); + const ssize_t res = send(s_sock, &ack, 1, 0); if (res != 1) ERROR_LOG_FMT(GDB_STUB, "send failed"); } -static void gdb_read_command() +static void ReadCommand() { - cmd_len = 0; - memset(cmd_bfr, 0, sizeof cmd_bfr); + s_cmd_len = 0; + memset(s_cmd_bfr, 0, sizeof s_cmd_bfr); - u8 c = gdb_read_byte(); + u8 c = ReadByte(); if (c == '+') { // ignore ack @@ -192,8 +201,8 @@ static void gdb_read_command() else if (c == 0x03) { CPU::Break(); - gdb_signal(GDB_SIGTRAP); - hasControl = true; + SendSignal(Signal::Sigtrap); + s_has_control = true; return; } else if (c != GDB_STUB_START) @@ -202,146 +211,138 @@ static void gdb_read_command() return; } - while ((c = gdb_read_byte()) != GDB_STUB_END) + while ((c = ReadByte()) != GDB_STUB_END) { - cmd_bfr[cmd_len++] = c; - if (cmd_len == sizeof cmd_bfr) + s_cmd_bfr[s_cmd_len++] = c; + if (s_cmd_len == sizeof s_cmd_bfr) { ERROR_LOG_FMT(GDB_STUB, "gdb: cmd_bfr overflow"); - gdb_nak(); + Nack(); return; } } - u8 chk_read = hex2char(gdb_read_byte()) << 4; - chk_read |= hex2char(gdb_read_byte()); + u8 chk_read = Hex2char(ReadByte()) << 4; + chk_read |= Hex2char(ReadByte()); - const u8 chk_calc = gdb_calc_chksum(); + const u8 chk_calc = CalculateChecksum(); if (chk_calc != chk_read) { ERROR_LOG_FMT(GDB_STUB, "gdb: invalid checksum: calculated {:02x} and read {:02x} for ${}# (length: {})", - chk_calc, chk_read, CommandBufferAsString(), cmd_len); - cmd_len = 0; + chk_calc, chk_read, CommandBufferAsString(), s_cmd_len); + s_cmd_len = 0; - gdb_nak(); + Nack(); return; } DEBUG_LOG_FMT(GDB_STUB, "gdb: read command {} with a length of {}: {}", - static_cast(cmd_bfr[0]), cmd_len, CommandBufferAsString()); - gdb_ack(); + static_cast(s_cmd_bfr[0]), s_cmd_len, CommandBufferAsString()); + Ack(); } -static int gdb_data_available() +static bool IsDataAvailable() { struct timeval t; fd_set _fds, *fds = &_fds; FD_ZERO(fds); - FD_SET(sock, fds); + FD_SET(s_sock, fds); t.tv_sec = 0; t.tv_usec = 20; - if (select(sock + 1, fds, nullptr, nullptr, &t) < 0) + if (select(s_sock + 1, fds, nullptr, nullptr, &t) < 0) { ERROR_LOG_FMT(GDB_STUB, "select failed"); - return 0; + return false; } - if (FD_ISSET(sock, fds)) - return 1; - return 0; + if (FD_ISSET(s_sock, fds)) + return true; + return false; } -static void gdb_reply(const char* reply) +static void SendReply(const char* reply) { - if (!gdb_active()) + if (!IsActive()) return; - memset(cmd_bfr, 0, sizeof cmd_bfr); + memset(s_cmd_bfr, 0, sizeof s_cmd_bfr); - cmd_len = (u32)strlen(reply); - if (cmd_len + 4 > sizeof cmd_bfr) + s_cmd_len = (u32)strlen(reply); + if (s_cmd_len + 4 > sizeof s_cmd_bfr) ERROR_LOG_FMT(GDB_STUB, "cmd_bfr overflow in gdb_reply"); - memcpy(cmd_bfr + 1, reply, cmd_len); + memcpy(s_cmd_bfr + 1, reply, s_cmd_len); - cmd_len++; - const u8 chk = gdb_calc_chksum(); - cmd_len--; - cmd_bfr[0] = GDB_STUB_START; - cmd_bfr[cmd_len + 1] = GDB_STUB_END; - cmd_bfr[cmd_len + 2] = nibble2hex(chk >> 4); - cmd_bfr[cmd_len + 3] = nibble2hex(chk); + s_cmd_len++; + const u8 chk = CalculateChecksum(); + s_cmd_len--; + s_cmd_bfr[0] = GDB_STUB_START; + s_cmd_bfr[s_cmd_len + 1] = GDB_STUB_END; + s_cmd_bfr[s_cmd_len + 2] = Nibble2hex(chk >> 4); + s_cmd_bfr[s_cmd_len + 3] = Nibble2hex(chk); - DEBUG_LOG_FMT(GDB_STUB, "gdb: reply (len: {}): {}", cmd_len, CommandBufferAsString()); + DEBUG_LOG_FMT(GDB_STUB, "gdb: reply (len: {}): {}", s_cmd_len, CommandBufferAsString()); - const char* ptr = (const char*)cmd_bfr; - u32 left = cmd_len + 4; + const char* ptr = (const char*)s_cmd_bfr; + u32 left = s_cmd_len + 4; while (left > 0) { - const int n = send(sock, ptr, left, 0); + const int n = send(s_sock, ptr, left, 0); if (n < 0) { ERROR_LOG_FMT(GDB_STUB, "gdb: send failed"); - return gdb_deinit(); + return Deinit(); } left -= n; ptr += n; } } -static void gdb_handle_query() +static void HandleQuery() { DEBUG_LOG_FMT(GDB_STUB, "gdb: query '{}'", CommandBufferAsString() + 1); - if (!strcmp((const char*)(cmd_bfr + 1), "TStatus")) + if (!strcmp((const char*)(s_cmd_bfr + 1), "TStatus")) { - return gdb_reply("T0"); + return SendReply("T0"); } - gdb_reply(""); + SendReply(""); } -static void gdb_handle_set_thread() +static void HandleSetThread() { - if (memcmp(cmd_bfr, "Hg0", 3) == 0 || memcmp(cmd_bfr, "Hc-1", 4) == 0 || - memcmp(cmd_bfr, "Hc0", 3) == 0 || memcmp(cmd_bfr, "Hc1", 3) == 0) - return gdb_reply("OK"); - gdb_reply("E01"); + if (memcmp(s_cmd_bfr, "Hg0", 3) == 0 || memcmp(s_cmd_bfr, "Hc-1", 4) == 0 || + memcmp(s_cmd_bfr, "Hc0", 3) == 0 || memcmp(s_cmd_bfr, "Hc1", 3) == 0) + return SendReply("OK"); + SendReply("E01"); } -static void gdb_handle_thread_alive() +static void HandleIsThreadAlive() { - if (memcmp(cmd_bfr, "T0", 2) == 0 || memcmp(cmd_bfr, "T1", 4) == 0 || - memcmp(cmd_bfr, "T-1", 3) == 0) - return gdb_reply("OK"); - gdb_reply("E01"); -} - -static void gdb_handle_signal() -{ - char bfr[128]; - memset(bfr, 0, sizeof bfr); - sprintf(bfr, "T%02x%02x:%08x;%02x:%08x;", sig, 64, PC, 1, GPR(1)); - gdb_reply(bfr); + if (memcmp(s_cmd_bfr, "T0", 2) == 0 || memcmp(s_cmd_bfr, "T1", 4) == 0 || + memcmp(s_cmd_bfr, "T-1", 3) == 0) + return SendReply("OK"); + SendReply("E01"); } static void wbe32hex(u8* p, u32 v) { u32 i; for (i = 0; i < 8; i++) - p[i] = nibble2hex(v >> (28 - 4 * i)); + p[i] = Nibble2hex(v >> (28 - 4 * i)); } static void wbe64hex(u8* p, u64 v) { u32 i; for (i = 0; i < 16; i++) - p[i] = nibble2hex(v >> (60 - 4 * i)); + p[i] = Nibble2hex(v >> (60 - 4 * i)); } static u32 re32hex(u8* p) @@ -350,7 +351,7 @@ static u32 re32hex(u8* p) u32 res = 0; for (i = 0; i < 8; i++) - res = (res << 4) | hex2char(p[i]); + res = (res << 4) | Hex2char(p[i]); return res; } @@ -361,22 +362,22 @@ static u64 re64hex(u8* p) u64 res = 0; for (i = 0; i < 16; i++) - res = (res << 4) | hex2char(p[i]); + res = (res << 4) | Hex2char(p[i]); return res; } -static void gdb_read_register() +static void ReadRegister() { static u8 reply[64]; u32 id; memset(reply, 0, sizeof reply); - id = hex2char(cmd_bfr[1]); - if (cmd_bfr[2] != '\0') + id = Hex2char(s_cmd_bfr[1]); + if (s_cmd_bfr[2] != '\0') { id <<= 4; - id |= hex2char(cmd_bfr[2]); + id |= Hex2char(s_cmd_bfr[2]); } if (id < 32) @@ -416,15 +417,15 @@ static void gdb_read_register() wbe32hex(reply, FPSCR.Hex); break; default: - return gdb_reply("E01"); + return SendReply("E01"); break; } } - gdb_reply((char*)reply); + SendReply((char*)reply); } -static void gdb_read_registers() +static void ReadRegisters() { static u8 bfr[GDB_BFR_MAX - 4]; u8* bufptr = bfr; @@ -438,13 +439,13 @@ static void gdb_read_registers() } bufptr += 32 * 8; - gdb_reply((char*)bfr); + SendReply((char*)bfr); } -static void gdb_write_registers() +static void WriteRegisters() { u32 i; - u8* bufptr = cmd_bfr; + u8* bufptr = s_cmd_bfr; for (i = 0; i < 32; i++) { @@ -452,21 +453,21 @@ static void gdb_write_registers() } bufptr += 32 * 8; - gdb_reply("OK"); + SendReply("OK"); } -static void gdb_write_register() +static void WriteRegister() { u32 id; - u8* bufptr = cmd_bfr + 3; + u8* bufptr = s_cmd_bfr + 3; - id = hex2char(cmd_bfr[1]); - if (cmd_bfr[2] != '=') + id = Hex2char(s_cmd_bfr[1]); + if (s_cmd_bfr[2] != '=') { ++bufptr; id <<= 4; - id |= hex2char(cmd_bfr[2]); + id |= Hex2char(s_cmd_bfr[2]); } if (id < 32) @@ -506,15 +507,15 @@ static void gdb_write_register() FPSCR.Hex = re32hex(bufptr); break; default: - return gdb_reply("E01"); + return SendReply("E01"); break; } } - gdb_reply("OK"); + SendReply("OK"); } -static void gdb_read_mem() +static void ReadMemory() { static u8 reply[GDB_BFR_MAX - 4]; u32 addr, len; @@ -522,70 +523,57 @@ static void gdb_read_mem() i = 1; addr = 0; - while (cmd_bfr[i] != ',') - addr = (addr << 4) | hex2char(cmd_bfr[i++]); + while (s_cmd_bfr[i] != ',') + addr = (addr << 4) | Hex2char(s_cmd_bfr[i++]); i++; len = 0; - while (i < cmd_len) - len = (len << 4) | hex2char(cmd_bfr[i++]); + while (i < s_cmd_len) + len = (len << 4) | Hex2char(s_cmd_bfr[i++]); DEBUG_LOG_FMT(GDB_STUB, "gdb: read memory: {:08x} bytes from {:08x}", len, addr); if (len * 2 > sizeof reply) - gdb_reply("E01"); + SendReply("E01"); u8* data = Memory::GetPointer(addr); if (!data) - return gdb_reply("E0"); - mem2hex(reply, data, len); + return SendReply("E0"); + Mem2hex(reply, data, len); reply[len * 2] = '\0'; - gdb_reply((char*)reply); + SendReply((char*)reply); } -static void gdb_write_mem() +static void WriteMemory() { u32 addr, len; u32 i; i = 1; addr = 0; - while (cmd_bfr[i] != ',') - addr = (addr << 4) | hex2char(cmd_bfr[i++]); + while (s_cmd_bfr[i] != ',') + addr = (addr << 4) | Hex2char(s_cmd_bfr[i++]); i++; len = 0; - while (cmd_bfr[i] != ':') - len = (len << 4) | hex2char(cmd_bfr[i++]); + while (s_cmd_bfr[i] != ':') + len = (len << 4) | Hex2char(s_cmd_bfr[i++]); DEBUG_LOG_FMT(GDB_STUB, "gdb: write memory: {:08x} bytes to {:08x}", len, addr); u8* dst = Memory::GetPointer(addr); if (!dst) - return gdb_reply("E00"); - hex2mem(dst, cmd_bfr + i + 1, len); - gdb_reply("OK"); + return SendReply("E00"); + Hex2mem(dst, s_cmd_bfr + i + 1, len); + SendReply("OK"); } -// forces a break on next instruction check -void gdb_break() +static void Step() { - step_break = 1; - send_signal = 1; + CPU::EnableStepping(true); + Core::CallOnStateChangedCallbacks(Core::State::Paused); } -static void gdb_step() +static bool AddBreakpoint(BreakpointType type, u32 addr, u32 len) { - send_signal = 1; -} - -static void gdb_continue() -{ - send_signal = 1; - CPU::EnableStepping(false); - Core::CallOnStateChangedCallbacks(Core::State::Running); -} - -bool gdb_add_bp(u32 type, u32 addr, u32 len) -{ - if (type == GDB_BP_TYPE_X) + if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft) { PowerPC::breakpoints.Add(addr); DEBUG_LOG_FMT(GDB_STUB, "gdb: added {} breakpoint: {:08x} bytes at {:08x}", type, len, addr); @@ -596,8 +584,10 @@ bool gdb_add_bp(u32 type, u32 addr, u32 len) new_memcheck.start_address = addr; new_memcheck.end_address = addr + len - 1; new_memcheck.is_ranged = (len > 1); - new_memcheck.is_break_on_read = (type == GDB_BP_TYPE_R || type == GDB_BP_TYPE_A); - new_memcheck.is_break_on_write = (type == GDB_BP_TYPE_W || type == GDB_BP_TYPE_A); + new_memcheck.is_break_on_read = + (type == BreakpointType::Read || type == BreakpointType::Access); + new_memcheck.is_break_on_write = + (type == BreakpointType::Write || type == BreakpointType::Access); new_memcheck.break_on_hit = true; new_memcheck.log_on_hit = false; new_memcheck.is_enabled = true; @@ -607,161 +597,127 @@ bool gdb_add_bp(u32 type, u32 addr, u32 len) return true; } -static void _gdb_add_bp() +static void HandleAddBreakpoint() { u32 type; u32 i, addr = 0, len = 0; - type = hex2char(cmd_bfr[1]); - switch (type) - { - case 0: - case 1: - type = GDB_BP_TYPE_X; - break; - case 2: - type = GDB_BP_TYPE_W; - break; - case 3: - type = GDB_BP_TYPE_R; - break; - case 4: - type = GDB_BP_TYPE_A; - break; - default: - return gdb_reply("E01"); - } + type = Hex2char(s_cmd_bfr[1]); + if (type > 4) + return SendReply("E01"); i = 3; - while (cmd_bfr[i] != ',') - addr = addr << 4 | hex2char(cmd_bfr[i++]); + while (s_cmd_bfr[i] != ',') + addr = addr << 4 | Hex2char(s_cmd_bfr[i++]); i++; - while (i < cmd_len) - len = len << 4 | hex2char(cmd_bfr[i++]); + while (i < s_cmd_len) + len = len << 4 | Hex2char(s_cmd_bfr[i++]); - if (!gdb_add_bp(type, addr, len)) - return gdb_reply("E02"); - gdb_reply("OK"); + if (!AddBreakpoint(static_cast(type), addr, len)) + return SendReply("E02"); + SendReply("OK"); } -static void gdb_remove_bp() +static void HandleRemoveBreakpoint() { u32 type, addr, len, i; - type = hex2char(cmd_bfr[1]); - switch (type) - { - case 0: - case 1: - type = GDB_BP_TYPE_X; - break; - case 2: - type = GDB_BP_TYPE_W; - break; - case 3: - type = GDB_BP_TYPE_R; - break; - case 4: - type = GDB_BP_TYPE_A; - break; - default: - return gdb_reply("E01"); - } + type = Hex2char(s_cmd_bfr[1]); + if (type >= 4) + return SendReply("E01"); addr = 0; len = 0; i = 3; - while (cmd_bfr[i] != ',') - addr = (addr << 4) | hex2char(cmd_bfr[i++]); + while (s_cmd_bfr[i] != ',') + addr = (addr << 4) | Hex2char(s_cmd_bfr[i++]); i++; - while (i < cmd_len) - len = (len << 4) | hex2char(cmd_bfr[i++]); + while (i < s_cmd_len) + len = (len << 4) | Hex2char(s_cmd_bfr[i++]); - gdb_bp_remove(type, addr, len); - gdb_reply("OK"); + RemoveBreakpoint(static_cast(type), addr, len); + SendReply("OK"); } - -void gdb_handle_exception(bool loop_until_continue) +void ProcessCommands(bool loop_until_continue) { - while (gdb_active()) + while (IsActive()) { if (CPU::GetState() == CPU::State::PowerDown) { - gdb_deinit(); + Deinit(); INFO_LOG_FMT(GDB_STUB, "killed by power down"); return; } - if (!gdb_data_available()) + if (!IsDataAvailable()) { if (loop_until_continue) continue; else return; } - gdb_read_command(); + ReadCommand(); // No more commands - if (cmd_len == 0) + if (s_cmd_len == 0) continue; - switch (cmd_bfr[0]) + switch (s_cmd_bfr[0]) { case 'q': - gdb_handle_query(); + HandleQuery(); break; case 'H': - gdb_handle_set_thread(); + HandleSetThread(); break; case 'T': - gdb_handle_thread_alive(); + HandleIsThreadAlive(); break; case '?': - gdb_handle_signal(); + SendSignal(Signal::Sigterm); break; case 'k': - gdb_deinit(); + Deinit(); INFO_LOG_FMT(GDB_STUB, "killed by gdb"); return; case 'g': - gdb_read_registers(); + ReadRegisters(); break; case 'G': - gdb_write_registers(); + WriteRegisters(); break; case 'p': - gdb_read_register(); + ReadRegister(); break; case 'P': - gdb_write_register(); + WriteRegister(); break; case 'm': - gdb_read_mem(); + ReadMemory(); break; case 'M': - gdb_write_mem(); + WriteMemory(); PowerPC::ppcState.iCache.Reset(); Host_UpdateDisasmDialog(); break; case 's': - gdb_step(); return; case 'C': case 'c': - gdb_continue(); - hasControl = false; + CPU::Continue(); + s_has_control = false; return; case 'z': - gdb_remove_bp(); + HandleRemoveBreakpoint(); break; case 'Z': - _gdb_add_bp(); + HandleAddBreakpoint(); break; default: - gdb_reply(""); + SendReply(""); break; } } @@ -769,11 +725,11 @@ void gdb_handle_exception(bool loop_until_continue) // exported functions -static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t server_addrlen, - sockaddr* client_addr, socklen_t* client_addrlen); +static void InitGeneric(int domain, const sockaddr* server_addr, socklen_t server_addrlen, + sockaddr* client_addr, socklen_t* client_addrlen); #ifndef _WIN32 -void gdb_init_local(const char* socket) +void InitLocal(const char* socket) { unlink(socket); @@ -781,11 +737,11 @@ void gdb_init_local(const char* socket) addr.sun_family = AF_UNIX; strcpy(addr.sun_path, socket); - gdb_init_generic(PF_LOCAL, (const sockaddr*)&addr, sizeof(addr), NULL, NULL); + InitGeneric(PF_LOCAL, (const sockaddr*)&addr, sizeof(addr), NULL, NULL); } #endif -void gdb_init(u32 port) +void Init(u32 port) { sockaddr_in saddr_server = {}; sockaddr_in saddr_client; @@ -796,94 +752,86 @@ void gdb_init(u32 port) socklen_t client_addrlen = sizeof(saddr_client); - gdb_init_generic(PF_INET, (const sockaddr*)&saddr_server, sizeof(saddr_server), - (sockaddr*)&saddr_client, &client_addrlen); + InitGeneric(PF_INET, (const sockaddr*)&saddr_server, sizeof(saddr_server), + (sockaddr*)&saddr_client, &client_addrlen); saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); } -static void gdb_init_generic(int domain, const sockaddr* server_addr, socklen_t server_addrlen, - sockaddr* client_addr, socklen_t* client_addrlen) +static void InitGeneric(int domain, const sockaddr* server_addr, socklen_t server_addrlen, + sockaddr* client_addr, socklen_t* client_addrlen) { s_socket_context.emplace(); - tmpsock = socket(domain, SOCK_STREAM, 0); - if (tmpsock == -1) + s_tmpsock = socket(domain, SOCK_STREAM, 0); + if (s_tmpsock == -1) ERROR_LOG_FMT(GDB_STUB, "Failed to create gdb socket"); int on = 1; - if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof on) < 0) + if (setsockopt(s_tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof on) < 0) ERROR_LOG_FMT(GDB_STUB, "Failed to setsockopt"); - if (bind(tmpsock, server_addr, server_addrlen) < 0) + if (bind(s_tmpsock, server_addr, server_addrlen) < 0) ERROR_LOG_FMT(GDB_STUB, "Failed to bind gdb socket"); - if (listen(tmpsock, 1) < 0) + if (listen(s_tmpsock, 1) < 0) ERROR_LOG_FMT(GDB_STUB, "Failed to listen to gdb socket"); INFO_LOG_FMT(GDB_STUB, "Waiting for gdb to connect..."); - sock = accept(tmpsock, client_addr, client_addrlen); - if (sock < 0) + s_sock = accept(s_tmpsock, client_addr, client_addrlen); + if (s_sock < 0) ERROR_LOG_FMT(GDB_STUB, "Failed to accept gdb client"); INFO_LOG_FMT(GDB_STUB, "Client connected."); #ifdef _WIN32 closesocket(s_tmpsock); #else - close(tmpsock); + close(s_tmpsock); #endif - tmpsock = -1; + s_tmpsock = -1; - m_gdbStubUpdateEvent = CoreTiming::RegisterEvent("GDBStubUpdate", GDBStubUpdateCallback); - CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, m_gdbStubUpdateEvent); - hasControl = true; + s_update_event = CoreTiming::RegisterEvent("GDBStubUpdate", UpdateCallback); + CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event); + s_has_control = true; } -void gdb_deinit() +void Deinit() { - if (tmpsock != -1) + if (s_tmpsock != -1) { - shutdown(tmpsock, SHUT_RDWR); - tmpsock = -1; + shutdown(s_tmpsock, SHUT_RDWR); + s_tmpsock = -1; } - if (sock != -1) + if (s_sock != -1) { - shutdown(sock, SHUT_RDWR); - sock = -1; + shutdown(s_sock, SHUT_RDWR); + s_sock = -1; } s_socket_context.reset(); - hasControl = false; + s_has_control = false; } -bool gdb_active() +bool IsActive() { - return tmpsock != -1 || sock != -1; + return s_tmpsock != -1 || s_sock != -1; } -bool gdb_hasControl() +bool HasControl() { - return hasControl; + return s_has_control; } -void gdb_takeControl() +void TakeControl() { - hasControl = true; + s_has_control = true; } -int gdb_signal(u32 s) +void SendSignal(Signal signal) { - if (sock == -1) - return 1; - - sig = s; - - if (send_signal) - { - gdb_handle_signal(); - send_signal = 0; - } - - return 0; + char bfr[128] = {}; + fmt::format_to(bfr, "T{:02x}{:02x}:{:08x};{:02x}:{:08x};", signal, 64, PC, 1, GPR(1)); + SendReply(bfr); } +} // namespace GDBStub diff --git a/Source/Core/Core/PowerPC/GDBStub.h b/Source/Core/Core/PowerPC/GDBStub.h index 56bfa35d14..d7580dbf8c 100644 --- a/Source/Core/Core/PowerPC/GDBStub.h +++ b/Source/Core/Core/PowerPC/GDBStub.h @@ -8,42 +8,21 @@ #include "Common/CommonTypes.h" #include "Core/CoreTiming.h" -typedef enum +namespace GDBStub { - GDB_SIGTRAP = 5, - GDB_SIGTERM = 15, -} gdb_signals; - -typedef enum +enum class Signal { - GDB_BP_TYPE_NONE = 0, - GDB_BP_TYPE_X, - GDB_BP_TYPE_R, - GDB_BP_TYPE_W, - GDB_BP_TYPE_A -} gdb_bp_type; + Sigtrap = 5, + Sigterm = 15, +}; -const s64 GDB_UPDATE_CYCLES = 100000; +void Init(u32 port); +void InitLocal(const char* socket); +void Deinit(); +bool IsActive(); +bool HasControl(); +void TakeControl(); -void GDBStubUpdateCallback(u64 userdata, s64 cycles_late); - -void gdb_init(u32 port); -void gdb_init_local(const char* socket); -void gdb_deinit(); -bool gdb_active(); -bool gdb_hasControl(); -void gdb_takeControl(); -void gdb_break(); - -void gdb_handle_exception(bool loopUntilContinue); -int gdb_signal(u32 signal); - -int gdb_bp_x(u32 addr); -int gdb_bp_r(u32 addr); -int gdb_bp_w(u32 addr); -int gdb_bp_a(u32 addr); - -bool gdb_add_bp(u32 type, u32 addr, u32 len); -void gdb_handle_exception(bool loop_until_continue); -void SendSignal(u32 signal); +void ProcessCommands(bool loop_until_continue); +void SendSignal(Signal signal); } // namespace GDBStub diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 453097f016..ac48988080 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -293,8 +293,8 @@ void Interpreter::Run() #endif INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PC); CPU::Break(); - if (gdb_active()) - gdb_takeControl(); + if (GDBStub::IsActive()) + GDBStub::TakeControl(); if (PowerPC::breakpoints.IsTempBreakPoint(PC)) PowerPC::breakpoints.Remove(PC); diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index a027720a4f..8742868bc5 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -519,8 +519,8 @@ static void Memcheck(u32 address, u64 var, bool write, size_t size) CPU::Break(); - if (gdb_active()) - gdb_takeControl(); + if (GDBStub::IsActive()) + GDBStub::TakeControl(); // Fake a DSI so that all the code that tests for it in order to skip // the rest of the instruction will apply. (This means that diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index d124643560..40cdfdac53 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -614,8 +614,8 @@ void CheckBreakPoints() if (PowerPC::breakpoints.IsBreakPointBreakOnHit(PC)) { CPU::Break(); - if (gdb_active()) - gdb_takeControl(); + if (GDBStub::IsActive()) + GDBStub::TakeControl(); } if (PowerPC::breakpoints.IsBreakPointLogOnHit(PC)) { From 2f7a3e59e5193497601afabe41b7dcc0b07f1482 Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Fri, 1 Oct 2021 12:06:23 -0400 Subject: [PATCH 11/13] GDBStub: upgrade some logs from debug to info --- Source/Core/Core/PowerPC/GDBStub.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index bbf61f8111..22afbe06e3 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -156,7 +156,7 @@ static void RemoveBreakpoint(BreakpointType type, u32 addr, u32 len) while (PowerPC::breakpoints.IsAddressBreakPoint(addr)) { PowerPC::breakpoints.Remove(addr); - DEBUG_LOG_FMT(GDB_STUB, "gdb: removed a breakpoint: {:08x} bytes at {:08x}", len, addr); + INFO_LOG_FMT(GDB_STUB, "gdb: removed a breakpoint: {:08x} bytes at {:08x}", len, addr); } } else @@ -164,7 +164,7 @@ static void RemoveBreakpoint(BreakpointType type, u32 addr, u32 len) while (PowerPC::memchecks.GetMemCheck(addr, len) != nullptr) { PowerPC::memchecks.Remove(addr); - DEBUG_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr); + INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr); } } } @@ -207,7 +207,7 @@ static void ReadCommand() } else if (c != GDB_STUB_START) { - DEBUG_LOG_FMT(GDB_STUB, "gdb: read invalid byte {:02x}", c); + WARN_LOG_FMT(GDB_STUB, "gdb: read invalid byte {:02x}", c); return; } @@ -530,7 +530,7 @@ static void ReadMemory() len = 0; while (i < s_cmd_len) len = (len << 4) | Hex2char(s_cmd_bfr[i++]); - DEBUG_LOG_FMT(GDB_STUB, "gdb: read memory: {:08x} bytes from {:08x}", len, addr); + INFO_LOG_FMT(GDB_STUB, "gdb: read memory: {:08x} bytes from {:08x}", len, addr); if (len * 2 > sizeof reply) SendReply("E01"); @@ -556,7 +556,7 @@ static void WriteMemory() len = 0; while (s_cmd_bfr[i] != ':') len = (len << 4) | Hex2char(s_cmd_bfr[i++]); - DEBUG_LOG_FMT(GDB_STUB, "gdb: write memory: {:08x} bytes to {:08x}", len, addr); + INFO_LOG_FMT(GDB_STUB, "gdb: write memory: {:08x} bytes to {:08x}", len, addr); u8* dst = Memory::GetPointer(addr); if (!dst) @@ -576,7 +576,7 @@ static bool AddBreakpoint(BreakpointType type, u32 addr, u32 len) if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft) { PowerPC::breakpoints.Add(addr); - DEBUG_LOG_FMT(GDB_STUB, "gdb: added {} breakpoint: {:08x} bytes at {:08x}", type, len, addr); + INFO_LOG_FMT(GDB_STUB, "gdb: added {} breakpoint: {:08x} bytes at {:08x}", type, len, addr); } else { From 7ad586fe2cb6afbf849d76d687ab48f49a70f798 Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Fri, 1 Oct 2021 12:17:17 -0400 Subject: [PATCH 12/13] GDBStub: Make step force pausing even if play was pressed --- Source/Core/Core/PowerPC/GDBStub.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 22afbe06e3..19a7de357e 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -704,6 +704,7 @@ void ProcessCommands(bool loop_until_continue) Host_UpdateDisasmDialog(); break; case 's': + Step(); return; case 'C': case 'c': From 6a4d607e094c71281b8f9836f42186c8f065553e Mon Sep 17 00:00:00 2001 From: aldelaro5 Date: Fri, 1 Oct 2021 12:23:58 -0400 Subject: [PATCH 13/13] GDBStub: Add log when break is sent --- Source/Core/Core/PowerPC/GDBStub.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 19a7de357e..2d5dac1efb 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -203,6 +203,7 @@ static void ReadCommand() CPU::Break(); SendSignal(Signal::Sigtrap); s_has_control = true; + INFO_LOG_FMT(GDB_STUB, "gdb: CPU::Break due to break command"); return; } else if (c != GDB_STUB_START)