- added patch to Improving progress/error output for telnet & GDB monitor
authormifi <mifi@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 13 Feb 2008 19:02:17 +0000 (19:02 +0000)
committermifi <mifi@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 13 Feb 2008 19:02:17 +0000 (19:02 +0000)
(thanks to √ėyvind for the patch)

git-svn-id: svn://svn.berlios.de/openocd/trunk@293 b42882b7-edfa-0310-969c-e2dbd0fdcd60

src/helper/command.c
src/helper/log.c
src/helper/log.h
src/server/gdb_server.c
src/server/telnet_server.c

index afd8667..9f756d4 100644 (file)
@@ -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;
        }
        
index 7440707..db0bc0b 100644 (file)
@@ -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;
+       }
+}
index 6e799ad..34646e7 100644 (file)
@@ -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 */
index d48101f..b15c29d 100644 (file)
 
 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':
index 3a74f5a..af49050 100644 (file)
@@ -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)