From b7fd1225ba18d0ba1c6fc734575958e61a4c4d86 Mon Sep 17 00:00:00 2001 From: Matthew Parlane Date: Sun, 6 Jan 2013 23:28:27 +1300 Subject: [PATCH 1/4] Started gdb stub support. --- CMakeLists.txt | 6 + Source/Core/Common/Src/Log.h | 1 + Source/Core/Common/Src/LogManager.cpp | 1 + Source/Core/Core/CMakeLists.txt | 4 + Source/Core/Core/Src/ConfigManager.cpp | 4 + Source/Core/Core/Src/Core.cpp | 28 + Source/Core/Core/Src/CoreParameter.cpp | 3 + Source/Core/Core/Src/CoreParameter.h | 3 + Source/Core/Core/Src/PowerPC/GDBStub.cpp | 942 ++++++++++++++++++ Source/Core/Core/Src/PowerPC/GDBStub.h | 61 ++ .../Src/PowerPC/Interpreter/Interpreter.cpp | 20 +- 11 files changed, 1071 insertions(+), 2 deletions(-) create mode 100644 Source/Core/Core/Src/PowerPC/GDBStub.cpp create mode 100644 Source/Core/Core/Src/PowerPC/GDBStub.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b025de11ef..0349500ba8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,6 +222,12 @@ if(FASTLOG) add_definitions(-DDEBUGFAST) endif() + +option(GDBSTUB "Enable gdb stub for remote debugging." OFF) +if(GDBSTUB) + add_definitions(-DUSE_GDBSTUB) +endif(GDBSTUB) + # For now GLES and EGL are tied to each other. # Enabling GLES also disables the OpenGL plugin. option(USE_GLES "Enables GLES, disables OGL" OFF) diff --git a/Source/Core/Common/Src/Log.h b/Source/Core/Common/Src/Log.h index e24fd8583c..f88a386c2c 100644 --- a/Source/Core/Common/Src/Log.h +++ b/Source/Core/Common/Src/Log.h @@ -44,6 +44,7 @@ enum LOG_TYPE { DVDINTERFACE, DYNA_REC, EXPANSIONINTERFACE, + GDB_STUB, POWERPC, GPFIFO, OSHLE, diff --git a/Source/Core/Common/Src/LogManager.cpp b/Source/Core/Common/Src/LogManager.cpp index a79c413cf8..dc9f461480 100644 --- a/Source/Core/Common/Src/LogManager.cpp +++ b/Source/Core/Common/Src/LogManager.cpp @@ -57,6 +57,7 @@ LogManager::LogManager() m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVDInterface"); m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "ExpansionInt"); + m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt"); m_Log[LogTypes::POWERPC] = new LogContainer("PowerPC", "IBM CPU"); m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE"); diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 6ffeeaec3a..1cf7f0a493 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -222,5 +222,9 @@ if(OPROFILE_FOUND) set(LIBS ${LIBS} opagent bfd) endif(OPROFILE_FOUND) +if(GDBSTUB) + set(SRCS ${SRCS} Src/PowerPC/GDBStub.cpp) +endif(GDBSTUB) + add_library(core STATIC ${SRCS}) target_link_libraries(core ${LIBS}) diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index 180e6c981d..183b35c968 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -157,6 +157,7 @@ void SConfig::SaveSettings() ini.Set("General", "RecursiveGCMPaths", m_RecursiveISOFolder); ini.Set("General", "NANDRoot", m_NANDPath); ini.Set("General", "WirelessMac", m_WirelessMac); + ini.Set("General", "GDBPort", m_LocalCoreStartupParameter.iGDBPort); // Interface ini.Set("Interface", "ConfirmStop", m_LocalCoreStartupParameter.bConfirmStop); @@ -270,6 +271,9 @@ void SConfig::LoadSettings() { ini.Get("General", "LastFilename", &m_LastFilename); ini.Get("General", "ShowLag", &m_ShowLag, false); + #ifdef USE_GDBSTUB + ini.Get("General", "GDBPort", &(m_LocalCoreStartupParameter.iGDBPort), -1); + #endif m_ISOFolder.clear(); int numGCMPaths; diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index e92b9088bc..0fa1d44134 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -55,6 +55,9 @@ #include "PowerPC/PowerPC.h" #include "PowerPC/JitCommon/JitBase.h" +#ifdef USE_GDBSTUB +#include "PowerPC/GDBStub.h" +#endif #include "DSPEmulator.h" #include "ConfigManager.h" @@ -101,6 +104,9 @@ std::string g_stateFileName; std::thread g_EmuThread; static std::thread g_cpu_thread; +#ifdef USE_GDBSTUB +static std::thread g_gdb_thread; +#endif static bool g_requestRefreshInfo = false; static int g_pauseAndLockDepth = 0; @@ -448,6 +454,20 @@ void EmuThread() else cpuThreadFunc = CpuThread; + #ifdef USE_GDBSTUB + if(_CoreParameter.iGDBPort > 0) + { + INFO_LOG(GDB_STUB, "Trying to start the GDB Stub listening on port %d.", _CoreParameter.iGDBPort); + Core::SetState(Core::CORE_PAUSE); + gdb_init(_CoreParameter.iGDBPort); + + g_gdb_thread = std::thread(gdb_thread); + + //gdb_signal(SIGTRAP); + gdb_add_bp(GDB_BP_TYPE_X, 0x80004050, 4); + } + #endif + // ENTER THE VIDEO THREAD LOOP if (_CoreParameter.bCPUThread) { @@ -491,6 +511,14 @@ void EmuThread() g_cpu_thread.join(); INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str()); + + #ifdef USE_GDBSTUB + // Wait for g_gdb_thread to exit + INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping GDB thread ...").c_str()); + gdb_deinit(); + g_gdb_thread.join(); + INFO_LOG(CONSOLE, "%s", StopMessage(true, "GDB thread stopped.").c_str()); + #endif VolumeHandler::EjectVolume(); FileMon::Close(); diff --git a/Source/Core/Core/Src/CoreParameter.cpp b/Source/Core/Core/Src/CoreParameter.cpp index dee2452cb3..2c75a17eb3 100644 --- a/Source/Core/Core/Src/CoreParameter.cpp +++ b/Source/Core/Core/Src/CoreParameter.cpp @@ -68,6 +68,9 @@ SCoreStartupParameter::SCoreStartupParameter() void SCoreStartupParameter::LoadDefaults() { bEnableDebugging = false; + #ifdef USE_GDBSTUB + iGDBPort = -1; + #endif iCPUCore = 1; bCPUThread = false; bSkipIdle = false; diff --git a/Source/Core/Core/Src/CoreParameter.h b/Source/Core/Core/Src/CoreParameter.h index e67935906b..959997de70 100644 --- a/Source/Core/Core/Src/CoreParameter.h +++ b/Source/Core/Core/Src/CoreParameter.h @@ -71,6 +71,9 @@ struct SCoreStartupParameter // Settings bool bEnableDebugging; + #ifdef USE_GDBSTUB + int iGDBPort; + #endif bool bAutomaticStart; bool bBootToPause; diff --git a/Source/Core/Core/Src/PowerPC/GDBStub.cpp b/Source/Core/Core/Src/PowerPC/GDBStub.cpp new file mode 100644 index 0000000000..1ba5433638 --- /dev/null +++ b/Source/Core/Core/Src/PowerPC/GDBStub.cpp @@ -0,0 +1,942 @@ +// Copyright (C) 2010 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Originally written by Sven Peter for anergistic. + +#include "GDBStub.h" + +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#endif +#include + + +#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 int tmpsock = -1; +static int sock = -1; +static struct sockaddr_in saddr_server, saddr_client; + +static u8 cmd_bfr[GDB_BFR_MAX]; +static u32 cmd_len; + +static u32 sig = 0; +static u32 send_signal = 0; + +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]; + +// private helpers +static u8 hex2char(u8 hex) +{ + if (hex >= '0' && hex <= '9') + return hex - '0'; + else if (hex >= 'a' && hex <= 'f') + return hex - 'a' + 0xa; + else if (hex >= 'A' && hex <= 'F') + return hex - 'A' + 0xa; + + ERROR_LOG(GDB_STUB, "Invalid nibble: %c (%02x)\n", hex, hex); + return 0; +} + +static u8 nibble2hex(u8 n) +{ + n &= 0xf; + if (n < 0xa) + return '0' + n; + else + return 'A' + n - 0xa; +} + +static void mem2hex(u8 *dst, u8 *src, u32 len) +{ + u8 tmp; + + while (len-- > 0) { + tmp = *src++; + *dst++ = nibble2hex(tmp>>4); + *dst++ = nibble2hex(tmp); + } +} + +static void hex2mem(u8 *dst, u8 *src, u32 len) +{ + while (len-- > 0) { + *dst = hex2char(*src++) << 4; + *dst++ |= hex2char(*src++); + } +} + +static u8 gdb_read_byte() +{ + ssize_t res; + u8 c = '+'; + + res = recv(sock, &c, 1, MSG_WAITALL); + if (res != 1) + { + ERROR_LOG(GDB_STUB, "recv failed : %ld", res); + gdb_deinit(); + } + + return c; +} + +static u8 gdb_calc_chksum() +{ + u32 len = cmd_len; + u8 *ptr = cmd_bfr; + u8 c = 0; + + while(len-- > 0) + c += *ptr++; + + 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 NULL; + } +} + +static gdb_bp_t *gdb_bp_empty_slot(u32 type) +{ + gdb_bp_t *p; + u32 i; + + p = gdb_bp_ptr(type); + if (p == NULL) + return NULL; + + for (i = 0; i < GDB_MAX_BP; i++) { + if (p[i].active == 0) + return &p[i]; + } + + return NULL; +} + +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 == NULL) + return NULL; + + 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 NULL; +} + +static void gdb_bp_remove(u32 type, u32 addr, u32 len) +{ + gdb_bp_t *p; + + do { + p = gdb_bp_find(type, addr, len); + if (p != NULL) { + DEBUG_LOG(GDB_STUB, "gdb: removed a breakpoint: %08x bytes at %08x\n", len, addr); + p->active = 0; + memset(p, 0, sizeof p); + } + } while (p != NULL); +} + +static int gdb_bp_check(u32 addr, u32 type) +{ + gdb_bp_t *p; + u32 i; + + p = gdb_bp_ptr(type); + if (p == NULL) + 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; +} + +static void gdb_nak() +{ + const char nak = GDB_STUB_NAK; + ssize_t res; + + res = send(sock, &nak, 1, 0); + if (res != 1) + ERROR_LOG(GDB_STUB, "send failed"); +} + +static void gdb_ack() +{ + const char ack = GDB_STUB_ACK; + ssize_t res; + + res = send(sock, &ack, 1, 0); + if (res != 1) + ERROR_LOG(GDB_STUB, "send failed"); +} + +static void gdb_read_command() +{ + u8 c; + u8 chk_read, chk_calc; + + cmd_len = 0; + memset(cmd_bfr, 0, sizeof cmd_bfr); + + c = gdb_read_byte(); + if (c == '+') + { + //ignore ack + return; + } + else if (c == 0x03) + { + CCPU::Break(); + gdb_signal(SIGTRAP); + return; + } + else if (c != GDB_STUB_START) { + DEBUG_LOG(GDB_STUB, "gdb: read invalid byte %02x\n", c); + return; + } + + while ((c = gdb_read_byte()) != GDB_STUB_END) { + cmd_bfr[cmd_len++] = c; + if (cmd_len == sizeof cmd_bfr) + ERROR_LOG(GDB_STUB, "gdb: cmd_bfr overflow\n"); + } + + chk_read = hex2char(gdb_read_byte()) << 4; + chk_read |= hex2char(gdb_read_byte()); + + chk_calc = gdb_calc_chksum(); + + if (chk_calc != chk_read) { + ERROR_LOG(GDB_STUB, "gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)\n", chk_calc, chk_read, cmd_bfr, cmd_len); + cmd_len = 0; + + gdb_nak(); + } + + DEBUG_LOG(GDB_STUB, "gdb: read command %c with a length of %d: %s\n", cmd_bfr[0], cmd_len, cmd_bfr); +} + +static int gdb_data_available() { + struct timeval t; + fd_set _fds, *fds = &_fds; + + FD_ZERO(fds); + FD_SET(sock, fds); + + t.tv_sec = 0; + t.tv_usec = 20; + + if (select(sock + 1, fds, NULL, NULL, &t) < 0) + { + ERROR_LOG(GDB_STUB, "select failed"); + return 0; + } + + if (FD_ISSET(sock, fds)) + return 1; + return 0; +} + +static void gdb_reply(const char *reply) +{ + u8 chk; + u32 left; + u8 *ptr; + int n; + + memset(cmd_bfr, 0, sizeof cmd_bfr); + + cmd_len = strlen(reply); + if (cmd_len + 4 > sizeof cmd_bfr) + ERROR_LOG(GDB_STUB, "cmd_bfr overflow in gdb_reply"); + + memcpy(cmd_bfr + 1, reply, cmd_len); + + cmd_len++; + 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); + + DEBUG_LOG(GDB_STUB, "gdb: reply (len: %d): %s\n", cmd_len, cmd_bfr); + + ptr = cmd_bfr; + left = cmd_len + 4; + while (left > 0) { + n = send(sock, ptr, left, 0); + if (n < 0) + ERROR_LOG(GDB_STUB, "gdb: send failed"); + left -= n; + ptr += n; + } +} + +static void gdb_handle_query() +{ + gdb_ack(); + DEBUG_LOG(GDB_STUB, "gdb: query '%s'\n", cmd_bfr+1); + + if (!strcmp((const char *)(cmd_bfr+1), "TStatus")) + { + return gdb_reply("T0"); + } + + gdb_reply(""); +} + +static void gdb_handle_set_thread() +{ + gdb_ack(); + if (memcmp(cmd_bfr, "Hg0", 3) == 0 || + memcmp(cmd_bfr, "Hc-1", 4) == 0 || + memcmp(cmd_bfr, "Hc0", 4) == 0) + return gdb_reply("OK"); + gdb_reply("E01"); +} + +static void gdb_handle_signal() +{ + char bfr[128]; + + gdb_ack(); + memset(bfr, 0, sizeof bfr); + sprintf(bfr, "T%02x%02x:%08x;%02x:%08x;", sig, 64, PC, 1, GPR(1)); + gdb_reply(bfr); +} + +static void wbe32hex(u8 *p, u32 v) +{ + u32 i; + for (i = 0; i < 8; 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)); +} + +static void gdb_read_register() +{ + static u8 reply[64]; + u32 id; + + memset(reply, 0, sizeof reply); + id = hex2char(cmd_bfr[1]) << 4; + id |= hex2char(cmd_bfr[2]); + + gdb_ack(); + switch (id) { + case 0 ... 31: + wbe32hex(reply, GPR(id)); + break; + case 32 ... 63: + wbe64hex(reply, riPS0(id-32)); + break; + case 64: + wbe32hex(reply, PC); + break; + case 65: + wbe32hex(reply, MSR); + break; + case 66: + wbe32hex(reply, GetCR()); + break; + case 67: + wbe32hex(reply, LR); + break; + case 68: + wbe32hex(reply, CTR); + break; + case 69: + wbe32hex(reply, PowerPC::ppcState.spr[SPR_XER]); + break; + case 70: + wbe32hex(reply, 0x0BADC0DE); + break; + case 71: + wbe32hex(reply, FPSCR.Hex); + break; + default: + return gdb_reply("E01"); + break; + } + + gdb_reply((char *)reply); +} + +static void gdb_read_registers() +{ + static u8 bfr[GDB_BFR_MAX - 4]; + u8 * bufptr = bfr; + u32 i; + + gdb_ack(); + memset(bfr, 0, sizeof bfr); + + for (i = 0; i < 32; i++) { + wbe32hex(bufptr + i*4, GPR(i)); + } + bufptr += 32 * 4; + + for (i = 0; i < 32; i++) { + wbe64hex(bufptr + i*4, riPS0(i)); + } + bufptr += 64 * 4; + + wbe32hex(bufptr, PC); bufptr += 4; + wbe32hex(bufptr, MSR); bufptr += 4; + wbe32hex(bufptr, GetCR()); bufptr += 4; + wbe32hex(bufptr, LR); bufptr += 4; + + + wbe32hex(bufptr, CTR); bufptr += 4; + wbe32hex(bufptr, PowerPC::ppcState.spr[SPR_XER]); bufptr += 4; + // MQ register not used. + wbe32hex(bufptr, 0x0BADC0DE); bufptr += 4; + + + + gdb_reply((char *)bfr); +} + +static u32 re32hex(u8 *p) +{ + u32 i; + u32 res = 0; + + for (i = 0; i < 8; i++) + res = (res << 4) | hex2char(p[i]); + + return res; +} + +static u64 re64hex(u8 *p) +{ + u32 i; + u64 res = 0; + + for (i = 0; i < 16; i++) + res = (res << 4) | hex2char(p[i]); + + return res; +} + +static void gdb_write_registers() +{ + gdb_ack(); + + u32 i; + u8 * bufptr = cmd_bfr; + + for (i = 0; i < 32; i++) { + GPR(i) = re32hex(bufptr + i*4); + } + bufptr += 32 * 4; + + for (i = 0; i < 32; i++) { + riPS0(i) = re64hex(bufptr + i*4); + } + bufptr += 64 * 4; + + PC = re32hex(bufptr); bufptr += 4; + MSR = re32hex(bufptr); bufptr += 4; + SetCR(re32hex(bufptr)); bufptr += 4; + LR = re32hex(bufptr); bufptr += 4; + + + CTR = re32hex(bufptr); bufptr += 4; + PowerPC::ppcState.spr[SPR_XER] = re32hex(bufptr); bufptr += 4; + // MQ register not used. + (void)re32hex(bufptr); bufptr += 4; + + + gdb_reply("OK"); +} + +static void gdb_write_register() +{ + u32 id; + + gdb_ack(); + + id = hex2char(cmd_bfr[1]) << 4; + id |= hex2char(cmd_bfr[2]); + + + u8 * bufptr = cmd_bfr + 4; + + + switch (id) { + case 0 ... 31: + GPR(id) = re32hex(bufptr); + break; + case 32 ... 63: + riPS0(id-32) = re64hex(bufptr); + break; + case 64: + PC = re32hex(bufptr); + break; + case 65: + MSR = re32hex(bufptr); + break; + case 66: + SetCR(re32hex(bufptr)); + break; + case 67: + LR = re32hex(bufptr); + break; + case 68: + CTR = re32hex(bufptr); + break; + case 69: + PowerPC::ppcState.spr[SPR_XER] = re32hex(bufptr); + break; + case 70: + // do nothing, we dont have MQ + break; + case 71: + FPSCR.Hex = re32hex(bufptr); + break; + default: + return gdb_reply("E01"); + break; + } + + gdb_reply("OK"); +} + +static void gdb_read_mem() +{ + static u8 reply[GDB_BFR_MAX - 4]; + u32 addr, len; + u32 i; + + gdb_ack(); + + i = 1; + addr = 0; + while (cmd_bfr[i] != ',') + addr = (addr << 4) | hex2char(cmd_bfr[i++]); + i++; + + len = 0; + while (i < cmd_len) + len = (len << 4) | hex2char(cmd_bfr[i++]); + DEBUG_LOG(GDB_STUB, "gdb: read memory: %08x bytes from %08x\n", len, addr); + + if (len*2 > sizeof reply) + gdb_reply("E01"); + + mem2hex(reply, Memory::GetPointer(addr), len); + reply[len*2] = '\0'; + gdb_reply((char *)reply); +} + +static void gdb_write_mem() +{ + u32 addr, len; + u32 i; + + gdb_ack(); + + i = 1; + addr = 0; + while (cmd_bfr[i] != ',') + addr = (addr << 4) | hex2char(cmd_bfr[i++]); + i++; + + len = 0; + while (cmd_bfr[i] != ':') + len = (len << 4) | hex2char(cmd_bfr[i++]); + DEBUG_LOG(GDB_STUB, "gdb: write memory: %08x bytes to %08x\n", len, addr); + + hex2mem(Memory::GetPointer(addr), cmd_bfr + i, len); + gdb_reply("OK"); +} + +static void gdb_continue() +{ + gdb_ack(); + CCPU::EnableStepping(false); + m_GdbWaitEvent.Set(); + send_signal = 1; +} + + +bool gdb_add_bp(u32 type, u32 addr, u32 len) +{ + gdb_bp_t *bp; + bp = gdb_bp_empty_slot(type); + if (bp == NULL) + return false; + + bp->active = 1; + bp->addr = addr; + bp->len = len; + + DEBUG_LOG(GDB_STUB, "gdb: added %d breakpoint: %08x bytes at %08x\n", type, bp->len, bp->addr); + return true; +} + +static void _gdb_add_bp() +{ + u32 type; + u32 i, addr = 0, len = 0; + + gdb_ack(); + + 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"); + } + + i = 3; + while (cmd_bfr[i] != ',') + addr = addr << 4 | hex2char(cmd_bfr[i++]); + i++; + + while (i < cmd_len) + len = len << 4 | hex2char(cmd_bfr[i++]); + + if (!gdb_add_bp(type, addr, len)) + return gdb_reply("E02"); + gdb_reply("OK"); +} + +static void gdb_remove_bp() +{ + u32 type, addr, len, i; + + gdb_ack(); + + 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"); + } + + addr = 0; + len = 0; + + i = 3; + while (cmd_bfr[i] != ',') + addr = (addr << 4) | hex2char(cmd_bfr[i++]); + i++; + + while (i < cmd_len) + len = (len << 4) | hex2char(cmd_bfr[i++]); + + gdb_bp_remove(type, addr, len); + gdb_reply("OK"); +} + +static void gdb_parse_command() +{ + if (cmd_len == 0) + return; + + switch(cmd_bfr[0]) { + case 'q': + gdb_handle_query(); + break; + case 'H': + gdb_handle_set_thread(); + break; + case '?': + gdb_handle_signal(); + break; + case 'k': + gdb_ack(); + gdb_deinit(); + INFO_LOG(GDB_STUB, "killed by gdb"); + break; + case 'g': + gdb_read_registers(); + break; + case 'G': + gdb_write_registers(); + break; + case 'p': + gdb_read_register(); + break; + case 'P': + gdb_write_register(); + break; + case 'm': + gdb_read_mem(); + break; + case 'M': + gdb_write_mem(); + break; + case 's': + case 'C': + case 'c': + gdb_continue(); + break; + case 'v': + gdb_ack(); + gdb_reply(""); + break; + case 'z': + gdb_remove_bp(); + break; + case 'Z': + _gdb_add_bp(); + break; + default: + gdb_ack(); + gdb_reply(""); + break; + } +} + +#ifdef _WIN32 +WSADATA InitData; +#endif + +// exported functions + +void gdb_init(u32 port) +{ + socklen_t len; + int on; + #ifdef _WIN32 + WSAStartup(MAKEWORD(2,2), &InitData); + #endif + + m_GdbWaitEvent.Reset(); + + 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(AF_INET, SOCK_STREAM, 0); + if (tmpsock == -1) + ERROR_LOG(GDB_STUB, "Failed to create gdb socket"); + + on = 1; + if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) < 0) + ERROR_LOG(GDB_STUB, "Failed to setsockopt"); + + memset(&saddr_server, 0, sizeof saddr_server); + saddr_server.sin_family = AF_INET; + saddr_server.sin_port = htons(port); + saddr_server.sin_addr.s_addr = INADDR_ANY; + + if (bind(tmpsock, (struct sockaddr *)&saddr_server, sizeof saddr_server) < 0) + ERROR_LOG(GDB_STUB, "Failed to bind gdb socket"); + + if (listen(tmpsock, 1) < 0) + ERROR_LOG(GDB_STUB, "Failed to listen to gdb socket"); + + INFO_LOG(GDB_STUB, "Waiting for gdb to connect...\n"); + sock = accept(tmpsock, (struct sockaddr *)&saddr_client, &len); + + if (sock < 0) + ERROR_LOG(GDB_STUB, "Failed to accept gdb client"); + INFO_LOG(GDB_STUB, "Client connected.\n"); + + saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); + /*if (((saddr_client.sin_addr.s_addr >> 24) & 0xff) != 127 || + * ((saddr_client.sin_addr.s_addr >> 16) & 0xff) != 0 || + * ((saddr_client.sin_addr.s_addr >> 8) & 0xff) != 0 || + * ((saddr_client.sin_addr.s_addr >> 0) & 0xff) != 1) + * ERROR_LOG(GDB_STUB, "gdb: incoming connection not from localhost"); + */ + close(tmpsock); + tmpsock = -1; +} + + +void gdb_deinit() +{ + if (tmpsock != -1) + { + close(tmpsock); + tmpsock = -1; + } + if (sock != -1) + { + close(sock); + sock = -1; + } + + m_GdbWaitEvent.Set(); + m_GdbWaitEvent.Reset(); + + #ifdef _WIN32 + WSACleanup(); + #endif +} + +bool gdb_active() +{ + return tmpsock != -1 || sock != -1; +} + +void gdb_thread() +{ + while(sock != -1) + { + gdb_handle_events(); + } +} + +void gdb_handle_events() +{ + if (sock == -1) + return; + + while (sock != -1 && gdb_data_available()) { + gdb_read_command(); + gdb_parse_command(); + } +} + +int gdb_signal(u32 s) +{ + if (sock == -1) + return 1; + + sig = s; + + if (send_signal) { + gdb_handle_signal(); + send_signal = 0; + } + + return 0; +} + +int gdb_bp_x(u32 addr) +{ + if (sock == -1) + return 0; + + 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/Src/PowerPC/GDBStub.h b/Source/Core/Core/Src/PowerPC/GDBStub.h new file mode 100644 index 0000000000..4fcaa76298 --- /dev/null +++ b/Source/Core/Core/Src/PowerPC/GDBStub.h @@ -0,0 +1,61 @@ +// Copyright (C) 2010 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Originally written by Sven Peter for anergistic. + +#ifndef GDB_H__ +#define GDB_H__ + +#include +#include "Common.h" +#include "Thread.h" +#include "PowerPC.h" +#include "../HW/CPU.h" +#include "../HW/Memmap.h" + +#ifdef _WIN32 +#define SIGTRAP 5 +#define SIGTERM 15 +#define MSG_WAITALL 8 +#endif + +typedef enum { + GDB_BP_TYPE_NONE = 0, + GDB_BP_TYPE_X, + GDB_BP_TYPE_R, + GDB_BP_TYPE_W, + GDB_BP_TYPE_A +} gdb_bp_type; + +void gdb_init(u32 port); +void gdb_deinit(); +bool gdb_active(); + +void gdb_thread(); +void gdb_handle_events(); +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); + +static Common::Event m_GdbWaitEvent; + +#endif diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp index a8277d868a..f7604a4f12 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp @@ -27,6 +27,10 @@ #include "../../IPC_HLE/WII_IPC_HLE.h" #include "Atomic.h" +#ifdef USE_GDBSTUB +#include "../GDBStub.h" +#endif + namespace { u32 last_pc; @@ -99,7 +103,18 @@ void Trace( UGeckoInstruction &instCode ) int Interpreter::SingleStepInner(void) { static UGeckoInstruction instCode; - + + #ifdef USE_GDBSTUB + if (gdb_active() && gdb_bp_x(PC)) { + + Host_UpdateDisasmDialog(); + + gdb_signal(SIGTRAP); + gdb_handle_events(); + m_GdbWaitEvent.Wait(); + } + #endif + NPC = PC + sizeof(UGeckoInstruction); instCode.hex = Memory::Read_Opcode(PC); @@ -218,7 +233,8 @@ void Interpreter::Run() if (PCVec.size() > ShowSteps) PCVec.erase(PCVec.begin()); #endif - + + //2: check for breakpoint if (PowerPC::breakpoints.IsAddressBreakPoint(PC)) { From 9f13e69be46b07c64bedb9b225f06fb8f738bb7e Mon Sep 17 00:00:00 2001 From: Matthew Parlane Date: Tue, 8 Jan 2013 20:26:07 +1300 Subject: [PATCH 2/4] GDB Stub now works with ida and gdb. Implemented stepping correctly. TODO: Peek incoming data to socket for an interrupt. Memory breakpoints. Fix bug with initial step from entry point. Tidy up code. Wishlist: Implement some common query packets. Jit support. --- Source/Core/Core/Src/Core.cpp | 42 ++-- Source/Core/Core/Src/HW/CPU.cpp | 8 +- Source/Core/Core/Src/PowerPC/GDBStub.cpp | 216 +++++++++--------- Source/Core/Core/Src/PowerPC/GDBStub.h | 5 +- .../Src/PowerPC/Interpreter/Interpreter.cpp | 3 +- 5 files changed, 126 insertions(+), 148 deletions(-) diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 0fa1d44134..f864b35328 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -104,9 +104,6 @@ std::string g_stateFileName; std::thread g_EmuThread; static std::thread g_cpu_thread; -#ifdef USE_GDBSTUB -static std::thread g_gdb_thread; -#endif static bool g_requestRefreshInfo = false; static int g_pauseAndLockDepth = 0; @@ -328,6 +325,15 @@ void CpuThread() g_bStarted = true; + + #ifdef USE_GDBSTUB + if(_CoreParameter.iGDBPort > 0) + { + gdb_init(_CoreParameter.iGDBPort); + gdb_handle_exception(); + } + #endif + // Enter CPU run loop. When we leave it - we are done. CCPU::Run(); @@ -453,20 +459,6 @@ void EmuThread() cpuThreadFunc = FifoPlayerThread; else cpuThreadFunc = CpuThread; - - #ifdef USE_GDBSTUB - if(_CoreParameter.iGDBPort > 0) - { - INFO_LOG(GDB_STUB, "Trying to start the GDB Stub listening on port %d.", _CoreParameter.iGDBPort); - Core::SetState(Core::CORE_PAUSE); - gdb_init(_CoreParameter.iGDBPort); - - g_gdb_thread = std::thread(gdb_thread); - - //gdb_signal(SIGTRAP); - gdb_add_bp(GDB_BP_TYPE_X, 0x80004050, 4); - } - #endif // ENTER THE VIDEO THREAD LOOP if (_CoreParameter.bCPUThread) @@ -507,19 +499,17 @@ void EmuThread() // Wait for g_cpu_thread to exit INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str()); - + + #ifdef USE_GDBSTUB + INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping GDB ...").c_str()); + gdb_deinit(); + INFO_LOG(CONSOLE, "%s", StopMessage(true, "GDB stopped.").c_str()); + #endif + g_cpu_thread.join(); INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str()); - #ifdef USE_GDBSTUB - // Wait for g_gdb_thread to exit - INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping GDB thread ...").c_str()); - gdb_deinit(); - g_gdb_thread.join(); - INFO_LOG(CONSOLE, "%s", StopMessage(true, "GDB thread stopped.").c_str()); - #endif - VolumeHandler::EjectVolume(); FileMon::Close(); diff --git a/Source/Core/Core/Src/HW/CPU.cpp b/Source/Core/Core/Src/HW/CPU.cpp index a7a272e263..fd9a1603b8 100644 --- a/Source/Core/Core/Src/HW/CPU.cpp +++ b/Source/Core/Core/Src/HW/CPU.cpp @@ -31,7 +31,7 @@ namespace { static Common::Event m_StepEvent; - static Common::Event *m_SyncEvent; + static Common::Event *m_SyncEvent = NULL; static std::mutex m_csCpuOccupied; } @@ -42,13 +42,13 @@ void CCPU::Init(int cpu_core) cpu_core = Movie::GetCPUMode(); } PowerPC::Init(cpu_core); - m_SyncEvent = 0; + m_SyncEvent = NULL; } void CCPU::Shutdown() { PowerPC::Shutdown(); - m_SyncEvent = 0; + m_SyncEvent = NULL; } void CCPU::Run() @@ -84,7 +84,7 @@ reswitch: //4: update disasm dialog if (m_SyncEvent) { m_SyncEvent->Set(); - m_SyncEvent = 0; + m_SyncEvent = NULL; } Host_UpdateDisasmDialog(); break; diff --git a/Source/Core/Core/Src/PowerPC/GDBStub.cpp b/Source/Core/Core/Src/PowerPC/GDBStub.cpp index 1ba5433638..745287e575 100644 --- a/Source/Core/Core/Src/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/Src/PowerPC/GDBStub.cpp @@ -34,6 +34,7 @@ #endif #include +#include "Host.h" #define GDB_BFR_MAX 10000 #define GDB_MAX_BP 10 @@ -53,6 +54,7 @@ static u32 cmd_len; static u32 sig = 0; static u32 send_signal = 0; +static u32 step_break = 0; typedef struct { u32 active; @@ -102,8 +104,8 @@ static void mem2hex(u8 *dst, u8 *src, u32 len) static void hex2mem(u8 *dst, u8 *src, u32 len) { while (len-- > 0) { - *dst = hex2char(*src++) << 4; - *dst++ |= hex2char(*src++); + *dst++ = (hex2char(*src) << 4) | hex2char(*(src+1)); + src += 2; } } @@ -266,7 +268,11 @@ static void gdb_read_command() while ((c = gdb_read_byte()) != GDB_STUB_END) { cmd_bfr[cmd_len++] = c; if (cmd_len == sizeof cmd_bfr) + { ERROR_LOG(GDB_STUB, "gdb: cmd_bfr overflow\n"); + gdb_nak(); + return; + } } chk_read = hex2char(gdb_read_byte()) << 4; @@ -279,9 +285,11 @@ static void gdb_read_command() cmd_len = 0; gdb_nak(); + return; } DEBUG_LOG(GDB_STUB, "gdb: read command %c with a length of %d: %s\n", cmd_bfr[0], cmd_len, cmd_bfr); + gdb_ack(); } static int gdb_data_available() { @@ -312,6 +320,9 @@ static void gdb_reply(const char *reply) u8 *ptr; int n; + if(!gdb_active()) + return; + memset(cmd_bfr, 0, sizeof cmd_bfr); cmd_len = strlen(reply); @@ -335,7 +346,10 @@ static void gdb_reply(const char *reply) while (left > 0) { n = send(sock, ptr, left, 0); if (n < 0) + { ERROR_LOG(GDB_STUB, "gdb: send failed"); + return gdb_deinit(); + } left -= n; ptr += n; } @@ -343,7 +357,6 @@ static void gdb_reply(const char *reply) static void gdb_handle_query() { - gdb_ack(); DEBUG_LOG(GDB_STUB, "gdb: query '%s'\n", cmd_bfr+1); if (!strcmp((const char *)(cmd_bfr+1), "TStatus")) @@ -356,10 +369,10 @@ static void gdb_handle_query() static void gdb_handle_set_thread() { - gdb_ack(); if (memcmp(cmd_bfr, "Hg0", 3) == 0 || memcmp(cmd_bfr, "Hc-1", 4) == 0 || - memcmp(cmd_bfr, "Hc0", 4) == 0) + memcmp(cmd_bfr, "Hc0", 4) == 0 || + memcmp(cmd_bfr, "Hc1", 4) == 0) return gdb_reply("OK"); gdb_reply("E01"); } @@ -367,8 +380,6 @@ static void gdb_handle_set_thread() static void gdb_handle_signal() { char bfr[128]; - - gdb_ack(); memset(bfr, 0, sizeof bfr); sprintf(bfr, "T%02x%02x:%08x;%02x:%08x;", sig, 64, PC, 1, GPR(1)); gdb_reply(bfr); @@ -397,7 +408,6 @@ static void gdb_read_register() id = hex2char(cmd_bfr[1]) << 4; id |= hex2char(cmd_bfr[2]); - gdb_ack(); switch (id) { case 0 ... 31: wbe32hex(reply, GPR(id)); @@ -443,16 +453,15 @@ static void gdb_read_registers() u8 * bufptr = bfr; u32 i; - gdb_ack(); memset(bfr, 0, sizeof bfr); for (i = 0; i < 32; i++) { - wbe32hex(bufptr + i*4, GPR(i)); + wbe32hex(bufptr + i*8, GPR(i)); } bufptr += 32 * 4; for (i = 0; i < 32; i++) { - wbe64hex(bufptr + i*4, riPS0(i)); + wbe64hex(bufptr + i*16, riPS0(i)); } bufptr += 64 * 4; @@ -496,8 +505,6 @@ static u64 re64hex(u8 *p) static void gdb_write_registers() { - gdb_ack(); - u32 i; u8 * bufptr = cmd_bfr; @@ -530,8 +537,6 @@ static void gdb_write_register() { u32 id; - gdb_ack(); - id = hex2char(cmd_bfr[1]) << 4; id |= hex2char(cmd_bfr[2]); @@ -584,8 +589,6 @@ static void gdb_read_mem() u32 addr, len; u32 i; - gdb_ack(); - i = 1; addr = 0; while (cmd_bfr[i] != ',') @@ -599,8 +602,10 @@ static void gdb_read_mem() if (len*2 > sizeof reply) gdb_reply("E01"); - - mem2hex(reply, Memory::GetPointer(addr), len); + u8 * data = Memory::GetPointer(addr); + if (!data) + return gdb_reply("E0"); + mem2hex(reply, data, len); reply[len*2] = '\0'; gdb_reply((char *)reply); } @@ -610,8 +615,6 @@ static void gdb_write_mem() u32 addr, len; u32 i; - gdb_ack(); - i = 1; addr = 0; while (cmd_bfr[i] != ',') @@ -623,15 +626,21 @@ static void gdb_write_mem() len = (len << 4) | hex2char(cmd_bfr[i++]); DEBUG_LOG(GDB_STUB, "gdb: write memory: %08x bytes to %08x\n", len, addr); - hex2mem(Memory::GetPointer(addr), cmd_bfr + i, len); + u8 * dst = Memory::GetPointer(addr); + if (!dst) + return gdb_reply("E00"); + hex2mem(dst, cmd_bfr + i + 1, len); gdb_reply("OK"); } +static void gdb_step() +{ + step_break = 1; + send_signal = 1; +} + static void gdb_continue() { - gdb_ack(); - CCPU::EnableStepping(false); - m_GdbWaitEvent.Set(); send_signal = 1; } @@ -656,8 +665,6 @@ static void _gdb_add_bp() u32 type; u32 i, addr = 0, len = 0; - gdb_ack(); - type = hex2char(cmd_bfr[1]); switch (type) { case 0: @@ -694,8 +701,6 @@ static void gdb_remove_bp() { u32 type, addr, len, i; - gdb_ack(); - type = hex2char(cmd_bfr[1]); switch (type) { case 0: @@ -730,63 +735,66 @@ static void gdb_remove_bp() gdb_reply("OK"); } -static void gdb_parse_command() +void gdb_handle_exception() { - if (cmd_len == 0) - return; - - switch(cmd_bfr[0]) { - case 'q': - gdb_handle_query(); - break; - case 'H': - gdb_handle_set_thread(); - break; - case '?': - gdb_handle_signal(); - break; - case 'k': - gdb_ack(); - gdb_deinit(); - INFO_LOG(GDB_STUB, "killed by gdb"); - break; - case 'g': - gdb_read_registers(); - break; - case 'G': - gdb_write_registers(); - break; - case 'p': - gdb_read_register(); - break; - case 'P': - gdb_write_register(); - break; - case 'm': - gdb_read_mem(); - break; - case 'M': - gdb_write_mem(); - break; - case 's': - case 'C': - case 'c': - gdb_continue(); - break; - case 'v': - gdb_ack(); - gdb_reply(""); - break; - case 'z': - gdb_remove_bp(); - break; - case 'Z': - _gdb_add_bp(); - break; - default: - gdb_ack(); - gdb_reply(""); - break; + while (gdb_active()) { + if(!gdb_data_available()) + continue; + gdb_read_command(); + if (cmd_len == 0) + continue; + + switch(cmd_bfr[0]) { + case 'q': + gdb_handle_query(); + break; + case 'H': + gdb_handle_set_thread(); + break; + case '?': + gdb_handle_signal(); + break; + case 'k': + gdb_deinit(); + INFO_LOG(GDB_STUB, "killed by gdb"); + return; + case 'g': + gdb_read_registers(); + break; + case 'G': + gdb_write_registers(); + break; + case 'p': + gdb_read_register(); + break; + case 'P': + gdb_write_register(); + break; + case 'm': + gdb_read_mem(); + break; + case 'M': + gdb_write_mem(); + PowerPC::ppcState.iCache.Reset(); + Host_UpdateDisasmDialog(); + break; + case 's': + gdb_step(); + return; + case 'C': + case 'c': + gdb_continue(); + return; + case 'z': + gdb_remove_bp(); + break; + case 'Z': + _gdb_add_bp(); + break; + default: + gdb_reply(""); + break; + } } } @@ -804,8 +812,6 @@ void gdb_init(u32 port) WSAStartup(MAKEWORD(2,2), &InitData); #endif - m_GdbWaitEvent.Reset(); - memset(bp_x, 0, sizeof bp_x); memset(bp_r, 0, sizeof bp_r); memset(bp_w, 0, sizeof bp_w); @@ -831,8 +837,8 @@ void gdb_init(u32 port) ERROR_LOG(GDB_STUB, "Failed to listen to gdb socket"); INFO_LOG(GDB_STUB, "Waiting for gdb to connect...\n"); - sock = accept(tmpsock, (struct sockaddr *)&saddr_client, &len); + sock = accept(tmpsock, (struct sockaddr *)&saddr_client, &len); if (sock < 0) ERROR_LOG(GDB_STUB, "Failed to accept gdb client"); INFO_LOG(GDB_STUB, "Client connected.\n"); @@ -853,18 +859,15 @@ void gdb_deinit() { if (tmpsock != -1) { - close(tmpsock); + shutdown(tmpsock, SHUT_RDWR); tmpsock = -1; } if (sock != -1) { - close(sock); + shutdown(sock, SHUT_RDWR); sock = -1; } - m_GdbWaitEvent.Set(); - m_GdbWaitEvent.Reset(); - #ifdef _WIN32 WSACleanup(); #endif @@ -875,25 +878,6 @@ bool gdb_active() return tmpsock != -1 || sock != -1; } -void gdb_thread() -{ - while(sock != -1) - { - gdb_handle_events(); - } -} - -void gdb_handle_events() -{ - if (sock == -1) - return; - - while (sock != -1 && gdb_data_available()) { - gdb_read_command(); - gdb_parse_command(); - } -} - int gdb_signal(u32 s) { if (sock == -1) @@ -914,6 +898,14 @@ int gdb_bp_x(u32 addr) if (sock == -1) return 0; + if (step_break) + { + step_break = 0; + + DEBUG_LOG(GDB_STUB, "Step was successful."); + return 1; + } + return gdb_bp_check(addr, GDB_BP_TYPE_X); } diff --git a/Source/Core/Core/Src/PowerPC/GDBStub.h b/Source/Core/Core/Src/PowerPC/GDBStub.h index 4fcaa76298..cf01d22c8b 100644 --- a/Source/Core/Core/Src/PowerPC/GDBStub.h +++ b/Source/Core/Core/Src/PowerPC/GDBStub.h @@ -45,8 +45,7 @@ void gdb_init(u32 port); void gdb_deinit(); bool gdb_active(); -void gdb_thread(); -void gdb_handle_events(); +void gdb_handle_exception(); int gdb_signal(u32 signal); int gdb_bp_x(u32 addr); @@ -56,6 +55,4 @@ int gdb_bp_a(u32 addr); bool gdb_add_bp(u32 type, u32 addr, u32 len); -static Common::Event m_GdbWaitEvent; - #endif diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp index f7604a4f12..094c12b38c 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp @@ -110,8 +110,7 @@ int Interpreter::SingleStepInner(void) Host_UpdateDisasmDialog(); gdb_signal(SIGTRAP); - gdb_handle_events(); - m_GdbWaitEvent.Wait(); + gdb_handle_exception(); } #endif From 1211a67191e2539702d25c5581611678e99ad08c Mon Sep 17 00:00:00 2001 From: Matthew Parlane Date: Tue, 8 Jan 2013 20:32:10 +1300 Subject: [PATCH 3/4] Missed an ifdef. --- Source/Core/Core/Src/ConfigManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index 183b35c968..c7d89afb5e 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -157,7 +157,9 @@ void SConfig::SaveSettings() ini.Set("General", "RecursiveGCMPaths", m_RecursiveISOFolder); ini.Set("General", "NANDRoot", m_NANDPath); ini.Set("General", "WirelessMac", m_WirelessMac); + #ifdef USE_GDBSTUB ini.Set("General", "GDBPort", m_LocalCoreStartupParameter.iGDBPort); + #endif // Interface ini.Set("Interface", "ConfirmStop", m_LocalCoreStartupParameter.bConfirmStop); From 936b047b124ffd59644c63ef69c427edc2703918 Mon Sep 17 00:00:00 2001 From: Matthew Parlane Date: Tue, 8 Jan 2013 20:56:26 +1300 Subject: [PATCH 4/4] Fixed bug on entry that caused first step to trigger two stops at start. --- Source/Core/Core/Src/Core.cpp | 3 ++- Source/Core/Core/Src/PowerPC/GDBStub.cpp | 9 +++++++-- Source/Core/Core/Src/PowerPC/GDBStub.h | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index f864b35328..34db612513 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -330,7 +330,8 @@ void CpuThread() if(_CoreParameter.iGDBPort > 0) { gdb_init(_CoreParameter.iGDBPort); - gdb_handle_exception(); + // break at next instruction (the first instruction) + gdb_break(); } #endif diff --git a/Source/Core/Core/Src/PowerPC/GDBStub.cpp b/Source/Core/Core/Src/PowerPC/GDBStub.cpp index 745287e575..d7dfc46a56 100644 --- a/Source/Core/Core/Src/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/Src/PowerPC/GDBStub.cpp @@ -633,18 +633,23 @@ static void gdb_write_mem() gdb_reply("OK"); } -static void gdb_step() +// forces a break on next instruction check +void gdb_break() { step_break = 1; send_signal = 1; } +static void gdb_step() +{ + gdb_break(); +} + static void gdb_continue() { send_signal = 1; } - bool gdb_add_bp(u32 type, u32 addr, u32 len) { gdb_bp_t *bp; diff --git a/Source/Core/Core/Src/PowerPC/GDBStub.h b/Source/Core/Core/Src/PowerPC/GDBStub.h index cf01d22c8b..300f74bf91 100644 --- a/Source/Core/Core/Src/PowerPC/GDBStub.h +++ b/Source/Core/Core/Src/PowerPC/GDBStub.h @@ -44,6 +44,7 @@ typedef enum { void gdb_init(u32 port); void gdb_deinit(); bool gdb_active(); +void gdb_break(); void gdb_handle_exception(); int gdb_signal(u32 signal);