GDBstub base implementation (gdb is happy)
This commit is contained in:
		@@ -1,5 +1,7 @@
 | 
				
			|||||||
#include "gdbstub.h"
 | 
					#include "gdbstub.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "cpu/rv32cpu.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
@@ -16,10 +18,77 @@ typedef struct sockaddr_in sockaddr_in_t;
 | 
				
			|||||||
typedef struct sockaddr sockaddr_t;
 | 
					typedef struct sockaddr sockaddr_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define GDBSTUB_PORT 1234
 | 
					#define GDBSTUB_PORT 1234
 | 
				
			||||||
 | 
					#define PACKET_BUFFER_SIZE 2048
 | 
				
			||||||
 | 
					
 | 
				
			||||||
socket_t gdbstub_server_socket;
 | 
					socket_t gdbstub_server_socket;
 | 
				
			||||||
socket_t gdb_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
 | 
					 * Starts a server that will listen for GDB connections
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -68,4 +137,44 @@ void gdbstub_wait_for_connection()
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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 "h, " OPTION_SEPARATOR "?, --help\t\tPrint this help message\n");
 | 
				
			||||||
	printf("  " OPTION_SEPARATOR "v, --version\t\t\tPrint version information\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 "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()
 | 
					static void print_version()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user