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.
This commit is contained in:
Matthew Parlane 2013-01-08 20:26:07 +13:00
parent b7fd1225ba
commit 9f13e69be4
5 changed files with 126 additions and 148 deletions

View File

@ -104,9 +104,6 @@ std::string g_stateFileName;
std::thread g_EmuThread; std::thread g_EmuThread;
static std::thread g_cpu_thread; static std::thread g_cpu_thread;
#ifdef USE_GDBSTUB
static std::thread g_gdb_thread;
#endif
static bool g_requestRefreshInfo = false; static bool g_requestRefreshInfo = false;
static int g_pauseAndLockDepth = 0; static int g_pauseAndLockDepth = 0;
@ -328,6 +325,15 @@ void CpuThread()
g_bStarted = true; 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. // Enter CPU run loop. When we leave it - we are done.
CCPU::Run(); CCPU::Run();
@ -454,20 +460,6 @@ void EmuThread()
else else
cpuThreadFunc = CpuThread; 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 // ENTER THE VIDEO THREAD LOOP
if (_CoreParameter.bCPUThread) if (_CoreParameter.bCPUThread)
{ {
@ -508,18 +500,16 @@ void EmuThread()
// Wait for g_cpu_thread to exit // Wait for g_cpu_thread to exit
INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str()); 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(); g_cpu_thread.join();
INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str()); 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(); VolumeHandler::EjectVolume();
FileMon::Close(); FileMon::Close();

View File

@ -31,7 +31,7 @@
namespace namespace
{ {
static Common::Event m_StepEvent; static Common::Event m_StepEvent;
static Common::Event *m_SyncEvent; static Common::Event *m_SyncEvent = NULL;
static std::mutex m_csCpuOccupied; static std::mutex m_csCpuOccupied;
} }
@ -42,13 +42,13 @@ void CCPU::Init(int cpu_core)
cpu_core = Movie::GetCPUMode(); cpu_core = Movie::GetCPUMode();
} }
PowerPC::Init(cpu_core); PowerPC::Init(cpu_core);
m_SyncEvent = 0; m_SyncEvent = NULL;
} }
void CCPU::Shutdown() void CCPU::Shutdown()
{ {
PowerPC::Shutdown(); PowerPC::Shutdown();
m_SyncEvent = 0; m_SyncEvent = NULL;
} }
void CCPU::Run() void CCPU::Run()
@ -84,7 +84,7 @@ reswitch:
//4: update disasm dialog //4: update disasm dialog
if (m_SyncEvent) { if (m_SyncEvent) {
m_SyncEvent->Set(); m_SyncEvent->Set();
m_SyncEvent = 0; m_SyncEvent = NULL;
} }
Host_UpdateDisasmDialog(); Host_UpdateDisasmDialog();
break; break;

View File

@ -34,6 +34,7 @@
#endif #endif
#include <stdarg.h> #include <stdarg.h>
#include "Host.h"
#define GDB_BFR_MAX 10000 #define GDB_BFR_MAX 10000
#define GDB_MAX_BP 10 #define GDB_MAX_BP 10
@ -53,6 +54,7 @@ static u32 cmd_len;
static u32 sig = 0; static u32 sig = 0;
static u32 send_signal = 0; static u32 send_signal = 0;
static u32 step_break = 0;
typedef struct { typedef struct {
u32 active; u32 active;
@ -102,8 +104,8 @@ static void mem2hex(u8 *dst, u8 *src, u32 len)
static void hex2mem(u8 *dst, u8 *src, u32 len) static void hex2mem(u8 *dst, u8 *src, u32 len)
{ {
while (len-- > 0) { while (len-- > 0) {
*dst = hex2char(*src++) << 4; *dst++ = (hex2char(*src) << 4) | hex2char(*(src+1));
*dst++ |= hex2char(*src++); src += 2;
} }
} }
@ -266,7 +268,11 @@ static void gdb_read_command()
while ((c = gdb_read_byte()) != GDB_STUB_END) { while ((c = gdb_read_byte()) != GDB_STUB_END) {
cmd_bfr[cmd_len++] = c; cmd_bfr[cmd_len++] = c;
if (cmd_len == sizeof cmd_bfr) if (cmd_len == sizeof cmd_bfr)
{
ERROR_LOG(GDB_STUB, "gdb: cmd_bfr overflow\n"); ERROR_LOG(GDB_STUB, "gdb: cmd_bfr overflow\n");
gdb_nak();
return;
}
} }
chk_read = hex2char(gdb_read_byte()) << 4; chk_read = hex2char(gdb_read_byte()) << 4;
@ -279,9 +285,11 @@ static void gdb_read_command()
cmd_len = 0; cmd_len = 0;
gdb_nak(); 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); 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() { static int gdb_data_available() {
@ -312,6 +320,9 @@ static void gdb_reply(const char *reply)
u8 *ptr; u8 *ptr;
int n; int n;
if(!gdb_active())
return;
memset(cmd_bfr, 0, sizeof cmd_bfr); memset(cmd_bfr, 0, sizeof cmd_bfr);
cmd_len = strlen(reply); cmd_len = strlen(reply);
@ -335,7 +346,10 @@ static void gdb_reply(const char *reply)
while (left > 0) { while (left > 0) {
n = send(sock, ptr, left, 0); n = send(sock, ptr, left, 0);
if (n < 0) if (n < 0)
{
ERROR_LOG(GDB_STUB, "gdb: send failed"); ERROR_LOG(GDB_STUB, "gdb: send failed");
return gdb_deinit();
}
left -= n; left -= n;
ptr += n; ptr += n;
} }
@ -343,7 +357,6 @@ static void gdb_reply(const char *reply)
static void gdb_handle_query() static void gdb_handle_query()
{ {
gdb_ack();
DEBUG_LOG(GDB_STUB, "gdb: query '%s'\n", cmd_bfr+1); DEBUG_LOG(GDB_STUB, "gdb: query '%s'\n", cmd_bfr+1);
if (!strcmp((const char *)(cmd_bfr+1), "TStatus")) if (!strcmp((const char *)(cmd_bfr+1), "TStatus"))
@ -356,10 +369,10 @@ static void gdb_handle_query()
static void gdb_handle_set_thread() static void gdb_handle_set_thread()
{ {
gdb_ack();
if (memcmp(cmd_bfr, "Hg0", 3) == 0 || if (memcmp(cmd_bfr, "Hg0", 3) == 0 ||
memcmp(cmd_bfr, "Hc-1", 4) == 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"); return gdb_reply("OK");
gdb_reply("E01"); gdb_reply("E01");
} }
@ -367,8 +380,6 @@ static void gdb_handle_set_thread()
static void gdb_handle_signal() static void gdb_handle_signal()
{ {
char bfr[128]; char bfr[128];
gdb_ack();
memset(bfr, 0, sizeof bfr); memset(bfr, 0, sizeof bfr);
sprintf(bfr, "T%02x%02x:%08x;%02x:%08x;", sig, 64, PC, 1, GPR(1)); sprintf(bfr, "T%02x%02x:%08x;%02x:%08x;", sig, 64, PC, 1, GPR(1));
gdb_reply(bfr); gdb_reply(bfr);
@ -397,7 +408,6 @@ static void gdb_read_register()
id = hex2char(cmd_bfr[1]) << 4; id = hex2char(cmd_bfr[1]) << 4;
id |= hex2char(cmd_bfr[2]); id |= hex2char(cmd_bfr[2]);
gdb_ack();
switch (id) { switch (id) {
case 0 ... 31: case 0 ... 31:
wbe32hex(reply, GPR(id)); wbe32hex(reply, GPR(id));
@ -443,16 +453,15 @@ static void gdb_read_registers()
u8 * bufptr = bfr; u8 * bufptr = bfr;
u32 i; u32 i;
gdb_ack();
memset(bfr, 0, sizeof bfr); memset(bfr, 0, sizeof bfr);
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
wbe32hex(bufptr + i*4, GPR(i)); wbe32hex(bufptr + i*8, GPR(i));
} }
bufptr += 32 * 4; bufptr += 32 * 4;
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
wbe64hex(bufptr + i*4, riPS0(i)); wbe64hex(bufptr + i*16, riPS0(i));
} }
bufptr += 64 * 4; bufptr += 64 * 4;
@ -496,8 +505,6 @@ static u64 re64hex(u8 *p)
static void gdb_write_registers() static void gdb_write_registers()
{ {
gdb_ack();
u32 i; u32 i;
u8 * bufptr = cmd_bfr; u8 * bufptr = cmd_bfr;
@ -530,8 +537,6 @@ static void gdb_write_register()
{ {
u32 id; u32 id;
gdb_ack();
id = hex2char(cmd_bfr[1]) << 4; id = hex2char(cmd_bfr[1]) << 4;
id |= hex2char(cmd_bfr[2]); id |= hex2char(cmd_bfr[2]);
@ -584,8 +589,6 @@ static void gdb_read_mem()
u32 addr, len; u32 addr, len;
u32 i; u32 i;
gdb_ack();
i = 1; i = 1;
addr = 0; addr = 0;
while (cmd_bfr[i] != ',') while (cmd_bfr[i] != ',')
@ -599,8 +602,10 @@ static void gdb_read_mem()
if (len*2 > sizeof reply) if (len*2 > sizeof reply)
gdb_reply("E01"); gdb_reply("E01");
u8 * data = Memory::GetPointer(addr);
mem2hex(reply, Memory::GetPointer(addr), len); if (!data)
return gdb_reply("E0");
mem2hex(reply, data, len);
reply[len*2] = '\0'; reply[len*2] = '\0';
gdb_reply((char *)reply); gdb_reply((char *)reply);
} }
@ -610,8 +615,6 @@ static void gdb_write_mem()
u32 addr, len; u32 addr, len;
u32 i; u32 i;
gdb_ack();
i = 1; i = 1;
addr = 0; addr = 0;
while (cmd_bfr[i] != ',') while (cmd_bfr[i] != ',')
@ -623,15 +626,21 @@ static void gdb_write_mem()
len = (len << 4) | hex2char(cmd_bfr[i++]); len = (len << 4) | hex2char(cmd_bfr[i++]);
DEBUG_LOG(GDB_STUB, "gdb: write memory: %08x bytes to %08x\n", len, addr); 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"); gdb_reply("OK");
} }
static void gdb_step()
{
step_break = 1;
send_signal = 1;
}
static void gdb_continue() static void gdb_continue()
{ {
gdb_ack();
CCPU::EnableStepping(false);
m_GdbWaitEvent.Set();
send_signal = 1; send_signal = 1;
} }
@ -656,8 +665,6 @@ static void _gdb_add_bp()
u32 type; u32 type;
u32 i, addr = 0, len = 0; u32 i, addr = 0, len = 0;
gdb_ack();
type = hex2char(cmd_bfr[1]); type = hex2char(cmd_bfr[1]);
switch (type) { switch (type) {
case 0: case 0:
@ -694,8 +701,6 @@ static void gdb_remove_bp()
{ {
u32 type, addr, len, i; u32 type, addr, len, i;
gdb_ack();
type = hex2char(cmd_bfr[1]); type = hex2char(cmd_bfr[1]);
switch (type) { switch (type) {
case 0: case 0:
@ -730,63 +735,66 @@ static void gdb_remove_bp()
gdb_reply("OK"); gdb_reply("OK");
} }
static void gdb_parse_command() void gdb_handle_exception()
{ {
if (cmd_len == 0) while (gdb_active()) {
return; if(!gdb_data_available())
continue;
gdb_read_command();
if (cmd_len == 0)
continue;
switch(cmd_bfr[0]) { switch(cmd_bfr[0]) {
case 'q': case 'q':
gdb_handle_query(); gdb_handle_query();
break; break;
case 'H': case 'H':
gdb_handle_set_thread(); gdb_handle_set_thread();
break; break;
case '?': case '?':
gdb_handle_signal(); gdb_handle_signal();
break; break;
case 'k': case 'k':
gdb_ack(); gdb_deinit();
gdb_deinit(); INFO_LOG(GDB_STUB, "killed by gdb");
INFO_LOG(GDB_STUB, "killed by gdb"); return;
break; case 'g':
case 'g': gdb_read_registers();
gdb_read_registers(); break;
break; case 'G':
case 'G': gdb_write_registers();
gdb_write_registers(); break;
break; case 'p':
case 'p': gdb_read_register();
gdb_read_register(); break;
break; case 'P':
case 'P': gdb_write_register();
gdb_write_register(); break;
break; case 'm':
case 'm': gdb_read_mem();
gdb_read_mem(); break;
break; case 'M':
case 'M': gdb_write_mem();
gdb_write_mem(); PowerPC::ppcState.iCache.Reset();
break; Host_UpdateDisasmDialog();
case 's': break;
case 'C': case 's':
case 'c': gdb_step();
gdb_continue(); return;
break; case 'C':
case 'v': case 'c':
gdb_ack(); gdb_continue();
gdb_reply(""); return;
break; case 'z':
case 'z': gdb_remove_bp();
gdb_remove_bp(); break;
break; case 'Z':
case 'Z': _gdb_add_bp();
_gdb_add_bp(); break;
break; default:
default: gdb_reply("");
gdb_ack(); break;
gdb_reply(""); }
break;
} }
} }
@ -804,8 +812,6 @@ void gdb_init(u32 port)
WSAStartup(MAKEWORD(2,2), &InitData); WSAStartup(MAKEWORD(2,2), &InitData);
#endif #endif
m_GdbWaitEvent.Reset();
memset(bp_x, 0, sizeof bp_x); memset(bp_x, 0, sizeof bp_x);
memset(bp_r, 0, sizeof bp_r); memset(bp_r, 0, sizeof bp_r);
memset(bp_w, 0, sizeof bp_w); 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"); ERROR_LOG(GDB_STUB, "Failed to listen to gdb socket");
INFO_LOG(GDB_STUB, "Waiting for gdb to connect...\n"); 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) if (sock < 0)
ERROR_LOG(GDB_STUB, "Failed to accept gdb client"); ERROR_LOG(GDB_STUB, "Failed to accept gdb client");
INFO_LOG(GDB_STUB, "Client connected.\n"); INFO_LOG(GDB_STUB, "Client connected.\n");
@ -853,18 +859,15 @@ void gdb_deinit()
{ {
if (tmpsock != -1) if (tmpsock != -1)
{ {
close(tmpsock); shutdown(tmpsock, SHUT_RDWR);
tmpsock = -1; tmpsock = -1;
} }
if (sock != -1) if (sock != -1)
{ {
close(sock); shutdown(sock, SHUT_RDWR);
sock = -1; sock = -1;
} }
m_GdbWaitEvent.Set();
m_GdbWaitEvent.Reset();
#ifdef _WIN32 #ifdef _WIN32
WSACleanup(); WSACleanup();
#endif #endif
@ -875,25 +878,6 @@ bool gdb_active()
return tmpsock != -1 || sock != -1; 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) int gdb_signal(u32 s)
{ {
if (sock == -1) if (sock == -1)
@ -914,6 +898,14 @@ int gdb_bp_x(u32 addr)
if (sock == -1) if (sock == -1)
return 0; 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); return gdb_bp_check(addr, GDB_BP_TYPE_X);
} }

View File

@ -45,8 +45,7 @@ void gdb_init(u32 port);
void gdb_deinit(); void gdb_deinit();
bool gdb_active(); bool gdb_active();
void gdb_thread(); void gdb_handle_exception();
void gdb_handle_events();
int gdb_signal(u32 signal); int gdb_signal(u32 signal);
int gdb_bp_x(u32 addr); 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); bool gdb_add_bp(u32 type, u32 addr, u32 len);
static Common::Event m_GdbWaitEvent;
#endif #endif

View File

@ -110,8 +110,7 @@ int Interpreter::SingleStepInner(void)
Host_UpdateDisasmDialog(); Host_UpdateDisasmDialog();
gdb_signal(SIGTRAP); gdb_signal(SIGTRAP);
gdb_handle_events(); gdb_handle_exception();
m_GdbWaitEvent.Wait();
} }
#endif #endif