Implemented port-specific wrappers and logic for gdb stub
This commit is contained in:
parent
850010a96b
commit
cb2d7f800a
|
@ -1 +1 @@
|
|||
Subproject commit b00d0f815b3996a13ce87a4d9d6d7038353e77e6
|
||||
Subproject commit 8ce6abf8d32291ad66a3724123a9a583b9a3bb4b
|
|
@ -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
|
||||
|
||||
#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)
|
||||
{
|
||||
struct msg msg;
|
||||
|
||||
msg.type = MSG_TYPE_REMOVE_BREAKPOINT;
|
||||
|
||||
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
|
||||
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)
|
||||
{
|
||||
const unsigned short port = 3333;
|
||||
if (server_socket > 0) {
|
||||
fprintf(stderr, "gdb server already started\n");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
const unsigned short port = 3333;
|
||||
|
||||
if (server_socket > 0)
|
||||
StopServer(server_socket);
|
||||
server_socket = StartServer(port);
|
||||
|
||||
server_socket = StartServer(port);
|
||||
|
||||
if (server_socket > 0)
|
||||
printf("GDB server started on port %hu.\n", port);
|
||||
else
|
||||
fprintf(stderr, "Could not start GDB server\n");
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue