diff --git a/src/gdbstub/gdbstub.c b/src/gdbstub/gdbstub.c new file mode 100644 index 0000000..5e9cfbe --- /dev/null +++ b/src/gdbstub/gdbstub.c @@ -0,0 +1,71 @@ +#include "gdbstub.h" + +#include +#include +#include +#include + +/* Sockets */ +#include +#include +#include +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 +typedef int socket_t; +typedef struct sockaddr_in sockaddr_in_t; +typedef struct sockaddr sockaddr_t; + +#define GDBSTUB_PORT 1234 + +socket_t gdbstub_server_socket; +socket_t gdb_socket; + +/* +* Starts a server that will listen for GDB connections +*/ +void gdbstub_start() +{ + socket_t sock = socket(AF_INET, SOCK_STREAM, 0); + if(sock == INVALID_SOCKET) + { + fprintf(stderr, "Could not create gdbstub server socket: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + sockaddr_in_t sin = {0}; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_family = AF_INET; + sin.sin_port = htons(GDBSTUB_PORT); + + if(bind(sock, (sockaddr_t*) &sin, sizeof(sin)) == SOCKET_ERROR) + { + fprintf(stderr, "Could not bind gdbstub server socket: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + if(listen(sock, 1) == SOCKET_ERROR) + { + fprintf(stderr, "Could not listen gdbstub server socket: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + gdbstub_server_socket = sock; +} + +/* +* Wait for a client (gdb) to connect to this server +*/ +void gdbstub_wait_for_connection() +{ + sockaddr_in_t csin = {0}; + socket_t c_socket; + socklen_t sinsize = sizeof(csin); + + c_socket = accept(gdbstub_server_socket, (sockaddr_t*) &csin, &sinsize); + if(c_socket == INVALID_SOCKET) + { + fprintf(stderr, "Could not accept client on gdbstub server: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + gdb_socket = c_socket; +} diff --git a/src/gdbstub/gdbstub.h b/src/gdbstub/gdbstub.h new file mode 100644 index 0000000..5a56014 --- /dev/null +++ b/src/gdbstub/gdbstub.h @@ -0,0 +1,7 @@ +#ifndef GDBSTUB_H +#define GDBSTUB_H + +void gdbstub_start(); +void gdbstub_wait_for_connection(); + +#endif diff --git a/src/main.c b/src/main.c index 2bf27ad..b275777 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include "memory/memory.h" #include "bootloader/bootloader.h" #include "cpu/rv32cpu.h" +#include "gdbstub/gdbstub.h" char* CURRENT_NAME; @@ -20,6 +21,12 @@ int main(int argc, char** argv) cpu_init(); cpu0->pc = entry_point; + if(gdbstub) + { + gdbstub_start(); + gdbstub_wait_for_connection(); + } + // CPU simulation cpu_loop(cpu0); diff --git a/src/option.c b/src/option.c index 0a6e896..7c36ed8 100644 --- a/src/option.c +++ b/src/option.c @@ -7,6 +7,7 @@ uint64_t memory_size = 512 * 1024 * 1024; char* file_path; +bool gdbstub = false; static void print_usage(); static void print_help(); @@ -94,6 +95,11 @@ void parse_options(int argc, char** argv) break; } + case 's': + { + gdbstub = true; + break; + } default: { fprintf(stderr, "Error: Unknown short option -%c\n", argv[i][k]); @@ -150,6 +156,11 @@ static int parse_long_option(char* str, char* argq) return 1; } + else if(strcmp(str, "gdb-stub") == 0) + { + gdbstub = true; + return 0; + } else { fprintf(stderr, "Error: Unknown long option " OPTION_SEPARATOR OPTION_SEPARATOR "%s\n", str); @@ -169,7 +180,8 @@ static void print_help() printf("Options:\n"); printf(" " OPTION_SEPARATOR "h, " OPTION_SEPARATOR "?, --help\t\tPrint this help message\n"); printf(" " OPTION_SEPARATOR "v, --version\t\t\tPrint version information\n"); - printf(" " OPTION_SEPARATOR "m, --memory\t\t\tSet the simulated memory size, in MiB\n"); + printf(" " OPTION_SEPARATOR "m, --memory\t\t\tSet the simulated memory size, in MiB (max 4096)\n"); + printf(" " OPTION_SEPARATOR "s, --gdb-stub\t\t\tLaunch a gdb stub server, for remote gdb debugging\n"); } static void print_version() diff --git a/src/vriscv.h b/src/vriscv.h index 4009074..b34c4b7 100644 --- a/src/vriscv.h +++ b/src/vriscv.h @@ -14,6 +14,7 @@ extern char* CURRENT_NAME; /* Program options */ extern size_t memory_size; extern char* file_path; +extern bool gdbstub; void parse_options(int argc, char** argv); #endif