Pavel Chromy
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 25 Feb 2008 17:32:53 +0000 (17:32 +0000)
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 25 Feb 2008 17:32:53 +0000 (17:32 +0000)
- multiple log listeners
- added OUTPUT() to replace printf
- fix formatting

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

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

index 4b6de26c2889ff1c37aa562bb0bf2058700d036a..f13a86c15da1e2f5928f1f1a589642c981612ff0 100644 (file)
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   part of this file is taken from libcli (libcli.sourceforge.net)       *
- *   Copyright (C) David Parrish (david@dparrish.com)                      *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "command.h"
-
-#include "log.h"
-#include "time_support.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <unistd.h>
-
-void command_print_help_line(command_context_t* context, struct command_s *command, int indent);
-
-int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-int build_unique_lengths(command_context_t *context, command_t *commands)
-{
-       command_t *c, *p;
-
-       /* iterate through all commands */
-       for (c = commands; c; c = c->next)
-       {
-               /* find out how many characters are required to uniquely identify a command */
-               for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)
-               {
-                       int foundmatch = 0;
-                       
-                       /* for every command, see if the current length is enough */
-                       for (p = commands; p; p = p->next)
-                       {
-                               /* ignore the command itself */
-                               if (c == p)
-                                       continue;
-                               
-                               /* compare commands up to the current length */
-                               if (strncmp(p->name, c->name, c->unique_len) == 0)
-                                       foundmatch++;
-                       }
-                       
-                       /* when none of the commands matched, we've found the minimum length required */
-                       if (!foundmatch)
-                               break;
-               }
-               
-               /* if the current command has children, build the unique lengths for them */
-               if (c->children)
-                       build_unique_lengths(context, c->children);
-       }
-       
-       return ERROR_OK;
-}
-
-/* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n). 
- * Makes a difference on ARM7 types machines and is not observable on GHz machines.
- */
-static int unique_length_dirty = 1; 
-
-command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
-{
-       command_t *c, *p;
-       unique_length_dirty = 1;
-       
-       if (!context || !name)
-               return NULL;
-                               
-       c = malloc(sizeof(command_t));
-       
-       c->name = strdup(name);
-       c->parent = parent;
-       c->children = NULL;
-       c->handler = handler;
-       c->mode = mode;
-       if (help)
-               c->help = strdup(help);
-       else
-               c->help = NULL;
-       c->unique_len = 0;
-       c->next = NULL;
-       
-       /* place command in tree */
-       if (parent)
-       {
-               if (parent->children)
-               {
-                       /* find last child */
-                       for (p = parent->children; p && p->next; p = p->next);
-                       if (p)
-                               p->next = c;
-               }
-               else
-               {
-                       parent->children = c;
-               }
-       }
-       else
-       {
-               if (context->commands)
-               {
-                       /* find last command */
-                       for (p = context->commands; p && p->next; p = p->next);
-                       if (p)
-                               p->next = c;
-               }
-               else
-               {
-                       context->commands = c;
-               }
-       }
-       
-       return c;
-}
-
-int unregister_command(command_context_t *context, char *name)
-{
-       unique_length_dirty = 1;
-       
-       command_t *c, *p = NULL, *c2;
-       
-       if ((!context) || (!name))
-               return ERROR_INVALID_ARGUMENTS;
-       
-       /* find command */
-       for (c = context->commands; c; c = c->next)
-       {
-               if (strcmp(name, c->name) == 0)
-               {
-                       /* unlink command */
-                       if (p)
-                       {
-                               p->next = c->next;
-                       }
-                       else
-                       {
-                               context->commands = c->next;
-                       }
-                       
-                       /* unregister children */
-                       if (c->children)
-                       {
-                               for (c2 = c->children; c2; c2 = c2->next)
-                               {
-                                       free(c2->name);
-                                       if (c2->help)
-                                               free(c2->help);
-                                       free(c2);
-                               }
-                       }
-                       
-                       /* delete command */
-                       free(c->name);
-                       if (c->help)
-                               free(c->help);
-                       free(c);
-               }
-               
-               /* remember the last command for unlinking */
-               p = c;
-       }
-       
-       return ERROR_OK;
-}
-
-int parse_line(char *line, char *words[], int max_words)
-{
-       int nwords = 0;
-       char *p = line;
-       char *word_start = line;
-       int inquote = 0;
-
-       while (nwords < max_words - 1)
-       {
-               /* check if we reached
-                * a terminating NUL
-                * a matching closing quote character " or '
-                * we're inside a word but not a quote, and the current character is whitespace
-                */
-               if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
-               {
-                       /* we're inside a word or quote, and reached its end*/
-                       if (word_start)
-                       {
-                               int len;
-                               char *word_end=p;
-                               
-                               /* This will handle extra whitespace within quotes */
-                               while (isspace(*word_start)&&(word_start<word_end))
-                                       word_start++;
-                               while (isspace(*(word_end-1))&&(word_start<word_end))
-                                       word_end--;
-                               len = word_end - word_start;
-                               
-                               if (len>0)
-                               {
-                                       /* copy the word */
-                                       memcpy(words[nwords] = malloc(len + 1), word_start, len);
-                                       /* add terminating NUL */
-                                       words[nwords++][len] = 0;
-                               }
-                       }
-                       /* we're done parsing the line */
-                       if (!*p)
-                               break;
-
-                       /* skip over trailing quote or whitespace*/
-                       if (inquote || isspace(*p))
-                               p++;
-                       while (isspace(*p))
-                               p++;
-                       
-                       inquote = 0;
-                       word_start = 0;
-               }
-               else if (*p == '"' || *p == '\'')
-               {
-                       /* we've reached the beginning of a quote */
-                       inquote = *p++;
-                       word_start = p;
-               }
-               else
-               {
-                       /* we've reached the beginning of a new word */
-                       if (!word_start)
-                               word_start = p;
-                       
-                       /* normal character, skip */
-                       p++;
-               }
-       }
-       
-       return nwords;
-}
-
-void command_print(command_context_t *context, char *format, ...)
-{
-       char *buffer = NULL;
-       int n, size = 0;
-       char *p;
-
-       /* process format string */
-       for (;;)
-       {
-               va_list ap;
-               va_start(ap, format);
-               if (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
-               {
-                       /* increase buffer until it fits the whole string */
-                       if (!(p = realloc(buffer, size += 4096)))
-                       {
-                               /* gotta free up */
-                               if (buffer)
-                                       free(buffer);
-                               va_end(ap);
-                               return;
-                       }
-       
-                       buffer = p;
-                       
-                       va_end(ap);
-                       continue;
-               }
-               va_end(ap);
-               break;
-       }
-       
-       /* vsnprintf failed */
-       if (n < 0)
-       {
-               if (buffer)
-                       free(buffer);
-               return;
-       }
-
-       p = buffer;
-       
-       /* process lines in buffer */
-       do {
-               char *next = strchr(p, '\n');
-               
-               if (next)
-                       *next++ = 0;
-
-               if (context->output_handler)
-                       context->output_handler(context, p);
-
-               p = next;
-       } while (p);
-       
-       if (buffer)
-               free(buffer);
-}
-
-int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
-{
-       command_t *c;
-       
-       if (unique_length_dirty)
-       {
-               unique_length_dirty = 0;
-               /* update unique lengths */
-               build_unique_lengths(context, context->commands);
-       }
-       
-       for (c = commands; c; c = c->next)
-       {
-               if (strncasecmp(c->name, words[start_word], c->unique_len))
-                       continue;
-
-               if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
-                       continue;
-               
-               if ((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) )
-               {
-                       if (!c->children)
-                       {
-                               if (!c->handler)
-                               {
-                                       command_print(context, "No handler for command");
-                                       break;
-                               }
-                               else
-                               {
-                                       int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
-                                       if (retval == ERROR_COMMAND_SYNTAX_ERROR)
-                                       {
-                                               command_print(context, "Syntax error:");
-                                               command_print_help_line(context, c, 0);
-                                       }
-                                       return retval; 
-                               }
-                       }
-                       else
-                       {
-                               if (start_word == num_words - 1)
-                               {
-                                       command_print(context, "Incomplete command");
-                                       break;
-                               }
-                               return find_and_run_command(context, c->children, words, num_words, start_word + 1);
-                       }
-               }
-       }
-       
-       command_print(context, "Command %s not found", words[start_word]);
-       return ERROR_OK;
-}
-
-static int command_run_line_inner(command_context_t *context, char *line)
-{
-       int nwords;
-       char *words[128] = {0};
-       int retval;
-       int i;
-       
-       if ((!context) || (!line))
-               return ERROR_INVALID_ARGUMENTS;
-       
-       /* skip preceding whitespace */
-       while (isspace(*line))
-               line++;
-       
-       /* empty line, ignore */
-       if (!*line)
-               return ERROR_OK;
-       
-       /* ignore comments */
-       if (*line && (line[0] == '#'))
-               return ERROR_OK;
-       
-       if (context->echo)
-       {
-               command_print(context, "%s", line);
-       }
-
-       nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
-       
-       if (nwords > 0)
-               retval = find_and_run_command(context, context->commands, words, nwords, 0);
-       else
-               return ERROR_INVALID_ARGUMENTS;
-       
-       for (i = 0; i < nwords; i++)
-               free(words[i]);
-       
-       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;
-       int old_command_mode;
-       char *buffer=malloc(4096);
-       if (buffer==NULL)
-       {
-               return ERROR_INVALID_ARGUMENTS;
-       }
-       
-       old_command_mode = context->mode;
-       context->mode = mode;
-       
-       while (fgets(buffer, 4096, file))
-       {
-               char *p;
-               char *cmd, *end;
-               
-               /* stop processing line after a comment (#, !) or a LF, CR were encountered */
-               if ((p = strpbrk(buffer, "#!\r\n")))
-                       *p = 0;
-
-               /* skip over leading whitespace */
-               cmd = buffer;
-               while (isspace(*cmd))
-                       cmd++;
-
-               /* empty (all whitespace) line? */
-               if (!*cmd)
-                       continue;
-               
-               /* search the end of the current line, ignore trailing whitespace */
-               for (p = end = cmd; *p; p++)
-                       if (!isspace(*p))
-                               end = p;
-               
-               /* terminate end */
-               *++end = 0;
-               if (strcasecmp(cmd, "quit") == 0)
-                       break;
-
-               /* run line */
-               if ((retval = command_run_line_inner(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)
-                       break;
-       }
-       
-       context->mode = old_command_mode;
-
-       
-       free(buffer);
-       
-       return retval;
-}
-
-void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
-{
-       command_t *c;
-       char indents[32] = {0};
-       char *help = "no help available";
-       char name_buf[64];
-       int i;
-       
-       for (i = 0; i < indent; i+=2)
-       {
-               indents[i*2] = ' ';
-               indents[i*2+1] = '-';
-       }
-       indents[i*2] = 0;
-       
-       if (command->help)
-               help = command->help;
-               
-       snprintf(name_buf, 64, command->name);
-       strncat(name_buf, indents, 64);
-       command_print(context, "%20s\t%s", name_buf, help);
-       
-       if (command->children)
-       {
-               for (c = command->children; c; c = c->next)
-               {
-                       command_print_help_line(context, c, indent + 1);
-               }
-       }
-}
-
-int command_print_help(command_context_t* context, char* name, char** args, int argc)
-{
-       command_t *c;
-
-       for (c = context->commands; c; c = c->next)
-       {
-               if (argc == 1)
-               {
-                        if (strncasecmp(c->name, args[0], c->unique_len))
-                                continue;
-
-                        if (strncasecmp(c->name, args[0], strlen(args[0])))
-                                continue;
-               } 
-
-               command_print_help_line(context, c, 0);
-       }
-       
-       return ERROR_OK;
-}
-
-void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
-{
-       context->output_handler = output_handler;
-       context->output_handler_priv = priv;
-}
-
-command_context_t* copy_command_context(command_context_t* context)
-{
-       command_context_t* copy_context = malloc(sizeof(command_context_t));
-
-       *copy_context = *context;
-       
-       return copy_context;
-}
-
-int command_done(command_context_t *context)
-{
-       free(context);
-       context = NULL;
-       
-       return ERROR_OK;
-}
-
-command_context_t* command_init()
-{
-       command_context_t* context = malloc(sizeof(command_context_t));
-       
-       context->mode = COMMAND_EXEC;
-       context->commands = NULL;
-       context->current_target = 0;
-       context->echo = 0;
-       context->output_handler = NULL;
-       context->output_handler_priv = NULL;
-       
-       register_command(context, NULL, "help", command_print_help,
-                                        COMMAND_EXEC, "display this help");
-       
-       register_command(context, NULL, "sleep", handle_sleep_command,
-                                        COMMAND_ANY, "sleep for <n> milliseconds");
-       
-       register_command(context, NULL, "time", handle_time_command,
-                                        COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");
-       
-       return context;
-}
-
-/* sleep command sleeps for <n> miliseconds
- * this is useful in target startup scripts
- */
-int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       unsigned long duration = 0;
-       
-       if (argc == 1)
-       {
-               duration = strtoul(args[0], NULL, 0);
-               usleep(duration * 1000);
-       }
-
-       return ERROR_OK;
-}
-
-int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       if (argc<1)
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       
-       duration_t duration;
-       char *duration_text;
-       int retval;
-       
-       duration_start_measure(&duration);
-       
-       retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc, 0);
-       
-       duration_stop_measure(&duration, &duration_text);
-       
-       float t=duration.duration.tv_sec;
-       t+=((float)duration.duration.tv_usec / 1000000.0);
-       command_print(cmd_ctx, "%s took %fs", args[0], t);
-       
-       free(duration_text);
-
-       return retval;
-}
+/***************************************************************************\r
+ *   Copyright (C) 2005 by Dominic Rath                                    *\r
+ *   Dominic.Rath@gmx.de                                                   *\r
+ *                                                                         *\r
+ *   part of this file is taken from libcli (libcli.sourceforge.net)       *\r
+ *   Copyright (C) David Parrish (david@dparrish.com)                      *\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version.                                   *\r
+ *                                                                         *\r
+ *   This program is distributed in the hope that it will be useful,       *\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
+ *   GNU General Public License for more details.                          *\r
+ *                                                                         *\r
+ *   You should have received a copy of the GNU General Public License     *\r
+ *   along with this program; if not, write to the                         *\r
+ *   Free Software Foundation, Inc.,                                       *\r
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
+ ***************************************************************************/\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "replacements.h"\r
+\r
+#include "command.h"\r
+\r
+#include "log.h"\r
+#include "time_support.h"\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <stdarg.h>\r
+#include <stdio.h>\r
+#include <unistd.h>\r
+\r
+void command_print_help_line(command_context_t* context, struct command_s *command, int indent);\r
+\r
+int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+int build_unique_lengths(command_context_t *context, command_t *commands)\r
+{\r
+       command_t *c, *p;\r
+\r
+       /* iterate through all commands */\r
+       for (c = commands; c; c = c->next)\r
+       {\r
+               /* find out how many characters are required to uniquely identify a command */\r
+               for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)\r
+               {\r
+                       int foundmatch = 0;\r
+                       \r
+                       /* for every command, see if the current length is enough */\r
+                       for (p = commands; p; p = p->next)\r
+                       {\r
+                               /* ignore the command itself */\r
+                               if (c == p)\r
+                                       continue;\r
+                               \r
+                               /* compare commands up to the current length */\r
+                               if (strncmp(p->name, c->name, c->unique_len) == 0)\r
+                                       foundmatch++;\r
+                       }\r
+                       \r
+                       /* when none of the commands matched, we've found the minimum length required */\r
+                       if (!foundmatch)\r
+                               break;\r
+               }\r
+               \r
+               /* if the current command has children, build the unique lengths for them */\r
+               if (c->children)\r
+                       build_unique_lengths(context, c->children);\r
+       }\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+/* Avoid evaluating this each time we add a command. Reduces overhead from O(n^2) to O(n). \r
+ * Makes a difference on ARM7 types machines and is not observable on GHz machines.\r
+ */\r
+static int unique_length_dirty = 1; \r
+\r
+command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)\r
+{\r
+       command_t *c, *p;\r
+       unique_length_dirty = 1;\r
+       \r
+       if (!context || !name)\r
+               return NULL;\r
+                               \r
+       c = malloc(sizeof(command_t));\r
+       \r
+       c->name = strdup(name);\r
+       c->parent = parent;\r
+       c->children = NULL;\r
+       c->handler = handler;\r
+       c->mode = mode;\r
+       if (help)\r
+               c->help = strdup(help);\r
+       else\r
+               c->help = NULL;\r
+       c->unique_len = 0;\r
+       c->next = NULL;\r
+       \r
+       /* place command in tree */\r
+       if (parent)\r
+       {\r
+               if (parent->children)\r
+               {\r
+                       /* find last child */\r
+                       for (p = parent->children; p && p->next; p = p->next);\r
+                       if (p)\r
+                               p->next = c;\r
+               }\r
+               else\r
+               {\r
+                       parent->children = c;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               if (context->commands)\r
+               {\r
+                       /* find last command */\r
+                       for (p = context->commands; p && p->next; p = p->next);\r
+                       if (p)\r
+                               p->next = c;\r
+               }\r
+               else\r
+               {\r
+                       context->commands = c;\r
+               }\r
+       }\r
+       \r
+       return c;\r
+}\r
+\r
+int unregister_command(command_context_t *context, char *name)\r
+{\r
+       unique_length_dirty = 1;\r
+       \r
+       command_t *c, *p = NULL, *c2;\r
+       \r
+       if ((!context) || (!name))\r
+               return ERROR_INVALID_ARGUMENTS;\r
+       \r
+       /* find command */\r
+       for (c = context->commands; c; c = c->next)\r
+       {\r
+               if (strcmp(name, c->name) == 0)\r
+               {\r
+                       /* unlink command */\r
+                       if (p)\r
+                       {\r
+                               p->next = c->next;\r
+                       }\r
+                       else\r
+                       {\r
+                               context->commands = c->next;\r
+                       }\r
+                       \r
+                       /* unregister children */\r
+                       if (c->children)\r
+                       {\r
+                               for (c2 = c->children; c2; c2 = c2->next)\r
+                               {\r
+                                       free(c2->name);\r
+                                       if (c2->help)\r
+                                               free(c2->help);\r
+                                       free(c2);\r
+                               }\r
+                       }\r
+                       \r
+                       /* delete command */\r
+                       free(c->name);\r
+                       if (c->help)\r
+                               free(c->help);\r
+                       free(c);\r
+               }\r
+               \r
+               /* remember the last command for unlinking */\r
+               p = c;\r
+       }\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+int parse_line(char *line, char *words[], int max_words)\r
+{\r
+       int nwords = 0;\r
+       char *p = line;\r
+       char *word_start = line;\r
+       int inquote = 0;\r
+\r
+       while (nwords < max_words - 1)\r
+       {\r
+               /* check if we reached\r
+                * a terminating NUL\r
+                * a matching closing quote character " or '\r
+                * we're inside a word but not a quote, and the current character is whitespace\r
+                */\r
+               if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))\r
+               {\r
+                       /* we're inside a word or quote, and reached its end*/\r
+                       if (word_start)\r
+                       {\r
+                               int len;\r
+                               char *word_end=p;\r
+                               \r
+                               /* This will handle extra whitespace within quotes */\r
+                               while (isspace(*word_start)&&(word_start<word_end))\r
+                                       word_start++;\r
+                               while (isspace(*(word_end-1))&&(word_start<word_end))\r
+                                       word_end--;\r
+                               len = word_end - word_start;\r
+                               \r
+                               if (len>0)\r
+                               {\r
+                                       /* copy the word */\r
+                                       memcpy(words[nwords] = malloc(len + 1), word_start, len);\r
+                                       /* add terminating NUL */\r
+                                       words[nwords++][len] = 0;\r
+                               }\r
+                       }\r
+                       /* we're done parsing the line */\r
+                       if (!*p)\r
+                               break;\r
+\r
+                       /* skip over trailing quote or whitespace*/\r
+                       if (inquote || isspace(*p))\r
+                               p++;\r
+                       while (isspace(*p))\r
+                               p++;\r
+                       \r
+                       inquote = 0;\r
+                       word_start = 0;\r
+               }\r
+               else if (*p == '"' || *p == '\'')\r
+               {\r
+                       /* we've reached the beginning of a quote */\r
+                       inquote = *p++;\r
+                       word_start = p;\r
+               }\r
+               else\r
+               {\r
+                       /* we've reached the beginning of a new word */\r
+                       if (!word_start)\r
+                               word_start = p;\r
+                       \r
+                       /* normal character, skip */\r
+                       p++;\r
+               }\r
+       }\r
+       \r
+       return nwords;\r
+}\r
+\r
+void command_print(command_context_t *context, char *format, ...)\r
+{\r
+       char *buffer = NULL;\r
+       int n, size = 0;\r
+       char *p;\r
+\r
+       /* process format string */\r
+       for (;;)\r
+       {\r
+               va_list ap;\r
+               va_start(ap, format);\r
+               if (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)\r
+               {\r
+                       /* increase buffer until it fits the whole string */\r
+                       if (!(p = realloc(buffer, size += 4096)))\r
+                       {\r
+                               /* gotta free up */\r
+                               if (buffer)\r
+                                       free(buffer);\r
+                               va_end(ap);\r
+                               return;\r
+                       }\r
+       \r
+                       buffer = p;\r
+                       \r
+                       va_end(ap);\r
+                       continue;\r
+               }\r
+               va_end(ap);\r
+               break;\r
+       }\r
+       \r
+       /* vsnprintf failed */\r
+       if (n < 0)\r
+       {\r
+               if (buffer)\r
+                       free(buffer);\r
+               return;\r
+       }\r
+\r
+       p = buffer;\r
+       \r
+       /* process lines in buffer */\r
+       do {\r
+               char *next = strchr(p, '\n');\r
+               \r
+               if (next)\r
+                       *next++ = 0;\r
+\r
+               if (context->output_handler)\r
+                       context->output_handler(context, p);\r
+\r
+               p = next;\r
+       } while (p);\r
+       \r
+       if (buffer)\r
+               free(buffer);\r
+}\r
+\r
+int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)\r
+{\r
+       command_t *c;\r
+       \r
+       if (unique_length_dirty)\r
+       {\r
+               unique_length_dirty = 0;\r
+               /* update unique lengths */\r
+               build_unique_lengths(context, context->commands);\r
+       }\r
+       \r
+       for (c = commands; c; c = c->next)\r
+       {\r
+               if (strncasecmp(c->name, words[start_word], c->unique_len))\r
+                       continue;\r
+\r
+               if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))\r
+                       continue;\r
+               \r
+               if ((context->mode == COMMAND_CONFIG) || (c->mode == COMMAND_ANY) || (c->mode == context->mode) )\r
+               {\r
+                       if (!c->children)\r
+                       {\r
+                               if (!c->handler)\r
+                               {\r
+                                       command_print(context, "No handler for command");\r
+                                       break;\r
+                               }\r
+                               else\r
+                               {\r
+                                       int retval = c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);\r
+                                       if (retval == ERROR_COMMAND_SYNTAX_ERROR)\r
+                                       {\r
+                                               command_print(context, "Syntax error:");\r
+                                               command_print_help_line(context, c, 0);\r
+                                       }\r
+                                       return retval; \r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               if (start_word == num_words - 1)\r
+                               {\r
+                                       command_print(context, "Incomplete command");\r
+                                       break;\r
+                               }\r
+                               return find_and_run_command(context, c->children, words, num_words, start_word + 1);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       command_print(context, "Command %s not found", words[start_word]);\r
+       return ERROR_OK;\r
+}\r
+\r
+int command_run_line(command_context_t *context, char *line)\r
+{\r
+       int nwords;\r
+       char *words[128] = {0};\r
+       int retval;\r
+       int i;\r
+       \r
+       if ((!context) || (!line))\r
+               return ERROR_INVALID_ARGUMENTS;\r
+       \r
+       /* skip preceding whitespace */\r
+       while (isspace(*line))\r
+               line++;\r
+       \r
+       /* empty line, ignore */\r
+       if (!*line)\r
+               return ERROR_OK;\r
+       \r
+       /* ignore comments */\r
+       if (*line && (line[0] == '#'))\r
+               return ERROR_OK;\r
+       \r
+       if (context->echo)\r
+       {\r
+               command_print(context, "%s", line);\r
+       }\r
+\r
+       nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));\r
+       \r
+       if (nwords > 0)\r
+               retval = find_and_run_command(context, context->commands, words, nwords, 0);\r
+       else\r
+               return ERROR_INVALID_ARGUMENTS;\r
+       \r
+       for (i = 0; i < nwords; i++)\r
+               free(words[i]);\r
+       \r
+       return retval;\r
+}\r
+\r
+int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)\r
+{\r
+       int retval = ERROR_OK;\r
+       int old_command_mode;\r
+       char *buffer=malloc(4096);\r
+       if (buffer==NULL)\r
+       {\r
+               return ERROR_INVALID_ARGUMENTS;\r
+       }\r
+       \r
+       old_command_mode = context->mode;\r
+       context->mode = mode;\r
+       \r
+       while (fgets(buffer, 4096, file))\r
+       {\r
+               char *p;\r
+               char *cmd, *end;\r
+               \r
+               /* stop processing line after a comment (#, !) or a LF, CR were encountered */\r
+               if ((p = strpbrk(buffer, "#!\r\n")))\r
+                       *p = 0;\r
+\r
+               /* skip over leading whitespace */\r
+               cmd = buffer;\r
+               while (isspace(*cmd))\r
+                       cmd++;\r
+\r
+               /* empty (all whitespace) line? */\r
+               if (!*cmd)\r
+                       continue;\r
+               \r
+               /* search the end of the current line, ignore trailing whitespace */\r
+               for (p = end = cmd; *p; p++)\r
+                       if (!isspace(*p))\r
+                               end = p;\r
+               \r
+               /* terminate end */\r
+               *++end = 0;\r
+               if (strcasecmp(cmd, "quit") == 0)\r
+                       break;\r
+\r
+               /* run line */\r
+               if ((retval = command_run_line(context, cmd)) == ERROR_COMMAND_CLOSE_CONNECTION)\r
+                       break;\r
+       }\r
+       \r
+       context->mode = old_command_mode;\r
+\r
+       \r
+       free(buffer);\r
+       \r
+       return retval;\r
+}\r
+\r
+void command_print_help_line(command_context_t* context, struct command_s *command, int indent)\r
+{\r
+       command_t *c;\r
+       char indents[32] = {0};\r
+       char *help = "no help available";\r
+       char name_buf[64];\r
+       int i;\r
+       \r
+       for (i = 0; i < indent; i+=2)\r
+       {\r
+               indents[i*2] = ' ';\r
+               indents[i*2+1] = '-';\r
+       }\r
+       indents[i*2] = 0;\r
+       \r
+       if (command->help)\r
+               help = command->help;\r
+               \r
+       snprintf(name_buf, 64, command->name);\r
+       strncat(name_buf, indents, 64);\r
+       command_print(context, "%20s\t%s", name_buf, help);\r
+       \r
+       if (command->children)\r
+       {\r
+               for (c = command->children; c; c = c->next)\r
+               {\r
+                       command_print_help_line(context, c, indent + 1);\r
+               }\r
+       }\r
+}\r
+\r
+int command_print_help(command_context_t* context, char* name, char** args, int argc)\r
+{\r
+       command_t *c;\r
+\r
+       for (c = context->commands; c; c = c->next)\r
+       {\r
+               if (argc == 1)\r
+               {\r
+                        if (strncasecmp(c->name, args[0], c->unique_len))\r
+                                continue;\r
+\r
+                        if (strncasecmp(c->name, args[0], strlen(args[0])))\r
+                                continue;\r
+               } \r
+\r
+               command_print_help_line(context, c, 0);\r
+       }\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)\r
+{\r
+       context->output_handler = output_handler;\r
+       context->output_handler_priv = priv;\r
+}\r
+\r
+command_context_t* copy_command_context(command_context_t* context)\r
+{\r
+       command_context_t* copy_context = malloc(sizeof(command_context_t));\r
+\r
+       *copy_context = *context;\r
+       \r
+       return copy_context;\r
+}\r
+\r
+int command_done(command_context_t *context)\r
+{\r
+       free(context);\r
+       context = NULL;\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+command_context_t* command_init()\r
+{\r
+       command_context_t* context = malloc(sizeof(command_context_t));\r
+       \r
+       context->mode = COMMAND_EXEC;\r
+       context->commands = NULL;\r
+       context->current_target = 0;\r
+       context->echo = 0;\r
+       context->output_handler = NULL;\r
+       context->output_handler_priv = NULL;\r
+       \r
+       register_command(context, NULL, "help", command_print_help,\r
+                                        COMMAND_EXEC, "display this help");\r
+       \r
+       register_command(context, NULL, "sleep", handle_sleep_command,\r
+                                        COMMAND_ANY, "sleep for <n> milliseconds");\r
+       \r
+       register_command(context, NULL, "time", handle_time_command,\r
+                                        COMMAND_ANY, "time <cmd + args> - execute <cmd + args> and print time it took");\r
+       \r
+       return context;\r
+}\r
+\r
+/* sleep command sleeps for <n> miliseconds\r
+ * this is useful in target startup scripts\r
+ */\r
+int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       unsigned long duration = 0;\r
+       \r
+       if (argc == 1)\r
+       {\r
+               duration = strtoul(args[0], NULL, 0);\r
+               usleep(duration * 1000);\r
+       }\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int handle_time_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       if (argc<1)\r
+               return ERROR_COMMAND_SYNTAX_ERROR;\r
+       \r
+       duration_t duration;\r
+       char *duration_text;\r
+       int retval;\r
+       \r
+       duration_start_measure(&duration);\r
+       \r
+       retval = find_and_run_command(cmd_ctx, cmd_ctx->commands, args, argc, 0);\r
+       \r
+       duration_stop_measure(&duration, &duration_text);\r
+       \r
+       float t=duration.duration.tv_sec;\r
+       t+=((float)duration.duration.tv_usec / 1000000.0);\r
+       command_print(cmd_ctx, "%s took %fs", args[0], t);\r
+       \r
+       free(duration_text);\r
+\r
+       return retval;\r
+}\r
index 8567c037a3f9536ebfe0bf2dcf28ccf5bc9b7897..90077ea3ea1d2f046c740573326ed7991c59bdd3 100644 (file)
 int debug_level = -1;\r
 \r
 static FILE* log_output;\r
 int debug_level = -1;\r
 \r
 static FILE* log_output;\r
+static log_callback_t *log_callbacks = NULL;\r
 \r
 \r
-static void *privData;\r
-static logCallback callback;\r
 static time_t start;\r
 \r
 static time_t start;\r
 \r
-void log_setCallback(logCallback c, void *p)\r
-{\r
-       callback = c;\r
-       privData = p;\r
-}\r
-\r
-static char *log_strings[5] = \r
+static char *log_strings[5] =\r
 {\r
        "User:   ",\r
        "Error:  ",\r
 {\r
        "User:   ",\r
        "Error:  ",\r
@@ -59,12 +52,22 @@ void log_printf(enum log_levels level, const char *file, int line, const char *f
        count++;\r
        va_list args;\r
        char buffer[512];\r
        count++;\r
        va_list args;\r
        char buffer[512];\r
+       log_callback_t *cb;\r
 \r
        if (level > debug_level)\r
                return;\r
 \r
        va_start(args, format);\r
        vsnprintf(buffer, 512, format, args);\r
 \r
        if (level > debug_level)\r
                return;\r
 \r
        va_start(args, format);\r
        vsnprintf(buffer, 512, format, args);\r
+       va_end(args);\r
+\r
+       if (level == LOG_OUTPUT)\r
+       {\r
+               /* do not prepend any headers, just print out what we were given and return */\r
+               fputs(buffer, log_output);\r
+               fflush(log_output);\r
+               return;\r
+       }\r
 \r
        char *f = strrchr(file, '/');\r
        if (f != NULL)\r
 \r
        char *f = strrchr(file, '/');\r
        if (f != NULL)\r
@@ -84,14 +87,15 @@ void log_printf(enum log_levels level, const char *file, int line, const char *f
 \r
        fflush(log_output);\r
        \r
 \r
        fflush(log_output);\r
        \r
-       va_end(args);\r
-\r
        /* Never forward LOG_DEBUG, too verbose and they can be found in the log if need be */\r
        /* Never forward LOG_DEBUG, too verbose and they can be found in the log if need be */\r
-       if (callback && (level <= LOG_INFO))\r
+       if (level <= LOG_INFO)\r
        {\r
        {\r
-               va_start(args, format);\r
-               callback(privData, file, line, function, format, args);\r
-               va_end(args);\r
+               for (cb = log_callbacks; cb; cb = cb->next)\r
+               {\r
+                       va_start(args, format);\r
+                       cb->fn(cb->priv, file, line, function, format, args);\r
+                       va_end(args);\r
+               }\r
        }\r
 }\r
 \r
        }\r
 }\r
 \r
@@ -164,8 +168,51 @@ int set_log_output(struct command_context_s *cmd_ctx, FILE *output)
        return ERROR_OK;\r
 }\r
 \r
        return ERROR_OK;\r
 }\r
 \r
+/* add/remove log callback handler */\r
+int log_add_callback(log_callback_fn fn, void *priv)\r
+{\r
+       log_callback_t *cb;\r
+\r
+       /* prevent the same callback to be registered more than once, just for sure */\r
+       for (cb = log_callbacks; cb; cb = cb->next)\r
+       {\r
+               if (cb->fn == fn && cb->priv == priv)\r
+                       return ERROR_INVALID_ARGUMENTS;\r
+       }\r
+\r
+       /* alloc memory, it is safe just to return in case of an error, no need for the caller to check this */\r
+       if ((cb = malloc(sizeof(log_callback_t))) == NULL)\r
+               return ERROR_BUF_TOO_SMALL;\r
+\r
+       /* add item to the beginning of the linked list */\r
+       cb->fn = fn;\r
+       cb->priv = priv;\r
+       cb->next = log_callbacks;\r
+       log_callbacks = cb;\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int log_remove_callback(log_callback_fn fn, void *priv)\r
+{\r
+       log_callback_t *cb, **p;\r
+\r
+       for (p = &log_callbacks; cb = *p; p = &(*p)->next)\r
+       {\r
+           if (cb->fn == fn && cb->priv == priv)\r
+           {\r
+               *p = cb->next;\r
+                       free(cb);\r
+                       return ERROR_OK;\r
+               }\r
+       }\r
+\r
+       /* no such item */\r
+       return ERROR_INVALID_ARGUMENTS;\r
+}\r
+\r
 /* return allocated string w/printf() result */\r
 /* return allocated string w/printf() result */\r
-char *allocPrintf(const char *fmt, va_list ap)\r
+char *alloc_printf(const char *fmt, va_list ap)\r
 {\r
        char *string = NULL;\r
        \r
 {\r
        char *string = NULL;\r
        \r
index ab32760a96b3c7e2190d8856d7874d76b24deae6..61050009bfe6fae0aeb15f5d545087d5de6dc73e 100644 (file)
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#ifndef ERROR_H
-#define ERROR_H
-
-#include "replacements.h"
-#include "command.h"
-
-#include <stdarg.h>
-
-/* logging priorities 
- * LOG_USER - user messages. Could be anything from information 
- *            to progress messags. These messages do not represent
- *            incorrect or unexpected behaviour, just normal execution. 
- * LOG_ERROR - fatal errors, that are likely to cause program abort
- * LOG_WARNING - non-fatal errors, that may be resolved later
- * LOG_INFO - state information, etc.
- * LOG_DEBUG - debug statements, execution trace
- */
-enum log_levels
-{
-       LOG_USER = -1,
-       LOG_ERROR = 0,
-       LOG_WARNING = 1,
-       LOG_INFO = 2,
-       LOG_DEBUG = 3
-};
-
-extern void log_printf(enum log_levels level, const char *file, int line, 
-       const char *function, const char *format, ...) 
-       __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 *priv, const char *file, int line, 
-               const char *function, const char *format, va_list args);
-
-extern void log_setCallback(logCallback callback, void *priv);         
-
-extern int debug_level;
-
-/* Avoid fn call and building parameter list if we're not outputting the information.
- * Matters on feeble CPUs for DEBUG/INFO statements that are involved frequently */
-
-#define DEBUG(expr ...) \
-       do { if (debug_level >= LOG_DEBUG) \
-               log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \
-       } while(0)
-
-#define INFO(expr ...) \
-       do { if (debug_level >= LOG_INFO) \
-               log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \
-       } while(0)
-
-#define WARNING(expr ...) \
-       do { \
-               log_printf (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr); \
-       } while(0)
-
-#define ERROR(expr ...) \
-       do { \
-               log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \
-       } while(0)
-
-#define USER(expr ...) \
-       do { \
-               log_printf (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr); \
-       } while(0)
-
-
-/* general failures
- * error codes < 100
- */
-#define ERROR_OK                                       (0)
-#define ERROR_INVALID_ARGUMENTS                (-1)
-#define ERROR_NO_CONFIG_FILE           (-2)
-#define ERROR_BUF_TOO_SMALL                    (-3)
-
-char *allocPrintf(const char *fmt, va_list ap);
-
-#endif /* LOG_H */
+/***************************************************************************\r
+ *   Copyright (C) 2005 by Dominic Rath                                    *\r
+ *   Dominic.Rath@gmx.de                                                   *\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version.                                   *\r
+ *                                                                         *\r
+ *   This program is distributed in the hope that it will be useful,       *\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
+ *   GNU General Public License for more details.                          *\r
+ *                                                                         *\r
+ *   You should have received a copy of the GNU General Public License     *\r
+ *   along with this program; if not, write to the                         *\r
+ *   Free Software Foundation, Inc.,                                       *\r
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
+ ***************************************************************************/\r
+#ifndef ERROR_H\r
+#define ERROR_H\r
+\r
+#include "replacements.h"\r
+#include "command.h"\r
+\r
+#include <stdarg.h>\r
+\r
+/* logging priorities \r
+ * LOG_USER - user messages. Could be anything from information \r
+ *            to progress messags. These messages do not represent\r
+ *            incorrect or unexpected behaviour, just normal execution. \r
+ * LOG_ERROR - fatal errors, that are likely to cause program abort\r
+ * LOG_WARNING - non-fatal errors, that may be resolved later\r
+ * LOG_INFO - state information, etc.\r
+ * LOG_DEBUG - debug statements, execution trace\r
+ */\r
+enum log_levels\r
+{\r
+       LOG_OUTPUT = -2,\r
+       LOG_USER = -1,\r
+       LOG_ERROR = 0,\r
+       LOG_WARNING = 1,\r
+       LOG_INFO = 2,\r
+       LOG_DEBUG = 3\r
+};\r
+\r
+extern void log_printf(enum log_levels level, const char *file, int line, \r
+       const char *function, const char *format, ...) \r
+       __attribute__ ((format (printf, 5, 6)));\r
+extern int log_register_commands(struct command_context_s *cmd_ctx);\r
+extern int log_init(struct command_context_s *cmd_ctx);\r
+extern int set_log_output(struct command_context_s *cmd_ctx, FILE *output);\r
+\r
+typedef void (*log_callback_fn)(void *priv, const char *file, int line,\r
+               const char *function, const char *format, va_list args);\r
+\r
+typedef struct log_callback_s\r
+{\r
+    log_callback_fn fn;\r
+       void *priv;\r
+    struct log_callback_s *next;\r
+} log_callback_t;\r
+\r
+extern int log_add_callback(log_callback_fn fn, void *priv);\r
+extern int log_remove_callback(log_callback_fn fn, void *priv);\r
+\r
+char *alloc_printf(const char *fmt, va_list ap);\r
+\r
+extern int debug_level;\r
+\r
+/* Avoid fn call and building parameter list if we're not outputting the information.\r
+ * Matters on feeble CPUs for DEBUG/INFO statements that are involved frequently */\r
+\r
+#define DEBUG(expr ...) \\r
+       do { if (debug_level >= LOG_DEBUG) \\r
+               log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \\r
+       } while(0)\r
+\r
+#define INFO(expr ...) \\r
+       do { if (debug_level >= LOG_INFO) \\r
+               log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \\r
+       } while(0)\r
+\r
+#define WARNING(expr ...) \\r
+       do { \\r
+               log_printf (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr); \\r
+       } while(0)\r
+\r
+#define ERROR(expr ...) \\r
+       do { \\r
+               log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \\r
+       } while(0)\r
+\r
+#define USER(expr ...) \\r
+       do { \\r
+               log_printf (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr); \\r
+       } while(0)\r
+\r
+#define OUTPUT(expr ...) \\r
+       do { \\r
+               log_printf (LOG_OUTPUT, __FILE__, __LINE__, __FUNCTION__, expr); \\r
+       } while(0)\r
+\r
+\r
+/* general failures\r
+ * error codes < 100\r
+ */\r
+#define ERROR_OK                                       (0)\r
+#define ERROR_INVALID_ARGUMENTS                (-1)\r
+#define ERROR_NO_CONFIG_FILE           (-2)\r
+#define ERROR_BUF_TOO_SMALL                    (-3)\r
+\r
+#endif /* LOG_H */\r
index 1e717be898973a319766112f3fe29ed991fbf809..4232cb443979510540464ef81f5565066ab33d71 100644 (file)
@@ -113,13 +113,13 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[]
 \r
        if (help_flag)\r
        {\r
 \r
        if (help_flag)\r
        {\r
-               printf("Open On-Chip Debugger\n(c) 2005 by Dominic Rath\n\n");\r
-               printf("--help       | -h\tdisplay this help\n");\r
-               printf("--file       | -f\tuse configuration file <name>\n");\r
-               printf("--search     | -s\tdir to search for config files and scripts.\n");\r
-               printf("--debug      | -d\tset debug level <0-3>\n");\r
-               printf("--log_output | -l\tredirect log output to file <name>\n");\r
-               printf("--command    | -c\trun <command>\n");\r
+               OUTPUT("Open On-Chip Debugger\n(c) 2005 by Dominic Rath\n\n");\r
+               OUTPUT("--help       | -h\tdisplay this help\n");\r
+               OUTPUT("--file       | -f\tuse configuration file <name>\n");\r
+               OUTPUT("--search     | -s\tdir to search for config files and scripts.\n");\r
+               OUTPUT("--debug      | -d\tset debug level <0-3>\n");\r
+               OUTPUT("--log_output | -l\tredirect log output to file <name>\n");\r
+               OUTPUT("--command    | -c\trun <command>\n");\r
                exit(-1);\r
        }       \r
 \r
                exit(-1);\r
        }       \r
 \r
index b636d06d388f7f9aab5cba16f620a7517f309090..c2f877648f2acdf2ebf880ab62d54000a15c2bcd 100644 (file)
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-#define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "log.h"
-#include "types.h"
-#include "jtag.h"
-#include "configuration.h"
-#include "interpreter.h"
-#include "xsvf.h"
-#include "target.h"
-#include "flash.h"
-#include "nand.h"
-#include "pld.h"
-
-#include "command.h"
-#include "server.h"
-#include "telnet_server.h"
-#include "gdb_server.h"
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <strings.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-/* Give TELNET a way to find out what version this is */
-int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       command_print(cmd_ctx, OPENOCD_VERSION);
-
-       return ERROR_OK;
-}
-
-void exit_handler(void)
-{
-       /* close JTAG interface */
-       if (jtag && jtag->quit)
-               jtag->quit();
-}
-
-int main(int argc, char *argv[])
-{
-       /* initialize commandline interface */
-       command_context_t *cmd_ctx, *cfg_cmd_ctx;
-       cmd_ctx = command_init();
-
-       register_command(cmd_ctx, NULL, "version", handle_version_command,
-                                        COMMAND_EXEC, "show OpenOCD version");
-       
-       /* register subsystem commands */
-       server_register_commands(cmd_ctx);
-       telnet_register_commands(cmd_ctx);
-       gdb_register_commands(cmd_ctx);
-       log_register_commands(cmd_ctx);
-       jtag_register_commands(cmd_ctx);
-       interpreter_register_commands(cmd_ctx);
-       xsvf_register_commands(cmd_ctx);
-       target_register_commands(cmd_ctx);
-       flash_register_commands(cmd_ctx);
-       nand_register_commands(cmd_ctx);
-       pld_register_commands(cmd_ctx);
-       
-       if (log_init(cmd_ctx) != ERROR_OK)
-               return EXIT_FAILURE;
-       DEBUG("log init complete");
-       
-       printf( OPENOCD_VERSION );
-       printf( "\n$URL$\n");
-  
-       DEBUG( OPENOCD_VERSION );
+/***************************************************************************\r
+ *   Copyright (C) 2005 by Dominic Rath                                    *\r
+ *   Dominic.Rath@gmx.de                                                   *\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version.                                   *\r
+ *                                                                         *\r
+ *   This program is distributed in the hope that it will be useful,       *\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
+ *   GNU General Public License for more details.                          *\r
+ *                                                                         *\r
+ *   You should have received a copy of the GNU General Public License     *\r
+ *   along with this program; if not, write to the                         *\r
+ *   Free Software Foundation, Inc.,                                       *\r
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
+ ***************************************************************************/\r
+\r
+#define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "log.h"\r
+#include "types.h"\r
+#include "jtag.h"\r
+#include "configuration.h"\r
+#include "interpreter.h"\r
+#include "xsvf.h"\r
+#include "target.h"\r
+#include "flash.h"\r
+#include "nand.h"\r
+#include "pld.h"\r
+\r
+#include "command.h"\r
+#include "server.h"\r
+#include "telnet_server.h"\r
+#include "gdb_server.h"\r
+\r
+#include <sys/time.h>\r
+#include <sys/types.h>\r
+#include <strings.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+#include <errno.h>\r
+\r
+/* Give TELNET a way to find out what version this is */\r
+int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       command_print(cmd_ctx, OPENOCD_VERSION);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+void exit_handler(void)\r
+{\r
+       /* close JTAG interface */\r
+       if (jtag && jtag->quit)\r
+               jtag->quit();\r
+}\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+       /* initialize commandline interface */\r
+       command_context_t *cmd_ctx, *cfg_cmd_ctx;\r
+       cmd_ctx = command_init();\r
+\r
+       register_command(cmd_ctx, NULL, "version", handle_version_command,\r
+                                        COMMAND_EXEC, "show OpenOCD version");\r
+\r
+       /* register subsystem commands */\r
+       server_register_commands(cmd_ctx);\r
+       telnet_register_commands(cmd_ctx);\r
+       gdb_register_commands(cmd_ctx);\r
+       log_register_commands(cmd_ctx);\r
+       jtag_register_commands(cmd_ctx);\r
+       interpreter_register_commands(cmd_ctx);\r
+       xsvf_register_commands(cmd_ctx);\r
+       target_register_commands(cmd_ctx);\r
+       flash_register_commands(cmd_ctx);\r
+       nand_register_commands(cmd_ctx);\r
+       pld_register_commands(cmd_ctx);\r
+       \r
+       if (log_init(cmd_ctx) != ERROR_OK)\r
+               return EXIT_FAILURE;\r
+       DEBUG("log init complete");\r
+       \r
+       printf( OPENOCD_VERSION );\r
+       printf( "\n$URL$\n");\r
+  \r
+       DEBUG( OPENOCD_VERSION );\r
        DEBUG( "$URL$");\r
        DEBUG( "$URL$");\r
-
-       cfg_cmd_ctx = copy_command_context(cmd_ctx);
-       cfg_cmd_ctx->mode = COMMAND_CONFIG;
-       command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL);
-       
-       if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK)
-               return EXIT_FAILURE;
-
-       if (parse_config_file(cfg_cmd_ctx) != ERROR_OK)
-               return EXIT_FAILURE;
-       
-       command_done(cfg_cmd_ctx);
-
-       command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
-
-       atexit(exit_handler);
-
-       if (jtag_init(cmd_ctx) != ERROR_OK)
-               return EXIT_FAILURE;
-       DEBUG("jtag init complete");
-
-       if (target_init(cmd_ctx) != ERROR_OK)
-               return EXIT_FAILURE;
-       DEBUG("target init complete");
-
-       if (flash_init_drivers(cmd_ctx) != ERROR_OK)
-               return EXIT_FAILURE;
-       DEBUG("flash init complete");
-
-       if (nand_init(cmd_ctx) != ERROR_OK)
-               return EXIT_FAILURE;
-       DEBUG("NAND init complete");
-
-       if (pld_init(cmd_ctx) != ERROR_OK)
-               return EXIT_FAILURE;
-       DEBUG("pld init complete");
-
-       /* initialize tcp server */
-       server_init();
-       
-       /* initialize telnet subsystem */
-       telnet_init("Open On-Chip Debugger");
-       gdb_init();
-       
-       /* call any target resets */
-       if (target_init_reset(cmd_ctx) != ERROR_OK)
-               return EXIT_FAILURE;
-       DEBUG("target init reset complete");
-       
-       /* handle network connections */
-       server_loop(cmd_ctx);
-       
-       /* shut server down */
-       server_quit();
-       
-       /* free commandline interface */
-       command_done(cmd_ctx);
-       
-       return EXIT_SUCCESS;
-}
+\r
+       cfg_cmd_ctx = copy_command_context(cmd_ctx);\r
+       cfg_cmd_ctx->mode = COMMAND_CONFIG;\r
+       command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL);\r
+       \r
+       if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK)\r
+               return EXIT_FAILURE;\r
+\r
+       if (parse_config_file(cfg_cmd_ctx) != ERROR_OK)\r
+               return EXIT_FAILURE;\r
+       \r
+       command_done(cfg_cmd_ctx);\r
+\r
+       command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);\r
+\r
+       atexit(exit_handler);\r
+\r
+       if (jtag_init(cmd_ctx) != ERROR_OK)\r
+               return EXIT_FAILURE;\r
+       DEBUG("jtag init complete");\r
+\r
+       if (target_init(cmd_ctx) != ERROR_OK)\r
+               return EXIT_FAILURE;\r
+       DEBUG("target init complete");\r
+\r
+       if (flash_init_drivers(cmd_ctx) != ERROR_OK)\r
+               return EXIT_FAILURE;\r
+       DEBUG("flash init complete");\r
+\r
+       if (nand_init(cmd_ctx) != ERROR_OK)\r
+               return EXIT_FAILURE;\r
+       DEBUG("NAND init complete");\r
+\r
+       if (pld_init(cmd_ctx) != ERROR_OK)\r
+               return EXIT_FAILURE;\r
+       DEBUG("pld init complete");\r
+\r
+       /* initialize tcp server */\r
+       server_init();\r
+\r
+       /* initialize telnet subsystem */\r
+       telnet_init("Open On-Chip Debugger");\r
+       gdb_init();\r
+\r
+       /* call any target resets */\r
+       if (target_init_reset(cmd_ctx) != ERROR_OK)\r
+               return EXIT_FAILURE;\r
+       DEBUG("target init reset complete");\r
+\r
+       /* handle network connections */\r
+       server_loop(cmd_ctx);\r
+\r
+       /* shut server down */\r
+       server_quit();\r
+\r
+       /* free commandline interface */\r
+       command_done(cmd_ctx);\r
+\r
+       return EXIT_SUCCESS;\r
+}\r
index 49630579bc2394bada1363c5ba90b3e686d8006f..fa203e7a6ece8b29a015fa2bebe7646558f21e48 100644 (file)
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "gdb_server.h"
-
-#include "server.h"
-#include "log.h"
-#include "binarybuffer.h"
-#include "jtag.h"
-#include "breakpoints.h"
-#include "flash.h"
-#include "target_request.h"
-#include "configuration.h"
-
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#if 0
-#define _DEBUG_GDB_IO_
-#endif
-
-static unsigned short gdb_port;
-static const char *DIGITS = "0123456789abcdef";
-
-static void gdb_log_callback(void *priv, const char *file, int line, 
-               const char *function, const char *format, va_list args);
-
-enum gdb_detach_mode
-{
-       GDB_DETACH_RESUME,
-       GDB_DETACH_RESET,
-       GDB_DETACH_HALT,
-       GDB_DETACH_NOTHING
-};
-
-/* target behaviour on gdb detach */
-enum gdb_detach_mode detach_mode = GDB_DETACH_RESUME;
-
-/* set if we are sending a memory map to gdb
- * via qXfer:memory-map:read packet */
-int gdb_use_memory_map = 0;
-int gdb_flash_program = 0;
-
-/* if set, data aborts cause an error to be reported in memory read packets
- * see the code in gdb_read_memory_packet() for further explanations */
-int gdb_report_data_abort = 0;
-
-int gdb_last_signal(target_t *target)
-{
-       switch (target->debug_reason)
-       {
-               case DBG_REASON_DBGRQ:
-                       return 0x2; /* SIGINT */
-               case DBG_REASON_BREAKPOINT:
-               case DBG_REASON_WATCHPOINT:
-               case DBG_REASON_WPTANDBKPT:
-                       return 0x05; /* SIGTRAP */
-               case DBG_REASON_SINGLESTEP:
-                       return 0x05; /* SIGTRAP */
-               case DBG_REASON_NOTHALTED:
-                       return 0x0; /* no signal... shouldn't happen */
-               default:
-                       ERROR("BUG: undefined debug reason");
-                       exit(-1);
-       }
-}
-
-int gdb_get_char(connection_t *connection, int* next_char)
-{
-       gdb_connection_t *gdb_con = connection->priv;
-
-#ifdef _DEBUG_GDB_IO_
-       char *debug_buffer;
-#endif
-
-       if (gdb_con->buf_cnt-- > 0)
-       {
-               *next_char = *(gdb_con->buf_p++);
-               if (gdb_con->buf_cnt > 0)
-                       connection->input_pending = 1;
-               else
-                       connection->input_pending = 0;
-
-#ifdef _DEBUG_GDB_IO_
-               DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
-#endif
-
-               return ERROR_OK;
-       }
-
-       for (;;)
-       {
-#ifndef _WIN32
-               /* a non-blocking socket will block if there is 0 bytes available on the socket,
-                * but return with as many bytes as are available immediately
-                */
-               struct timeval tv;
-               fd_set read_fds;
-               
-               FD_ZERO(&read_fds);
-               FD_SET(connection->fd, &read_fds);
-               
-               tv.tv_sec = 1;
-               tv.tv_usec = 0;
-               if (select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0)
-               {
-                       /* This can typically be because a "monitor" command took too long
-                        * before printing any progress messages
-                        */
-                       return ERROR_GDB_TIMEOUT; 
-               }
-#endif
-               gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
-               if (gdb_con->buf_cnt > 0)
-               {
-                       break;
-               }
-               if (gdb_con->buf_cnt == 0)
-               {
-                       gdb_con->closed = 1;
-                       return ERROR_SERVER_REMOTE_CLOSED;
-               }
-
-#ifdef _WIN32
-               errno = WSAGetLastError();
-
-               switch(errno)
-               {
-                       case WSAEWOULDBLOCK:
-                               usleep(1000);
-                               break;
-                       case WSAECONNABORTED:
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       case WSAECONNRESET:
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       default:
-                               ERROR("read: %d", errno);
-                               exit(-1);
-               }
-#else
-               switch(errno)
-               {
-                       case EAGAIN:
-                               usleep(1000);
-                               break;
-                       case ECONNABORTED:
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       case ECONNRESET:
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       default:
-                               ERROR("read: %s", strerror(errno));
-                               return ERROR_SERVER_REMOTE_CLOSED;
-               }
-#endif
-       }
-
-#ifdef _DEBUG_GDB_IO_
-       debug_buffer = malloc(gdb_con->buf_cnt + 1);
-       memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt);
-       debug_buffer[gdb_con->buf_cnt] = 0;
-       DEBUG("received '%s'", debug_buffer);
-       free(debug_buffer);
-#endif
-
-       gdb_con->buf_p = gdb_con->buffer;
-       gdb_con->buf_cnt--;
-       *next_char = *(gdb_con->buf_p++);
-       if (gdb_con->buf_cnt > 0)
-               connection->input_pending = 1;
-       else
-               connection->input_pending = 0;  
-#ifdef _DEBUG_GDB_IO_
-       DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
-#endif
-
-       return ERROR_OK;
-}
-
-int gdb_putback_char(connection_t *connection, int last_char)
-{
-       gdb_connection_t *gdb_con = connection->priv;
-
-       if (gdb_con->buf_p > gdb_con->buffer)
-       {
-               *(--gdb_con->buf_p) = last_char;
-               gdb_con->buf_cnt++;
-       }
-       else
-       {
-               ERROR("BUG: couldn't put character back");      
-       }
-
-       return ERROR_OK;
-}
-
-/* The only way we can detect that the socket is closed is the first time
- * we write to it, we will fail. Subsequent write operations will
- * succeed. Shudder! */
-int gdb_write(connection_t *connection, void *data, int len)
-{
-       gdb_connection_t *gdb_con = connection->priv;
-       if (gdb_con->closed)
-               return ERROR_SERVER_REMOTE_CLOSED;
-
-       if (write_socket(connection->fd, data, len) == len)
-       {
-               return ERROR_OK;
-       }
-       gdb_con->closed = 1;
-       return ERROR_SERVER_REMOTE_CLOSED;
-}
-
-int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
-{
-       int i;
-       unsigned char my_checksum = 0;
-#ifdef _DEBUG_GDB_IO_
-       char *debug_buffer;
-#endif
-       int reply;
-       int retval;
-       gdb_connection_t *gdb_con = connection->priv;
-
-       for (i = 0; i < len; i++)
-               my_checksum += buffer[i];
-
-       while (1)
-       {
-#ifdef _DEBUG_GDB_IO_
-               debug_buffer = malloc(len + 1);
-               memcpy(debug_buffer, buffer, len);
-               debug_buffer[len] = 0;
-               DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum);
-               free(debug_buffer);
-#endif
-#if 0
-               char checksum[3];
-               gdb_write(connection, "$", 1);
-               if (len > 0)
-                       gdb_write(connection, buffer, len);
-               gdb_write(connection, "#", 1);
-               
-               snprintf(checksum, 3, "%2.2x", my_checksum);
-               
-               gdb_write(connection, checksum, 2);
-#else
-               void *allocated = NULL;
-               char stackAlloc[1024];
-               char *t = stackAlloc;
-               int totalLen = 1 + len + 1 + 2;
-               if (totalLen > sizeof(stackAlloc))
-               {
-                       allocated = malloc(totalLen);
-                       t = allocated;
-                       if (allocated == NULL)
-                       {
-                               ERROR("Ran out of memory trying to reply packet %d\n", totalLen);
-                               exit(-1);
-                       }
-               }
-               t[0] = '$';
-               memcpy(t + 1, buffer, len);
-               t[1 + len] = '#';
-               t[1 + len + 1] = DIGITS[(my_checksum >> 4) & 0xf];
-               t[1 + len + 2] = DIGITS[my_checksum & 0xf];
-               
-               gdb_write(connection, t, totalLen);
-               
-               if (allocated)
-               {
-                       free(allocated);
-               }
-#endif
-               if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
-                       return retval;
-
-               if (reply == '+')
-                       break;
-               else if (reply == '-')
-               {
-                       /* Stop sending output packets for now */
-                       log_setCallback(NULL, NULL);
-                       WARNING("negative reply, retrying");
-               }
-               else if (reply == 0x3)
-               {
-                       gdb_con->ctrl_c = 1;
-                       if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
-                               return retval;
-                       if (reply == '+')
-                               break;
-                       else if (reply == '-')
-                       {
-                               /* Stop sending output packets for now */
-                               log_setCallback(NULL, NULL);
-                               WARNING("negative reply, retrying");
-                       }
-                       else
-                       {
-                               ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       }
-               }
-               else
-               {
-                       ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);
-                       return ERROR_SERVER_REMOTE_CLOSED;
-               }
-       }
-       if (gdb_con->closed)
-               return ERROR_SERVER_REMOTE_CLOSED;
-
-       return ERROR_OK;
-}
-
-int gdb_put_packet(connection_t *connection, char *buffer, int len)
-{
-       gdb_connection_t *gdb_con = connection->priv;
-       gdb_con->busy = 1;
-       int retval = gdb_put_packet_inner(connection, buffer, len);
-       gdb_con->busy = 0;
-       return retval;
-}
-
-int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
-{
-       int character;
-       int count = 0;
-       int retval;
-       char checksum[3];
-       unsigned char my_checksum = 0;
-       gdb_connection_t *gdb_con = connection->priv;
-
-       while (1)
-       {
-               do
-               {
-                       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                               return retval;
-
-#ifdef _DEBUG_GDB_IO_
-                       DEBUG("character: '%c'", character);
-#endif
-
-                       switch (character)
-                       {
-                               case '$':
-                                       break;
-                               case '+':
-                                       WARNING("acknowledgment received, but no packet pending");
-                                       break;
-                               case '-':
-                                       WARNING("negative acknowledgment, but no packet pending");
-                                       break;
-                               case 0x3:
-                                       gdb_con->ctrl_c = 1;
-                                       *len = 0;
-                                       return ERROR_OK;
-                               default:
-                                       WARNING("ignoring character 0x%x", character);
-                                       break;
-                       }
-               } while (character != '$');
-
-               my_checksum = 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.
-                        * We need to leave at least 2 bytes in the buffer to have
-                        * gdb_get_char() update various bits and bobs correctly. 
-                        */
-                       if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len))
-                       {
-                               /* The compiler will struggle a bit with constant propagation and
-                                * aliasing, so we help it by showing that these values do not
-                                * change inside the loop 
-                                */ 
-                               int i;
-                               char *buf = gdb_con->buf_p;
-                               int run = gdb_con->buf_cnt - 2;
-                               i = 0;
-                               int done = 0;
-                               while (i < run)
-                               {
-                                       character = *buf++;
-                                       i++;
-                                       if (character == '#')
-                                       {
-                                               /* Danger! character can be '#' when esc is 
-                                                * used so we need an explicit boolean for done here.
-                                                */
-                                               done = 1;
-                                               break;
-                                       }
-                                       
-                                       if (character == '}')
-                                       {
-                                               /* data transmitted in binary mode (X packet)
-                                                * uses 0x7d as escape character */
-                                               my_checksum += character & 0xff;
-                                               character = *buf++;
-                                               i++;
-                                               my_checksum += character & 0xff;
-                                               buffer[count++] = (character ^ 0x20) & 0xff;
-                                       } else
-                                       {
-                                               my_checksum += character & 0xff;
-                                               buffer[count++] = character & 0xff;
-                                       }
-                               }
-                               gdb_con->buf_p += i;
-                               gdb_con->buf_cnt -= i;
-                               if (done) 
-                                       break;
-                       } 
-                       if (count > *len)
-                       {
-                               ERROR("packet buffer too small");
-                               return ERROR_GDB_BUFFER_TOO_SMALL;
-                       }
-                       
-                       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                               return retval;
-
-                       if (character == '#')
-                               break;
-
-                       if (character == '}')
-                       {
-                               /* data transmitted in binary mode (X packet)
-                                * uses 0x7d as escape character */
-                               my_checksum += character & 0xff;
-                               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                                       return retval;
-                               my_checksum += character & 0xff;
-                               buffer[count++] = (character ^ 0x20) & 0xff;
-                       }
-                       else
-                       {
-                               my_checksum += character & 0xff;
-                               buffer[count++] = character & 0xff;
-                       }
-
-               }
-
-               *len = count;
-
-               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                       return retval;
-               checksum[0] = character;
-               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                       return retval;
-               checksum[1] = character;
-               checksum[2] = 0;
-
-               if (my_checksum == strtoul(checksum, NULL, 16))
-               {
-                       gdb_write(connection, "+", 1);
-                       break;
-               }
-
-               WARNING("checksum error, requesting retransmission");
-               gdb_write(connection, "-", 1);
-       }
-       if (gdb_con->closed)
-               return ERROR_SERVER_REMOTE_CLOSED;
-
-       return ERROR_OK;
-}
-
-int gdb_get_packet(connection_t *connection, char *buffer, int *len)
-{
-       gdb_connection_t *gdb_con = connection->priv;
-       gdb_con->busy = 1;
-       int retval = gdb_get_packet_inner(connection, buffer, len);
-       gdb_con->busy = 0;
-       return retval;
-}
-       
-int gdb_output_con(connection_t *connection, char* line)
-{
-       char *hex_buffer;
-       int i, bin_size;
-
-       bin_size = strlen(line);
-
-       hex_buffer = malloc(bin_size*2 + 4);
-
-       hex_buffer[0] = 'O';
-       for (i=0; i<bin_size; i++)
-               snprintf(hex_buffer + 1 + i*2, 3, "%2.2x", line[i]);
-       hex_buffer[bin_size*2+1] = '0';
-       hex_buffer[bin_size*2+2] = 'a';
-       hex_buffer[bin_size*2+3] = 0x0;
-
-       gdb_put_packet(connection, hex_buffer, bin_size*2 + 3);
-
-       free(hex_buffer);
-       return ERROR_OK;
-}
-
-int gdb_output(struct command_context_s *context, char* line)
-{
-       /* this will be dumped to the log and also sent as an O packet if possible */
-       USER(line); 
-       return ERROR_OK;
-}
-
-int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)
-{
-       FILE *script;
-       struct command_context_s *cmd_ctx = priv;
-       
-       if (target->gdb_program_script)
-       {
-               script = open_file_from_path(cmd_ctx, target->gdb_program_script, "r");
-               if (!script)
-               {
-                       ERROR("couldn't open script file %s", target->gdb_program_script);
-                               return ERROR_OK;
-               }
-
-               INFO("executing gdb_program script '%s'", target->gdb_program_script);
-               command_run_file(cmd_ctx, script, COMMAND_EXEC);
-               fclose(script);
-               
-               jtag_execute_queue();
-       }
-       
-       return ERROR_OK;
-}
-
-int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
-{
-       connection_t *connection = priv;
-       gdb_connection_t *gdb_connection = connection->priv;
-       char sig_reply[4];
-       int signal;
-
-       switch (event)
-       {
-               case TARGET_EVENT_HALTED:
-                       /* In the GDB protocol when we are stepping or coninuing execution,
-                        * we have a lingering reply. Upon receiving a halted event 
-                        * when we have that lingering packet, we reply to the original
-                        * step or continue packet.
-                        * 
-                        * Executing monitor commands can bring the target in and
-                        * out of the running state so we'll see lots of TARGET_EVENT_XXX
-                        * that are to be ignored.
-                        */
-                       if (gdb_connection->frontend_state == TARGET_RUNNING)
-                       {
-                               /* stop forwarding log packets! */
-                               log_setCallback(NULL, NULL);
-                               
-                               if (gdb_connection->ctrl_c)
-                               {
-                                       signal = 0x2;
-                                       gdb_connection->ctrl_c = 0;
-                               }
-                               else
-                               {
-                                       signal = gdb_last_signal(target);
-                               }
-
-                               snprintf(sig_reply, 4, "T%2.2x", signal);
-                               gdb_put_packet(connection, sig_reply, 3);
-                               gdb_connection->frontend_state = TARGET_HALTED;
-                       }
-                       break;
-               case TARGET_EVENT_GDB_PROGRAM:
-                       gdb_program_handler(target, event, connection->cmd_ctx);
-                       break;
-               default:
-                       break;
-       }
-
-       return ERROR_OK;
-}
-
-int gdb_new_connection(connection_t *connection)
-{
-       gdb_connection_t *gdb_connection = malloc(sizeof(gdb_connection_t));
-       gdb_service_t *gdb_service = connection->service->priv;
-       int retval;
-       int initial_ack;
-
-       connection->priv = gdb_connection;
-
-       /* initialize gdb connection information */
-       gdb_connection->buf_p = gdb_connection->buffer;
-       gdb_connection->buf_cnt = 0;
-       gdb_connection->ctrl_c = 0;
-       gdb_connection->frontend_state = TARGET_HALTED;
-       gdb_connection->vflash_image = NULL;
-       gdb_connection->closed = 0;
-       gdb_connection->busy = 0;
-       
-       /* output goes through gdb connection */
-       command_set_output_handler(connection->cmd_ctx, gdb_output, connection);
-
-       /* register callback to be informed about target events */
-       target_register_event_callback(gdb_target_callback_event_handler, connection);  
-
-       /* a gdb session just attached, put the target in halt mode */
-       if (((retval = gdb_service->target->type->halt(gdb_service->target)) != ERROR_OK) &&
-                       (retval != ERROR_TARGET_ALREADY_HALTED))
-       {
-               ERROR("error(%d) when trying to halt target, falling back to \"reset halt\"", retval);
-               command_run_line(connection->cmd_ctx, "reset halt");
-       }
-
-       /* This will time out after 1 second */
-       command_run_line(connection->cmd_ctx, "wait_halt 1");
-
-       /* remove the initial ACK from the incoming buffer */
-       if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)
-               return retval;
-
-       if (initial_ack != '+')
-               gdb_putback_char(connection, initial_ack);
-
-       return ERROR_OK;
-}
-
-int gdb_connection_closed(connection_t *connection)
-{
-       gdb_service_t *gdb_service = connection->service->priv;
-       gdb_connection_t *gdb_connection = connection->priv;
-
-       /* see if an image built with vFlash commands is left */
-       if (gdb_connection->vflash_image)
-       {
-               image_close(gdb_connection->vflash_image);
-               free(gdb_connection->vflash_image);
-               gdb_connection->vflash_image = NULL;
-       }
-
-       /* if this connection registered a debug-message receiver delete it */
-       delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target);
-       
-       if (connection->priv)
-       {
-               free(connection->priv);
-               connection->priv = NULL;
-       }
-       else
-       {
-               ERROR("BUG: connection->priv == NULL");
-       }
-
-       target_unregister_event_callback(gdb_target_callback_event_handler, connection);
-       log_setCallback(NULL, NULL);
-
-       return ERROR_OK;
-}
-
-void gdb_send_error(connection_t *connection, u8 the_error)
-{
-       char err[4];
-       snprintf(err, 4, "E%2.2X", the_error );
-       gdb_put_packet(connection, err, 3);
-}
-
-int gdb_last_signal_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
-{
-       char sig_reply[4];
-       int signal;
-
-       signal = gdb_last_signal(target);
-
-       snprintf(sig_reply, 4, "S%2.2x", signal);
-       gdb_put_packet(connection, sig_reply, 3);
-
-       return ERROR_OK;
-}
-
-/* Convert register to string of bits. NB! The # of bits in the
- * register might be non-divisible by 8(a byte), in which
- * case an entire byte is shown. */
-void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg)
-{
-       int i;
-
-       u8 *buf;
-       int buf_len;
-       buf = reg->value;
-       buf_len = CEIL(reg->size, 8); 
-
-       if (target->endianness == TARGET_LITTLE_ENDIAN)
-       {
-               for (i = 0; i < buf_len; i++)
-               {
-                       tstr[i*2]   = DIGITS[(buf[i]>>4) & 0xf];
-                       tstr[i*2+1] = DIGITS[buf[i]&0xf];
-               }
-       }
-       else
-       {
-               for (i = 0; i < buf_len; i++)
-               {
-                       tstr[(buf_len-1-i)*2]   = DIGITS[(buf[i]>>4)&0xf];
-                       tstr[(buf_len-1-i)*2+1] = DIGITS[buf[i]&0xf];
-               }
-       }       
-}
-
-void gdb_target_to_str(target_t *target, char *tstr, char *str)
-{
-       int str_len = strlen(tstr);
-       int i;
-
-       if (str_len % 2)
-       {
-               ERROR("BUG: gdb value with uneven number of characters encountered");
-               exit(-1);
-       }
-
-       if (target->endianness == TARGET_LITTLE_ENDIAN)
-       {
-               for (i = 0; i < str_len; i+=2)
-               {
-                       str[str_len - i - 1] = tstr[i + 1];
-                       str[str_len - i - 2] = tstr[i];
-               }
-       }
-       else
-       {
-               for (i = 0; i < str_len; i++)
-               {
-                       str[i] = tstr[i];
-               }
-       }       
-}
-
-int gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
-{
-       reg_t **reg_list;
-       int reg_list_size;
-       int retval;
-       int reg_packet_size = 0;
-       char *reg_packet;
-       char *reg_packet_p;
-       int i;
-
-#ifdef _DEBUG_GDB_IO_
-       DEBUG("-");
-#endif
-
-       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
-       {
-               switch (retval)
-               {
-                       case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers but we're not halted, dropping connection");
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       default:
-                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
-                               ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
-                               exit(-1);
-               }
-       }
-
-       for (i = 0; i < reg_list_size; i++)
-       {
-               reg_packet_size += reg_list[i]->size;
-       }
-
-       reg_packet = malloc(CEIL(reg_packet_size, 8) * 2);
-       reg_packet_p = reg_packet;
-
-       for (i = 0; i < reg_list_size; i++)
-       {
-               gdb_str_to_target(target, reg_packet_p, reg_list[i]);
-               reg_packet_p += CEIL(reg_list[i]->size, 8) * 2;
-       }
-
-#ifdef _DEBUG_GDB_IO_
-       {
-               char *reg_packet_p;
-               reg_packet_p = strndup(reg_packet, CEIL(reg_packet_size, 8) * 2);
-               DEBUG("reg_packet: %s", reg_packet_p);
-               free(reg_packet_p);
-       }
-#endif
-
-       gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);
-       free(reg_packet);
-
-       free(reg_list);
-
-       return ERROR_OK;
-}
-
-int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       int i;
-       reg_t **reg_list;
-       int reg_list_size;
-       int retval;
-       char *packet_p;
-
-#ifdef _DEBUG_GDB_IO_
-       DEBUG("-");
-#endif
-
-       /* skip command character */
-       packet++;
-       packet_size--;
-
-       if (packet_size % 2)
-       {
-               WARNING("GDB set_registers packet with uneven characters received, dropping connection");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
-       {
-               switch (retval)
-               {
-                       case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb tried to registers but we're not halted, dropping connection");
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       default:
-                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
-                               ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
-                               exit(-1);
-               }
-       }
-
-       packet_p = packet;
-       for (i = 0; i < reg_list_size; i++)
-       {
-               u8 *bin_buf;
-               char *hex_buf;
-               reg_arch_type_t *arch_type;
-
-               /* convert from GDB-string (target-endian) to hex-string (big-endian) */
-               hex_buf = malloc(CEIL(reg_list[i]->size, 8) * 2);
-               gdb_target_to_str(target, packet_p, hex_buf);
-
-               /* convert hex-string to binary buffer */
-               bin_buf = malloc(CEIL(reg_list[i]->size, 8));
-               str_to_buf(hex_buf, CEIL(reg_list[i]->size, 8) * 2, bin_buf, reg_list[i]->size, 16);
-
-               /* get register arch_type, and call set method */       
-               arch_type = register_get_arch_type(reg_list[i]->arch_type);
-               if (arch_type == NULL)
-               {
-                       ERROR("BUG: encountered unregistered arch type");
-                       exit(-1);
-               }
-               arch_type->set(reg_list[i], bin_buf);
-
-               /* advance packet pointer */            
-               packet_p += (CEIL(reg_list[i]->size, 8) * 2);
-
-               free(bin_buf);
-               free(hex_buf);
-       }
-
-       /* free reg_t *reg_list[] array allocated by get_gdb_reg_list */ 
-       free(reg_list);
-
-       gdb_put_packet(connection, "OK", 2);
-
-       return ERROR_OK;
-}
-
-int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       char *reg_packet;
-       int reg_num = strtoul(packet + 1, NULL, 16);
-       reg_t **reg_list;
-       int reg_list_size;
-       int retval;
-
-#ifdef _DEBUG_GDB_IO_
-       DEBUG("-");
-#endif
-
-       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
-       {
-               switch (retval)
-               {
-                       case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb requested registers but we're not halted, dropping connection");
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       default:
-                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
-                               ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
-                               exit(-1);
-               }
-       }
-
-       if (reg_list_size <= reg_num)
-       {
-               ERROR("gdb requested a non-existing register");
-               exit(-1);
-       }
-
-       reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
-
-       gdb_str_to_target(target, reg_packet, reg_list[reg_num]);
-
-       gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2);
-
-       free(reg_list);
-       free(reg_packet);
-
-       return ERROR_OK;
-}
-
-int gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       char *separator;
-       char *hex_buf;
-       u8 *bin_buf;
-       int reg_num = strtoul(packet + 1, &separator, 16);
-       reg_t **reg_list;
-       int reg_list_size;
-       int retval;
-       reg_arch_type_t *arch_type;
-
-       DEBUG("-");
-
-       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
-       {
-               switch (retval)
-               {
-                       case ERROR_TARGET_NOT_HALTED:
-                               ERROR("gdb tried to set a register but we're not halted, dropping connection");
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       default:
-                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */
-                               ERROR("BUG: unexpected error returned by get_gdb_reg_list()");
-                               exit(-1);
-               }
-       }
-
-       if (reg_list_size < reg_num)
-       {
-               ERROR("gdb requested a non-existing register");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       if (*separator != '=')
-       {
-               ERROR("GDB 'set register packet', but no '=' following the register number");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       /* convert from GDB-string (target-endian) to hex-string (big-endian) */
-       hex_buf = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
-       gdb_target_to_str(target, separator + 1, hex_buf);
-
-       /* convert hex-string to binary buffer */
-       bin_buf = malloc(CEIL(reg_list[reg_num]->size, 8));
-       str_to_buf(hex_buf, CEIL(reg_list[reg_num]->size, 8) * 2, bin_buf, reg_list[reg_num]->size, 16);
-
-       /* get register arch_type, and call set method */       
-       arch_type = register_get_arch_type(reg_list[reg_num]->arch_type);
-       if (arch_type == NULL)
-       {
-               ERROR("BUG: encountered unregistered arch type");
-               exit(-1);
-       }
-       arch_type->set(reg_list[reg_num], bin_buf);
-
-       gdb_put_packet(connection, "OK", 2);
-
-       free(bin_buf);
-       free(hex_buf);
-       free(reg_list);
-
-       return ERROR_OK;
-}
-
-int gdb_memory_packet_error(connection_t *connection, int retval)
-{
-       switch (retval)
-       {
-               case ERROR_TARGET_NOT_HALTED:
-                       ERROR("gdb tried to read memory but we're not halted, dropping connection");
-                       return ERROR_SERVER_REMOTE_CLOSED;
-               case ERROR_TARGET_DATA_ABORT:
-                       gdb_send_error(connection, EIO);
-                       break;
-               case ERROR_TARGET_TRANSLATION_FAULT:
-                       gdb_send_error(connection, EFAULT);
-                       break;
-               case ERROR_TARGET_UNALIGNED_ACCESS:
-                       gdb_send_error(connection, EFAULT);
-                       break;
-               default:
-                       /* This could be that the target reset itself. */
-                       ERROR("unexpected error %i. Dropping connection.", retval);
-                       return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       return ERROR_OK;
-}
-
-/* We don't have to worry about the default 2 second timeout for GDB packets,
- * because GDB breaks up large memory reads into smaller reads.
- * 
- * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????
- */
-int gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       char *separator;
-       u32 addr = 0;
-       u32 len = 0;
-
-       u8 *buffer;
-       char *hex_buffer;
-
-       int retval = ERROR_OK;
-
-       /* skip command character */
-       packet++;
-
-       addr = strtoul(packet, &separator, 16);
-
-       if (*separator != ',')
-       {
-               ERROR("incomplete read memory packet received, dropping connection");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       len = strtoul(separator+1, NULL, 16);
-
-       buffer = malloc(len);
-
-       DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
-
-       retval = target_read_buffer(target, addr, len, buffer);
-
-       if ((retval == ERROR_TARGET_DATA_ABORT) && (!gdb_report_data_abort))
-       {
-               /* TODO : Here we have to lie and send back all zero's lest stack traces won't work.
-                * At some point this might be fixed in GDB, in which case this code can be removed.
-                * 
-                * OpenOCD developers are acutely aware of this problem, but there is nothing
-                * gained by involving the user in this problem that hopefully will get resolved
-                * eventually
-                * 
-                * http://sourceware.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=2395
-                *
-                * For now, the default is to fix up things to make current GDB versions work.
-                * This can be overwritten using the gdb_report_data_abort <'enable'|'disable'> command.
-                */
-               memset(buffer, 0, len);
-               retval = ERROR_OK;
-       }
-
-       if (retval == ERROR_OK)
-       {
-               hex_buffer = malloc(len * 2 + 1);
-
-               int i;
-               for (i = 0; i < len; i++)
-               {
-                       u8 t = buffer[i];
-                       hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf];
-                       hex_buffer[2 * i + 1] = DIGITS[t & 0xf];
-               }
-
-               gdb_put_packet(connection, hex_buffer, len * 2);
-
-               free(hex_buffer);
-       }
-       else
-       {
-               retval = gdb_memory_packet_error(connection, retval);
-       }
-
-       free(buffer);
-
-       return retval;
-}
-
-int gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       char *separator;
-       u32 addr = 0;
-       u32 len = 0;
-
-       u8 *buffer;
-
-       int i;
-       int retval;
-
-       /* skip command character */
-       packet++;
-
-       addr = strtoul(packet, &separator, 16);
-
-       if (*separator != ',')
-       {
-               ERROR("incomplete write memory packet received, dropping connection");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       len = strtoul(separator+1, &separator, 16);
-
-       if (*(separator++) != ':')
-       {
-               ERROR("incomplete write memory packet received, dropping connection");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       buffer = malloc(len);
-
-       DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
-
-       for (i=0; i<len; i++)
-       {
-               u32 tmp;
-               sscanf(separator + 2*i, "%2x", &tmp);
-               buffer[i] = tmp;
-       }
-
-       retval = target_write_buffer(target, addr, len, buffer);
-
-       if (retval == ERROR_OK)
-       {
-               gdb_put_packet(connection, "OK", 2);
-       }
-       else
-       {
-               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
-                       return retval; 
-       }
-
-       free(buffer);
-
-       return ERROR_OK;
-}
-
-int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       char *separator;
-       u32 addr = 0;
-       u32 len = 0;
-
-       int retval;
-
-       /* skip command character */
-       packet++;
-
-       addr = strtoul(packet, &separator, 16);
-
-       if (*separator != ',')
-       {
-               ERROR("incomplete write memory binary packet received, dropping connection");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       len = strtoul(separator+1, &separator, 16);
-
-       if (*(separator++) != ':')
-       {
-               ERROR("incomplete write memory binary packet received, dropping connection");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       retval = ERROR_OK;
-       if (len)
-       {
-               DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
-
-               retval = target_write_buffer(target, addr, len, (u8*)separator);
-       }
-
-       if (retval == ERROR_OK)
-       {
-               gdb_put_packet(connection, "OK", 2);
-       }
-       else
-       {
-               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
-                       return retval; 
-       }
-
-       return ERROR_OK;
-}
-
-void gdb_step_continue_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       int current = 0;
-       u32 address = 0x0;
-
-       DEBUG("-");
-
-       if (packet_size > 1)
-       {
-               packet[packet_size] = 0;
-               address = strtoul(packet + 1, NULL, 16);
-       }
-       else
-       {
-               current = 1;
-       }
-
-       if (packet[0] == 'c')
-       {
-               DEBUG("continue");
-               target->type->resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */
-       }
-       else if (packet[0] == 's')
-       {
-               DEBUG("step");
-               target->type->step(target, current, address, 0); /* step at current or address, don't handle breakpoints */
-       }
-}
-
-int gdb_bp_wp_packet_error(connection_t *connection, int retval)
-{
-       switch (retval)
-       {
-               case ERROR_TARGET_NOT_HALTED:
-                       ERROR("gdb tried to set a breakpoint but we're not halted, dropping connection");
-                       return ERROR_SERVER_REMOTE_CLOSED;
-                       break;
-               case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:
-                       gdb_send_error(connection, EBUSY);
-                       break;
-               default:
-                       ERROR("BUG: unexpected error %i", retval);
-                       exit(-1);
-       }
-
-       return ERROR_OK;
-}
-
-int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       int type;
-       enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */;
-       enum watchpoint_rw wp_type;
-       u32 address;
-       u32 size;
-       char *separator;
-       int retval;
-
-       DEBUG("-");
-
-       type = strtoul(packet + 1, &separator, 16);
-
-       if (type == 0)  /* memory breakpoint */
-               bp_type = BKPT_SOFT;
-       else if (type == 1) /* hardware breakpoint */
-               bp_type = BKPT_HARD;
-       else if (type == 2) /* write watchpoint */
-               wp_type = WPT_WRITE;
-       else if (type == 3) /* read watchpoint */
-               wp_type = WPT_READ;
-       else if (type == 4) /* access watchpoint */
-               wp_type = WPT_ACCESS;
-
-       if (*separator != ',')
-       {
-               ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       address = strtoul(separator+1, &separator, 16);
-
-       if (*separator != ',')
-       {
-               ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       size = strtoul(separator+1, &separator, 16);
-
-       switch (type)
-       {
-               case 0:
-               case 1:
-                       if (packet[0] == 'Z')
-                       {
-                               if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK)
-                               {
-                                       if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)
-                                               return retval;
-                               }
-                               else
-                               {
-                                       gdb_put_packet(connection, "OK", 2);
-                               }
-                       }
-                       else
-                       {
-                               breakpoint_remove(target, address);
-                               gdb_put_packet(connection, "OK", 2);
-                       }
-                       break;
-               case 2:
-               case 3:
-               case 4:
-               {
-                       if (packet[0] == 'Z')
-                       {
-                               if ((retval = watchpoint_add(target, address, size, type-2, 0, 0xffffffffu)) != ERROR_OK)
-                               {
-                                       if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)
-                                               return retval;
-                               }
-                               else
-                               {
-                                       gdb_put_packet(connection, "OK", 2);
-                               }
-                       }
-                       else
-                       {
-                               watchpoint_remove(target, address);
-                               gdb_put_packet(connection, "OK", 2);
-                       }
-                       break;
-               }
-               default:
-                       break;
-       }
-
-       return ERROR_OK;
-}
-
-/* print out a string and allocate more space as needed, mainly used for XML at this point */
-void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, ...)
-{
-       if (*retval != ERROR_OK)
-       {
-               return;
-       }
-       int first = 1;
-       
-       for (;;)
-       {
-               if ((*xml == NULL) || (!first))
-               {
-                       /* start by 0 to exercise all the code paths.
-                        * Need minimum 2 bytes to fit 1 char and 0 terminator. */
-                        
-                       *size = *size * 2 + 2;
-                       char *t = *xml;
-                       *xml = realloc(*xml, *size);
-                       if (*xml == NULL)
-                       {
-                               if (t)
-                                       free(t);
-                               *retval = ERROR_SERVER_REMOTE_CLOSED;
-                               return;
-                       }
-               }
-               
-           va_list ap;
-           int ret;
-           va_start(ap, fmt);
-           ret = vsnprintf(*xml + *pos, *size - *pos, fmt, ap);
-           va_end(ap);
-           if ((ret > 0) && ((ret + 1) < *size - *pos))
-           {
-               *pos += ret;
-               return;
-           }
-           /* there was just enough or not enough space, allocate more. */
-           first = 0;
-       }
-}
-
-static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len)
-{
-       char *separator;
-       
-       /* Extract and NUL-terminate the annex. */
-       *annex = buf;
-       while (*buf && *buf != ':')
-               buf++;
-       if (*buf == '\0')
-               return -1;
-       *buf++ = 0;
-       
-       /* After the read marker and annex, qXfer looks like a
-        * traditional 'm' packet. */
-       
-       *ofs = strtoul(buf, &separator, 16);
-
-       if (*separator != ',')
-               return -1;
-
-       *len = strtoul(separator+1, NULL, 16);
-       
-       return 0;
-}
-
-int gdb_calc_blocksize(flash_bank_t *bank)
-{
-       int i;
-       int block_size = 0xffffffff;
-       
-       /* loop through all sectors and return smallest sector size */
-       
-       for (i = 0; i < bank->num_sectors; i++)
-       {
-               if (bank->sectors[i].size < block_size)
-                       block_size = bank->sectors[i].size;
-       }
-       
-       return block_size;
-}
-
-int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       command_context_t *cmd_ctx = connection->cmd_ctx;
-       
-       if (strstr(packet, "qRcmd,"))
-       {
-               if (packet_size > 6)
-               {
-                       char *cmd;
-                       int i;
-                       cmd = malloc((packet_size - 6)/2 + 1);
-                       for (i=0; i < (packet_size - 6)/2; i++)
-                       {
-                               u32 tmp;
-                               sscanf(packet + 6 + 2*i, "%2x", &tmp);
-                               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);
-               }
-               gdb_put_packet(connection, "OK", 2);
-               return ERROR_OK;
-       }
-       else if (strstr(packet, "qCRC:"))
-       {
-               if (packet_size > 5)
-               {
-                       int retval;
-                       char gdb_reply[10];
-                       char *separator;
-                       u32 checksum;
-                       u32 addr = 0;
-                       u32 len = 0;
-                       
-                       /* skip command character */
-                       packet += 5;
-                       
-                       addr = strtoul(packet, &separator, 16);
-                       
-                       if (*separator != ',')
-                       {
-                               ERROR("incomplete read memory packet received, dropping connection");
-                               return ERROR_SERVER_REMOTE_CLOSED;
-                       }
-                       
-                       len = strtoul(separator + 1, NULL, 16);
-                       
-                       retval = target_checksum_memory(target, addr, len, &checksum);
-                       
-                       if (retval == ERROR_OK)
-                       {
-                               snprintf(gdb_reply, 10, "C%8.8x", checksum);
-                               gdb_put_packet(connection, gdb_reply, 9);
-                       }
-                       else
-                       {
-                               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)
-                                       return retval; 
-                       }
-                       
-                       return ERROR_OK;
-               }
-       }
-       else if (strstr(packet, "qSupported"))
-       {
-               /* we currently support packet size and qXfer:memory-map:read (if enabled)
-                * disable qXfer:features:read for the moment */
-               int retval = ERROR_OK;
-               char *buffer = NULL;
-               int pos = 0;
-               int size = 0;
-
-               xml_printf(&retval, &buffer, &pos, &size, 
-                               "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-",
-                               (GDB_BUFFER_SIZE - 1), gdb_use_memory_map == 1 ? '+' : '-');
-               
-               if (retval != ERROR_OK)
-               {
-                       gdb_send_error(connection, 01);
-                       return ERROR_OK;
-               }
-               
-               gdb_put_packet(connection, buffer, strlen(buffer));
-               free(buffer);
-               
-               return ERROR_OK;
-       }
-       else if (strstr(packet, "qXfer:memory-map:read::"))
-       {
-               /* We get away with only specifying flash here. Regions that are not
-                * specified are treated as if we provided no memory map(if not we 
-                * could detect the holes and mark them as RAM).
-                * Normally we only execute this code once, but no big deal if we
-                * have to regenerate it a couple of times. */
-                
-               flash_bank_t *p;
-               char *xml = NULL;
-               int size = 0;
-               int pos = 0;
-               int retval = ERROR_OK;
-               
-               int offset;
-               int length;
-               char *separator;
-               int blocksize;
-               
-               /* skip command character */
-               packet += 23;
-               
-               offset = strtoul(packet, &separator, 16);
-               length = strtoul(separator + 1, &separator, 16);
-               
-               xml_printf(&retval, &xml, &pos, &size, "<memory-map>\n");
-               
-               int i = 0;
-               for (;;)
-               {
-                       p = get_flash_bank_by_num(i);
-                       if (p == NULL)
-                               break;
-                       
-                       /* if device has uneven sector sizes, eg. str7, lpc
-                        * we pass the smallest sector size to gdb memory map */
-                       blocksize = gdb_calc_blocksize(p);
-                       
-                       xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" start=\"0x%x\" length=\"0x%x\">\n" \
-                               "<property name=\"blocksize\">0x%x</property>\n" \
-                               "</memory>\n", \
-                               p->base, p->size, blocksize);
-                       i++;
-               }
-               
-               xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n");
-
-               if (retval != ERROR_OK)
-               {
-                       gdb_send_error(connection, retval);
-                       return retval;
-               }
-                               
-               if (offset + length > pos)
-               {
-                       length = pos - offset;
-               }
-
-               char *t = malloc(length + 1);
-               t[0] = 'l';
-               memcpy(t + 1, xml + offset, length);
-               gdb_put_packet(connection, t, length + 1);
-               
-               free(t);
-               free(xml);
-               return ERROR_OK;
-       }
-       else if (strstr(packet, "qXfer:features:read:"))
-       {                
-               char *xml = NULL;
-               int size = 0;
-               int pos = 0;
-               int retval = ERROR_OK;
-               
-               int offset;
-               unsigned int length;
-               char *annex;
-               
-               /* skip command character */
-               packet += 20;
-               
-               if (decode_xfer_read(packet, &annex, &offset, &length) < 0)
-               {
-                       gdb_send_error(connection, 01);
-                       return ERROR_OK;
-               }
-               
-               if (strcmp(annex, "target.xml") != 0)
-               {
-                       gdb_send_error(connection, 01);
-                       return ERROR_OK;
-               }
-                               
-               xml_printf(&retval, &xml, &pos, &size, \
-                       "l<target version=\"1.0\">\n<architecture>arm</architecture>\n</target>\n");
-                                       
-               if (retval != ERROR_OK)
-               {
-                       gdb_send_error(connection, retval);
-                       return retval;
-               }
-               
-               gdb_put_packet(connection, xml, strlen(xml) + 1);
-               
-               free(xml);
-               return ERROR_OK;
-       }
-       
-       gdb_put_packet(connection, "", 0);
-       return ERROR_OK;
-}
-
-int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
-{
-       gdb_connection_t *gdb_connection = connection->priv;
-       gdb_service_t *gdb_service = connection->service->priv;
-       int result;
-
-       /* if flash programming disabled - send a empty reply */
-       
-       if (gdb_flash_program == 0)
-       {
-               gdb_put_packet(connection, "", 0);
-               return ERROR_OK;
-       }
-       
-       if (strstr(packet, "vFlashErase:"))
-       {
-               unsigned long addr;
-               unsigned long length;
-       
-               char *parse = packet + 12;
-               if (*parse == '\0')
-               {
-                       ERROR("incomplete vFlashErase packet received, dropping connection");
-                       return ERROR_SERVER_REMOTE_CLOSED;
-               }
-
-               addr = strtoul(parse, &parse, 16);
-
-               if (*(parse++) != ',' || *parse == '\0')
-               {
-                       ERROR("incomplete vFlashErase packet received, dropping connection");
-                       return ERROR_SERVER_REMOTE_CLOSED;
-               }
-
-               length = strtoul(parse, &parse, 16);
-
-               if (*parse != '\0')
-               {
-                       ERROR("incomplete vFlashErase packet received, dropping connection");
-                       return ERROR_SERVER_REMOTE_CLOSED;
-               }
-               
-               /* assume all sectors need erasing - stops any problems
-                * when flash_write is called multiple times */
-               flash_set_dirty();
-               
-               /* perform any target specific operations before the erase */
-               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);
-               
-               /* perform erase */
-               if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)
-               {
-                       /* GDB doesn't evaluate the actual error number returned,
-                        * treat a failed erase as an I/O error
-                        */
-                       gdb_send_error(connection, EIO);
-                       ERROR("flash_erase returned %i", result);
-               }
-               else
-                       gdb_put_packet(connection, "OK", 2);
-               
-               return ERROR_OK;
-       }
-
-       if (strstr(packet, "vFlashWrite:"))
-       {
-               unsigned long addr;
-               unsigned long length;
-               char *parse = packet + 12;
-
-               if (*parse == '\0')
-               {
-                       ERROR("incomplete vFlashErase packet received, dropping connection");
-                       return ERROR_SERVER_REMOTE_CLOSED;
-               }
-               addr = strtoul(parse, &parse, 16);
-               if (*(parse++) != ':')
-               {
-                       ERROR("incomplete vFlashErase packet received, dropping connection");
-                       return ERROR_SERVER_REMOTE_CLOSED;
-               }
-               length = packet_size - (parse - packet);
-               
-               /* create a new image if there isn't already one */
-               if (gdb_connection->vflash_image == NULL)
-               {
-                       gdb_connection->vflash_image = malloc(sizeof(image_t));
-                       image_open(gdb_connection->vflash_image, "", "build");
-               }
-
-               /* create new section with content from packet buffer */
-               image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse);
-
-               gdb_put_packet(connection, "OK", 2);
-
-               return ERROR_OK;
-       }
-
-       if (!strcmp(packet, "vFlashDone"))
-       {
-               u32 written;
-
-               /* process the flashing buffer. No need to erase as GDB
-                * always issues a vFlashErase first. */
-               if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0)) != ERROR_OK)
-               {
-                       if (result == ERROR_FLASH_DST_OUT_OF_BANK)
-                               gdb_put_packet(connection, "E.memtype", 9);
-                       else
-                               gdb_send_error(connection, EIO);
-                       }
-               else
-               {
-                       DEBUG("wrote %u bytes from vFlash image to flash", written);
-                       gdb_put_packet(connection, "OK", 2);
-               }
-               
-               image_close(gdb_connection->vflash_image);
-               free(gdb_connection->vflash_image);
-               gdb_connection->vflash_image = NULL;
-               
-               return ERROR_OK;
-       }
-
-       gdb_put_packet(connection, "", 0);
-       return ERROR_OK;
-}
-
-int gdb_detach(connection_t *connection, target_t *target)
-{
-       switch( detach_mode )
-       {
-               case GDB_DETACH_RESUME:
-                       target->type->resume(target, 1, 0, 1, 0);
-                       break;
-               
-               case GDB_DETACH_RESET:
-                       target_process_reset(connection->cmd_ctx);
-                       break;
-               
-               case GDB_DETACH_HALT:
-                       target->type->halt(target);
-                       break;
-               
-               case GDB_DETACH_NOTHING:
-                       break;
-       }
-       
-       gdb_put_packet(connection, "OK", 2);
-       
-       return ERROR_OK;
-}
-
-static void gdb_log_callback(void *priv, const char *file, int line, 
-               const char *function, const char *format, va_list args)
-{
-       connection_t *connection = priv;
-       gdb_connection_t *gdb_con = connection->priv;
-       
-       if (gdb_con->busy)
-       {
-               /* do not reply this using the O packet */
-               return;
-       }
-
-       char *t = allocPrintf(format, args);
-       if (t == NULL)
-               return;
-       
-       gdb_output_con(connection, t); 
-       
-       free(t);
-}
-
-int gdb_input_inner(connection_t *connection)
-{
-       gdb_service_t *gdb_service = connection->service->priv;
-       target_t *target = gdb_service->target;
-       char packet[GDB_BUFFER_SIZE];
-       int packet_size;
-       int retval;
-       gdb_connection_t *gdb_con = connection->priv;
-       static int extended_protocol = 0;
-
-       /* drain input buffer */
-       do
-       {
-               packet_size = GDB_BUFFER_SIZE-1;
-               if ((retval = gdb_get_packet(connection, packet, &packet_size)) != ERROR_OK)
-               {
-                       return retval;
-               }
-
-               /* terminate with zero */
-               packet[packet_size] = 0;
-
-               DEBUG("received packet: '%s'", packet);
-
-               if (packet_size > 0)
-               {
-                       retval = ERROR_OK;
-                       switch (packet[0])
-                       {
-                               case 'H':
-                                       /* Hct... -- set thread 
-                                        * we don't have threads, send empty reply */
-                                       gdb_put_packet(connection, NULL, 0);
-                                       break;
-                               case 'q':
-                                       retval = gdb_query_packet(connection, target, packet, packet_size);
-                                       break;
-                               case 'g':
-                                       retval = gdb_get_registers_packet(connection, target, packet, packet_size);
-                                       break;
-                               case 'G':
-                                       retval = gdb_set_registers_packet(connection, target, packet, packet_size);
-                                       break;
-                               case 'p':
-                                       retval = gdb_get_register_packet(connection, target, packet, packet_size);
-                                       break;
-                               case 'P':
-                                       retval = gdb_set_register_packet(connection, target, packet, packet_size);
-                                       break;
-                               case 'm':
-                                       retval = gdb_read_memory_packet(connection, target, packet, packet_size);
-                                       break;
-                               case 'M':
-                                       retval = gdb_write_memory_packet(connection, target, packet, packet_size);
-                                       break;
-                               case 'z':
-                               case 'Z':
-                                       retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);
-                                       break;
-                               case '?':
-                                       gdb_last_signal_packet(connection, target, packet, packet_size);
-                                       break;
-                               case 'c':
-                               case 's':
-                                       {
-                                       /* We're running/stepping, in which case we can 
-                                        * forward log output until the target is halted */
-                                               gdb_connection_t *gdb_con = connection->priv;
-                                               gdb_con->frontend_state = TARGET_RUNNING;
-                                               log_setCallback(gdb_log_callback, connection);
-                                               gdb_step_continue_packet(connection, target, packet, packet_size);
-                                       }
-                                       break;
-                               case 'v':
-                                       retval = gdb_v_packet(connection, target, packet, packet_size);
-                                       break;
-                               case 'D':
-                                       retval = gdb_detach(connection, target);
-                                       extended_protocol = 0;
-                                       break;
-                               case 'X':
-                                       if ((retval = gdb_write_memory_binary_packet(connection, target, packet, packet_size)) != ERROR_OK)
-                                               return retval;
-                                       break;
-                               case 'k':
-                                       if (extended_protocol != 0)
-                                               break;
-                                       gdb_put_packet(connection, "OK", 2);
-                                       return ERROR_SERVER_REMOTE_CLOSED;
-                               case '!':
-                                       /* handle extended remote protocol */
-                                       extended_protocol = 1;
-                                       gdb_put_packet(connection, "OK", 2);
-                                       break;
-                               case 'R':
-                                       /* handle extended restart packet */
-                                       target_process_reset(connection->cmd_ctx);
-                                       break;
-                               default:
-                                       /* ignore unkown packets */
-                                       DEBUG("ignoring 0x%2.2x packet", packet[0]);
-                                       gdb_put_packet(connection, NULL, 0);
-                                       break;
-                       }
-
-                       /* if a packet handler returned an error, exit input loop */
-                       if (retval != ERROR_OK)
-                               return retval;
-               }
-
-               if (gdb_con->ctrl_c)
-               {
-                       if (target->state == TARGET_RUNNING)
-                       {
-                               target->type->halt(target);
-                               gdb_con->ctrl_c = 0;
-                       }
-               }
-
-       } while (gdb_con->buf_cnt > 0);
-
-       return ERROR_OK;
-}
-
-int gdb_input(connection_t *connection)
-{
-       int retval = gdb_input_inner(connection);
-       if (retval == ERROR_SERVER_REMOTE_CLOSED)
-               return retval;
-       /* we'll recover from any other errors(e.g. temporary timeouts, etc.) */
-       return ERROR_OK;
-}
-
-int gdb_init()
-{
-       gdb_service_t *gdb_service;
-       target_t *target = targets;
-       int i = 0;
-
-       if (!target)
-       {
-               WARNING("no gdb ports allocated as no target has been specified");
-               return ERROR_OK;
-       }
-
-       if (gdb_port == 0)
-       {
-               WARNING("no gdb port specified, using default port 3333");
-               gdb_port = 3333;
-       }
-
-       while (target)
-       {
-               char service_name[8];
-
-               snprintf(service_name, 8, "gdb-%2.2i", i);
-
-               gdb_service = malloc(sizeof(gdb_service_t));
-               gdb_service->target = target;
-
-               add_service("gdb", CONNECTION_GDB, gdb_port + i, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
-
-               DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i);
-
-               i++;
-               target = target->next;
-       }
-
-       return ERROR_OK;
-}
-
-/* daemon configuration command gdb_port */
-int handle_gdb_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       if (argc == 0)
-               return ERROR_OK;
-
-       /* only if the port wasn't overwritten by cmdline */
-       if (gdb_port == 0)
-               gdb_port = strtoul(args[0], NULL, 0);
-
-       return ERROR_OK;
-}
-
-int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       if (argc == 1)
-       {
-               if (strcmp(args[0], "resume") == 0)
-               {
-                       detach_mode = GDB_DETACH_RESUME;
-                       return ERROR_OK;
-               }
-               else if (strcmp(args[0], "reset") == 0)
-               {
-                       detach_mode = GDB_DETACH_RESET;
-                       return ERROR_OK;
-               }
-               else if (strcmp(args[0], "halt") == 0)
-               {
-                       detach_mode = GDB_DETACH_HALT;
-                       return ERROR_OK;
-               }
-               else if (strcmp(args[0], "nothing") == 0)
-               {
-                       detach_mode = GDB_DETACH_NOTHING;
-                       return ERROR_OK;
-               }
-       }
-       
-       WARNING("invalid gdb_detach configuration directive: %s", args[0]);
-       return ERROR_OK;
-}
-
-int handle_gdb_memory_map_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       if (argc == 1)
-       {
-               if (strcmp(args[0], "enable") == 0)
-               {
-                       gdb_use_memory_map = 1;
-                       return ERROR_OK;
-               }
-               else if (strcmp(args[0], "disable") == 0)
-               {
-                       gdb_use_memory_map = 0;
-                       return ERROR_OK;
-               }
-       }
-       
-       WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);
-       return ERROR_OK;
-}
-
-int handle_gdb_flash_program_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       if (argc == 1)
-       {
-               if (strcmp(args[0], "enable") == 0)
-               {
-                       gdb_flash_program = 1;
-                       return ERROR_OK;
-               }
-               else if (strcmp(args[0], "disable") == 0)
-               {
-                       gdb_flash_program = 0;
-                       return ERROR_OK;
-               }
-       }
-       
-       WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);
-       return ERROR_OK;
-}
-
-int handle_gdb_report_data_abort_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       if (argc == 1)
-       {
-               if (strcmp(args[0], "enable") == 0)
-               {
-                       gdb_report_data_abort = 1;
-                       return ERROR_OK;
-               }
-               else if (strcmp(args[0], "disable") == 0)
-               {
-                       gdb_report_data_abort = 0;
-                       return ERROR_OK;
-               }
-       }
-       
-       WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]);
-       return ERROR_OK;
-}
-
-int gdb_register_commands(command_context_t *command_context)
-{
-       register_command(command_context, NULL, "gdb_port", handle_gdb_port_command,
-                       COMMAND_CONFIG, "");
-       register_command(command_context, NULL, "gdb_detach", handle_gdb_detach_command,
-                       COMMAND_CONFIG, "");
-       register_command(command_context, NULL, "gdb_memory_map", handle_gdb_memory_map_command,
-                       COMMAND_CONFIG, "");
-       register_command(command_context, NULL, "gdb_flash_program", handle_gdb_flash_program_command,
-                       COMMAND_CONFIG, "");
-       register_command(command_context, NULL, "gdb_report_data_abort", handle_gdb_report_data_abort_command,
-                       COMMAND_CONFIG, "");
-       return ERROR_OK;
-}
+/***************************************************************************\r
+ *   Copyright (C) 2005 by Dominic Rath                                    *\r
+ *   Dominic.Rath@gmx.de                                                   *\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version.                                   *\r
+ *                                                                         *\r
+ *   This program is distributed in the hope that it will be useful,       *\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
+ *   GNU General Public License for more details.                          *\r
+ *                                                                         *\r
+ *   You should have received a copy of the GNU General Public License     *\r
+ *   along with this program; if not, write to the                         *\r
+ *   Free Software Foundation, Inc.,                                       *\r
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
+ ***************************************************************************/\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "replacements.h"\r
+\r
+#include "gdb_server.h"\r
+\r
+#include "server.h"\r
+#include "log.h"\r
+#include "binarybuffer.h"\r
+#include "jtag.h"\r
+#include "breakpoints.h"\r
+#include "flash.h"\r
+#include "target_request.h"\r
+#include "configuration.h"\r
+\r
+#include <string.h>\r
+#include <errno.h>\r
+#include <unistd.h>\r
+#include <stdlib.h>\r
+\r
+#if 0\r
+#define _DEBUG_GDB_IO_\r
+#endif\r
+\r
+static unsigned short gdb_port;\r
+static const char *DIGITS = "0123456789abcdef";\r
+\r
+static void gdb_log_callback(void *priv, const char *file, int line, \r
+               const char *function, const char *format, va_list args);\r
+\r
+enum gdb_detach_mode\r
+{\r
+       GDB_DETACH_RESUME,\r
+       GDB_DETACH_RESET,\r
+       GDB_DETACH_HALT,\r
+       GDB_DETACH_NOTHING\r
+};\r
+\r
+/* target behaviour on gdb detach */\r
+enum gdb_detach_mode detach_mode = GDB_DETACH_RESUME;\r
+\r
+/* set if we are sending a memory map to gdb\r
+ * via qXfer:memory-map:read packet */\r
+int gdb_use_memory_map = 0;\r
+int gdb_flash_program = 0;\r
+\r
+/* if set, data aborts cause an error to be reported in memory read packets\r
+ * see the code in gdb_read_memory_packet() for further explanations */\r
+int gdb_report_data_abort = 0;\r
+\r
+int gdb_last_signal(target_t *target)\r
+{\r
+       switch (target->debug_reason)\r
+       {\r
+               case DBG_REASON_DBGRQ:\r
+                       return 0x2; /* SIGINT */\r
+               case DBG_REASON_BREAKPOINT:\r
+               case DBG_REASON_WATCHPOINT:\r
+               case DBG_REASON_WPTANDBKPT:\r
+                       return 0x05; /* SIGTRAP */\r
+               case DBG_REASON_SINGLESTEP:\r
+                       return 0x05; /* SIGTRAP */\r
+               case DBG_REASON_NOTHALTED:\r
+                       return 0x0; /* no signal... shouldn't happen */\r
+               default:\r
+                       ERROR("BUG: undefined debug reason");\r
+                       exit(-1);\r
+       }\r
+}\r
+\r
+int gdb_get_char(connection_t *connection, int* next_char)\r
+{\r
+       gdb_connection_t *gdb_con = connection->priv;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+       char *debug_buffer;\r
+#endif\r
+\r
+       if (gdb_con->buf_cnt-- > 0)\r
+       {\r
+               *next_char = *(gdb_con->buf_p++);\r
+               if (gdb_con->buf_cnt > 0)\r
+                       connection->input_pending = 1;\r
+               else\r
+                       connection->input_pending = 0;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+               DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);\r
+#endif\r
+\r
+               return ERROR_OK;\r
+       }\r
+\r
+       for (;;)\r
+       {\r
+#ifndef _WIN32\r
+               /* a non-blocking socket will block if there is 0 bytes available on the socket,\r
+                * but return with as many bytes as are available immediately\r
+                */\r
+               struct timeval tv;\r
+               fd_set read_fds;\r
+               \r
+               FD_ZERO(&read_fds);\r
+               FD_SET(connection->fd, &read_fds);\r
+               \r
+               tv.tv_sec = 1;\r
+               tv.tv_usec = 0;\r
+               if (select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0)\r
+               {\r
+                       /* This can typically be because a "monitor" command took too long\r
+                        * before printing any progress messages\r
+                        */\r
+                       return ERROR_GDB_TIMEOUT; \r
+               }\r
+#endif\r
+               gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);\r
+               if (gdb_con->buf_cnt > 0)\r
+               {\r
+                       break;\r
+               }\r
+               if (gdb_con->buf_cnt == 0)\r
+               {\r
+                       gdb_con->closed = 1;\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+               }\r
+\r
+#ifdef _WIN32\r
+               errno = WSAGetLastError();\r
+\r
+               switch(errno)\r
+               {\r
+                       case WSAEWOULDBLOCK:\r
+                               usleep(1000);\r
+                               break;\r
+                       case WSAECONNABORTED:\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       case WSAECONNRESET:\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       default:\r
+                               ERROR("read: %d", errno);\r
+                               exit(-1);\r
+               }\r
+#else\r
+               switch(errno)\r
+               {\r
+                       case EAGAIN:\r
+                               usleep(1000);\r
+                               break;\r
+                       case ECONNABORTED:\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       case ECONNRESET:\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       default:\r
+                               ERROR("read: %s", strerror(errno));\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+               }\r
+#endif\r
+       }\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+       debug_buffer = malloc(gdb_con->buf_cnt + 1);\r
+       memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt);\r
+       debug_buffer[gdb_con->buf_cnt] = 0;\r
+       DEBUG("received '%s'", debug_buffer);\r
+       free(debug_buffer);\r
+#endif\r
+\r
+       gdb_con->buf_p = gdb_con->buffer;\r
+       gdb_con->buf_cnt--;\r
+       *next_char = *(gdb_con->buf_p++);\r
+       if (gdb_con->buf_cnt > 0)\r
+               connection->input_pending = 1;\r
+       else\r
+               connection->input_pending = 0;  \r
+#ifdef _DEBUG_GDB_IO_\r
+       DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);\r
+#endif\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_putback_char(connection_t *connection, int last_char)\r
+{\r
+       gdb_connection_t *gdb_con = connection->priv;\r
+\r
+       if (gdb_con->buf_p > gdb_con->buffer)\r
+       {\r
+               *(--gdb_con->buf_p) = last_char;\r
+               gdb_con->buf_cnt++;\r
+       }\r
+       else\r
+       {\r
+               ERROR("BUG: couldn't put character back");      \r
+       }\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+/* The only way we can detect that the socket is closed is the first time\r
+ * we write to it, we will fail. Subsequent write operations will\r
+ * succeed. Shudder! */\r
+int gdb_write(connection_t *connection, void *data, int len)\r
+{\r
+       gdb_connection_t *gdb_con = connection->priv;\r
+       if (gdb_con->closed)\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+\r
+       if (write_socket(connection->fd, data, len) == len)\r
+       {\r
+               return ERROR_OK;\r
+       }\r
+       gdb_con->closed = 1;\r
+       return ERROR_SERVER_REMOTE_CLOSED;\r
+}\r
+\r
+int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)\r
+{\r
+       int i;\r
+       unsigned char my_checksum = 0;\r
+#ifdef _DEBUG_GDB_IO_\r
+       char *debug_buffer;\r
+#endif\r
+       int reply;\r
+       int retval;\r
+       gdb_connection_t *gdb_con = connection->priv;\r
+\r
+       for (i = 0; i < len; i++)\r
+               my_checksum += buffer[i];\r
+\r
+       while (1)\r
+       {\r
+#ifdef _DEBUG_GDB_IO_\r
+               debug_buffer = malloc(len + 1);\r
+               memcpy(debug_buffer, buffer, len);\r
+               debug_buffer[len] = 0;\r
+               DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum);\r
+               free(debug_buffer);\r
+#endif\r
+#if 0\r
+               char checksum[3];\r
+               gdb_write(connection, "$", 1);\r
+               if (len > 0)\r
+                       gdb_write(connection, buffer, len);\r
+               gdb_write(connection, "#", 1);\r
+               \r
+               snprintf(checksum, 3, "%2.2x", my_checksum);\r
+               \r
+               gdb_write(connection, checksum, 2);\r
+#else\r
+               void *allocated = NULL;\r
+               char stackAlloc[1024];\r
+               char *t = stackAlloc;\r
+               int totalLen = 1 + len + 1 + 2;\r
+               if (totalLen > sizeof(stackAlloc))\r
+               {\r
+                       allocated = malloc(totalLen);\r
+                       t = allocated;\r
+                       if (allocated == NULL)\r
+                       {\r
+                               ERROR("Ran out of memory trying to reply packet %d\n", totalLen);\r
+                               exit(-1);\r
+                       }\r
+               }\r
+               t[0] = '$';\r
+               memcpy(t + 1, buffer, len);\r
+               t[1 + len] = '#';\r
+               t[1 + len + 1] = DIGITS[(my_checksum >> 4) & 0xf];\r
+               t[1 + len + 2] = DIGITS[my_checksum & 0xf];\r
+               \r
+               gdb_write(connection, t, totalLen);\r
+               \r
+               if (allocated)\r
+               {\r
+                       free(allocated);\r
+               }\r
+#endif\r
+               if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)\r
+                       return retval;\r
+\r
+               if (reply == '+')\r
+                       break;\r
+               else if (reply == '-')\r
+               {\r
+                       /* Stop sending output packets for now */\r
+                       log_remove_callback(gdb_log_callback, connection);\r
+                       WARNING("negative reply, retrying");\r
+               }\r
+               else if (reply == 0x3)\r
+               {\r
+                       gdb_con->ctrl_c = 1;\r
+                       if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)\r
+                               return retval;\r
+                       if (reply == '+')\r
+                               break;\r
+                       else if (reply == '-')\r
+                       {\r
+                               /* Stop sending output packets for now */\r
+                               log_remove_callback(gdb_log_callback, connection);\r
+                               WARNING("negative reply, retrying");\r
+                       }\r
+                       else\r
+                       {\r
+                               ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       ERROR("unknown character 0x%2.2x in reply, dropping connection", reply);\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+               }\r
+       }\r
+       if (gdb_con->closed)\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_put_packet(connection_t *connection, char *buffer, int len)\r
+{\r
+       gdb_connection_t *gdb_con = connection->priv;\r
+       gdb_con->busy = 1;\r
+       int retval = gdb_put_packet_inner(connection, buffer, len);\r
+       gdb_con->busy = 0;\r
+       return retval;\r
+}\r
+\r
+int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)\r
+{\r
+       int character;\r
+       int count = 0;\r
+       int retval;\r
+       char checksum[3];\r
+       unsigned char my_checksum = 0;\r
+       gdb_connection_t *gdb_con = connection->priv;\r
+\r
+       while (1)\r
+       {\r
+               do\r
+               {\r
+                       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+                               return retval;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+                       DEBUG("character: '%c'", character);\r
+#endif\r
+\r
+                       switch (character)\r
+                       {\r
+                               case '$':\r
+                                       break;\r
+                               case '+':\r
+                                       WARNING("acknowledgment received, but no packet pending");\r
+                                       break;\r
+                               case '-':\r
+                                       WARNING("negative acknowledgment, but no packet pending");\r
+                                       break;\r
+                               case 0x3:\r
+                                       gdb_con->ctrl_c = 1;\r
+                                       *len = 0;\r
+                                       return ERROR_OK;\r
+                               default:\r
+                                       WARNING("ignoring character 0x%x", character);\r
+                                       break;\r
+                       }\r
+               } while (character != '$');\r
+\r
+               my_checksum = 0;\r
+               \r
+               count = 0;\r
+               gdb_connection_t *gdb_con = connection->priv;\r
+               for (;;)\r
+               {\r
+                       /* The common case is that we have an entire packet with no escape chars.\r
+                        * We need to leave at least 2 bytes in the buffer to have\r
+                        * gdb_get_char() update various bits and bobs correctly. \r
+                        */\r
+                       if ((gdb_con->buf_cnt > 2) && ((gdb_con->buf_cnt+count) < *len))\r
+                       {\r
+                               /* The compiler will struggle a bit with constant propagation and\r
+                                * aliasing, so we help it by showing that these values do not\r
+                                * change inside the loop \r
+                                */ \r
+                               int i;\r
+                               char *buf = gdb_con->buf_p;\r
+                               int run = gdb_con->buf_cnt - 2;\r
+                               i = 0;\r
+                               int done = 0;\r
+                               while (i < run)\r
+                               {\r
+                                       character = *buf++;\r
+                                       i++;\r
+                                       if (character == '#')\r
+                                       {\r
+                                               /* Danger! character can be '#' when esc is \r
+                                                * used so we need an explicit boolean for done here.\r
+                                                */\r
+                                               done = 1;\r
+                                               break;\r
+                                       }\r
+                                       \r
+                                       if (character == '}')\r
+                                       {\r
+                                               /* data transmitted in binary mode (X packet)\r
+                                                * uses 0x7d as escape character */\r
+                                               my_checksum += character & 0xff;\r
+                                               character = *buf++;\r
+                                               i++;\r
+                                               my_checksum += character & 0xff;\r
+                                               buffer[count++] = (character ^ 0x20) & 0xff;\r
+                                       } else\r
+                                       {\r
+                                               my_checksum += character & 0xff;\r
+                                               buffer[count++] = character & 0xff;\r
+                                       }\r
+                               }\r
+                               gdb_con->buf_p += i;\r
+                               gdb_con->buf_cnt -= i;\r
+                               if (done) \r
+                                       break;\r
+                       } \r
+                       if (count > *len)\r
+                       {\r
+                               ERROR("packet buffer too small");\r
+                               return ERROR_GDB_BUFFER_TOO_SMALL;\r
+                       }\r
+                       \r
+                       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+                               return retval;\r
+\r
+                       if (character == '#')\r
+                               break;\r
+\r
+                       if (character == '}')\r
+                       {\r
+                               /* data transmitted in binary mode (X packet)\r
+                                * uses 0x7d as escape character */\r
+                               my_checksum += character & 0xff;\r
+                               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+                                       return retval;\r
+                               my_checksum += character & 0xff;\r
+                               buffer[count++] = (character ^ 0x20) & 0xff;\r
+                       }\r
+                       else\r
+                       {\r
+                               my_checksum += character & 0xff;\r
+                               buffer[count++] = character & 0xff;\r
+                       }\r
+\r
+               }\r
+\r
+               *len = count;\r
+\r
+               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+                       return retval;\r
+               checksum[0] = character;\r
+               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)\r
+                       return retval;\r
+               checksum[1] = character;\r
+               checksum[2] = 0;\r
+\r
+               if (my_checksum == strtoul(checksum, NULL, 16))\r
+               {\r
+                       gdb_write(connection, "+", 1);\r
+                       break;\r
+               }\r
+\r
+               WARNING("checksum error, requesting retransmission");\r
+               gdb_write(connection, "-", 1);\r
+       }\r
+       if (gdb_con->closed)\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_get_packet(connection_t *connection, char *buffer, int *len)\r
+{\r
+       gdb_connection_t *gdb_con = connection->priv;\r
+       gdb_con->busy = 1;\r
+       int retval = gdb_get_packet_inner(connection, buffer, len);\r
+       gdb_con->busy = 0;\r
+       return retval;\r
+}\r
+       \r
+int gdb_output_con(connection_t *connection, char* line)\r
+{\r
+       char *hex_buffer;\r
+       int i, bin_size;\r
+\r
+       bin_size = strlen(line);\r
+\r
+       hex_buffer = malloc(bin_size*2 + 4);\r
+\r
+       hex_buffer[0] = 'O';\r
+       for (i=0; i<bin_size; i++)\r
+               snprintf(hex_buffer + 1 + i*2, 3, "%2.2x", line[i]);\r
+       hex_buffer[bin_size*2+1] = '0';\r
+       hex_buffer[bin_size*2+2] = 'a';\r
+       hex_buffer[bin_size*2+3] = 0x0;\r
+\r
+       gdb_put_packet(connection, hex_buffer, bin_size*2 + 3);\r
+\r
+       free(hex_buffer);\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_output(struct command_context_s *context, char* line)\r
+{\r
+       /* this will be dumped to the log and also sent as an O packet if possible */\r
+       USER(line); \r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_program_handler(struct target_s *target, enum target_event event, void *priv)\r
+{\r
+       FILE *script;\r
+       struct command_context_s *cmd_ctx = priv;\r
+       \r
+       if (target->gdb_program_script)\r
+       {\r
+               script = open_file_from_path(cmd_ctx, target->gdb_program_script, "r");\r
+               if (!script)\r
+               {\r
+                       ERROR("couldn't open script file %s", target->gdb_program_script);\r
+                               return ERROR_OK;\r
+               }\r
+\r
+               INFO("executing gdb_program script '%s'", target->gdb_program_script);\r
+               command_run_file(cmd_ctx, script, COMMAND_EXEC);\r
+               fclose(script);\r
+               \r
+               jtag_execute_queue();\r
+       }\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)\r
+{\r
+       connection_t *connection = priv;\r
+       gdb_connection_t *gdb_connection = connection->priv;\r
+       char sig_reply[4];\r
+       int signal;\r
+\r
+       switch (event)\r
+       {\r
+               case TARGET_EVENT_HALTED:\r
+                       /* In the GDB protocol when we are stepping or coninuing execution,\r
+                        * we have a lingering reply. Upon receiving a halted event \r
+                        * when we have that lingering packet, we reply to the original\r
+                        * step or continue packet.\r
+                        * \r
+                        * Executing monitor commands can bring the target in and\r
+                        * out of the running state so we'll see lots of TARGET_EVENT_XXX\r
+                        * that are to be ignored.\r
+                        */\r
+                       if (gdb_connection->frontend_state == TARGET_RUNNING)\r
+                       {\r
+                               /* stop forwarding log packets! */\r
+                               log_remove_callback(gdb_log_callback, connection);\r
+                               \r
+                               if (gdb_connection->ctrl_c)\r
+                               {\r
+                                       signal = 0x2;\r
+                                       gdb_connection->ctrl_c = 0;\r
+                               }\r
+                               else\r
+                               {\r
+                                       signal = gdb_last_signal(target);\r
+                               }\r
+\r
+                               snprintf(sig_reply, 4, "T%2.2x", signal);\r
+                               gdb_put_packet(connection, sig_reply, 3);\r
+                               gdb_connection->frontend_state = TARGET_HALTED;\r
+                       }\r
+                       break;\r
+               case TARGET_EVENT_GDB_PROGRAM:\r
+                       gdb_program_handler(target, event, connection->cmd_ctx);\r
+                       break;\r
+               default:\r
+                       break;\r
+       }\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_new_connection(connection_t *connection)\r
+{\r
+       gdb_connection_t *gdb_connection = malloc(sizeof(gdb_connection_t));\r
+       gdb_service_t *gdb_service = connection->service->priv;\r
+       int retval;\r
+       int initial_ack;\r
+\r
+       connection->priv = gdb_connection;\r
+\r
+       /* initialize gdb connection information */\r
+       gdb_connection->buf_p = gdb_connection->buffer;\r
+       gdb_connection->buf_cnt = 0;\r
+       gdb_connection->ctrl_c = 0;\r
+       gdb_connection->frontend_state = TARGET_HALTED;\r
+       gdb_connection->vflash_image = NULL;\r
+       gdb_connection->closed = 0;\r
+       gdb_connection->busy = 0;\r
+       \r
+       /* output goes through gdb connection */\r
+       command_set_output_handler(connection->cmd_ctx, gdb_output, connection);\r
+\r
+       /* register callback to be informed about target events */\r
+       target_register_event_callback(gdb_target_callback_event_handler, connection);  \r
+\r
+       /* a gdb session just attached, put the target in halt mode */\r
+       if (((retval = gdb_service->target->type->halt(gdb_service->target)) != ERROR_OK) &&\r
+                       (retval != ERROR_TARGET_ALREADY_HALTED))\r
+       {\r
+               ERROR("error(%d) when trying to halt target, falling back to \"reset halt\"", retval);\r
+               command_run_line(connection->cmd_ctx, "reset halt");\r
+       }\r
+\r
+       /* This will time out after 1 second */\r
+       command_run_line(connection->cmd_ctx, "wait_halt 1");\r
+\r
+       /* remove the initial ACK from the incoming buffer */\r
+       if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)\r
+               return retval;\r
+\r
+       if (initial_ack != '+')\r
+               gdb_putback_char(connection, initial_ack);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_connection_closed(connection_t *connection)\r
+{\r
+       gdb_service_t *gdb_service = connection->service->priv;\r
+       gdb_connection_t *gdb_connection = connection->priv;\r
+\r
+       /* see if an image built with vFlash commands is left */\r
+       if (gdb_connection->vflash_image)\r
+       {\r
+               image_close(gdb_connection->vflash_image);\r
+               free(gdb_connection->vflash_image);\r
+               gdb_connection->vflash_image = NULL;\r
+       }\r
+\r
+       /* if this connection registered a debug-message receiver delete it */\r
+       delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target);\r
+       \r
+       if (connection->priv)\r
+       {\r
+               free(connection->priv);\r
+               connection->priv = NULL;\r
+       }\r
+       else\r
+       {\r
+               ERROR("BUG: connection->priv == NULL");\r
+       }\r
+\r
+       target_unregister_event_callback(gdb_target_callback_event_handler, connection);\r
+       log_remove_callback(gdb_log_callback, connection);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+void gdb_send_error(connection_t *connection, u8 the_error)\r
+{\r
+       char err[4];\r
+       snprintf(err, 4, "E%2.2X", the_error );\r
+       gdb_put_packet(connection, err, 3);\r
+}\r
+\r
+int gdb_last_signal_packet(connection_t *connection, target_t *target, char* packet, int packet_size)\r
+{\r
+       char sig_reply[4];\r
+       int signal;\r
+\r
+       signal = gdb_last_signal(target);\r
+\r
+       snprintf(sig_reply, 4, "S%2.2x", signal);\r
+       gdb_put_packet(connection, sig_reply, 3);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+/* Convert register to string of bits. NB! The # of bits in the\r
+ * register might be non-divisible by 8(a byte), in which\r
+ * case an entire byte is shown. */\r
+void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg)\r
+{\r
+       int i;\r
+\r
+       u8 *buf;\r
+       int buf_len;\r
+       buf = reg->value;\r
+       buf_len = CEIL(reg->size, 8); \r
+\r
+       if (target->endianness == TARGET_LITTLE_ENDIAN)\r
+       {\r
+               for (i = 0; i < buf_len; i++)\r
+               {\r
+                       tstr[i*2]   = DIGITS[(buf[i]>>4) & 0xf];\r
+                       tstr[i*2+1] = DIGITS[buf[i]&0xf];\r
+               }\r
+       }\r
+       else\r
+       {\r
+               for (i = 0; i < buf_len; i++)\r
+               {\r
+                       tstr[(buf_len-1-i)*2]   = DIGITS[(buf[i]>>4)&0xf];\r
+                       tstr[(buf_len-1-i)*2+1] = DIGITS[buf[i]&0xf];\r
+               }\r
+       }       \r
+}\r
+\r
+void gdb_target_to_str(target_t *target, char *tstr, char *str)\r
+{\r
+       int str_len = strlen(tstr);\r
+       int i;\r
+\r
+       if (str_len % 2)\r
+       {\r
+               ERROR("BUG: gdb value with uneven number of characters encountered");\r
+               exit(-1);\r
+       }\r
+\r
+       if (target->endianness == TARGET_LITTLE_ENDIAN)\r
+       {\r
+               for (i = 0; i < str_len; i+=2)\r
+               {\r
+                       str[str_len - i - 1] = tstr[i + 1];\r
+                       str[str_len - i - 2] = tstr[i];\r
+               }\r
+       }\r
+       else\r
+       {\r
+               for (i = 0; i < str_len; i++)\r
+               {\r
+                       str[i] = tstr[i];\r
+               }\r
+       }       \r
+}\r
+\r
+int gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size)\r
+{\r
+       reg_t **reg_list;\r
+       int reg_list_size;\r
+       int retval;\r
+       int reg_packet_size = 0;\r
+       char *reg_packet;\r
+       char *reg_packet_p;\r
+       int i;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+       DEBUG("-");\r
+#endif\r
+\r
+       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)\r
+       {\r
+               switch (retval)\r
+               {\r
+                       case ERROR_TARGET_NOT_HALTED:\r
+                               ERROR("gdb requested registers but we're not halted, dropping connection");\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       default:\r
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */\r
+                               ERROR("BUG: unexpected error returned by get_gdb_reg_list()");\r
+                               exit(-1);\r
+               }\r
+       }\r
+\r
+       for (i = 0; i < reg_list_size; i++)\r
+       {\r
+               reg_packet_size += reg_list[i]->size;\r
+       }\r
+\r
+       reg_packet = malloc(CEIL(reg_packet_size, 8) * 2);\r
+       reg_packet_p = reg_packet;\r
+\r
+       for (i = 0; i < reg_list_size; i++)\r
+       {\r
+               gdb_str_to_target(target, reg_packet_p, reg_list[i]);\r
+               reg_packet_p += CEIL(reg_list[i]->size, 8) * 2;\r
+       }\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+       {\r
+               char *reg_packet_p;\r
+               reg_packet_p = strndup(reg_packet, CEIL(reg_packet_size, 8) * 2);\r
+               DEBUG("reg_packet: %s", reg_packet_p);\r
+               free(reg_packet_p);\r
+       }\r
+#endif\r
+\r
+       gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);\r
+       free(reg_packet);\r
+\r
+       free(reg_list);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       int i;\r
+       reg_t **reg_list;\r
+       int reg_list_size;\r
+       int retval;\r
+       char *packet_p;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+       DEBUG("-");\r
+#endif\r
+\r
+       /* skip command character */\r
+       packet++;\r
+       packet_size--;\r
+\r
+       if (packet_size % 2)\r
+       {\r
+               WARNING("GDB set_registers packet with uneven characters received, dropping connection");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)\r
+       {\r
+               switch (retval)\r
+               {\r
+                       case ERROR_TARGET_NOT_HALTED:\r
+                               ERROR("gdb tried to registers but we're not halted, dropping connection");\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       default:\r
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */\r
+                               ERROR("BUG: unexpected error returned by get_gdb_reg_list()");\r
+                               exit(-1);\r
+               }\r
+       }\r
+\r
+       packet_p = packet;\r
+       for (i = 0; i < reg_list_size; i++)\r
+       {\r
+               u8 *bin_buf;\r
+               char *hex_buf;\r
+               reg_arch_type_t *arch_type;\r
+\r
+               /* convert from GDB-string (target-endian) to hex-string (big-endian) */\r
+               hex_buf = malloc(CEIL(reg_list[i]->size, 8) * 2);\r
+               gdb_target_to_str(target, packet_p, hex_buf);\r
+\r
+               /* convert hex-string to binary buffer */\r
+               bin_buf = malloc(CEIL(reg_list[i]->size, 8));\r
+               str_to_buf(hex_buf, CEIL(reg_list[i]->size, 8) * 2, bin_buf, reg_list[i]->size, 16);\r
+\r
+               /* get register arch_type, and call set method */       \r
+               arch_type = register_get_arch_type(reg_list[i]->arch_type);\r
+               if (arch_type == NULL)\r
+               {\r
+                       ERROR("BUG: encountered unregistered arch type");\r
+                       exit(-1);\r
+               }\r
+               arch_type->set(reg_list[i], bin_buf);\r
+\r
+               /* advance packet pointer */            \r
+               packet_p += (CEIL(reg_list[i]->size, 8) * 2);\r
+\r
+               free(bin_buf);\r
+               free(hex_buf);\r
+       }\r
+\r
+       /* free reg_t *reg_list[] array allocated by get_gdb_reg_list */ \r
+       free(reg_list);\r
+\r
+       gdb_put_packet(connection, "OK", 2);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       char *reg_packet;\r
+       int reg_num = strtoul(packet + 1, NULL, 16);\r
+       reg_t **reg_list;\r
+       int reg_list_size;\r
+       int retval;\r
+\r
+#ifdef _DEBUG_GDB_IO_\r
+       DEBUG("-");\r
+#endif\r
+\r
+       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)\r
+       {\r
+               switch (retval)\r
+               {\r
+                       case ERROR_TARGET_NOT_HALTED:\r
+                               ERROR("gdb requested registers but we're not halted, dropping connection");\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       default:\r
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */\r
+                               ERROR("BUG: unexpected error returned by get_gdb_reg_list()");\r
+                               exit(-1);\r
+               }\r
+       }\r
+\r
+       if (reg_list_size <= reg_num)\r
+       {\r
+               ERROR("gdb requested a non-existing register");\r
+               exit(-1);\r
+       }\r
+\r
+       reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);\r
+\r
+       gdb_str_to_target(target, reg_packet, reg_list[reg_num]);\r
+\r
+       gdb_put_packet(connection, reg_packet, CEIL(reg_list[reg_num]->size, 8) * 2);\r
+\r
+       free(reg_list);\r
+       free(reg_packet);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       char *separator;\r
+       char *hex_buf;\r
+       u8 *bin_buf;\r
+       int reg_num = strtoul(packet + 1, &separator, 16);\r
+       reg_t **reg_list;\r
+       int reg_list_size;\r
+       int retval;\r
+       reg_arch_type_t *arch_type;\r
+\r
+       DEBUG("-");\r
+\r
+       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)\r
+       {\r
+               switch (retval)\r
+               {\r
+                       case ERROR_TARGET_NOT_HALTED:\r
+                               ERROR("gdb tried to set a register but we're not halted, dropping connection");\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       default:\r
+                               /* this is a bug condition - get_gdb_reg_list() may not return any other error */\r
+                               ERROR("BUG: unexpected error returned by get_gdb_reg_list()");\r
+                               exit(-1);\r
+               }\r
+       }\r
+\r
+       if (reg_list_size < reg_num)\r
+       {\r
+               ERROR("gdb requested a non-existing register");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       if (*separator != '=')\r
+       {\r
+               ERROR("GDB 'set register packet', but no '=' following the register number");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       /* convert from GDB-string (target-endian) to hex-string (big-endian) */\r
+       hex_buf = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);\r
+       gdb_target_to_str(target, separator + 1, hex_buf);\r
+\r
+       /* convert hex-string to binary buffer */\r
+       bin_buf = malloc(CEIL(reg_list[reg_num]->size, 8));\r
+       str_to_buf(hex_buf, CEIL(reg_list[reg_num]->size, 8) * 2, bin_buf, reg_list[reg_num]->size, 16);\r
+\r
+       /* get register arch_type, and call set method */       \r
+       arch_type = register_get_arch_type(reg_list[reg_num]->arch_type);\r
+       if (arch_type == NULL)\r
+       {\r
+               ERROR("BUG: encountered unregistered arch type");\r
+               exit(-1);\r
+       }\r
+       arch_type->set(reg_list[reg_num], bin_buf);\r
+\r
+       gdb_put_packet(connection, "OK", 2);\r
+\r
+       free(bin_buf);\r
+       free(hex_buf);\r
+       free(reg_list);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_memory_packet_error(connection_t *connection, int retval)\r
+{\r
+       switch (retval)\r
+       {\r
+               case ERROR_TARGET_NOT_HALTED:\r
+                       ERROR("gdb tried to read memory but we're not halted, dropping connection");\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+               case ERROR_TARGET_DATA_ABORT:\r
+                       gdb_send_error(connection, EIO);\r
+                       break;\r
+               case ERROR_TARGET_TRANSLATION_FAULT:\r
+                       gdb_send_error(connection, EFAULT);\r
+                       break;\r
+               case ERROR_TARGET_UNALIGNED_ACCESS:\r
+                       gdb_send_error(connection, EFAULT);\r
+                       break;\r
+               default:\r
+                       /* This could be that the target reset itself. */\r
+                       ERROR("unexpected error %i. Dropping connection.", retval);\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+/* We don't have to worry about the default 2 second timeout for GDB packets,\r
+ * because GDB breaks up large memory reads into smaller reads.\r
+ * \r
+ * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????\r
+ */\r
+int gdb_read_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       char *separator;\r
+       u32 addr = 0;\r
+       u32 len = 0;\r
+\r
+       u8 *buffer;\r
+       char *hex_buffer;\r
+\r
+       int retval = ERROR_OK;\r
+\r
+       /* skip command character */\r
+       packet++;\r
+\r
+       addr = strtoul(packet, &separator, 16);\r
+\r
+       if (*separator != ',')\r
+       {\r
+               ERROR("incomplete read memory packet received, dropping connection");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       len = strtoul(separator+1, NULL, 16);\r
+\r
+       buffer = malloc(len);\r
+\r
+       DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);\r
+\r
+       retval = target_read_buffer(target, addr, len, buffer);\r
+\r
+       if ((retval == ERROR_TARGET_DATA_ABORT) && (!gdb_report_data_abort))\r
+       {\r
+               /* TODO : Here we have to lie and send back all zero's lest stack traces won't work.\r
+                * At some point this might be fixed in GDB, in which case this code can be removed.\r
+                * \r
+                * OpenOCD developers are acutely aware of this problem, but there is nothing\r
+                * gained by involving the user in this problem that hopefully will get resolved\r
+                * eventually\r
+                * \r
+                * http://sourceware.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gdb&pr=2395\r
+                *\r
+                * For now, the default is to fix up things to make current GDB versions work.\r
+                * This can be overwritten using the gdb_report_data_abort <'enable'|'disable'> command.\r
+                */\r
+               memset(buffer, 0, len);\r
+               retval = ERROR_OK;\r
+       }\r
+\r
+       if (retval == ERROR_OK)\r
+       {\r
+               hex_buffer = malloc(len * 2 + 1);\r
+\r
+               int i;\r
+               for (i = 0; i < len; i++)\r
+               {\r
+                       u8 t = buffer[i];\r
+                       hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf];\r
+                       hex_buffer[2 * i + 1] = DIGITS[t & 0xf];\r
+               }\r
+\r
+               gdb_put_packet(connection, hex_buffer, len * 2);\r
+\r
+               free(hex_buffer);\r
+       }\r
+       else\r
+       {\r
+               retval = gdb_memory_packet_error(connection, retval);\r
+       }\r
+\r
+       free(buffer);\r
+\r
+       return retval;\r
+}\r
+\r
+int gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       char *separator;\r
+       u32 addr = 0;\r
+       u32 len = 0;\r
+\r
+       u8 *buffer;\r
+\r
+       int i;\r
+       int retval;\r
+\r
+       /* skip command character */\r
+       packet++;\r
+\r
+       addr = strtoul(packet, &separator, 16);\r
+\r
+       if (*separator != ',')\r
+       {\r
+               ERROR("incomplete write memory packet received, dropping connection");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       len = strtoul(separator+1, &separator, 16);\r
+\r
+       if (*(separator++) != ':')\r
+       {\r
+               ERROR("incomplete write memory packet received, dropping connection");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       buffer = malloc(len);\r
+\r
+       DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);\r
+\r
+       for (i=0; i<len; i++)\r
+       {\r
+               u32 tmp;\r
+               sscanf(separator + 2*i, "%2x", &tmp);\r
+               buffer[i] = tmp;\r
+       }\r
+\r
+       retval = target_write_buffer(target, addr, len, buffer);\r
+\r
+       if (retval == ERROR_OK)\r
+       {\r
+               gdb_put_packet(connection, "OK", 2);\r
+       }\r
+       else\r
+       {\r
+               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)\r
+                       return retval; \r
+       }\r
+\r
+       free(buffer);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       char *separator;\r
+       u32 addr = 0;\r
+       u32 len = 0;\r
+\r
+       int retval;\r
+\r
+       /* skip command character */\r
+       packet++;\r
+\r
+       addr = strtoul(packet, &separator, 16);\r
+\r
+       if (*separator != ',')\r
+       {\r
+               ERROR("incomplete write memory binary packet received, dropping connection");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       len = strtoul(separator+1, &separator, 16);\r
+\r
+       if (*(separator++) != ':')\r
+       {\r
+               ERROR("incomplete write memory binary packet received, dropping connection");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       retval = ERROR_OK;\r
+       if (len)\r
+       {\r
+               DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);\r
+\r
+               retval = target_write_buffer(target, addr, len, (u8*)separator);\r
+       }\r
+\r
+       if (retval == ERROR_OK)\r
+       {\r
+               gdb_put_packet(connection, "OK", 2);\r
+       }\r
+       else\r
+       {\r
+               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)\r
+                       return retval; \r
+       }\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+void gdb_step_continue_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       int current = 0;\r
+       u32 address = 0x0;\r
+\r
+       DEBUG("-");\r
+\r
+       if (packet_size > 1)\r
+       {\r
+               packet[packet_size] = 0;\r
+               address = strtoul(packet + 1, NULL, 16);\r
+       }\r
+       else\r
+       {\r
+               current = 1;\r
+       }\r
+\r
+       if (packet[0] == 'c')\r
+       {\r
+               DEBUG("continue");\r
+               target->type->resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */\r
+       }\r
+       else if (packet[0] == 's')\r
+       {\r
+               DEBUG("step");\r
+               target->type->step(target, current, address, 0); /* step at current or address, don't handle breakpoints */\r
+       }\r
+}\r
+\r
+int gdb_bp_wp_packet_error(connection_t *connection, int retval)\r
+{\r
+       switch (retval)\r
+       {\r
+               case ERROR_TARGET_NOT_HALTED:\r
+                       ERROR("gdb tried to set a breakpoint but we're not halted, dropping connection");\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+                       break;\r
+               case ERROR_TARGET_RESOURCE_NOT_AVAILABLE:\r
+                       gdb_send_error(connection, EBUSY);\r
+                       break;\r
+               default:\r
+                       ERROR("BUG: unexpected error %i", retval);\r
+                       exit(-1);\r
+       }\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       int type;\r
+       enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */;\r
+       enum watchpoint_rw wp_type;\r
+       u32 address;\r
+       u32 size;\r
+       char *separator;\r
+       int retval;\r
+\r
+       DEBUG("-");\r
+\r
+       type = strtoul(packet + 1, &separator, 16);\r
+\r
+       if (type == 0)  /* memory breakpoint */\r
+               bp_type = BKPT_SOFT;\r
+       else if (type == 1) /* hardware breakpoint */\r
+               bp_type = BKPT_HARD;\r
+       else if (type == 2) /* write watchpoint */\r
+               wp_type = WPT_WRITE;\r
+       else if (type == 3) /* read watchpoint */\r
+               wp_type = WPT_READ;\r
+       else if (type == 4) /* access watchpoint */\r
+               wp_type = WPT_ACCESS;\r
+\r
+       if (*separator != ',')\r
+       {\r
+               ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       address = strtoul(separator+1, &separator, 16);\r
+\r
+       if (*separator != ',')\r
+       {\r
+               ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+\r
+       size = strtoul(separator+1, &separator, 16);\r
+\r
+       switch (type)\r
+       {\r
+               case 0:\r
+               case 1:\r
+                       if (packet[0] == 'Z')\r
+                       {\r
+                               if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK)\r
+                               {\r
+                                       if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)\r
+                                               return retval;\r
+                               }\r
+                               else\r
+                               {\r
+                                       gdb_put_packet(connection, "OK", 2);\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               breakpoint_remove(target, address);\r
+                               gdb_put_packet(connection, "OK", 2);\r
+                       }\r
+                       break;\r
+               case 2:\r
+               case 3:\r
+               case 4:\r
+               {\r
+                       if (packet[0] == 'Z')\r
+                       {\r
+                               if ((retval = watchpoint_add(target, address, size, type-2, 0, 0xffffffffu)) != ERROR_OK)\r
+                               {\r
+                                       if ((retval = gdb_bp_wp_packet_error(connection, retval)) != ERROR_OK)\r
+                                               return retval;\r
+                               }\r
+                               else\r
+                               {\r
+                                       gdb_put_packet(connection, "OK", 2);\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               watchpoint_remove(target, address);\r
+                               gdb_put_packet(connection, "OK", 2);\r
+                       }\r
+                       break;\r
+               }\r
+               default:\r
+                       break;\r
+       }\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+/* print out a string and allocate more space as needed, mainly used for XML at this point */\r
+void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, ...)\r
+{\r
+       if (*retval != ERROR_OK)\r
+       {\r
+               return;\r
+       }\r
+       int first = 1;\r
+       \r
+       for (;;)\r
+       {\r
+               if ((*xml == NULL) || (!first))\r
+               {\r
+                       /* start by 0 to exercise all the code paths.\r
+                        * Need minimum 2 bytes to fit 1 char and 0 terminator. */\r
+                        \r
+                       *size = *size * 2 + 2;\r
+                       char *t = *xml;\r
+                       *xml = realloc(*xml, *size);\r
+                       if (*xml == NULL)\r
+                       {\r
+                               if (t)\r
+                                       free(t);\r
+                               *retval = ERROR_SERVER_REMOTE_CLOSED;\r
+                               return;\r
+                       }\r
+               }\r
+               \r
+           va_list ap;\r
+           int ret;\r
+           va_start(ap, fmt);\r
+           ret = vsnprintf(*xml + *pos, *size - *pos, fmt, ap);\r
+           va_end(ap);\r
+           if ((ret > 0) && ((ret + 1) < *size - *pos))\r
+           {\r
+               *pos += ret;\r
+               return;\r
+           }\r
+           /* there was just enough or not enough space, allocate more. */\r
+           first = 0;\r
+       }\r
+}\r
+\r
+static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len)\r
+{\r
+       char *separator;\r
+       \r
+       /* Extract and NUL-terminate the annex. */\r
+       *annex = buf;\r
+       while (*buf && *buf != ':')\r
+               buf++;\r
+       if (*buf == '\0')\r
+               return -1;\r
+       *buf++ = 0;\r
+       \r
+       /* After the read marker and annex, qXfer looks like a\r
+        * traditional 'm' packet. */\r
+       \r
+       *ofs = strtoul(buf, &separator, 16);\r
+\r
+       if (*separator != ',')\r
+               return -1;\r
+\r
+       *len = strtoul(separator+1, NULL, 16);\r
+       \r
+       return 0;\r
+}\r
+\r
+int gdb_calc_blocksize(flash_bank_t *bank)\r
+{\r
+       int i;\r
+       int block_size = 0xffffffff;\r
+       \r
+       /* loop through all sectors and return smallest sector size */\r
+       \r
+       for (i = 0; i < bank->num_sectors; i++)\r
+       {\r
+               if (bank->sectors[i].size < block_size)\r
+                       block_size = bank->sectors[i].size;\r
+       }\r
+       \r
+       return block_size;\r
+}\r
+\r
+int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       command_context_t *cmd_ctx = connection->cmd_ctx;\r
+       \r
+       if (strstr(packet, "qRcmd,"))\r
+       {\r
+               if (packet_size > 6)\r
+               {\r
+                       char *cmd;\r
+                       int i;\r
+                       cmd = malloc((packet_size - 6)/2 + 1);\r
+                       for (i=0; i < (packet_size - 6)/2; i++)\r
+                       {\r
+                               u32 tmp;\r
+                               sscanf(packet + 6 + 2*i, "%2x", &tmp);\r
+                               cmd[i] = tmp;\r
+                       }\r
+                       cmd[(packet_size - 6)/2] = 0x0;\r
+                       \r
+                       /* We want to print all debug output to GDB connection */\r
+                       log_add_callback(gdb_log_callback, connection);\r
+                       target_call_timer_callbacks();\r
+                       command_run_line(cmd_ctx, cmd);\r
+                       free(cmd);\r
+               }\r
+               gdb_put_packet(connection, "OK", 2);\r
+               return ERROR_OK;\r
+       }\r
+       else if (strstr(packet, "qCRC:"))\r
+       {\r
+               if (packet_size > 5)\r
+               {\r
+                       int retval;\r
+                       char gdb_reply[10];\r
+                       char *separator;\r
+                       u32 checksum;\r
+                       u32 addr = 0;\r
+                       u32 len = 0;\r
+                       \r
+                       /* skip command character */\r
+                       packet += 5;\r
+                       \r
+                       addr = strtoul(packet, &separator, 16);\r
+                       \r
+                       if (*separator != ',')\r
+                       {\r
+                               ERROR("incomplete read memory packet received, dropping connection");\r
+                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                       }\r
+                       \r
+                       len = strtoul(separator + 1, NULL, 16);\r
+                       \r
+                       retval = target_checksum_memory(target, addr, len, &checksum);\r
+                       \r
+                       if (retval == ERROR_OK)\r
+                       {\r
+                               snprintf(gdb_reply, 10, "C%8.8x", checksum);\r
+                               gdb_put_packet(connection, gdb_reply, 9);\r
+                       }\r
+                       else\r
+                       {\r
+                               if ((retval = gdb_memory_packet_error(connection, retval)) != ERROR_OK)\r
+                                       return retval; \r
+                       }\r
+                       \r
+                       return ERROR_OK;\r
+               }\r
+       }\r
+       else if (strstr(packet, "qSupported"))\r
+       {\r
+               /* we currently support packet size and qXfer:memory-map:read (if enabled)\r
+                * disable qXfer:features:read for the moment */\r
+               int retval = ERROR_OK;\r
+               char *buffer = NULL;\r
+               int pos = 0;\r
+               int size = 0;\r
+\r
+               xml_printf(&retval, &buffer, &pos, &size, \r
+                               "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-",\r
+                               (GDB_BUFFER_SIZE - 1), gdb_use_memory_map == 1 ? '+' : '-');\r
+               \r
+               if (retval != ERROR_OK)\r
+               {\r
+                       gdb_send_error(connection, 01);\r
+                       return ERROR_OK;\r
+               }\r
+               \r
+               gdb_put_packet(connection, buffer, strlen(buffer));\r
+               free(buffer);\r
+               \r
+               return ERROR_OK;\r
+       }\r
+       else if (strstr(packet, "qXfer:memory-map:read::"))\r
+       {\r
+               /* We get away with only specifying flash here. Regions that are not\r
+                * specified are treated as if we provided no memory map(if not we \r
+                * could detect the holes and mark them as RAM).\r
+                * Normally we only execute this code once, but no big deal if we\r
+                * have to regenerate it a couple of times. */\r
+                \r
+               flash_bank_t *p;\r
+               char *xml = NULL;\r
+               int size = 0;\r
+               int pos = 0;\r
+               int retval = ERROR_OK;\r
+               \r
+               int offset;\r
+               int length;\r
+               char *separator;\r
+               int blocksize;\r
+               \r
+               /* skip command character */\r
+               packet += 23;\r
+               \r
+               offset = strtoul(packet, &separator, 16);\r
+               length = strtoul(separator + 1, &separator, 16);\r
+               \r
+               xml_printf(&retval, &xml, &pos, &size, "<memory-map>\n");\r
+               \r
+               int i = 0;\r
+               for (;;)\r
+               {\r
+                       p = get_flash_bank_by_num(i);\r
+                       if (p == NULL)\r
+                               break;\r
+                       \r
+                       /* if device has uneven sector sizes, eg. str7, lpc\r
+                        * we pass the smallest sector size to gdb memory map */\r
+                       blocksize = gdb_calc_blocksize(p);\r
+                       \r
+                       xml_printf(&retval, &xml, &pos, &size, "<memory type=\"flash\" start=\"0x%x\" length=\"0x%x\">\n" \\r
+                               "<property name=\"blocksize\">0x%x</property>\n" \\r
+                               "</memory>\n", \\r
+                               p->base, p->size, blocksize);\r
+                       i++;\r
+               }\r
+               \r
+               xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n");\r
+\r
+               if (retval != ERROR_OK)\r
+               {\r
+                       gdb_send_error(connection, retval);\r
+                       return retval;\r
+               }\r
+                               \r
+               if (offset + length > pos)\r
+               {\r
+                       length = pos - offset;\r
+               }\r
+\r
+               char *t = malloc(length + 1);\r
+               t[0] = 'l';\r
+               memcpy(t + 1, xml + offset, length);\r
+               gdb_put_packet(connection, t, length + 1);\r
+               \r
+               free(t);\r
+               free(xml);\r
+               return ERROR_OK;\r
+       }\r
+       else if (strstr(packet, "qXfer:features:read:"))\r
+       {                \r
+               char *xml = NULL;\r
+               int size = 0;\r
+               int pos = 0;\r
+               int retval = ERROR_OK;\r
+               \r
+               int offset;\r
+               unsigned int length;\r
+               char *annex;\r
+               \r
+               /* skip command character */\r
+               packet += 20;\r
+               \r
+               if (decode_xfer_read(packet, &annex, &offset, &length) < 0)\r
+               {\r
+                       gdb_send_error(connection, 01);\r
+                       return ERROR_OK;\r
+               }\r
+               \r
+               if (strcmp(annex, "target.xml") != 0)\r
+               {\r
+                       gdb_send_error(connection, 01);\r
+                       return ERROR_OK;\r
+               }\r
+                               \r
+               xml_printf(&retval, &xml, &pos, &size, \\r
+                       "l<target version=\"1.0\">\n<architecture>arm</architecture>\n</target>\n");\r
+                                       \r
+               if (retval != ERROR_OK)\r
+               {\r
+                       gdb_send_error(connection, retval);\r
+                       return retval;\r
+               }\r
+               \r
+               gdb_put_packet(connection, xml, strlen(xml) + 1);\r
+               \r
+               free(xml);\r
+               return ERROR_OK;\r
+       }\r
+       \r
+       gdb_put_packet(connection, "", 0);\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int packet_size)\r
+{\r
+       gdb_connection_t *gdb_connection = connection->priv;\r
+       gdb_service_t *gdb_service = connection->service->priv;\r
+       int result;\r
+\r
+       /* if flash programming disabled - send a empty reply */\r
+       \r
+       if (gdb_flash_program == 0)\r
+       {\r
+               gdb_put_packet(connection, "", 0);\r
+               return ERROR_OK;\r
+       }\r
+       \r
+       if (strstr(packet, "vFlashErase:"))\r
+       {\r
+               unsigned long addr;\r
+               unsigned long length;\r
+       \r
+               char *parse = packet + 12;\r
+               if (*parse == '\0')\r
+               {\r
+                       ERROR("incomplete vFlashErase packet received, dropping connection");\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+               }\r
+\r
+               addr = strtoul(parse, &parse, 16);\r
+\r
+               if (*(parse++) != ',' || *parse == '\0')\r
+               {\r
+                       ERROR("incomplete vFlashErase packet received, dropping connection");\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+               }\r
+\r
+               length = strtoul(parse, &parse, 16);\r
+\r
+               if (*parse != '\0')\r
+               {\r
+                       ERROR("incomplete vFlashErase packet received, dropping connection");\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+               }\r
+               \r
+               /* assume all sectors need erasing - stops any problems\r
+                * when flash_write is called multiple times */\r
+               flash_set_dirty();\r
+               \r
+               /* perform any target specific operations before the erase */\r
+               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_PROGRAM);\r
+               \r
+               /* perform erase */\r
+               if ((result = flash_erase_address_range(gdb_service->target, addr, length)) != ERROR_OK)\r
+               {\r
+                       /* GDB doesn't evaluate the actual error number returned,\r
+                        * treat a failed erase as an I/O error\r
+                        */\r
+                       gdb_send_error(connection, EIO);\r
+                       ERROR("flash_erase returned %i", result);\r
+               }\r
+               else\r
+                       gdb_put_packet(connection, "OK", 2);\r
+               \r
+               return ERROR_OK;\r
+       }\r
+\r
+       if (strstr(packet, "vFlashWrite:"))\r
+       {\r
+               unsigned long addr;\r
+               unsigned long length;\r
+               char *parse = packet + 12;\r
+\r
+               if (*parse == '\0')\r
+               {\r
+                       ERROR("incomplete vFlashErase packet received, dropping connection");\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+               }\r
+               addr = strtoul(parse, &parse, 16);\r
+               if (*(parse++) != ':')\r
+               {\r
+                       ERROR("incomplete vFlashErase packet received, dropping connection");\r
+                       return ERROR_SERVER_REMOTE_CLOSED;\r
+               }\r
+               length = packet_size - (parse - packet);\r
+               \r
+               /* create a new image if there isn't already one */\r
+               if (gdb_connection->vflash_image == NULL)\r
+               {\r
+                       gdb_connection->vflash_image = malloc(sizeof(image_t));\r
+                       image_open(gdb_connection->vflash_image, "", "build");\r
+               }\r
+\r
+               /* create new section with content from packet buffer */\r
+               image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse);\r
+\r
+               gdb_put_packet(connection, "OK", 2);\r
+\r
+               return ERROR_OK;\r
+       }\r
+\r
+       if (!strcmp(packet, "vFlashDone"))\r
+       {\r
+               u32 written;\r
+\r
+               /* process the flashing buffer. No need to erase as GDB\r
+                * always issues a vFlashErase first. */\r
+               if ((result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0)) != ERROR_OK)\r
+               {\r
+                       if (result == ERROR_FLASH_DST_OUT_OF_BANK)\r
+                               gdb_put_packet(connection, "E.memtype", 9);\r
+                       else\r
+                               gdb_send_error(connection, EIO);\r
+                       }\r
+               else\r
+               {\r
+                       DEBUG("wrote %u bytes from vFlash image to flash", written);\r
+                       gdb_put_packet(connection, "OK", 2);\r
+               }\r
+               \r
+               image_close(gdb_connection->vflash_image);\r
+               free(gdb_connection->vflash_image);\r
+               gdb_connection->vflash_image = NULL;\r
+               \r
+               return ERROR_OK;\r
+       }\r
+\r
+       gdb_put_packet(connection, "", 0);\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_detach(connection_t *connection, target_t *target)\r
+{\r
+       switch( detach_mode )\r
+       {\r
+               case GDB_DETACH_RESUME:\r
+                       target->type->resume(target, 1, 0, 1, 0);\r
+                       break;\r
+               \r
+               case GDB_DETACH_RESET:\r
+                       target_process_reset(connection->cmd_ctx);\r
+                       break;\r
+               \r
+               case GDB_DETACH_HALT:\r
+                       target->type->halt(target);\r
+                       break;\r
+               \r
+               case GDB_DETACH_NOTHING:\r
+                       break;\r
+       }\r
+       \r
+       gdb_put_packet(connection, "OK", 2);\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+static void gdb_log_callback(void *priv, const char *file, int line, \r
+               const char *function, const char *format, va_list args)\r
+{\r
+       connection_t *connection = priv;\r
+       gdb_connection_t *gdb_con = connection->priv;\r
+       \r
+       if (gdb_con->busy)\r
+       {\r
+               /* do not reply this using the O packet */\r
+               return;\r
+       }\r
+\r
+       char *t = alloc_printf(format, args);\r
+       if (t == NULL)\r
+               return;\r
+       \r
+       gdb_output_con(connection, t); \r
+       \r
+       free(t);\r
+}\r
+\r
+int gdb_input_inner(connection_t *connection)\r
+{\r
+       gdb_service_t *gdb_service = connection->service->priv;\r
+       target_t *target = gdb_service->target;\r
+       char packet[GDB_BUFFER_SIZE];\r
+       int packet_size;\r
+       int retval;\r
+       gdb_connection_t *gdb_con = connection->priv;\r
+       static int extended_protocol = 0;\r
+\r
+       /* drain input buffer */\r
+       do\r
+       {\r
+               packet_size = GDB_BUFFER_SIZE-1;\r
+               if ((retval = gdb_get_packet(connection, packet, &packet_size)) != ERROR_OK)\r
+               {\r
+                       return retval;\r
+               }\r
+\r
+               /* terminate with zero */\r
+               packet[packet_size] = 0;\r
+\r
+               DEBUG("received packet: '%s'", packet);\r
+\r
+               if (packet_size > 0)\r
+               {\r
+                       retval = ERROR_OK;\r
+                       switch (packet[0])\r
+                       {\r
+                               case 'H':\r
+                                       /* Hct... -- set thread \r
+                                        * we don't have threads, send empty reply */\r
+                                       gdb_put_packet(connection, NULL, 0);\r
+                                       break;\r
+                               case 'q':\r
+                                       retval = gdb_query_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case 'g':\r
+                                       retval = gdb_get_registers_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case 'G':\r
+                                       retval = gdb_set_registers_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case 'p':\r
+                                       retval = gdb_get_register_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case 'P':\r
+                                       retval = gdb_set_register_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case 'm':\r
+                                       retval = gdb_read_memory_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case 'M':\r
+                                       retval = gdb_write_memory_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case 'z':\r
+                               case 'Z':\r
+                                       retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case '?':\r
+                                       gdb_last_signal_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case 'c':\r
+                               case 's':\r
+                                       {\r
+                                       /* We're running/stepping, in which case we can \r
+                                        * forward log output until the target is halted */\r
+                                               gdb_connection_t *gdb_con = connection->priv;\r
+                                               gdb_con->frontend_state = TARGET_RUNNING;\r
+                                               log_add_callback(gdb_log_callback, connection);\r
+                                               gdb_step_continue_packet(connection, target, packet, packet_size);\r
+                                       }\r
+                                       break;\r
+                               case 'v':\r
+                                       retval = gdb_v_packet(connection, target, packet, packet_size);\r
+                                       break;\r
+                               case 'D':\r
+                                       retval = gdb_detach(connection, target);\r
+                                       extended_protocol = 0;\r
+                                       break;\r
+                               case 'X':\r
+                                       if ((retval = gdb_write_memory_binary_packet(connection, target, packet, packet_size)) != ERROR_OK)\r
+                                               return retval;\r
+                                       break;\r
+                               case 'k':\r
+                                       if (extended_protocol != 0)\r
+                                               break;\r
+                                       gdb_put_packet(connection, "OK", 2);\r
+                                       return ERROR_SERVER_REMOTE_CLOSED;\r
+                               case '!':\r
+                                       /* handle extended remote protocol */\r
+                                       extended_protocol = 1;\r
+                                       gdb_put_packet(connection, "OK", 2);\r
+                                       break;\r
+                               case 'R':\r
+                                       /* handle extended restart packet */\r
+                                       target_process_reset(connection->cmd_ctx);\r
+                                       break;\r
+                               default:\r
+                                       /* ignore unkown packets */\r
+                                       DEBUG("ignoring 0x%2.2x packet", packet[0]);\r
+                                       gdb_put_packet(connection, NULL, 0);\r
+                                       break;\r
+                       }\r
+\r
+                       /* if a packet handler returned an error, exit input loop */\r
+                       if (retval != ERROR_OK)\r
+                               return retval;\r
+               }\r
+\r
+               if (gdb_con->ctrl_c)\r
+               {\r
+                       if (target->state == TARGET_RUNNING)\r
+                       {\r
+                               target->type->halt(target);\r
+                               gdb_con->ctrl_c = 0;\r
+                       }\r
+               }\r
+\r
+       } while (gdb_con->buf_cnt > 0);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_input(connection_t *connection)\r
+{\r
+       int retval = gdb_input_inner(connection);\r
+       if (retval == ERROR_SERVER_REMOTE_CLOSED)\r
+               return retval;\r
+       /* we'll recover from any other errors(e.g. temporary timeouts, etc.) */\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_init()\r
+{\r
+       gdb_service_t *gdb_service;\r
+       target_t *target = targets;\r
+       int i = 0;\r
+\r
+       if (!target)\r
+       {\r
+               WARNING("no gdb ports allocated as no target has been specified");\r
+               return ERROR_OK;\r
+       }\r
+\r
+       if (gdb_port == 0)\r
+       {\r
+               WARNING("no gdb port specified, using default port 3333");\r
+               gdb_port = 3333;\r
+       }\r
+\r
+       while (target)\r
+       {\r
+               char service_name[8];\r
+\r
+               snprintf(service_name, 8, "gdb-%2.2i", i);\r
+\r
+               gdb_service = malloc(sizeof(gdb_service_t));\r
+               gdb_service->target = target;\r
+\r
+               add_service("gdb", CONNECTION_GDB, gdb_port + i, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);\r
+\r
+               DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + i);\r
+\r
+               i++;\r
+               target = target->next;\r
+       }\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+/* daemon configuration command gdb_port */\r
+int handle_gdb_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       if (argc == 0)\r
+               return ERROR_OK;\r
+\r
+       /* only if the port wasn't overwritten by cmdline */\r
+       if (gdb_port == 0)\r
+               gdb_port = strtoul(args[0], NULL, 0);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       if (argc == 1)\r
+       {\r
+               if (strcmp(args[0], "resume") == 0)\r
+               {\r
+                       detach_mode = GDB_DETACH_RESUME;\r
+                       return ERROR_OK;\r
+               }\r
+               else if (strcmp(args[0], "reset") == 0)\r
+               {\r
+                       detach_mode = GDB_DETACH_RESET;\r
+                       return ERROR_OK;\r
+               }\r
+               else if (strcmp(args[0], "halt") == 0)\r
+               {\r
+                       detach_mode = GDB_DETACH_HALT;\r
+                       return ERROR_OK;\r
+               }\r
+               else if (strcmp(args[0], "nothing") == 0)\r
+               {\r
+                       detach_mode = GDB_DETACH_NOTHING;\r
+                       return ERROR_OK;\r
+               }\r
+       }\r
+       \r
+       WARNING("invalid gdb_detach configuration directive: %s", args[0]);\r
+       return ERROR_OK;\r
+}\r
+\r
+int handle_gdb_memory_map_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       if (argc == 1)\r
+       {\r
+               if (strcmp(args[0], "enable") == 0)\r
+               {\r
+                       gdb_use_memory_map = 1;\r
+                       return ERROR_OK;\r
+               }\r
+               else if (strcmp(args[0], "disable") == 0)\r
+               {\r
+                       gdb_use_memory_map = 0;\r
+                       return ERROR_OK;\r
+               }\r
+       }\r
+       \r
+       WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);\r
+       return ERROR_OK;\r
+}\r
+\r
+int handle_gdb_flash_program_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       if (argc == 1)\r
+       {\r
+               if (strcmp(args[0], "enable") == 0)\r
+               {\r
+                       gdb_flash_program = 1;\r
+                       return ERROR_OK;\r
+               }\r
+               else if (strcmp(args[0], "disable") == 0)\r
+               {\r
+                       gdb_flash_program = 0;\r
+                       return ERROR_OK;\r
+               }\r
+       }\r
+       \r
+       WARNING("invalid gdb_memory_map configuration directive: %s", args[0]);\r
+       return ERROR_OK;\r
+}\r
+\r
+int handle_gdb_report_data_abort_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       if (argc == 1)\r
+       {\r
+               if (strcmp(args[0], "enable") == 0)\r
+               {\r
+                       gdb_report_data_abort = 1;\r
+                       return ERROR_OK;\r
+               }\r
+               else if (strcmp(args[0], "disable") == 0)\r
+               {\r
+                       gdb_report_data_abort = 0;\r
+                       return ERROR_OK;\r
+               }\r
+       }\r
+       \r
+       WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]);\r
+       return ERROR_OK;\r
+}\r
+\r
+int gdb_register_commands(command_context_t *command_context)\r
+{\r
+       register_command(command_context, NULL, "gdb_port", handle_gdb_port_command,\r
+                       COMMAND_CONFIG, "");\r
+       register_command(command_context, NULL, "gdb_detach", handle_gdb_detach_command,\r
+                       COMMAND_CONFIG, "");\r
+       register_command(command_context, NULL, "gdb_memory_map", handle_gdb_memory_map_command,\r
+                       COMMAND_CONFIG, "");\r
+       register_command(command_context, NULL, "gdb_flash_program", handle_gdb_flash_program_command,\r
+                       COMMAND_CONFIG, "");\r
+       register_command(command_context, NULL, "gdb_report_data_abort", handle_gdb_report_data_abort_command,\r
+                       COMMAND_CONFIG, "");\r
+       return ERROR_OK;\r
+}\r
index 899902a72d58d9fc32d6d4f51a4fd4f9f4c4de6d..830cf6410caa953b0316aa1b344a3f546cee6770 100644 (file)
-/***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "replacements.h"
-
-#include "telnet_server.h"
-
-#include "server.h"
-#include "log.h"
-#include "command.h"
-#include "target.h"
-#include "target_request.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-
-static unsigned short telnet_port = 0;
-
-int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
-static char *negotiate =
-               "\xFF\xFB\x03"          /* IAC WILL Suppress Go Ahead */
-               "\xFF\xFB\x01"          /* IAC WILL Echo */
-               "\xFF\xFD\x03"          /* IAC DO Suppress Go Ahead */
-               "\xFF\xFE\x01";         /* IAC DON'T Echo */
-               
-#define CTRL(c) (c - '@')
-       
-/* The only way we can detect that the socket is closed is the first time
- * we write to it, we will fail. Subsequent write operations will
- * succeed. Shudder!
- */
-int telnet_write(connection_t *connection, void *data, int len)
-{
-       telnet_connection_t *t_con = connection->priv;
-       if (t_con->closed)
-               return ERROR_SERVER_REMOTE_CLOSED;
-
-       if (write_socket(connection->fd, data, len) == len)
-       {
-               return ERROR_OK;
-       }
-       t_con->closed = 1;
-       return ERROR_SERVER_REMOTE_CLOSED;
-}
-
-int telnet_prompt(connection_t *connection)
-{
-       telnet_connection_t *t_con = connection->priv;
-
-       return telnet_write(connection, t_con->prompt, strlen(t_con->prompt));
-}
-
-int telnet_outputline(connection_t *connection, char* line)
-{
-       telnet_write(connection, line, strlen(line));
-       return telnet_write(connection, "\r\n\0", 3);
-}
-
-int telnet_output(struct command_context_s *cmd_ctx, char* line)
-{
-       connection_t *connection = cmd_ctx->output_handler_priv;
-       
-       return telnet_outputline(connection, line);
-}
-
-void telnet_log_callback(void *priv, const char *file, int line, 
-               const char *function, const char *format, va_list args)
-{
-       connection_t *connection = priv;
-       char *t = allocPrintf(format, args);
-       char *t2;
-       if (t == NULL)
-               return;
-       t2=t;
-       char *endline;
-       do 
-       {
-               if ((endline=strchr(t2, '\n'))!=NULL)
-               {
-                       *endline=0;
-               }
-               telnet_outputline(connection, t2);
-               t2=endline+1;
-       } while (endline);
-       
-       
-       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;
-       connection_t *connection = cmd_ctx->output_handler_priv;
-       telnet_connection_t *t_con = connection->priv;
-       
-       switch (event)
-       {
-               case TARGET_EVENT_HALTED:
-                       target_arch_state(target);
-                       if (!t_con->suppress_prompt)
-                               telnet_prompt(connection);
-                       break;
-               case TARGET_EVENT_RESUMED:
-                       if (!t_con->suppress_prompt)
-                               telnet_prompt(connection);
-                       break;
-               default:
-                       break;
-       }
-
-       return ERROR_OK;
-}
-
-int telnet_new_connection(connection_t *connection)
-{
-       telnet_connection_t *telnet_connection = malloc(sizeof(telnet_connection_t));
-       telnet_service_t *telnet_service = connection->service->priv;
-       int i;
-       
-       connection->priv = telnet_connection;
-       
-       /* initialize telnet connection information */
-       telnet_connection->closed = 0;
-       telnet_connection->line_size = 0;
-       telnet_connection->line_cursor = 0;
-       telnet_connection->option_size = 0;
-       telnet_connection->prompt = strdup("> ");
-       telnet_connection->suppress_prompt = 0;
-       telnet_connection->state = TELNET_STATE_DATA;
-       
-       /* output goes through telnet connection */
-       command_set_output_handler(connection->cmd_ctx, telnet_output, connection);
-       
-       /* negotiate telnet options */
-       telnet_write(connection, negotiate, strlen(negotiate));
-       
-       /* print connection banner */
-       if (telnet_service->banner)
-       {
-               telnet_write(connection, telnet_service->banner, strlen(telnet_service->banner));
-               telnet_write(connection, "\r\n\0", 3);
-       }
-       
-       telnet_prompt(connection);
-       
-       /* initialize history */
-       for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
-       {
-               telnet_connection->history[i] = NULL;
-       }
-       telnet_connection->next_history = 0;
-       telnet_connection->current_history = 0;
-
-       target_register_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx);
-       
-       return ERROR_OK;
-}
-
-void telnet_clear_line(connection_t *connection, telnet_connection_t *t_con)
-{
-       /* move to end of line */
-       if (t_con->line_cursor < t_con->line_size)
-       {
-               telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
-       }
-                                                       
-       /* backspace, overwrite with space, backspace */
-       while (t_con->line_size > 0)
-       {
-               telnet_write(connection, "\b \b", 3);
-               t_con->line_size--;
-       }
-       t_con->line_cursor = 0;
-}
-
-int telnet_input(connection_t *connection)
-{
-       int bytes_read;
-       char buffer[TELNET_BUFFER_SIZE];
-       char *buf_p;
-       telnet_connection_t *t_con = connection->priv;
-       command_context_t *command_context = connection->cmd_ctx;
-       
-       bytes_read = read_socket(connection->fd, buffer, TELNET_BUFFER_SIZE);
-       
-       if (bytes_read == 0)
-               return ERROR_SERVER_REMOTE_CLOSED;
-       else if (bytes_read == -1)
-       {
-               ERROR("error during read: %s", strerror(errno));
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-       
-       buf_p = buffer;
-       while (bytes_read)
-       {
-               switch (t_con->state)
-               {
-                       case TELNET_STATE_DATA:
-                               if (*buf_p == '\xff')
-                               {
-                                       t_con->state = TELNET_STATE_IAC;
-                               }
-                               else
-                               {
-                                       if (isprint(*buf_p)) /* printable character */
-                                       {
-                                               telnet_write(connection, buf_p, 1);
-                                               if (t_con->line_cursor == t_con->line_size)
-                                               {
-                                                       t_con->line[t_con->line_size++] = *buf_p;
-                                                       t_con->line_cursor++;
-                                               }
-                                               else
-                                               {
-                                                       int i;
-                                                       memmove(t_con->line + t_con->line_cursor + 1, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
-                                                       t_con->line[t_con->line_cursor++] = *buf_p;
-                                                       t_con->line_size++;
-                                                       telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
-                                                       for (i = t_con->line_cursor; i < t_con->line_size; i++)
-                                                       {
-                                                               telnet_write(connection, "\b", 1);
-                                                       }
-                                               }
-                                       }
-                                       else /* non-printable */
-                                       {
-                                               if (*buf_p == 0x1b) /* escape */
-                                               {
-                                                       t_con->state = TELNET_STATE_ESCAPE;
-                                                       t_con->last_escape = '\x00';
-                                               }
-                                               else if ((*buf_p == 0xd) || (*buf_p == 0xa)) /* CR/LF */
-                                               {
-                                                       int retval;
-                                                       
-                                                       /* skip over combinations with CR/LF + NUL */
-                                                       if (((*(buf_p + 1) == 0xa) || (*(buf_p + 1) == 0xd)) && (bytes_read > 1))
-                                                       {
-                                                               buf_p++;
-                                                               bytes_read--;
-                                                       }
-                                                       if ((*(buf_p + 1) == 0) && (bytes_read > 1))
-                                                       {
-                                                               buf_p++;
-                                                               bytes_read--;
-                                                       }
-                                                       t_con->line[t_con->line_size] = 0;
-                                                       
-                                                       telnet_write(connection, "\r\n\x00", 3);
-                                                       
-                                                       if (strcmp(t_con->line, "history") == 0)
-                                                       {
-                                                               int i;
-                                                               for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
-                                                               {
-                                                                       if (t_con->history[i])
-                                                                       {
-                                                                               telnet_write(connection, t_con->history[i], strlen(t_con->history[i]));
-                                                                               telnet_write(connection, "\r\n\x00", 3);
-                                                                       }
-                                                               }
-                                                               telnet_prompt(connection);
-                                                               t_con->line_size = 0;
-                                                               t_con->line_cursor = 0;
-                                                               continue;
-                                                       }
-                                                       
-                                                       log_setCallback(telnet_log_callback, connection);
-                                                       t_con->suppress_prompt = 1;
-                                                       
-                                                       if ((retval = command_run_line(command_context, t_con->line)) != ERROR_OK)
-                                                       {
-                                                               if (retval == ERROR_COMMAND_CLOSE_CONNECTION)
-                                                               {
-                                                                       return ERROR_SERVER_REMOTE_CLOSED;
-                                                               }
-                                                       }
-                                                       
-                                                       t_con->suppress_prompt = 0;
-                                                       
-                                                       /* Save only non-blank lines in the history */
-                                                       if (t_con->line_size > 0)
-                                                       {
-                                                               /* if the history slot is already taken, free it */
-                                                               if (t_con->history[t_con->next_history])
-                                                               {
-                                                                       free(t_con->history[t_con->next_history]);
-                                                               }
-               
-                                                               /* add line to history */
-                                                               t_con->history[t_con->next_history] = strdup(t_con->line);
-
-                                                               /* wrap history at TELNET_LINE_HISTORY_SIZE */
-                                                               t_con->next_history = (t_con->next_history + 1) % TELNET_LINE_HISTORY_SIZE;
-                                                       
-                                                               /* current history line starts at the new entry */
-                                                               t_con->current_history = t_con->next_history;
-                                                       
-                                                               if (t_con->history[t_con->current_history])
-                                                               {
-                                                                       free(t_con->history[t_con->current_history]);
-                                                               }
-                                                               t_con->history[t_con->current_history] = strdup("");
-                                                       }
-                                                       
-                                                       int t = telnet_prompt(connection);
-                                                       if (t == ERROR_SERVER_REMOTE_CLOSED)
-                                                               return t;
-                                                       
-                                                       t_con->line_size = 0;
-                                                       t_con->line_cursor = 0;
-                                               }
-                                               else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) /* delete character */
-                                               {
-                                                       if (t_con->line_cursor > 0)
-                                                       {
-                                                               if (t_con->line_cursor != t_con->line_size)
-                                                               {
-                                                                       int i;
-                                                                       telnet_write(connection, "\b", 1);
-                                                                       t_con->line_cursor--;
-                                                                       t_con->line_size--;
-                                                                       memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor);
-                                                                       
-                                                                       telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
-                                                                       telnet_write(connection, " \b", 2);
-                                                                       for (i = t_con->line_cursor; i < t_con->line_size; i++)
-                                                                       {
-                                                                               telnet_write(connection, "\b", 1);
-                                                                       }
-                                                               }
-                                                               else
-                                                               {
-                                                                       t_con->line_size--;
-                                                                       t_con->line_cursor--;
-                                                                       /* back space: move the 'printer' head one char back, overwrite with space, move back again */
-                                                                       telnet_write(connection, "\b \b", 3);
-                                                               }
-                                                       }
-                                               }
-                                               else if (*buf_p == 0x15) /* clear line */
-                                               {
-                                                       telnet_clear_line(connection, t_con);
-                                               }
-                                               else if (*buf_p == CTRL('B')) /* cursor left */
-                                               {
-                                                       if (t_con->line_cursor > 0)
-                                                       {
-                                                               telnet_write(connection, "\b", 1);
-                                                               t_con->line_cursor--;
-                                                       }
-                                                       t_con->state = TELNET_STATE_DATA;
-                                               }
-                                               else if (*buf_p == CTRL('F')) /* cursor right */
-                                               {
-                                                       if (t_con->line_cursor < t_con->line_size)
-                                                       {
-                                                               telnet_write(connection, t_con->line + t_con->line_cursor++, 1);
-                                                       }
-                                                       t_con->state = TELNET_STATE_DATA;
-                                               }
-                                               else
-                                               {
-                                                       DEBUG("unhandled nonprintable: %2.2x", *buf_p);
-                                               }
-                                       }
-                               }
-                               break;
-                       case TELNET_STATE_IAC:
-                               switch (*buf_p)
-                               {
-                                       case '\xfe':
-                                               t_con->state = TELNET_STATE_DONT;
-                                               break;
-                                       case '\xfd':
-                                               t_con->state = TELNET_STATE_DO;
-                                               break;
-                                       case '\xfc':
-                                               t_con->state = TELNET_STATE_WONT;
-                                               break;
-                                       case '\xfb':
-                                               t_con->state = TELNET_STATE_WILL;
-                                               break;
-                               }
-                               break;
-                       case TELNET_STATE_SB:
-                               break;
-                       case TELNET_STATE_SE:
-                               break;
-                       case TELNET_STATE_WILL:
-                       case TELNET_STATE_WONT:
-                       case TELNET_STATE_DO:
-                       case TELNET_STATE_DONT:
-                               t_con->state = TELNET_STATE_DATA;
-                               break;
-                       case TELNET_STATE_ESCAPE:
-                               if (t_con->last_escape == '[')
-                               {
-                                       if (*buf_p == 'D') /* cursor left */
-                                       {
-                                               if (t_con->line_cursor > 0)
-                                               {
-                                                       telnet_write(connection, "\b", 1);
-                                                       t_con->line_cursor--;
-                                               }
-                                               t_con->state = TELNET_STATE_DATA;
-                                       }
-                                       else if (*buf_p == 'C') /* cursor right */
-                                       {
-                                               if (t_con->line_cursor < t_con->line_size)
-                                               {
-                                                       telnet_write(connection, t_con->line + t_con->line_cursor++, 1);
-                                               }
-                                               t_con->state = TELNET_STATE_DATA;
-                                       }
-                                       else if (*buf_p == 'A') /* cursor up */
-                                       {
-                                               int last_history = (t_con->current_history > 0) ? t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1;
-                                               if (t_con->history[last_history])
-                                               {
-                                                       telnet_clear_line(connection, t_con);
-                                                       t_con->line_size = strlen(t_con->history[last_history]);
-                                                       t_con->line_cursor = t_con->line_size;
-                                                       memcpy(t_con->line, t_con->history[last_history], t_con->line_size + 1);
-                                                       telnet_write(connection, t_con->line, t_con->line_size);
-                                                       t_con->current_history = last_history;
-                                               }
-                                               t_con->state = TELNET_STATE_DATA;
-                                       }
-                                       else if (*buf_p == 'B') /* cursor down */
-                                       {
-                                               int next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE;
-                                               if (t_con->history[next_history])
-                                               {
-                                                       telnet_clear_line(connection, t_con);
-                                                       t_con->line_size = strlen(t_con->history[next_history]);
-                                                       t_con->line_cursor = t_con->line_size;
-                                                       memcpy(t_con->line, t_con->history[next_history], t_con->line_size + 1);
-                                                       telnet_write(connection, t_con->line, t_con->line_size);
-                                                       t_con->current_history = next_history;
-                                               }
-                                               t_con->state = TELNET_STATE_DATA;
-                                       }
-                                       else if (*buf_p == '3')
-                                       {
-                                               t_con->last_escape = *buf_p;
-                                       }
-                                       else
-                                       {
-                                               t_con->state = TELNET_STATE_DATA;
-                                       }
-                               }
-                               else if (t_con->last_escape == '3')
-                               {
-                                       /* Remove character */
-                                       if (*buf_p == '~')
-                                       {
-                                               if (t_con->line_cursor < t_con->line_size)
-                                               {
-                                                       int i;
-                                                       t_con->line_size--;
-                                                       /* remove char from line buffer */
-                                                       memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor);
-                                                       
-                                                       /* print remainder of buffer */
-                                                       telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);
-                                                       /* overwrite last char with whitespace */
-                                                       telnet_write(connection, " \b", 2);
-                                                       
-                                                       /* move back to cursor position*/
-                                                       for (i = t_con->line_cursor; i < t_con->line_size; i++)
-                                                       {
-                                                               telnet_write(connection, "\b", 1);
-                                                       }
-                                               }
-                                                       
-                                               t_con->state = TELNET_STATE_DATA;
-                                       }
-                                       else
-                                       {
-                                               t_con->state = TELNET_STATE_DATA;
-                                       }
-                               }
-                               else if (t_con->last_escape == '\x00')
-                               {
-                                       if (*buf_p == '[')
-                                       {
-                                               t_con->last_escape = *buf_p;
-                                       }
-                                       else
-                                       {
-                                               t_con->state = TELNET_STATE_DATA;
-                                       }
-                               }
-                               else
-                               {
-                                       ERROR("BUG: unexpected value in t_con->last_escape");
-                                       t_con->state = TELNET_STATE_DATA;
-                               }
-                               
-                               break;
-                       default:
-                               ERROR("unknown telnet state");
-                               exit(-1);
-               }
-
-               bytes_read--;
-               buf_p++;
-       }
-       
-       return ERROR_OK;
-}
-
-int telnet_connection_closed(connection_t *connection)
-{
-       telnet_connection_t *t_con = connection->priv;
-       int i;
-       
-       if (t_con->prompt)
-       {
-               free(t_con->prompt);
-               t_con->prompt = NULL;
-       }
-       
-       for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
-       {
-               if (t_con->history[i])
-               {
-                       free(t_con->history[i]);
-                       t_con->history[i] = NULL;
-               }
-       }
-       
-       /* if this connection registered a debug-message receiver delete it */
-       delete_debug_msg_receiver(connection->cmd_ctx, NULL);
-       
-       if (connection->priv)
-       {
-               free(connection->priv);
-               connection->priv = NULL;
-       }
-       else
-       {
-               ERROR("BUG: connection->priv == NULL");
-       }
-       
-       target_unregister_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx);
-
-       return ERROR_OK;
-}
-
-int telnet_set_prompt(connection_t *connection, char *prompt)
-{
-       telnet_connection_t *t_con = connection->priv;
-
-       t_con->prompt = strdup(prompt);
-       
-       return ERROR_OK;
-}
-
-int telnet_init(char *banner)
-{
-       telnet_service_t *telnet_service = malloc(sizeof(telnet_service_t));
-       
-       if (telnet_port == 0)
-       {
-               WARNING("no telnet port specified, using default port 4444");
-               telnet_port = 4444;
-       }
-       
-       telnet_service->banner = banner;
-       
-       add_service("telnet", CONNECTION_TELNET, telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service);
-       
-       return ERROR_OK;
-}
-
-int telnet_register_commands(command_context_t *command_context)
-{
-       register_command(command_context, NULL, "exit", handle_exit_command,
-                                        COMMAND_EXEC, "exit telnet session");
-       
-       register_command(command_context, NULL, "telnet_port", handle_telnet_port_command,
-                                        COMMAND_CONFIG, "");
-       
-       return ERROR_OK;
-}
-
-/* daemon configuration command telnet_port */
-int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       if (argc == 0)
-               return ERROR_OK;
-
-       /* only if the port wasn't overwritten by cmdline */
-       if (telnet_port == 0)
-               telnet_port = strtoul(args[0], NULL, 0);
-
-       return ERROR_OK;
-}
-
-int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
-       return ERROR_COMMAND_CLOSE_CONNECTION;
-}
+/***************************************************************************\r
+ *   Copyright (C) 2005 by Dominic Rath                                    *\r
+ *   Dominic.Rath@gmx.de                                                   *\r
+ *                                                                         *\r
+ *   This program is free software; you can redistribute it and/or modify  *\r
+ *   it under the terms of the GNU General Public License as published by  *\r
+ *   the Free Software Foundation; either version 2 of the License, or     *\r
+ *   (at your option) any later version.                                   *\r
+ *                                                                         *\r
+ *   This program is distributed in the hope that it will be useful,       *\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
+ *   GNU General Public License for more details.                          *\r
+ *                                                                         *\r
+ *   You should have received a copy of the GNU General Public License     *\r
+ *   along with this program; if not, write to the                         *\r
+ *   Free Software Foundation, Inc.,                                       *\r
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
+ ***************************************************************************/\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include "replacements.h"\r
+\r
+#include "telnet_server.h"\r
+\r
+#include "server.h"\r
+#include "log.h"\r
+#include "command.h"\r
+#include "target.h"\r
+#include "target_request.h"\r
+\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <errno.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+\r
+static unsigned short telnet_port = 0;\r
+\r
+int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
+\r
+static char *negotiate =\r
+               "\xFF\xFB\x03"          /* IAC WILL Suppress Go Ahead */\r
+               "\xFF\xFB\x01"          /* IAC WILL Echo */\r
+               "\xFF\xFD\x03"          /* IAC DO Suppress Go Ahead */\r
+               "\xFF\xFE\x01";         /* IAC DON'T Echo */\r
+               \r
+#define CTRL(c) (c - '@')\r
+       \r
+/* The only way we can detect that the socket is closed is the first time\r
+ * we write to it, we will fail. Subsequent write operations will\r
+ * succeed. Shudder!\r
+ */\r
+int telnet_write(connection_t *connection, void *data, int len)\r
+{\r
+       telnet_connection_t *t_con = connection->priv;\r
+       if (t_con->closed)\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+\r
+       if (write_socket(connection->fd, data, len) == len)\r
+       {\r
+               return ERROR_OK;\r
+       }\r
+       t_con->closed = 1;\r
+       return ERROR_SERVER_REMOTE_CLOSED;\r
+}\r
+\r
+int telnet_prompt(connection_t *connection)\r
+{\r
+       telnet_connection_t *t_con = connection->priv;\r
+\r
+       return telnet_write(connection, t_con->prompt, strlen(t_con->prompt));\r
+}\r
+\r
+int telnet_outputline(connection_t *connection, char* line)\r
+{\r
+       telnet_write(connection, line, strlen(line));\r
+       return telnet_write(connection, "\r\n\0", 3);\r
+}\r
+\r
+int telnet_output(struct command_context_s *cmd_ctx, char* line)\r
+{\r
+       connection_t *connection = cmd_ctx->output_handler_priv;\r
+       \r
+       return telnet_outputline(connection, line);\r
+}\r
+\r
+void telnet_log_callback(void *priv, const char *file, int line, \r
+               const char *function, const char *format, va_list args)\r
+{\r
+       connection_t *connection = priv;\r
+       char *t = alloc_printf(format, args);\r
+       char *t2;\r
+       if (t == NULL)\r
+               return;\r
+       t2=t;\r
+       char *endline;\r
+       do \r
+       {\r
+               if ((endline=strchr(t2, '\n'))!=NULL)\r
+               {\r
+                       *endline=0;\r
+               }\r
+               telnet_outputline(connection, t2);\r
+               t2=endline+1;\r
+       } while (endline);\r
+       \r
+       free(t);\r
+}\r
+\r
+int telnet_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)\r
+{\r
+       struct command_context_s *cmd_ctx = priv;\r
+       connection_t *connection = cmd_ctx->output_handler_priv;\r
+       telnet_connection_t *t_con = connection->priv;\r
+       \r
+       switch (event)\r
+       {\r
+               case TARGET_EVENT_HALTED:\r
+                       target_arch_state(target);\r
+                       if (!t_con->suppress_prompt)\r
+                               telnet_prompt(connection);\r
+                       break;\r
+               case TARGET_EVENT_RESUMED:\r
+                       if (!t_con->suppress_prompt)\r
+                               telnet_prompt(connection);\r
+                       break;\r
+               default:\r
+                       break;\r
+       }\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int telnet_new_connection(connection_t *connection)\r
+{\r
+       telnet_connection_t *telnet_connection = malloc(sizeof(telnet_connection_t));\r
+       telnet_service_t *telnet_service = connection->service->priv;\r
+       int i;\r
+       \r
+       connection->priv = telnet_connection;\r
+       \r
+       /* initialize telnet connection information */\r
+       telnet_connection->closed = 0;\r
+       telnet_connection->line_size = 0;\r
+       telnet_connection->line_cursor = 0;\r
+       telnet_connection->option_size = 0;\r
+       telnet_connection->prompt = strdup("> ");\r
+       telnet_connection->suppress_prompt = 0;\r
+       telnet_connection->state = TELNET_STATE_DATA;\r
+       \r
+       /* output goes through telnet connection */\r
+       command_set_output_handler(connection->cmd_ctx, telnet_output, connection);\r
+       \r
+       /* negotiate telnet options */\r
+       telnet_write(connection, negotiate, strlen(negotiate));\r
+       \r
+       /* print connection banner */\r
+       if (telnet_service->banner)\r
+       {\r
+               telnet_write(connection, telnet_service->banner, strlen(telnet_service->banner));\r
+               telnet_write(connection, "\r\n\0", 3);\r
+       }\r
+       \r
+       telnet_prompt(connection);\r
+       \r
+       /* initialize history */\r
+       for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)\r
+       {\r
+               telnet_connection->history[i] = NULL;\r
+       }\r
+       telnet_connection->next_history = 0;\r
+       telnet_connection->current_history = 0;\r
+\r
+       target_register_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx);\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+void telnet_clear_line(connection_t *connection, telnet_connection_t *t_con)\r
+{\r
+       /* move to end of line */\r
+       if (t_con->line_cursor < t_con->line_size)\r
+       {\r
+               telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);\r
+       }\r
+                                                       \r
+       /* backspace, overwrite with space, backspace */\r
+       while (t_con->line_size > 0)\r
+       {\r
+               telnet_write(connection, "\b \b", 3);\r
+               t_con->line_size--;\r
+       }\r
+       t_con->line_cursor = 0;\r
+}\r
+\r
+int telnet_input(connection_t *connection)\r
+{\r
+       int bytes_read;\r
+       char buffer[TELNET_BUFFER_SIZE];\r
+       char *buf_p;\r
+       telnet_connection_t *t_con = connection->priv;\r
+       command_context_t *command_context = connection->cmd_ctx;\r
+       \r
+       bytes_read = read_socket(connection->fd, buffer, TELNET_BUFFER_SIZE);\r
+       \r
+       if (bytes_read == 0)\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       else if (bytes_read == -1)\r
+       {\r
+               ERROR("error during read: %s", strerror(errno));\r
+               return ERROR_SERVER_REMOTE_CLOSED;\r
+       }\r
+       \r
+       buf_p = buffer;\r
+       while (bytes_read)\r
+       {\r
+               switch (t_con->state)\r
+               {\r
+                       case TELNET_STATE_DATA:\r
+                               if (*buf_p == '\xff')\r
+                               {\r
+                                       t_con->state = TELNET_STATE_IAC;\r
+                               }\r
+                               else\r
+                               {\r
+                                       if (isprint(*buf_p)) /* printable character */\r
+                                       {\r
+                                               telnet_write(connection, buf_p, 1);\r
+                                               if (t_con->line_cursor == t_con->line_size)\r
+                                               {\r
+                                                       t_con->line[t_con->line_size++] = *buf_p;\r
+                                                       t_con->line_cursor++;\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       int i;\r
+                                                       memmove(t_con->line + t_con->line_cursor + 1, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);\r
+                                                       t_con->line[t_con->line_cursor++] = *buf_p;\r
+                                                       t_con->line_size++;\r
+                                                       telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);\r
+                                                       for (i = t_con->line_cursor; i < t_con->line_size; i++)\r
+                                                       {\r
+                                                               telnet_write(connection, "\b", 1);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       else /* non-printable */\r
+                                       {\r
+                                               if (*buf_p == 0x1b) /* escape */\r
+                                               {\r
+                                                       t_con->state = TELNET_STATE_ESCAPE;\r
+                                                       t_con->last_escape = '\x00';\r
+                                               }\r
+                                               else if ((*buf_p == 0xd) || (*buf_p == 0xa)) /* CR/LF */\r
+                                               {\r
+                                                       int retval;\r
+                                                       \r
+                                                       /* skip over combinations with CR/LF + NUL */\r
+                                                       if (((*(buf_p + 1) == 0xa) || (*(buf_p + 1) == 0xd)) && (bytes_read > 1))\r
+                                                       {\r
+                                                               buf_p++;\r
+                                                               bytes_read--;\r
+                                                       }\r
+                                                       if ((*(buf_p + 1) == 0) && (bytes_read > 1))\r
+                                                       {\r
+                                                               buf_p++;\r
+                                                               bytes_read--;\r
+                                                       }\r
+                                                       t_con->line[t_con->line_size] = 0;\r
+                                                       \r
+                                                       telnet_write(connection, "\r\n\x00", 3);\r
+                                                       \r
+                                                       if (strcmp(t_con->line, "history") == 0)\r
+                                                       {\r
+                                                               int i;\r
+                                                               for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)\r
+                                                               {\r
+                                                                       if (t_con->history[i])\r
+                                                                       {\r
+                                                                               telnet_write(connection, t_con->history[i], strlen(t_con->history[i]));\r
+                                                                               telnet_write(connection, "\r\n\x00", 3);\r
+                                                                       }\r
+                                                               }\r
+                                                               telnet_prompt(connection);\r
+                                                               t_con->line_size = 0;\r
+                                                               t_con->line_cursor = 0;\r
+                                                               continue;\r
+                                                       }\r
+                                                       \r
+                                                       log_add_callback(telnet_log_callback, connection);\r
+                                                       t_con->suppress_prompt = 1;\r
+\r
+                                                       retval = command_run_line(command_context, t_con->line);\r
+                                                       \r
+                                                       log_remove_callback(telnet_log_callback, connection);\r
+                                                       t_con->suppress_prompt = 0;\r
+\r
+                                                       if (retval == ERROR_COMMAND_CLOSE_CONNECTION)\r
+                                                       {\r
+                                                               return ERROR_SERVER_REMOTE_CLOSED;\r
+                                                       }\r
+                                                       \r
+                                                       /* Save only non-blank lines in the history */\r
+                                                       if (t_con->line_size > 0)\r
+                                                       {\r
+                                                               /* if the history slot is already taken, free it */\r
+                                                               if (t_con->history[t_con->next_history])\r
+                                                               {\r
+                                                                       free(t_con->history[t_con->next_history]);\r
+                                                               }\r
+               \r
+                                                               /* add line to history */\r
+                                                               t_con->history[t_con->next_history] = strdup(t_con->line);\r
+\r
+                                                               /* wrap history at TELNET_LINE_HISTORY_SIZE */\r
+                                                               t_con->next_history = (t_con->next_history + 1) % TELNET_LINE_HISTORY_SIZE;\r
+                                                       \r
+                                                               /* current history line starts at the new entry */\r
+                                                               t_con->current_history = t_con->next_history;\r
+                                                       \r
+                                                               if (t_con->history[t_con->current_history])\r
+                                                               {\r
+                                                                       free(t_con->history[t_con->current_history]);\r
+                                                               }\r
+                                                               t_con->history[t_con->current_history] = strdup("");\r
+                                                       }\r
+                                                       \r
+                                                       int t = telnet_prompt(connection);\r
+                                                       if (t == ERROR_SERVER_REMOTE_CLOSED)\r
+                                                               return t;\r
+                                                       \r
+                                                       t_con->line_size = 0;\r
+                                                       t_con->line_cursor = 0;\r
+                                               }\r
+                                               else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) /* delete character */\r
+                                               {\r
+                                                       if (t_con->line_cursor > 0)\r
+                                                       {\r
+                                                               if (t_con->line_cursor != t_con->line_size)\r
+                                                               {\r
+                                                                       int i;\r
+                                                                       telnet_write(connection, "\b", 1);\r
+                                                                       t_con->line_cursor--;\r
+                                                                       t_con->line_size--;\r
+                                                                       memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor);\r
+                                                                       \r
+                                                                       telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);\r
+                                                                       telnet_write(connection, " \b", 2);\r
+                                                                       for (i = t_con->line_cursor; i < t_con->line_size; i++)\r
+                                                                       {\r
+                                                                               telnet_write(connection, "\b", 1);\r
+                                                                       }\r
+                                                               }\r
+                                                               else\r
+                                                               {\r
+                                                                       t_con->line_size--;\r
+                                                                       t_con->line_cursor--;\r
+                                                                       /* back space: move the 'printer' head one char back, overwrite with space, move back again */\r
+                                                                       telnet_write(connection, "\b \b", 3);\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                               else if (*buf_p == 0x15) /* clear line */\r
+                                               {\r
+                                                       telnet_clear_line(connection, t_con);\r
+                                               }\r
+                                               else if (*buf_p == CTRL('B')) /* cursor left */\r
+                                               {\r
+                                                       if (t_con->line_cursor > 0)\r
+                                                       {\r
+                                                               telnet_write(connection, "\b", 1);\r
+                                                               t_con->line_cursor--;\r
+                                                       }\r
+                                                       t_con->state = TELNET_STATE_DATA;\r
+                                               }\r
+                                               else if (*buf_p == CTRL('F')) /* cursor right */\r
+                                               {\r
+                                                       if (t_con->line_cursor < t_con->line_size)\r
+                                                       {\r
+                                                               telnet_write(connection, t_con->line + t_con->line_cursor++, 1);\r
+                                                       }\r
+                                                       t_con->state = TELNET_STATE_DATA;\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       DEBUG("unhandled nonprintable: %2.2x", *buf_p);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case TELNET_STATE_IAC:\r
+                               switch (*buf_p)\r
+                               {\r
+                                       case '\xfe':\r
+                                               t_con->state = TELNET_STATE_DONT;\r
+                                               break;\r
+                                       case '\xfd':\r
+                                               t_con->state = TELNET_STATE_DO;\r
+                                               break;\r
+                                       case '\xfc':\r
+                                               t_con->state = TELNET_STATE_WONT;\r
+                                               break;\r
+                                       case '\xfb':\r
+                                               t_con->state = TELNET_STATE_WILL;\r
+                                               break;\r
+                               }\r
+                               break;\r
+                       case TELNET_STATE_SB:\r
+                               break;\r
+                       case TELNET_STATE_SE:\r
+                               break;\r
+                       case TELNET_STATE_WILL:\r
+                       case TELNET_STATE_WONT:\r
+                       case TELNET_STATE_DO:\r
+                       case TELNET_STATE_DONT:\r
+                               t_con->state = TELNET_STATE_DATA;\r
+                               break;\r
+                       case TELNET_STATE_ESCAPE:\r
+                               if (t_con->last_escape == '[')\r
+                               {\r
+                                       if (*buf_p == 'D') /* cursor left */\r
+                                       {\r
+                                               if (t_con->line_cursor > 0)\r
+                                               {\r
+                                                       telnet_write(connection, "\b", 1);\r
+                                                       t_con->line_cursor--;\r
+                                               }\r
+                                               t_con->state = TELNET_STATE_DATA;\r
+                                       }\r
+                                       else if (*buf_p == 'C') /* cursor right */\r
+                                       {\r
+                                               if (t_con->line_cursor < t_con->line_size)\r
+                                               {\r
+                                                       telnet_write(connection, t_con->line + t_con->line_cursor++, 1);\r
+                                               }\r
+                                               t_con->state = TELNET_STATE_DATA;\r
+                                       }\r
+                                       else if (*buf_p == 'A') /* cursor up */\r
+                                       {\r
+                                               int last_history = (t_con->current_history > 0) ? t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1;\r
+                                               if (t_con->history[last_history])\r
+                                               {\r
+                                                       telnet_clear_line(connection, t_con);\r
+                                                       t_con->line_size = strlen(t_con->history[last_history]);\r
+                                                       t_con->line_cursor = t_con->line_size;\r
+                                                       memcpy(t_con->line, t_con->history[last_history], t_con->line_size + 1);\r
+                                                       telnet_write(connection, t_con->line, t_con->line_size);\r
+                                                       t_con->current_history = last_history;\r
+                                               }\r
+                                               t_con->state = TELNET_STATE_DATA;\r
+                                       }\r
+                                       else if (*buf_p == 'B') /* cursor down */\r
+                                       {\r
+                                               int next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE;\r
+                                               if (t_con->history[next_history])\r
+                                               {\r
+                                                       telnet_clear_line(connection, t_con);\r
+                                                       t_con->line_size = strlen(t_con->history[next_history]);\r
+                                                       t_con->line_cursor = t_con->line_size;\r
+                                                       memcpy(t_con->line, t_con->history[next_history], t_con->line_size + 1);\r
+                                                       telnet_write(connection, t_con->line, t_con->line_size);\r
+                                                       t_con->current_history = next_history;\r
+                                               }\r
+                                               t_con->state = TELNET_STATE_DATA;\r
+                                       }\r
+                                       else if (*buf_p == '3')\r
+                                       {\r
+                                               t_con->last_escape = *buf_p;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               t_con->state = TELNET_STATE_DATA;\r
+                                       }\r
+                               }\r
+                               else if (t_con->last_escape == '3')\r
+                               {\r
+                                       /* Remove character */\r
+                                       if (*buf_p == '~')\r
+                                       {\r
+                                               if (t_con->line_cursor < t_con->line_size)\r
+                                               {\r
+                                                       int i;\r
+                                                       t_con->line_size--;\r
+                                                       /* remove char from line buffer */\r
+                                                       memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor);\r
+                                                       \r
+                                                       /* print remainder of buffer */\r
+                                                       telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor);\r
+                                                       /* overwrite last char with whitespace */\r
+                                                       telnet_write(connection, " \b", 2);\r
+                                                       \r
+                                                       /* move back to cursor position*/\r
+                                                       for (i = t_con->line_cursor; i < t_con->line_size; i++)\r
+                                                       {\r
+                                                               telnet_write(connection, "\b", 1);\r
+                                                       }\r
+                                               }\r
+                                                       \r
+                                               t_con->state = TELNET_STATE_DATA;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               t_con->state = TELNET_STATE_DATA;\r
+                                       }\r
+                               }\r
+                               else if (t_con->last_escape == '\x00')\r
+                               {\r
+                                       if (*buf_p == '[')\r
+                                       {\r
+                                               t_con->last_escape = *buf_p;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               t_con->state = TELNET_STATE_DATA;\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       ERROR("BUG: unexpected value in t_con->last_escape");\r
+                                       t_con->state = TELNET_STATE_DATA;\r
+                               }\r
+                               \r
+                               break;\r
+                       default:\r
+                               ERROR("unknown telnet state");\r
+                               exit(-1);\r
+               }\r
+\r
+               bytes_read--;\r
+               buf_p++;\r
+       }\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+int telnet_connection_closed(connection_t *connection)\r
+{\r
+       telnet_connection_t *t_con = connection->priv;\r
+       int i;\r
+       \r
+       if (t_con->prompt)\r
+       {\r
+               free(t_con->prompt);\r
+               t_con->prompt = NULL;\r
+       }\r
+       \r
+       for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)\r
+       {\r
+               if (t_con->history[i])\r
+               {\r
+                       free(t_con->history[i]);\r
+                       t_con->history[i] = NULL;\r
+               }\r
+       }\r
+       \r
+       /* if this connection registered a debug-message receiver delete it */\r
+       delete_debug_msg_receiver(connection->cmd_ctx, NULL);\r
+       \r
+       if (connection->priv)\r
+       {\r
+               free(connection->priv);\r
+               connection->priv = NULL;\r
+       }\r
+       else\r
+       {\r
+               ERROR("BUG: connection->priv == NULL");\r
+       }\r
+       \r
+       target_unregister_event_callback(telnet_target_callback_event_handler, connection->cmd_ctx);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int telnet_set_prompt(connection_t *connection, char *prompt)\r
+{\r
+       telnet_connection_t *t_con = connection->priv;\r
+\r
+       t_con->prompt = strdup(prompt);\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+int telnet_init(char *banner)\r
+{\r
+       telnet_service_t *telnet_service = malloc(sizeof(telnet_service_t));\r
+       \r
+       if (telnet_port == 0)\r
+       {\r
+               WARNING("no telnet port specified, using default port 4444");\r
+               telnet_port = 4444;\r
+       }\r
+       \r
+       telnet_service->banner = banner;\r
+       \r
+       add_service("telnet", CONNECTION_TELNET, telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service);\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+int telnet_register_commands(command_context_t *command_context)\r
+{\r
+       register_command(command_context, NULL, "exit", handle_exit_command,\r
+                                        COMMAND_EXEC, "exit telnet session");\r
+       \r
+       register_command(command_context, NULL, "telnet_port", handle_telnet_port_command,\r
+                                        COMMAND_CONFIG, "");\r
+       \r
+       return ERROR_OK;\r
+}\r
+\r
+/* daemon configuration command telnet_port */\r
+int handle_telnet_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       if (argc == 0)\r
+               return ERROR_OK;\r
+\r
+       /* only if the port wasn't overwritten by cmdline */\r
+       if (telnet_port == 0)\r
+               telnet_port = strtoul(args[0], NULL, 0);\r
+\r
+       return ERROR_OK;\r
+}\r
+\r
+int handle_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
+{\r
+       return ERROR_COMMAND_CLOSE_CONNECTION;\r
+}\r

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)