all repos — mgba @ 244f19774210b923778e123b58df9dbb9173d14e

mGBA Game Boy Advance Emulator

src/debugger/gdb-stub.c (view raw)

  1#include "gdb-stub.h"
  2
  3#include <errno.h>
  4#include <fcntl.h>
  5#include <netinet/in.h>
  6#include <stdio.h>
  7#include <sys/socket.h>
  8#include <unistd.h>
  9
 10void _gdbStubDeinit(struct ARMDebugger* debugger) {
 11	struct GDBStub* stub = (struct GDBStub*) debugger;
 12	if (stub->socket >= 0) {
 13		GDBStubShutdown(stub);
 14	}
 15}
 16
 17void GDBStubCreate(struct GDBStub* stub) {
 18	stub->socket = -1;
 19	stub->connection = -1;
 20	stub->d.init = 0;
 21	stub->d.deinit = _gdbStubDeinit;
 22	stub->d.paused = 0;
 23}
 24
 25int GDBStubListen(struct GDBStub* stub, int port, uint32_t bindAddress) {
 26	if (stub->socket >= 0) {
 27		GDBStubShutdown(stub);
 28	}
 29	// TODO: support IPv6
 30	stub->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 31	if (stub->socket < 0) {
 32		printf("Couldn't open socket\n");
 33		return 0;
 34	}
 35
 36	struct sockaddr_in bindInfo = {
 37		.sin_family = AF_INET,
 38		.sin_port = htons(port),
 39		.sin_addr = {
 40			.s_addr = htonl(bindAddress)
 41		}
 42	};
 43	int err = bind(stub->socket, (const struct sockaddr*) &bindInfo, sizeof(struct sockaddr_in));
 44	if (err) {
 45		goto cleanup;
 46	}
 47	err = listen(stub->socket, 1);
 48	if (err) {
 49		goto cleanup;
 50	}
 51	int flags = fcntl(stub->socket, F_GETFL);
 52	if (flags == -1) {
 53		goto cleanup;
 54	}
 55	flags |= O_NONBLOCK;
 56	fcntl(stub->socket, F_SETFL, flags | O_NONBLOCK);
 57
 58	return 1;
 59
 60cleanup:
 61	close(stub->socket);
 62	stub->socket = -1;
 63	return 0;
 64}
 65
 66void GDBStubHangup(struct GDBStub* stub) {
 67	if (stub->connection >= 0) {
 68		close(stub->connection);
 69		stub->connection = -1;
 70	}
 71}
 72
 73void GDBStubShutdown(struct GDBStub* stub) {
 74	GDBStubHangup(stub);
 75	if (stub->socket >= 0) {
 76		close(stub->socket);
 77		stub->socket = -1;
 78	}
 79}
 80
 81void GDBStubUpdate(struct GDBStub* stub) {
 82	if (stub->connection == -1) {
 83		stub->connection = accept(stub->socket, 0, 0);
 84		if (errno == EWOULDBLOCK || errno == EAGAIN) {
 85			return;
 86		}
 87		if (stub->connection >= 0) {
 88			int flags = fcntl(stub->connection, F_GETFL);
 89			if (flags == -1) {
 90				goto connectionLost;
 91			}
 92			flags |= O_NONBLOCK;
 93			fcntl(stub->connection, F_SETFL, flags | O_NONBLOCK);
 94		} else {
 95			goto connectionLost;
 96		}
 97	}
 98	while (1) {
 99		ssize_t messageLen = recv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1, 0);
100		if (messageLen == 0) {
101			goto connectionLost;
102		}
103		if (messageLen == -1) {
104			if (errno == EWOULDBLOCK || errno == EAGAIN) {
105				return;
106			}
107			goto connectionLost;
108		}
109		stub->line[messageLen] = '\0';
110		printf("Received message: %s\n", stub->line);
111	}
112	return;
113
114connectionLost:
115	// TODO: add logging support to the debugging interface
116	printf("Connection lost\n");
117	GDBStubHangup(stub);
118}