GDBstub base implementation (gdb is happy)
This commit is contained in:
parent
c466d7d175
commit
43629abbd4
@ -1,5 +1,7 @@
|
||||
#include "gdbstub.h"
|
||||
|
||||
#include "cpu/rv32cpu.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -16,56 +18,163 @@ typedef struct sockaddr_in sockaddr_in_t;
|
||||
typedef struct sockaddr sockaddr_t;
|
||||
|
||||
#define GDBSTUB_PORT 1234
|
||||
#define PACKET_BUFFER_SIZE 2048
|
||||
|
||||
socket_t gdbstub_server_socket;
|
||||
socket_t gdb_socket;
|
||||
|
||||
void gdbstub_thread_gdb();
|
||||
|
||||
/*
|
||||
* Starts a server that will listen for GDB connections
|
||||
*/
|
||||
* Receive a packet from client gdb
|
||||
* Ignores the ACK on the way, and only returns the packet (not initial '$' symbol)
|
||||
*/
|
||||
static void gdbstub_recv_packet(char* packet, ssize_t* size)
|
||||
{
|
||||
char data;
|
||||
recv(gdb_socket, &data, 1, 0);
|
||||
|
||||
// Start of packet symbol is '$'
|
||||
// Skip data that is not packet (should only be ACK '+')
|
||||
if(data != '$')
|
||||
return gdbstub_recv_packet(packet, size);
|
||||
|
||||
// Receive packet until end of packet '#' symbol
|
||||
size_t i = 0;
|
||||
do
|
||||
{
|
||||
recv(gdb_socket, packet + i, 1, 0);
|
||||
i++;
|
||||
} while(packet[i - 1] != '#');
|
||||
|
||||
// Receive checksum after end of packet symbol
|
||||
recv(gdb_socket, packet + i, 1, 0);
|
||||
recv(gdb_socket, packet + i + 1, 1, 0);
|
||||
|
||||
if(size) *size = i + 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a packet to client gdb
|
||||
* Pass only the packet data as parameter to this function
|
||||
*/
|
||||
static void gdbstub_send_packet(char* packet, ssize_t size)
|
||||
{
|
||||
// Compute packet checksum
|
||||
char end[4] = {0};
|
||||
uint8_t sum = 0;
|
||||
for(size_t i = 0; i < size; i++)
|
||||
{
|
||||
sum += packet[i];
|
||||
}
|
||||
snprintf(end, 4, "#%02x", sum);
|
||||
|
||||
// Send ACK to last packet, and begin of packet symbol
|
||||
char begin[2] = {'+', '$'};
|
||||
send(gdb_socket, begin, 2, 0);
|
||||
|
||||
// Send the actual data of packet
|
||||
send(gdb_socket, packet, size, 0);
|
||||
|
||||
// Send 'end of packet' and checksum
|
||||
send(gdb_socket, end, 3, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a packet to client gdb saying we don't support asked feature
|
||||
*/
|
||||
static void gdbstub_send_unsupported()
|
||||
{
|
||||
char unsupported[] = "+$#00";
|
||||
send(gdb_socket, unsupported, 5, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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(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);
|
||||
}
|
||||
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;
|
||||
gdbstub_server_socket = sock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for a client (gdb) to connect to this server
|
||||
*/
|
||||
* 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);
|
||||
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);
|
||||
}
|
||||
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;
|
||||
gdb_socket = c_socket;
|
||||
|
||||
gdbstub_thread_gdb();
|
||||
}
|
||||
|
||||
void gdbstub_thread_gdb()
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
char packet[PACKET_BUFFER_SIZE];
|
||||
ssize_t packet_size;
|
||||
gdbstub_recv_packet(packet, &packet_size);
|
||||
// printf("<-: %.*s\n", (int) packet_size, packet);
|
||||
|
||||
// Analyse packet to respond correctly
|
||||
if(packet[0] == '?')
|
||||
{
|
||||
char* resp = "S05";
|
||||
gdbstub_send_packet(resp, 3);
|
||||
}
|
||||
else if(packet[0] == 'g')
|
||||
{
|
||||
char resp[32 * 8 + 8 + 1] = {0};
|
||||
|
||||
// All general purpose registers in host byte order as chars
|
||||
for(size_t i = 0; i < 32; i++)
|
||||
{
|
||||
uint32_t value = htonl(cpu0->regs.x[i]);
|
||||
snprintf(resp + i * 8, 9, "%08x", value);
|
||||
}
|
||||
|
||||
// PC register
|
||||
uint32_t pc = htonl(cpu0->pc);
|
||||
snprintf(resp + 32 * 8, 9, "%08x", pc);
|
||||
|
||||
// Final packet size, send packet
|
||||
size_t size = 32 * 8 + 8;
|
||||
gdbstub_send_packet(resp, size);
|
||||
}
|
||||
else gdbstub_send_unsupported();
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ static void print_help()
|
||||
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 (max 4096)\n");
|
||||
printf(" " OPTION_SEPARATOR "s, --gdb-stub\t\t\tLaunch a gdb stub server, for remote gdb debugging\n");
|
||||
printf(" " OPTION_SEPARATOR "s, --gdb-stub\t\tLaunch a gdb stub server (remote gdb debugging)\n");
|
||||
}
|
||||
|
||||
static void print_version()
|
||||
|
Loading…
Reference in New Issue
Block a user