mirror of https://github.com/mgba-emu/mgba.git
Debugger: Ensure GDB stub never hard-blocks
This commit is contained in:
parent
29623ecd0b
commit
973f1a64a0
|
@ -12,6 +12,8 @@
|
|||
#define SIGTRAP 5 /* Win32 Signals do not include SIGTRAP */
|
||||
#endif
|
||||
|
||||
#define SOCKET_TIMEOUT 50
|
||||
|
||||
enum GDBError {
|
||||
GDB_NO_ERROR = 0x00,
|
||||
GDB_BAD_ARGUMENTS = 0x06,
|
||||
|
@ -58,33 +60,13 @@ static void _gdbStubPoll(struct ARMDebugger* debugger) {
|
|||
return;
|
||||
}
|
||||
stub->untilPoll = GDB_STUB_INTERVAL;
|
||||
if (stub->shouldBlock) {
|
||||
stub->shouldBlock = false;
|
||||
if (!SocketSetBlocking(stub->socket, false)) {
|
||||
GDBStubHangup(stub);
|
||||
return;
|
||||
}
|
||||
if (!SOCKET_FAILED(stub->connection) && !SocketSetBlocking(stub->connection, false)) {
|
||||
GDBStubHangup(stub);
|
||||
return;
|
||||
}
|
||||
}
|
||||
GDBStubUpdate(stub);
|
||||
}
|
||||
|
||||
static void _gdbStubWait(struct ARMDebugger* debugger) {
|
||||
struct GDBStub* stub = (struct GDBStub*) debugger;
|
||||
if (!stub->shouldBlock) {
|
||||
stub->shouldBlock = true;
|
||||
if (!SocketSetBlocking(stub->socket, true)) {
|
||||
GDBStubHangup(stub);
|
||||
return;
|
||||
}
|
||||
if (!SOCKET_FAILED(stub->connection) && !SocketSetBlocking(stub->connection, true)) {
|
||||
GDBStubHangup(stub);
|
||||
return;
|
||||
}
|
||||
}
|
||||
GDBStubUpdate(stub);
|
||||
}
|
||||
|
||||
|
@ -195,12 +177,6 @@ static void _writeHostInfo(struct GDBStub* stub) {
|
|||
static void _continue(struct GDBStub* stub, const char* message) {
|
||||
stub->d.state = DEBUGGER_CUSTOM;
|
||||
stub->untilPoll = GDB_STUB_INTERVAL;
|
||||
if (!SOCKET_FAILED(stub->connection)) {
|
||||
if (!SocketSetBlocking(stub->connection, 0)) {
|
||||
GDBStubHangup(stub);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO: parse message
|
||||
UNUSED(message);
|
||||
}
|
||||
|
@ -484,6 +460,9 @@ int GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddr
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
if (!SocketSetBlocking(stub->socket, false)) {
|
||||
goto cleanup;
|
||||
}
|
||||
int err = SocketListen(stub->socket, 1);
|
||||
if (err) {
|
||||
goto cleanup;
|
||||
|
@ -496,14 +475,14 @@ cleanup:
|
|||
stub->d.log(&stub->d, DEBUGGER_LOG_ERROR, "Couldn't listen on port");
|
||||
}
|
||||
SocketClose(stub->socket);
|
||||
stub->socket = -1;
|
||||
stub->socket = INVALID_SOCKET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GDBStubHangup(struct GDBStub* stub) {
|
||||
if (!SOCKET_FAILED(stub->connection)) {
|
||||
SocketClose(stub->connection);
|
||||
stub->connection = -1;
|
||||
stub->connection = INVALID_SOCKET;
|
||||
}
|
||||
if (stub->d.state == DEBUGGER_PAUSED) {
|
||||
stub->d.state = DEBUGGER_RUNNING;
|
||||
|
@ -514,17 +493,27 @@ void GDBStubShutdown(struct GDBStub* stub) {
|
|||
GDBStubHangup(stub);
|
||||
if (!SOCKET_FAILED(stub->socket)) {
|
||||
SocketClose(stub->socket);
|
||||
stub->socket = -1;
|
||||
stub->socket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
void GDBStubUpdate(struct GDBStub* stub) {
|
||||
if (stub->socket == INVALID_SOCKET) {
|
||||
if (stub->d.state == DEBUGGER_PAUSED) {
|
||||
stub->d.state = DEBUGGER_RUNNING;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (stub->connection == INVALID_SOCKET) {
|
||||
if (stub->shouldBlock) {
|
||||
Socket reads = stub->socket;
|
||||
SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT);
|
||||
}
|
||||
stub->connection = SocketAccept(stub->socket, 0);
|
||||
if (!SOCKET_FAILED(stub->connection)) {
|
||||
if (!SocketSetBlocking(stub->connection, false)) {
|
||||
goto connectionLost;
|
||||
}
|
||||
ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED);
|
||||
} else if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
return;
|
||||
|
@ -533,6 +522,10 @@ void GDBStubUpdate(struct GDBStub* stub) {
|
|||
}
|
||||
}
|
||||
while (true) {
|
||||
if (stub->shouldBlock) {
|
||||
Socket reads = stub->connection;
|
||||
SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT);
|
||||
}
|
||||
ssize_t messageLen = SocketRecv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1);
|
||||
if (messageLen == 0) {
|
||||
goto connectionLost;
|
||||
|
|
|
@ -47,6 +47,8 @@ void GDBController::detach() {
|
|||
if (!isAttached()) {
|
||||
return;
|
||||
}
|
||||
SocketSetBlocking(m_gdbStub.socket, false);
|
||||
SocketSetBlocking(m_gdbStub.connection, false);
|
||||
m_gameController->threadInterrupt();
|
||||
GDBStubShutdown(&m_gdbStub);
|
||||
m_gameController->setDebugger(nullptr);
|
||||
|
|
|
@ -179,4 +179,73 @@ static inline int SocketSetTCPPush(Socket socket, int push) {
|
|||
return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0;
|
||||
}
|
||||
|
||||
static inline int SocketPoll(int nSockets, Socket* reads, Socket* writes, Socket* errors, int64_t timeoutMillis) {
|
||||
fd_set rset;
|
||||
fd_set wset;
|
||||
fd_set eset;
|
||||
FD_ZERO(&rset);
|
||||
FD_ZERO(&wset);
|
||||
FD_ZERO(&eset);
|
||||
int i;
|
||||
int maxFd = 0;
|
||||
if (reads) {
|
||||
for (i = 0; i < nSockets; ++i) {
|
||||
if (SOCKET_FAILED(reads[i])) {
|
||||
break;
|
||||
}
|
||||
if (reads[i] > maxFd) {
|
||||
maxFd = reads[i];
|
||||
}
|
||||
FD_SET(reads[i], &rset);
|
||||
reads[i] = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
if (writes) {
|
||||
for (i = 0; i < nSockets; ++i) {
|
||||
if (SOCKET_FAILED(writes[i])) {
|
||||
break;
|
||||
}
|
||||
if (writes[i] > maxFd) {
|
||||
maxFd = writes[i];
|
||||
}
|
||||
FD_SET(writes[i], &wset);
|
||||
writes[i] = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
if (errors) {
|
||||
for (i = 0; i < nSockets; ++i) {
|
||||
if (SOCKET_FAILED(errors[i])) {
|
||||
break;
|
||||
}
|
||||
if (errors[i] > maxFd) {
|
||||
maxFd = errors[i];
|
||||
}
|
||||
FD_SET(errors[i], &eset);
|
||||
errors[i] = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeoutMillis / 1000;
|
||||
tv.tv_usec = (timeoutMillis % 1000) * 1000;
|
||||
int result = select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv);
|
||||
int r = 0;
|
||||
int w = 0;
|
||||
int e = 0;
|
||||
for (i = 0; i < maxFd; ++i) {
|
||||
if (reads && FD_ISSET(i, &rset)) {
|
||||
reads[r] = i;
|
||||
++r;
|
||||
}
|
||||
if (writes && FD_ISSET(i, &wset)) {
|
||||
writes[w] = i;
|
||||
++w;
|
||||
}
|
||||
if (errors && FD_ISSET(i, &eset)) {
|
||||
errors[e] = i;
|
||||
++e;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue