From 2a0317e6f40a4f2d5d20ccdaae82100f0ad4340a Mon Sep 17 00:00:00 2001
From: mifi <mifi@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Date: Wed, 13 Feb 2008 19:02:17 +0000
Subject: [PATCH] =?UTF-8?q?-=20added=20patch=20to=20Improving=20progress/e?=
 =?UTF-8?q?rror=20output=20for=20telnet=20&=20GDB=20monitor=20(thanks=20to?=
 =?UTF-8?q?=20=C3=98yvind=20for=20the=20patch)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

git-svn-id: svn://svn.berlios.de/openocd/trunk@293 b42882b7-edfa-0310-969c-e2dbd0fdcd60
---
 src/helper/command.c       | 17 ++++++++--
 src/helper/log.c           | 64 ++++++++++++++++++++++++++++++-------
 src/helper/log.h           | 30 ++++++------------
 src/server/gdb_server.c    | 65 ++++++++++++++++++++++++++++++++++----
 src/server/telnet_server.c | 23 ++++++++++++++
 5 files changed, 158 insertions(+), 41 deletions(-)

diff --git a/src/helper/command.c b/src/helper/command.c
index afd866729..9f756d412 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -268,7 +268,7 @@ void command_print(command_context_t *context, char *format, ...)
 	/* process format string */
 	/* TODO: possible bug. va_list is undefined after the first call to vsnprintf */
 	while (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
-	{
+		{
 		/* increase buffer until it fits the whole string */
 		if (!(p = realloc(buffer, size += 4096)))
 		{
@@ -359,7 +359,7 @@ int find_and_run_command(command_context_t *context, command_t *commands, char *
 	return ERROR_OK;
 }
 
-int command_run_line(command_context_t *context, char *line)
+static int command_run_line_inner(command_context_t *context, char *line)
 {
 	int nwords;
 	char *words[128] = {0};
@@ -399,6 +399,17 @@ int command_run_line(command_context_t *context, char *line)
 	return retval;
 }
 
+int command_run_line(command_context_t *context, char *line)
+{
+	int retval=command_run_line_inner(context, line);
+	// we don't want any dangling callbacks!
+	// 
+	// Capturing output from logging is *very* loosly modeled on C/C++ exceptions.
+	// the capture must be set up at function entry and 
+	// stops when the function call returns
+	log_setCallback(NULL, NULL);
+	return retval;
+}
 int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
 {
 	int retval = ERROR_OK;
@@ -441,7 +452,7 @@ int command_run_file(command_context_t *context, FILE *file, enum command_mode m
 			break;
 
 		/* run line */
-		if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
+		if ((retval = command_run_line_inner(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
 			break;
 	}
 	
diff --git a/src/helper/log.c b/src/helper/log.c
index 744070788..db0bc0bd6 100644
--- a/src/helper/log.c
+++ b/src/helper/log.c
@@ -33,6 +33,16 @@ int debug_level = -1;
 
 static FILE* log_output;
 
+
+static void *privData;
+static logCallback callback;
+
+void log_setCallback(logCallback c, void *p)
+{
+	callback=c;
+	privData=p;
+}
+
 static char *log_strings[4] = 
 {
 	"Error:  ",
@@ -56,25 +66,18 @@ void log_printf(enum log_levels level, const char *file, int line, const char *f
 	fflush(log_output);
 	
 	va_end(args);
-}
 
-void short_log_printf(enum log_levels level, const char *format, ...)
+	if (callback)
 {
-	va_list args;
-	char buffer[512];
-
-	if (level > debug_level)
-		return;
-
 	va_start(args, format);
-	vsnprintf(buffer, 512, format, args);
 
-	fprintf(log_output, "%s %s\n", log_strings[level], buffer);
-	fflush(log_output);
+		callback(privData, file, line, function, format, args);
 
 	va_end(args);
 }
 
+}
+
 /* change the current debug level on the fly
  * 0: only ERRORS
  * 1: + WARNINGS
@@ -136,3 +139,42 @@ int log_init(struct command_context_s *cmd_ctx)
 	
 	return ERROR_OK;
 }
+	
+int set_log_output(struct command_context_s *cmd_ctx, FILE *output)
+{
+	log_output=output;
+	return ERROR_OK;
+}
+
+/* return allocated string w/printf() result */
+char *allocPrintf(const char *fmt, va_list ap)
+{
+	char *string=NULL;
+	int size=0; // start by 0 to exercise all the code paths. Need minimum 2 bytes to fit 1 char and 0 terminator.
+	int first=1;
+	for (;;)
+	{
+		if ((string==NULL)||(!first))
+		{
+			size=size*2+2;
+			char *t=string;
+			string=realloc(string, size);
+			if (string==NULL)
+			{
+				if (t!=NULL)
+					free(t);
+				return NULL;
+			}
+		}
+	
+	    int ret;
+	    ret = vsnprintf(string, size, fmt, ap);
+	    // NB! The result of the vsnprintf() might be an *EMPTY* string!
+	    if ((ret>=0)&&((ret+1)<size))
+	    {
+	    	return string;
+	    }
+	    // there was just enough or not enough space, allocate more.
+	    first=0;
+	}
+}
diff --git a/src/helper/log.h b/src/helper/log.h
index 6e799ad36..34646e702 100644
--- a/src/helper/log.h
+++ b/src/helper/log.h
@@ -44,6 +44,12 @@ extern void log_printf(enum log_levels level, const char *file, int line,
 	__attribute__ ((format (printf, 5, 6)));
 extern int log_register_commands(struct command_context_s *cmd_ctx);
 extern int log_init(struct command_context_s *cmd_ctx);
+extern int set_log_output(struct command_context_s *cmd_ctx, FILE *output);
+
+typedef void (*logCallback)(void *privData, const char *file, int line, 
+		const char *function, const char *format, va_list args);
+
+void log_setCallback(logCallback callback, void *privData);		
 
 extern int debug_level;
 
@@ -67,25 +73,6 @@ extern int debug_level;
 		log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \
 	} while(0)
 
-#define SDEBUG(expr ...) \
-	do { \
-		short_log_printf (LOG_DEBUG, expr); \
-	} while(0)
-
-#define SINFO(expr ...) \
-	do { \
-		short_log_printf (LOG_INFO, expr); \
-	} while(0)
-
-#define SWARNING(expr ...) \
-	do { \
-		short_log_printf (LOG_WARNING, expr); \
-	} while(0)
-
-#define SERROR(expr ...) \
-	do { \
-		short_log_printf (LOG_ERROR, expr); \
-	} while(0)
 
 /* general failures
  * error codes < 100
@@ -95,4 +82,7 @@ extern int debug_level;
 #define ERROR_NO_CONFIG_FILE		(-2)
 #define ERROR_BUF_TOO_SMALL			(-3)
 
-#endif /* ERROR_H */
+char *allocPrintf(const char *fmt, va_list ap);
+
+
+#endif /* LOG_H */
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index d48101f45..b15c29d38 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -44,6 +44,10 @@
 
 static unsigned short gdb_port;
 
+static void gdb_log_callback(void *privData, const char *file, int line, 
+		const char *function, const char *format, va_list args);
+
+
 enum gdb_detach_mode
 {
 	GDB_DETACH_RESUME,
@@ -180,7 +184,7 @@ int gdb_putback_char(connection_t *connection, int last_char)
 	return ERROR_OK;
 }
 
-int gdb_put_packet(connection_t *connection, char *buffer, int len)
+int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
 {
 	int i;
 	unsigned char my_checksum = 0;
@@ -245,10 +249,19 @@ int gdb_put_packet(connection_t *connection, char *buffer, int len)
 	return ERROR_OK;
 }
 
-int gdb_get_packet(connection_t *connection, char *buffer, int *len)
+int gdb_put_packet(connection_t *connection, char *buffer, int len)
+{
+	gdb_connection_t *gdb_connection = connection->priv;
+	gdb_connection->output_disable=1;
+	int retval=gdb_put_packet_inner(connection, buffer, len);
+	gdb_connection->output_disable=0;
+	return retval;
+}
+
+int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
 {
 	int character;
-	int count;
+	int count = 0;
 	int retval;
 	char checksum[3];
 	unsigned char my_checksum = 0;
@@ -286,8 +299,9 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len)
 		} while (character != '$');
 
 		my_checksum = 0;
-		count = 0;
 		
+		count=0;
+		gdb_connection_t *gdb_con = connection->priv;
 		for (;;)
 		{
 			/* The common case is that we have an entire packet with no escape chars.
@@ -391,11 +405,18 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len)
 	return ERROR_OK;
 }
 
-int gdb_output(struct command_context_s *context, char* line)
+int gdb_get_packet(connection_t *connection, char *buffer, int *len)
 {
-	connection_t *connection = context->output_handler_priv;
 	gdb_connection_t *gdb_connection = connection->priv;
+	gdb_connection->output_disable=1;
+	int retval=gdb_get_packet_inner(connection, buffer, len);
+	gdb_connection->output_disable=0;
+	return retval;
+}
 	
+int gdb_output_con(connection_t *connection, char* line)
+{
+	gdb_connection_t *gdb_connection = connection->priv;
 	char *hex_buffer;
 	int i, bin_size;
 
@@ -422,6 +443,12 @@ int gdb_output(struct command_context_s *context, char* line)
 	return ERROR_OK;
 }
 
+int gdb_output(struct command_context_s *context, char* line)
+{
+	connection_t *connection = context->output_handler_priv;
+	return gdb_output_con(connection, line);
+}
+
 int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)
 {
 	FILE *script;
@@ -458,6 +485,9 @@ int gdb_target_callback_event_handler(struct target_s *target, enum target_event
 		case TARGET_EVENT_HALTED:
 			if (gdb_connection->frontend_state == TARGET_RUNNING)
 			{
+				// stop forwarding log packets!
+				log_setCallback(NULL, NULL);
+				
 				if (gdb_connection->ctrl_c)
 				{
 					signal = 0x2;
@@ -895,7 +925,6 @@ int gdb_memory_packet_error(connection_t *connection, int retval)
 		case ERROR_TARGET_NOT_HALTED:
 			ERROR("gdb tried to read memory but we're not halted, dropping connection");
 			return ERROR_SERVER_REMOTE_CLOSED;
-			break;
 		case ERROR_TARGET_DATA_ABORT:
 			gdb_send_error(connection, EIO);
 			break;
@@ -1398,6 +1427,9 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
 				cmd[i] = tmp;
 			}
 			cmd[(packet_size - 6)/2] = 0x0;
+			
+			/* We want to print all debug output to GDB connection */
+			log_setCallback(gdb_log_callback, connection);
 			target_call_timer_callbacks();
 			command_run_line(cmd_ctx, cmd);
 			free(cmd);
@@ -1759,6 +1791,22 @@ int gdb_detach(connection_t *connection, target_t *target)
 	return ERROR_OK;
 }
 
+
+
+static void gdb_log_callback(void *privData, const char *file, int line, 
+		const char *function, const char *format, va_list args)
+{
+	connection_t *connection=(connection_t *)privData;
+	
+	char *t=allocPrintf(format, args);
+	if (t==NULL)
+		return;
+	
+	gdb_output_con(connection, t); 
+	
+	free(t);
+}
+
 int gdb_input(connection_t *connection)
 {
 	gdb_service_t *gdb_service = connection->service->priv;
@@ -1833,6 +1881,9 @@ int gdb_input(connection_t *connection)
 					break;
 				case 'c':
 				case 's':
+					/* We're running/stepping, in which case we can 
+					 * forward log output until the target is halted */
+					log_setCallback(gdb_log_callback, connection);
 					gdb_step_continue_packet(connection, target, packet, packet_size);
 					break;
 				case 'v':
diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c
index 3a74f5ac4..af49050a9 100644
--- a/src/server/telnet_server.c
+++ b/src/server/telnet_server.c
@@ -57,6 +57,12 @@ void telnet_prompt(connection_t *connection)
 	write_socket(connection->fd, t_con->prompt, strlen(t_con->prompt));
 }
 
+int telnet_outputline(connection_t *connection, char* line)
+{
+	write_socket(connection->fd, line, strlen(line));
+	return write_socket(connection->fd, "\r\n\0", 3);
+}
+
 int telnet_output(struct command_context_s *cmd_ctx, char* line)
 {
 	connection_t *connection = cmd_ctx->output_handler_priv;
@@ -67,6 +73,19 @@ int telnet_output(struct command_context_s *cmd_ctx, char* line)
 	return ERROR_OK;
 }
 
+void telnet_log_callback(void *privData, const char *file, int line, 
+		const char *function, const char *format, va_list args)
+{
+	connection_t *connection=(connection_t *)privData;
+	char *t=allocPrintf(format, args);
+	if (t==NULL)
+		return;
+	
+	telnet_outputline(connection, t);
+	
+	free(t);
+}
+
 int telnet_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
 {
 	struct command_context_s *cmd_ctx = priv;
@@ -244,6 +263,10 @@ int telnet_input(connection_t *connection)
 								continue;
 							}
 							
+
+							
+							log_setCallback(telnet_log_callback, connection);
+							
 							if ((retval = command_run_line(command_context, t_con->line)) != ERROR_OK)
 							{
 								if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
-- 
GitLab