summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2020-05-29 00:05:08 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2020-06-04 23:14:52 +0200
commitcb2d7f800a9fc276b96fd0927fa6d8ec9f5a31c8 (patch)
tree3fcd11e34885c4dddc459c875c94e3b958d7750a
parent850010a96b6cbc3eae03edd891e50325e017b678 (diff)
Implemented port-specific wrappers and logic for gdb stub
m---------gdbstub/gdbstub0
-rw-r--r--gdbstub/gdbstub_sys.c274
-rw-r--r--gdbstub/gdbstub_sys.h30
-rw-r--r--gui/LnxMain.c7
-rw-r--r--libpcsxcore/debug.c4
-rw-r--r--libpcsxcore/psxinterpreter.c64
-rw-r--r--libpcsxcore/socket.c3
-rw-r--r--libpcsxcore/socket.h2
-rw-r--r--win32/gui/WndMain.c7
9 files changed, 362 insertions, 29 deletions
diff --git a/gdbstub/gdbstub b/gdbstub/gdbstub
-Subproject b00d0f815b3996a13ce87a4d9d6d7038353e77e
+Subproject 8ce6abf8d32291ad66a3724123a9a583b9a3bb4
diff --git a/gdbstub/gdbstub_sys.c b/gdbstub/gdbstub_sys.c
index bfba9bf7..7773de67 100644
--- a/gdbstub/gdbstub_sys.c
+++ b/gdbstub/gdbstub_sys.c
@@ -3,8 +3,24 @@
#include "libpcsxcore/socket.h"
#include "libpcsxcore/r3000a.h"
#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#ifdef _POSIX_VERSION
+#include <pthread.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <mqueue.h>
+#include <errno.h>
+
+static pthread_t thread;
+static mqd_t in_queue, out_queue;
+#endif
static int server_socket, client_socket;
+static enum {
+ PAUSED,
+} state;
static void update_regs(struct dbg_state *const dbg_state)
{
@@ -56,13 +72,6 @@ static void update_regs(struct dbg_state *const dbg_state)
dbg_state->registers[DBG_CPU_MIPS_I_REG_PC] = psxRegs.pc;
}
-void dbg_sys_process(void)
-{
- static struct dbg_state dbg_state;
- update_regs(&dbg_state);
- dbg_main(&dbg_state);
-}
-
int dbg_sys_getc(void)
{
while (1) {
@@ -74,15 +83,22 @@ int dbg_sys_getc(void)
case READ_SOCKET_OK:
return packet;
- case READ_SOCKET_SHUTDOWN:
+ case READ_SOCKET_SHUTDOWN: {
+ struct msg msg;
+
+ printf("gdb shutdown\n");
client_socket = 0;
+ msg.type = MSG_TYPE_SHUTDOWN;
+
+ if (mq_send(out_queue, (const char *)&msg, sizeof msg, 0))
+ perror("dbg_sys_getc() mq_send()");
return EOF;
+ }
case READ_SOCKET_ERR_INVALID_ARG:
/* Fall through. */
case READ_SOCKET_ERR_RECV:
/* Fall through. */
-
default:
break;
}
@@ -106,27 +122,247 @@ int dbg_sys_mem_writeb(address addr, char val)
return 0;
}
+#ifdef _POSIX_VERSION
+static int wait_hit_or_break(struct msg *msg)
+{
+ do {
+ int ret = mq_receive(in_queue, (char *)msg, sizeof *msg, 0);
+
+ if (ret < 0 && errno == EAGAIN) {
+ /* Breakpoint has not been hit yet, look for incoming messages from gdb. */
+ char packet;
+ size_t len = sizeof packet;
+ const enum read_socket_err err = ReadSocket(client_socket, &packet, &len);
+
+ switch (err) {
+ case READ_SOCKET_OK:
+ if (len && packet == 0x03)
+ return 0;
+
+ break;
+
+ case READ_SOCKET_SHUTDOWN:
+ printf("gdb shutdown\n");
+ client_socket = 0;
+ msg->type = MSG_TYPE_SHUTDOWN;
+
+ if (mq_send(out_queue, (const char *)msg, sizeof *msg, 0))
+ perror("wait_hit_or_break() mq_send()");
+
+ return EOF;
+
+ case READ_SOCKET_ERR_INVALID_ARG:
+ /* Fall through. */
+ case READ_SOCKET_ERR_RECV:
+ /* Fall through. */
+ default:
+ break;
+ }
+ }
+ else if (msg->type != MSG_TYPE_HIT) {
+ fprintf(stderr, "unexpected msg.type %d\n", msg->type);
+ return 1;
+ }
+ else
+ return 0;
+ } while (1);
+
+ return 1;
+}
+#endif
+
+#ifdef _POSIX_VERSION
int dbg_sys_continue(void)
{
- return 0;
+ struct msg msg;
+
+ msg.type = MSG_TYPE_CONTINUE;
+
+ if (mq_send(out_queue, (const char *)&msg, sizeof msg, 0)) {
+ perror("dbg_sys_continue(): mq_send()");
+ return 1;
+ }
+
+ return wait_hit_or_break(&msg);
}
+#endif
+#ifdef _POSIX_VERSION
int dbg_sys_step(void)
{
+ struct msg msg;
+
+ msg.type = MSG_TYPE_STEP;
+
+ if (mq_send(out_queue, (const char *)&msg, sizeof msg, 0)) {
+ perror("dbg_sys_step(): mq_send()");
+ }
+
+ return wait_hit_or_break(&msg);
+}
+#endif
+
+#ifdef _POSIX_VERSION
+static int wait_ack(struct msg *msg)
+{
+ int ret;
+
+ do {
+ ret = mq_receive(in_queue, (char *)msg, sizeof *msg, 0);
+ } while (ret < 0 && errno == EAGAIN);
+
+ if (msg->type != MSG_TYPE_ACK) {
+ fprintf(stderr, "unexpected msg.type %d\n", msg->type);
+ return 1;
+ }
+
return 0;
}
+#endif
-void dbg_start(void)
+#ifdef _POSIX_VERSION
+int dbg_sys_breakpoint(address addr)
+{
+ struct msg msg;
+
+ msg.type = MSG_TYPE_BREAKPOINT;
+ msg.data.breakpoint.addr = addr;
+
+ if (mq_send(out_queue, (const char *)&msg, sizeof msg, 0)) {
+ perror("dbg_sys_breakpoint(): mq_send()");
+ }
+
+ return wait_ack(&msg);
+}
+#endif
+
+#ifdef _POSIX_VERSION
+int dbg_sys_del_breakpoint(address addr)
{
- const unsigned short port = 3333;
+ struct msg msg;
- if (server_socket > 0)
- StopServer(server_socket);
+ msg.type = MSG_TYPE_REMOVE_BREAKPOINT;
- server_socket = StartServer(port);
+ if (mq_send(out_queue, (const char *)&msg, sizeof msg, 0)) {
+ perror("dbg_sys_breakpoint(): mq_send()");
+ }
+
+ return wait_ack(&msg);
+}
+#endif
- if (server_socket > 0)
- printf("GDB server started on port %hu.\n", port);
- else
- fprintf(stderr, "Could not start GDB server\n");
+#ifdef _POSIX_VERSION
+static int queue_create(void)
+{
+ struct mq_attr attr;
+
+ attr.mq_msgsize = sizeof (struct msg);
+ attr.mq_flags = 0;
+ attr.mq_maxmsg = 4;
+
+ mq_unlink("/pcsxrin");
+ in_queue = mq_open("/pcsxrin", O_CREAT | O_RDWR | O_EXCL | O_NONBLOCK, 0600, &attr);
+
+ mq_unlink("/pcsxrout");
+ out_queue = mq_open("/pcsxrout", O_CREAT | O_RDWR | O_EXCL, 0600, &attr);
+
+ if ((out_queue < 0) || (in_queue < 0)) {
+ perror("mq_open()");
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+static int exit_loop;
+
+static void *loop(void *const args)
+{
+ struct dbg_state dbg_state = {0};
+
+ SetsBlock(server_socket);
+
+ if ((client_socket = GetClient(server_socket, 1)) < 0) {
+ fprintf(stderr, "GetClient() failed\n");
+ return NULL;
+ }
+
+ SetsNonblock(client_socket);
+
+ printf("Accepted gdb connection\n");
+
+ while (!exit_loop) {
+ update_regs(&dbg_state);
+ dbg_main(&dbg_state);
+ }
+
+ return NULL;
+}
+
+#ifdef _POSIX_VERSION
+static void start_thread(void)
+{
+ if (pthread_create(&thread, NULL, loop, NULL))
+ perror("could not start gdb server thread");
+}
+#endif
+
+#ifdef _POSIX_VERSION
+static void stop_thread(void)
+{
+ if (pthread_join(thread, NULL))
+ perror("pthread_join()");
+
+ mq_unlink("/pcsxrin");
+ mq_unlink("/pcsxrout");
+}
+#endif
+
+#ifdef _POSIX_VERSION
+void gdbstub_sys_recv(struct msg *msg)
+{
+ const ssize_t sz = mq_receive(out_queue, (char *)msg, sizeof *msg, 0);
+
+ if (sz < 0)
+ perror("mq_receive");
+}
+#endif
+
+#ifdef _POSIX_VERSION
+void gdbstub_sys_send(const struct msg *msg)
+{
+ if (mq_send(in_queue, (const char *)msg, sizeof *msg, 0)) {
+ perror("dbg_sys_send(): mq_send()");
+ }
+}
+#endif
+
+void dbg_stop(void)
+{
+ exit_loop = 1;
+ stop_thread();
+}
+
+void dbg_start(void)
+{
+ if (server_socket > 0) {
+ fprintf(stderr, "gdb server already started\n");
+ return;
+ }
+ else {
+ const unsigned short port = 3333;
+
+ server_socket = StartServer(port);
+
+ if (server_socket > 0) {
+ printf("GDB server started on port %hu.\n", port);
+ if (queue_create())
+ fprintf(stderr, "could not create gdb stub internal queues\n");
+ else
+ start_thread();
+ }
+ else
+ fprintf(stderr, "could not start GDB server\n");
+ }
}
diff --git a/gdbstub/gdbstub_sys.h b/gdbstub/gdbstub_sys.h
index 84bae1fa..f44dfcc9 100644
--- a/gdbstub/gdbstub_sys.h
+++ b/gdbstub/gdbstub_sys.h
@@ -42,7 +42,11 @@ enum DBG_REGISTER {
DBG_CPU_MIPS_I_REG_BAD,
DBG_CPU_MIPS_I_REG_CAUSE,
DBG_CPU_MIPS_I_REG_PC,
- DBG_CPU_NUM_REGISTERS
+
+ /* GDB requests 73, where 38 are the ones above and the rest
+ * are the floating-point registers. This way, unused registers
+ * are left to zero. */
+ DBG_CPU_NUM_REGISTERS = 73
};
typedef unsigned int reg;
@@ -52,7 +56,29 @@ struct dbg_state {
reg registers[DBG_CPU_NUM_REGISTERS];
};
+struct msg {
+ enum {
+ MSG_TYPE_CONTINUE,
+ MSG_TYPE_BREAKPOINT,
+ MSG_TYPE_STEP,
+ MSG_TYPE_ACK,
+ MSG_TYPE_REMOVE_BREAKPOINT,
+ MSG_TYPE_SHUTDOWN,
+
+ /* Response frames. */
+ MSG_TYPE_HIT
+ } type;
+
+ union {
+ struct {
+ address addr;
+ } breakpoint;
+ } data;
+};
+
void dbg_start(void);
-void dbg_sys_process(void);
+void dbg_stop(void);
+void gdbstub_sys_send(const struct msg *msg);
+void gdbstub_sys_recv(struct msg *msg);
#endif /* GDBSTUB_SYS_H */
diff --git a/gui/LnxMain.c b/gui/LnxMain.c
index 12aeb5fc..2e087ee3 100644
--- a/gui/LnxMain.c
+++ b/gui/LnxMain.c
@@ -321,6 +321,11 @@ int main(int argc, char *argv[]) {
SetIsoFile(isofilename);
runcd = RUN_CD;
}
+ else if (!strcmp(argv[i], "-gdb")) {
+ /* Force configuration. */
+ Config.Cpu = CPU_INTERPRETER;
+ Config.GdbServer = 1;
+ }
else if (!strcmp(argv[i], "-h") ||
!strcmp(argv[i], "-help") ||
!strcmp(argv[i], "--help")) {
@@ -461,6 +466,8 @@ int main(int argc, char *argv[]) {
psxCpu->Execute();
}
+ if (Config.GdbServer) dbg_stop();
+
return 0;
}
diff --git a/libpcsxcore/debug.c b/libpcsxcore/debug.c
index 463df73b..ecc9edc7 100644
--- a/libpcsxcore/debug.c
+++ b/libpcsxcore/debug.c
@@ -397,7 +397,7 @@ void DebugVSync() {
if (client_socket < 1)
{
- client_socket = GetClient(server_socket);
+ client_socket = GetClient(server_socket, 0);
if (client_socket > 0)
{
@@ -478,7 +478,7 @@ void ProcessDebug() {
if (client_socket < 1)
{
- client_socket = GetClient(server_socket);
+ client_socket = GetClient(server_socket, 0);
if (client_socket > 0)
{
diff --git a/libpcsxcore/psxinterpreter.c b/libpcsxcore/psxinterpreter.c
index a2bc0e1d..941fda4b 100644
--- a/libpcsxcore/psxinterpreter.c
+++ b/libpcsxcore/psxinterpreter.c
@@ -1198,6 +1198,68 @@ static void intClear(u32 Addr, u32 Size) {
static void intShutdown() {
}
+static void process_gdb(void) {
+ static int shutdown;
+ static u32 tgt_addr;
+ static int step, must_continue;
+ struct msg msg;
+
+ if (shutdown)
+ return;
+
+ if (step || (must_continue && tgt_addr && tgt_addr == psxRegs.pc)) {
+ msg.type = MSG_TYPE_HIT;
+#if DEBUG == 1
+ printf("hit address 0x%08X\n", psxRegs.pc);
+#endif
+ gdbstub_sys_send(&msg);
+ must_continue = 0;
+ step = 0;
+ }
+
+ if (!must_continue) {
+ gdbstub_sys_recv(&msg);
+
+ switch (msg.type) {
+ case MSG_TYPE_CONTINUE:
+ must_continue = 1;
+ break;
+
+ case MSG_TYPE_STEP:
+ step = 1;
+ break;
+
+ case MSG_TYPE_REMOVE_BREAKPOINT: {
+ struct msg out;
+
+ tgt_addr = 0;
+ out.type = MSG_TYPE_ACK;
+
+ gdbstub_sys_send(&out);
+ }
+ break;
+
+ case MSG_TYPE_BREAKPOINT: {
+ struct msg out;
+
+ tgt_addr = msg.data.breakpoint.addr;
+ out.type = MSG_TYPE_ACK;
+
+ gdbstub_sys_send(&out);
+ }
+ break;
+
+ case MSG_TYPE_SHUTDOWN:
+ shutdown = 1;
+ break;
+
+ default:
+ fprintf(stderr, "unknown msg.type %d\n", msg.type);
+ break;
+ }
+ }
+}
+
// interpreter execution
static inline void execI() {
u32 *code = Read_ICache(psxRegs.pc, FALSE);
@@ -1205,7 +1267,7 @@ static inline void execI() {
debugI();
- if (Config.GdbServer) dbg_sys_process();
+ if (Config.GdbServer) process_gdb();
else if (Config.Debug) ProcessDebug();
psxRegs.pc += 4;
diff --git a/libpcsxcore/socket.c b/libpcsxcore/socket.c
index 51aefdf7..eec4c96a 100644
--- a/libpcsxcore/socket.c
+++ b/libpcsxcore/socket.c
@@ -88,7 +88,7 @@ void StopServer(int s_socket) {
#endif
}
-int GetClient(int s_socket) {
+int GetClient(int s_socket, int blocking) {
int new_socket = accept(s_socket, NULL, NULL);
#ifdef _WIN32
@@ -100,6 +100,7 @@ int GetClient(int s_socket) {
#endif
#ifndef _WIN32
+ if (!blocking)
{
int flags;
flags = fcntl(new_socket, F_GETFL, 0);
diff --git a/libpcsxcore/socket.h b/libpcsxcore/socket.h
index 531a6485..852c76a4 100644
--- a/libpcsxcore/socket.h
+++ b/libpcsxcore/socket.h
@@ -35,7 +35,7 @@ enum read_socket_err
int StartServer(unsigned short port);
void StopServer(int s_socket);
-int GetClient(int s_socket);
+int GetClient(int s_socket, int blocking);
void CloseClient(int client_socket);
int HasClient(int client_socket);
diff --git a/win32/gui/WndMain.c b/win32/gui/WndMain.c
index 374b1877..4c01b200 100644
--- a/win32/gui/WndMain.c
+++ b/win32/gui/WndMain.c
@@ -238,6 +238,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
RunGui();
+ if (Config.GdbServer) dbg_stop();
+
return 0;
}
@@ -1570,7 +1572,7 @@ BOOL CALLBACK ConfigureCpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lPar
}
if (Config.GdbServer) {
- GdbStartServer();
+ dbg_start();
}
SaveConfig();
@@ -1996,8 +1998,7 @@ int SysInit() {
LoadMcds(Config.Mcd1, Config.Mcd2);
if (Config.Debug) StartDebugger();
-
- if (Config.GdbServer) GdbStartServer();
+ else if (Config.GdbServer) dbg_start();
return 0;
}