|
|
|
@ -1,5 +1,7 @@ |
|
|
|
|
#include "gdbstub.h" |
|
|
|
|
|
|
|
|
|
#include "cpu/rv32cpu.h" |
|
|
|
|
|
|
|
|
|
#include <errno.h> |
|
|
|
|
#include <stdlib.h> |
|
|
|
|
#include <stdio.h> |
|
|
|
@ -16,10 +18,77 @@ 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(); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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 |
|
|
|
|
*/ |
|
|
|
@ -68,4 +137,44 @@ void gdbstub_wait_for_connection() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|