From 59f7ab7c11533e5bec0209a8f42527a6c5b69b35 Mon Sep 17 00:00:00 2001
From: cnlohr <lohr85@gmail.com>
Date: Sat, 29 Apr 2023 06:15:42 -0400
Subject: [PATCH] Getting started on GDB server.

---
 minichlink/Makefile     |  11 +-
 minichlink/minichgdb.c  | 235 ++++++++++++++++++++++++++++++++++++++++
 minichlink/minichlink.c |  11 +-
 minichlink/minichlink.h |   5 +
 4 files changed, 255 insertions(+), 7 deletions(-)
 create mode 100644 minichlink/minichgdb.c

diff --git a/minichlink/Makefile b/minichlink/Makefile
index 3a367d4..0b6ba43 100644
--- a/minichlink/Makefile
+++ b/minichlink/Makefile
@@ -4,6 +4,8 @@ all : $(TOOLS)
 
 CFLAGS:=-O0 -g3 -Wall
 
+C_S:=minichlink.c pgm-wch-linke.c pgm-esp32s2-ch32xx.c nhc-link042.c minichgdb.c
+
 ifeq ($(OS),Windows_NT)
 	LDFLAGS:=-lpthread -lusb-1.0 -lsetupapi
 else
@@ -20,13 +22,14 @@ else
 	endif
 endif
 
+# will need mingw-w64-x86-64-dev gcc-mingw-w64-x86-64
+minichlink.exe : $(C_S)
+	x86_64-w64-mingw32-gcc -o $@ $^ -Os -s -lsetupapi ./libusb-1.0.dll
 
-
-
-minichlink : minichlink.c pgm-wch-linke.c pgm-esp32s2-ch32xx.c nhc-link042.c
+minichlink : $(C_S)
 	gcc -o $@ $^ $(LDFLAGS) $(CFLAGS) $(INCS)
 
-minichlink.so : minichlink.c pgm-wch-linke.c pgm-esp32s2-ch32xx.c nhc-link042.c
+minichlink.so : $(C_S)
 	gcc -o $@ $^ $(LDFLAGS) $(CFLAGS) $(INCS) -shared -fPIC
 
 install_udev_rules :
diff --git a/minichlink/minichgdb.c b/minichlink/minichgdb.c
new file mode 100644
index 0000000..9bbfc81
--- /dev/null
+++ b/minichlink/minichgdb.c
@@ -0,0 +1,235 @@
+#include "minichlink.h"
+
+#ifdef WIN32
+#include <winsock2.h>
+#define socklen_t uint32_t
+#define SHUT_RDWR SD_BOTH
+#define MSG_NOSIGNAL 0
+#else
+#define closesocket close
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/in.h>
+#endif
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <poll.h>
+uint16_t htons(uint16_t hostshort);
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+
+int listenMode; // 0 for uninit.  1 for server, 2 for client.
+int serverSocket;
+
+char gdbbuffer[65536];
+uint8_t gdbchecksum = 0;
+int gdbbufferplace = 0;
+int gdbbufferstate = 0;
+void HandleClientData( const uint8_t * rxdata, int len )
+{
+	int pl = 0;
+	do
+	{
+		int c = rxdata[pl];
+		if( c == '$' )
+		{
+			gdbbufferplace = 0;
+			gdbbufferstate = 1;
+		}
+
+		switch( gdbbufferstate )
+		{
+		default:
+			break;
+		case 1:
+			if( gdbbufferplace < 65535 )
+			{
+				gdbbuffer[gdbbufferplace++] = c;
+			}
+			if( c == '#' ) gdbbufferstate = 2;
+		case 2:
+		case 3:
+			if( c >= '0' && c <= '9' ) c = c - '0';
+			else if( c >= 'A' && c <= 'F' ) c = c - 'A' + 10;
+			else if( c >= 'a' && c <= 'f' ) c = c - 'a' + 10;
+			if( gdbbufferstate == 2 ) gdbchecksum = c << 4;
+			else if( gdbbufferstate == 3 ) gdbchecksum = c << 4;
+			gdbbufferstate++;
+			break;
+		case 4:
+			// Got a packet?
+		{
+			int i;
+			for( i = 0; i < gdbbufferplace; i++ )
+			{
+			}
+		}
+		}
+	if( gdbbufferstate == 0 )
+
+			printf( "rececived: %d\n", rx );
+			int i;
+			for( i = 0; i < rx;i ++ )
+			{
+				printf( "%02x (%c) ", buffer[i], buffer[i] );
+			}
+			printf( "\n" );
+
+}
+
+#define GDBSERVER_PORT 2345
+
+static int GDBListen()
+{
+	struct	sockaddr_in sin;
+	serverSocket = socket(AF_INET, SOCK_STREAM, 0);
+
+	//Make sure the socket worked.
+	if( serverSocket == -1 )
+	{
+		fprintf( stderr, "Error: Cannot create socket.\n" );
+		return -1;
+	}
+
+	//Disable SO_LINGER (Well, enable it but turn it way down)
+#ifdef WIN32
+	struct linger lx;
+	lx.l_onoff = 1;
+	lx.l_linger = 0;
+	setsockopt( serverSocket, SOL_SOCKET, SO_LINGER, (const char *)&lx, sizeof( lx ) );
+
+	//Enable SO_REUSEADDR
+	int reusevar = 1;
+	setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reusevar, sizeof(reusevar));
+#else
+	struct linger lx;
+	lx.l_onoff = 1;
+	lx.l_linger = 0;
+	setsockopt( serverSocket, SOL_SOCKET, SO_LINGER, &lx, sizeof( lx ) );
+
+	//Enable SO_REUSEADDR
+	int reusevar = 1;
+	setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &reusevar, sizeof(reusevar));
+#endif
+	//Setup socket for listening address.
+	memset( &sin, 0, sizeof( sin ) );
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = INADDR_ANY;
+	sin.sin_port = htons( GDBSERVER_PORT );
+
+	//Actually bind to the socket
+	if( bind( serverSocket, (struct sockaddr *) &sin, sizeof( sin ) ) == -1 )
+	{
+		fprintf( stderr, "Could not bind to socket: %d\n", GDBSERVER_PORT );
+		closesocket( serverSocket );
+		serverSocket = 0;
+		return -1;
+	}
+
+	//Finally listen.
+	if( listen( serverSocket, 5 ) == -1 )
+	{
+		fprintf(stderr, "Could not lieten to socket.");
+		closesocket( serverSocket );
+		serverSocket = 0;
+		return -1;
+	}
+	return 0;
+}
+
+int PollGDBServer()
+{
+	if( !serverSocket ) return -4;
+
+	struct pollfd allpolls[2];
+
+	int pollct = 1;
+	allpolls[0].fd = serverSocket;
+	allpolls[0].events = POLLIN;
+
+	//Do something to watch all currently-waiting sockets.
+	poll( allpolls, pollct, 0 );
+
+	//If there's faults, bail.
+	if( allpolls[0].revents & (POLLERR|POLLHUP) )
+	{
+		closesocket( serverSocket );
+		if( listenMode == 1 )
+		{
+			// Some sort of weird fatal close?  Is this even possible?
+			fprintf( stderr, "Error: serverSocke was forcibly closed\n" );
+			exit( -4 );
+		}
+		else if( listenMode == 2 )
+		{	
+			serverSocket = 0;
+			listenMode = 1;
+			GDBListen();
+		}
+	}
+	if( allpolls[0].revents & POLLIN )
+	{
+		if( listenMode == 1 )
+		{
+			struct   sockaddr_in tin;
+			socklen_t addrlen  = sizeof(tin);
+			memset( &tin, 0, addrlen );
+			int tsocket = accept( serverSocket, (struct sockaddr *)&tin, &addrlen );
+			closesocket( serverSocket );
+			serverSocket = tsocket;
+			listenMode = 2;
+			gdbbufferstate = 0;
+			// Established.
+		}
+		else if( listenMode == 2 )
+		{
+			// Got data from a peer.
+			uint8_t buffer[16384];
+			ssize_t rx = recv( serverSocket, buffer, sizeof( buffer ), MSG_NOSIGNAL );
+			HandleClientData( buffer, (int)rx );
+		}
+	}
+
+	if( listenMode == 2 )
+	{
+		// Otherwise, is anything else interesting going on?
+	}
+
+	return 0;
+}
+
+void ExitGDBServer()
+{
+	shutdown( serverSocket, SHUT_RDWR );
+}
+
+int SetupGDBServer()
+{
+#ifdef WIN32
+{
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    int err;
+    wVersionRequested = MAKEWORD(2, 2);
+
+    err = WSAStartup(wVersionRequested, &wsaData);
+    if (err != 0) {
+        /* Tell the user that we could not find a usable */
+        /* Winsock DLL.                                  */
+        fprintf( stderr, "WSAStartup failed with error: %d\n", err);
+        return 1;
+    }
+}
+#endif
+
+	listenMode = 1;
+
+	return GDBListen();
+}
+
+
diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c
index a384b37..db2afac 100644
--- a/minichlink/minichlink.c
+++ b/minichlink/minichlink.c
@@ -162,8 +162,12 @@ keep_going:
 				break;
 			case 'T':
 			{
+
 				if( !MCF.PollTerminal )
 					goto unimplemented;
+
+				SetupGDBServer();
+
 				do
 				{
 					uint8_t buffer[256];
@@ -177,6 +181,7 @@ keep_going:
 					{
 						fwrite( buffer, r, 1, stdout ); 
 					}
+					PollGDBServer();
 				} while( 1 );
 			}
 			case 's':
@@ -201,7 +206,7 @@ keep_going:
 					goto unimplemented;
 				break;
 			}
-			case 'g':
+			case 'm':
 			{
 				iarg+=1;
 				if( iarg >= argc )
@@ -474,14 +479,14 @@ help:
 	fprintf( stderr, " -D Configure NRST as GPIO\n" );
 	fprintf( stderr, " -d Configure NRST as NRST\n" );
 	fprintf( stderr, " -s [debug register] [value]\n" );
-	fprintf( stderr, " -g [debug register]\n" );
+	fprintf( stderr, " -m [debug register]\n" );
 //	fprintf( stderr, " -P Enable Read Protection (UNTESTED)\n" );
 //	fprintf( stderr, " -p Disable Read Protection (UNTESTED)\n" );
 	fprintf( stderr, " -w [binary image to write] [address, decimal or 0x, try0x08000000]\n" );
 	fprintf( stderr, " -r [output binary image] [memory address, decimal or 0x, try 0x08000000] [size, decimal or 0x, try 16384]\n" );
 	fprintf( stderr, "   Note: for memory addresses, you can use 'flash' 'launcher' 'bootloader' 'option' 'ram' and say \"ram+0x10\" for instance\n" );
 	fprintf( stderr, "   For filename, you can use - for raw or + for hex.\n" );
-	fprintf( stderr, " -T is a terminal. This MUST be the last argument.  You MUST have resumed or \n" );
+	fprintf( stderr, " -T is a terminal. This MUST be the last argument. Also, will start a gdbserver.\n" );
 
 	return -1;	
 
diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h
index 9a0e1e6..37aa8ab 100644
--- a/minichlink/minichlink.h
+++ b/minichlink/minichlink.h
@@ -123,5 +123,10 @@ int SetupAutomaticHighLevelFunctions( void * dev );
 // Useful for converting numbers like 0x, etc.
 int64_t SimpleReadNumberInt( const char * number, int64_t defaultNumber );
 
+
+int SetupGDBServer();
+int PollGDBServer();
+void ExitGDBServer();
+
 #endif
 
-- 
GitLab