gdbserver: gdb cmds returning failure on success
[openocd.git] / src / server / gdb_server.c
index 72f14095a244ed13185ef20a0110252c2b511d28..a84c618aff084177becbf0c85e9918e0a880c383 100644 (file)
@@ -2,7 +2,7 @@
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
- *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
+ *   Copyright (C) 2007-2010 Øyvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
  *   Copyright (C) 2008 by Spencer Oliver                                  *
 #include "config.h"
 #endif
 
-#include "replacements.h"
-
+#include <target/breakpoints.h>
+#include <target/target_request.h>
+#include <target/register.h>
+#include "server.h"
+#include <flash/nor/core.h>
 #include "gdb_server.h"
+#include <target/image.h>
+#include <jtag/jtag.h>
+
+
+/**
+ * @file
+ * GDB server implementation.
+ *
+ * This implements the GDB Remote Serial Protocol, over TCP connections,
+ * giving GDB access to the JTAG or other hardware debugging facilities
+ * found in most modern embedded processors.
+ */
+
+/* private connection data for GDB */
+struct gdb_connection
+{
+       char buffer[GDB_BUFFER_SIZE];
+       char *buf_p;
+       int buf_cnt;
+       int ctrl_c;
+       enum target_state frontend_state;
+       struct image *vflash_image;
+       int closed;
+       int busy;
+       int noack_mode;
+       bool sync;      /* set flag to true if you want the next stepi to return immediately.
+                      allowing GDB to pick up a fresh set of register values from the target
+                      without modifying the target state. */
+       /* We delay reporting memory write errors until next step/continue or memory
+        * write. This improves performance of gdb load significantly as the GDB packet
+        * can be replied immediately and a new GDB packet will be ready without delay
+        * (ca. 10% or so...).
+        */
+       bool mem_write_error;
+};
 
-#include "server.h"
-#include "log.h"
-#include "binarybuffer.h"
-#include "jtag.h"
-#include "breakpoints.h"
-#include "flash.h"
-#include "target.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 struct gdb_connection *current_gdb_connection;
+
 static int gdb_breakpoint_override;
 static enum breakpoint_type gdb_breakpoint_override_type;
 
-extern int gdb_error(connection_t *connection, int retval);
-static unsigned short gdb_port;
-static const char *DIGITS = "0123456789abcdef";
+static int gdb_error(struct connection *connection, int retval);
+static unsigned short gdb_port = 3333;
+static unsigned short gdb_port_next = 0;
+static const char DIGITS[16] = "0123456789abcdef";
 
-static void gdb_log_callback(void *priv, const char *file, int line,
+static void gdb_log_callback(void *priv, const char *file, unsigned line,
                const char *function, const char *string);
 
-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;
+/* number of gdb connections, mainly to suppress gdb related debugging spam
+ * in helper/log.c when no gdb connections are actually active */
+int gdb_actual_connections;
 
 /* set if we are sending a memory map to gdb
  * via qXfer:memory-map:read packet */
 /* enabled by default*/
-int gdb_use_memory_map = 1;
+static int gdb_use_memory_map = 1;
 /* enabled by default*/
-int gdb_flash_program = 1;
+static int gdb_flash_program = 1;
 
 /* 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;
+ * see the code in gdb_read_memory_packet() for further explanations.
+ * Disabled by default.
+ */
+static int gdb_report_data_abort;
 
-int gdb_last_signal(target_t *target)
+static int gdb_last_signal(struct target *target)
 {
        switch (target->debug_reason)
        {
@@ -102,20 +124,21 @@ int gdb_last_signal(target_t *target)
        }
 }
 
-int check_pending(connection_t *connection, int timeout_s, int *got_data)
+static int check_pending(struct connection *connection,
+               int timeout_s, int *got_data)
 {
        /* 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;
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *gdb_con = connection->priv;
        int t;
-       if (got_data==NULL)
+       if (got_data == NULL)
                got_data=&t;
-       *got_data=0;
+       *got_data = 0;
 
-       if (gdb_con->buf_cnt>0)
+       if (gdb_con->buf_cnt > 0)
        {
                *got_data = 1;
                return ERROR_OK;
@@ -126,12 +149,12 @@ int check_pending(connection_t *connection, int timeout_s, int *got_data)
 
        tv.tv_sec = timeout_s;
        tv.tv_usec = 0;
-       if (select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0)
+       if (socket_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
                 */
-               if (timeout_s>0)
+               if (timeout_s > 0)
                {
                        return ERROR_GDB_TIMEOUT;
                } else
@@ -139,34 +162,18 @@ int check_pending(connection_t *connection, int timeout_s, int *got_data)
                        return ERROR_OK;
                }
        }
-       *got_data=FD_ISSET(connection->fd, &read_fds)!=0;
+       *got_data = FD_ISSET(connection->fd, &read_fds) != 0;
        return ERROR_OK;
 }
 
-int gdb_get_char(connection_t *connection, int* next_char)
+static int gdb_get_char_inner(struct connection *connection, int* next_char)
 {
-       gdb_connection_t *gdb_con = connection->priv;
-       int retval=ERROR_OK;
+       struct gdb_connection *gdb_con = connection->priv;
+       int retval = ERROR_OK;
 
 #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_
-               LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
-#endif
-
-               return ERROR_OK;
-       }
-
        for (;;)
        {
                if (connection->service->type == CONNECTION_PIPE)
@@ -180,7 +187,7 @@ int gdb_get_char(connection_t *connection, int* next_char)
                                return retval;
                        gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
                }
-               
+
                if (gdb_con->buf_cnt > 0)
                {
                        break;
@@ -194,7 +201,7 @@ int gdb_get_char(connection_t *connection, int* next_char)
 #ifdef _WIN32
                errno = WSAGetLastError();
 
-               switch(errno)
+               switch (errno)
                {
                        case WSAEWOULDBLOCK:
                                usleep(1000);
@@ -210,7 +217,7 @@ int gdb_get_char(connection_t *connection, int* next_char)
                                exit(-1);
                }
 #else
-               switch(errno)
+               switch (errno)
                {
                        case EAGAIN:
                                usleep(1000);
@@ -251,9 +258,53 @@ int gdb_get_char(connection_t *connection, int* next_char)
        return retval;
 }
 
-int gdb_putback_char(connection_t *connection, int last_char)
+/**
+ * The cool thing about this fn is that it allows buf_p and buf_cnt to be
+ * held in registers in the inner loop.
+ *
+ * For small caches and embedded systems this is important!
+ */
+static inline int gdb_get_char_fast(struct connection *connection, int* next_char, char **buf_p, int *buf_cnt)
+{
+       int retval = ERROR_OK;
+
+       if ((*buf_cnt)-- > 0)
+       {
+               *next_char = **buf_p;
+               (*buf_p)++;
+               if (*buf_cnt > 0)
+                       connection->input_pending = 1;
+               else
+                       connection->input_pending = 0;
+
+#ifdef _DEBUG_GDB_IO_
+               LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
+#endif
+
+               return ERROR_OK;
+       }
+
+       struct gdb_connection *gdb_con = connection->priv;
+       gdb_con->buf_p = *buf_p;
+       gdb_con->buf_cnt = *buf_cnt;
+       retval = gdb_get_char_inner(connection, next_char);
+       *buf_p = gdb_con->buf_p;
+       *buf_cnt = gdb_con->buf_cnt;
+
+       return retval;
+}
+
+
+static int gdb_get_char(struct connection *connection, int* next_char)
 {
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *gdb_con = connection->priv;
+       return gdb_get_char_fast(connection, next_char, &gdb_con->buf_p, &gdb_con->buf_cnt);
+}
+
+
+static int gdb_putback_char(struct connection *connection, int last_char)
+{
+       struct gdb_connection *gdb_con = connection->priv;
 
        if (gdb_con->buf_p > gdb_con->buffer)
        {
@@ -271,12 +322,12 @@ int gdb_putback_char(connection_t *connection, int last_char)
 /* 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)
+static int gdb_write(struct connection *connection, void *data, int len)
 {
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *gdb_con = connection->priv;
        if (gdb_con->closed)
                return ERROR_SERVER_REMOTE_CLOSED;
-       
+
        if (connection->service->type == CONNECTION_PIPE)
        {
                /* write to stdout */
@@ -296,7 +347,8 @@ int gdb_write(connection_t *connection, void *data, int len)
        return ERROR_SERVER_REMOTE_CLOSED;
 }
 
-int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
+static int gdb_put_packet_inner(struct connection *connection,
+               char *buffer, int len)
 {
        int i;
        unsigned char my_checksum = 0;
@@ -305,7 +357,7 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
 #endif
        int reply;
        int retval;
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *gdb_con = connection->priv;
 
        for (i = 0; i < len; i++)
                my_checksum += buffer[i];
@@ -319,15 +371,16 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
        int gotdata;
        for (;;)
        {
-               if ((retval=check_pending(connection, 0, &gotdata))!=ERROR_OK)
+               retval = check_pending(connection, 0, &gotdata);
+               if (retval != ERROR_OK)
                        return retval;
                if (!gotdata)
                        break;
                if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
                        return retval;
-               if( reply == '$' ){
+               if (reply == '$') {
                        /* fix a problem with some IAR tools */
-                       gdb_putback_char( connection, reply );
+                       gdb_putback_char(connection, reply);
                        LOG_DEBUG("Unexpected start of new packet");
                        break;
                }
@@ -348,14 +401,14 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
 
                char local_buffer[1024];
                local_buffer[0] = '$';
-               if (len+4 <= sizeof(local_buffer))
+               if ((size_t)len + 4 <= sizeof(local_buffer))
                {
                        /* performance gain on smaller packets by only a single call to gdb_write() */
-                       memcpy(local_buffer+1, buffer, len++);
+                       memcpy(local_buffer + 1, buffer, len++);
                        local_buffer[len++] = '#';
                        local_buffer[len++] = DIGITS[(my_checksum >> 4) & 0xf];
                        local_buffer[len++] = DIGITS[my_checksum & 0xf];
-                       if((retval = gdb_write(connection, local_buffer, len)) != ERROR_OK)
+                       if ((retval = gdb_write(connection, local_buffer, len)) != ERROR_OK)
                        {
                                return retval;
                        }
@@ -367,15 +420,15 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
                        local_buffer[1] = '#';
                        local_buffer[2] = DIGITS[(my_checksum >> 4) & 0xf];
                        local_buffer[3] = DIGITS[my_checksum & 0xf];
-                       if((retval = gdb_write(connection, local_buffer, 1)) != ERROR_OK)
+                       if ((retval = gdb_write(connection, local_buffer, 1)) != ERROR_OK)
                        {
                                return retval;
                        }
-                       if((retval = gdb_write(connection, buffer, len)) != ERROR_OK)
+                       if ((retval = gdb_write(connection, buffer, len)) != ERROR_OK)
                        {
                                return retval;
                        }
-                       if((retval = gdb_write(connection, local_buffer+1, 3)) != ERROR_OK)
+                       if ((retval = gdb_write(connection, local_buffer + 1, 3)) != ERROR_OK)
                        {
                                return retval;
                        }
@@ -408,26 +461,26 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
                                log_remove_callback(gdb_log_callback, connection);
                                LOG_WARNING("negative reply, retrying");
                        }
-                       else if( reply == '$' ){
+                       else if (reply == '$') {
                                LOG_ERROR("GDB missing ack(1) - assumed good");
-                               gdb_putback_char( connection, reply );
+                               gdb_putback_char(connection, reply);
                                return ERROR_OK;
                        } else {
 
                                LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply);
-                               gdb_con->closed=1;
+                               gdb_con->closed = 1;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        }
                }
-               else if( reply == '$' ){
+               else if (reply == '$') {
                        LOG_ERROR("GDB missing ack(2) - assumed good");
-                       gdb_putback_char( connection, reply );
+                       gdb_putback_char(connection, reply);
                        return ERROR_OK;
                }
                else
                {
                        LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection", reply);
-                       gdb_con->closed=1;
+                       gdb_con->closed = 1;
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
        }
@@ -437,9 +490,9 @@ int gdb_put_packet_inner(connection_t *connection, char *buffer, int len)
        return ERROR_OK;
 }
 
-int gdb_put_packet(connection_t *connection, char *buffer, int len)
+static int gdb_put_packet(struct connection *connection, char *buffer, int len)
 {
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *gdb_con = connection->priv;
        gdb_con->busy = 1;
        int retval = gdb_put_packet_inner(connection, buffer, len);
        gdb_con->busy = 0;
@@ -450,32 +503,38 @@ int gdb_put_packet(connection_t *connection, char *buffer, int len)
        return retval;
 }
 
-static __inline__ int fetch_packet(connection_t *connection, int *checksum_ok, int noack, int *len, char *buffer)
+static __inline__ int fetch_packet(struct connection *connection, int *checksum_ok, int noack, int *len, char *buffer)
 {
        unsigned char my_checksum = 0;
        char checksum[3];
        int character;
-       int retval;
+       int retval = ERROR_OK;
 
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *gdb_con = connection->priv;
        my_checksum = 0;
        int count = 0;
        count = 0;
+
+       /* move this over into local variables to use registers and give the
+        * more freedom to optimize */
+       char *buf_p = gdb_con->buf_p;
+       int buf_cnt = gdb_con->buf_cnt;
+
        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))
+               if ((buf_cnt > 2) && ((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;
+                       char *buf = buf_p;
+                       int run = buf_cnt - 2;
                        i = 0;
                        int done = 0;
                        while (i < run)
@@ -507,19 +566,21 @@ static __inline__ int fetch_packet(connection_t *connection, int *checksum_ok, i
                                        buffer[count++] = character & 0xff;
                                }
                        }
-                       gdb_con->buf_p += i;
-                       gdb_con->buf_cnt -= i;
+                       buf_p += i;
+                       buf_cnt -= i;
                        if (done)
                                break;
                }
                if (count > *len)
                {
                        LOG_ERROR("packet buffer too small");
-                       return ERROR_GDB_BUFFER_TOO_SMALL;
+                       retval = ERROR_GDB_BUFFER_TOO_SMALL;
+                       break;
                }
 
-               if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
-                       return retval;
+               retval = gdb_get_char_fast(connection, &character, &buf_p, &buf_cnt);
+               if (retval != ERROR_OK)
+                       break;
 
                if (character == '#')
                        break;
@@ -529,8 +590,11 @@ static __inline__ int fetch_packet(connection_t *connection, int *checksum_ok, i
                        /* 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;
+
+                       retval = gdb_get_char_fast(connection, &character, &buf_p, &buf_cnt);
+                       if (retval != ERROR_OK)
+                               break;
+
                        my_checksum += character & 0xff;
                        buffer[count++] = (character ^ 0x20) & 0xff;
                }
@@ -541,6 +605,12 @@ static __inline__ int fetch_packet(connection_t *connection, int *checksum_ok, i
                }
        }
 
+       gdb_con->buf_p = buf_p;
+       gdb_con->buf_cnt = buf_cnt;
+
+       if (retval != ERROR_OK)
+               return retval;
+
        *len = count;
 
        if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
@@ -553,17 +623,18 @@ static __inline__ int fetch_packet(connection_t *connection, int *checksum_ok, i
 
        if (!noack)
        {
-               *checksum_ok=(my_checksum == strtoul(checksum, NULL, 16));
+               *checksum_ok = (my_checksum == strtoul(checksum, NULL, 16));
        }
 
        return ERROR_OK;
 }
 
-int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
+static int gdb_get_packet_inner(struct connection *connection,
+               char *buffer, int *len)
 {
        int character;
        int retval;
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *gdb_con = connection->priv;
 
        while (1)
        {
@@ -582,7 +653,7 @@ int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
                                        break;
                                case '+':
                                        /* gdb sends a dummy ack '+' at every remote connect - see remote_start_remote (remote.c)
-                                        * incase anyone tries to debug why they receive this warning every time */
+                                        * in case anyone tries to debug why they receive this warning every time */
                                        LOG_WARNING("acknowledgment received, but no packet pending");
                                        break;
                                case '-':
@@ -600,17 +671,17 @@ int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
 
 
 
-               int checksum_ok;
+               int checksum_ok = 0;
                /* explicit code expansion here to get faster inlined code in -O3 by not
                 * calculating checksum
                 */
                if (gdb_con->noack_mode)
                {
-                       if ((retval=fetch_packet(connection, &checksum_ok, 1, len, buffer))!=ERROR_OK)
+                       if ((retval = fetch_packet(connection, &checksum_ok, 1, len, buffer)) != ERROR_OK)
                                return retval;
                } else
                {
-                       if ((retval=fetch_packet(connection, &checksum_ok, 0, len, buffer))!=ERROR_OK)
+                       if ((retval = fetch_packet(connection, &checksum_ok, 0, len, buffer)) != ERROR_OK)
                                return retval;
                }
 
@@ -634,16 +705,16 @@ int gdb_get_packet_inner(connection_t *connection, char *buffer, int *len)
        return ERROR_OK;
 }
 
-int gdb_get_packet(connection_t *connection, char *buffer, int *len)
+static int gdb_get_packet(struct connection *connection, char *buffer, int *len)
 {
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *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, const char* line)
+static int gdb_output_con(struct connection *connection, const char* line)
 {
        char *hex_buffer;
        int i, bin_size;
@@ -655,9 +726,9 @@ int gdb_output_con(connection_t *connection, const char* line)
                return ERROR_GDB_BUFFER_TOO_SMALL;
 
        hex_buffer[0] = 'O';
-       for (i=0; i<bin_size; i++)
+       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 + 1] = 0;
 
        int retval = gdb_put_packet(connection, hex_buffer, bin_size*2 + 1);
 
@@ -665,7 +736,7 @@ int gdb_output_con(connection_t *connection, const char* line)
        return retval;
 }
 
-int gdb_output(struct command_context_s *context, const char* line)
+static int gdb_output(struct command_context *context, const char* line)
 {
        /* this will be dumped to the log and also sent as an O packet if possible */
        LOG_USER_N("%s", line);
@@ -673,11 +744,11 @@ int gdb_output(struct command_context_s *context, const char* line)
 }
 
 
-static void gdb_frontend_halted(struct target_s *target, connection_t *connection)
+static void gdb_frontend_halted(struct target *target, struct connection *connection)
 {
-       gdb_connection_t *gdb_connection = connection->priv;
+       struct gdb_connection *gdb_connection = connection->priv;
 
-       /* In the GDB protocol when we are stepping or coninuing execution,
+       /* In the GDB protocol when we are stepping or continuing 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.
@@ -710,23 +781,24 @@ static void gdb_frontend_halted(struct target_s *target, connection_t *connectio
        }
 }
 
-int gdb_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
+static int gdb_target_callback_event_handler(struct target *target,
+               enum target_event event, void *priv)
 {
        int retval;
-       connection_t *connection = priv;
+       struct connection *connection = priv;
 
-       target_handle_event( target, event );
+       target_handle_event(target, event);
        switch (event)
        {
-               case TARGET_EVENT_EARLY_HALTED:
+               case TARGET_EVENT_GDB_HALT:
                        gdb_frontend_halted(target, connection);
                        break;
                case TARGET_EVENT_HALTED:
                        target_call_event_callbacks(target, TARGET_EVENT_GDB_END);
                        break;
                case TARGET_EVENT_GDB_FLASH_ERASE_START:
-                       target_handle_event( target, TARGET_EVENT_OLD_gdb_program_config );
-                       if((retval = jtag_execute_queue()) != ERROR_OK)
+                       target_handle_event(target, TARGET_EVENT_OLD_gdb_program_config);
+                       if ((retval = jtag_execute_queue()) != ERROR_OK)
                        {
                                return retval;
                        }
@@ -738,10 +810,10 @@ int gdb_target_callback_event_handler(struct target_s *target, enum target_event
        return ERROR_OK;
 }
 
-int gdb_new_connection(connection_t *connection)
+static int gdb_new_connection(struct connection *connection)
 {
-       gdb_connection_t *gdb_connection = malloc(sizeof(gdb_connection_t));
-       gdb_service_t *gdb_service = connection->service->priv;
+       struct gdb_connection *gdb_connection = malloc(sizeof(struct gdb_connection));
+       struct gdb_service *gdb_service = connection->service->priv;
        int retval;
        int initial_ack;
 
@@ -756,6 +828,8 @@ int gdb_new_connection(connection_t *connection)
        gdb_connection->closed = 0;
        gdb_connection->busy = 0;
        gdb_connection->noack_mode = 0;
+       gdb_connection->sync = true;
+       gdb_connection->mem_write_error = false;
 
        /* send ACK to GDB for debug request */
        gdb_write(connection, "+", 1);
@@ -773,30 +847,6 @@ int gdb_new_connection(connection_t *connection)
        /* register callback to be informed about target events */
        target_register_event_callback(gdb_target_callback_event_handler, connection);
 
-       /* a gdb session just attached, try to put the target in halt mode.
-        *
-        * DANGER!!!!
-        *
-        * If the halt fails(e.g. target needs a reset, JTAG communication not
-        * working, etc.), then the GDB connect will succeed as
-        * the get_gdb_reg_list() will lie and return a register list with
-        * dummy values.
-        *
-        * This allows GDB monitor commands to be run from a GDB init script to
-        * initialize the target
-        *
-        * Also, since the halt() is asynchronous target connect will be
-        * instantaneous and thus avoiding annoying timeout problems during
-        * connect.
-        */
-       target_halt(gdb_service->target);
-       /* FIX!!!! could extended-remote work better here?
-        *
-        *  wait a tiny bit for halted state or we just continue. The
-        * GDB register packet will then contain garbage
-        */
-       target_wait_state(gdb_service->target, TARGET_HALTED, 500);
-
        /* remove the initial ACK from the incoming buffer */
        if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)
                return retval;
@@ -806,14 +856,52 @@ int gdb_new_connection(connection_t *connection)
         */
        if (initial_ack != '+')
                gdb_putback_char(connection, initial_ack);
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH );
+       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH);
+
+       if (gdb_use_memory_map)
+       {
+               /* Connect must fail if the memory map can't be set up correctly.
+                *
+                * This will cause an auto_probe to be invoked, which is either
+                * a no-op or it will fail when the target isn't ready(e.g. not halted).
+                */
+               int i;
+               for (i = 0; i < flash_get_bank_count(); i++)
+               {
+                       struct flash_bank *p;
+                       retval = get_flash_bank_by_num(i, &p);
+                       if (retval != ERROR_OK)
+                       {
+                               LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect.");
+                               return retval;
+                       }
+               }
+       }
+
+       gdb_actual_connections++;
+       LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s",
+                 gdb_actual_connections,
+                 target_name(gdb_service->target),
+                 target_state_name(gdb_service->target));
+
        return ERROR_OK;
 }
 
-int gdb_connection_closed(connection_t *connection)
+static int gdb_connection_closed(struct connection *connection)
 {
-       gdb_service_t *gdb_service = connection->service->priv;
-       gdb_connection_t *gdb_connection = connection->priv;
+       struct gdb_service *gdb_service = connection->service->priv;
+       struct gdb_connection *gdb_connection = connection->priv;
+
+       /* we're done forwarding messages. Tear down callback before
+        * cleaning up connection.
+        */
+       log_remove_callback(gdb_log_callback, connection);
+
+       gdb_actual_connections--;
+       LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d",
+                 target_name(gdb_service->target),
+                 target_state_name(gdb_service->target),
+                 gdb_actual_connections);
 
        /* see if an image built with vFlash commands is left */
        if (gdb_connection->vflash_image)
@@ -836,23 +924,25 @@ int gdb_connection_closed(connection_t *connection)
                LOG_ERROR("BUG: connection->priv == NULL");
        }
 
+
        target_unregister_event_callback(gdb_target_callback_event_handler, connection);
+
        target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_END);
-       log_remove_callback(gdb_log_callback, connection);
 
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH );
+       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH);
 
        return ERROR_OK;
 }
 
-void gdb_send_error(connection_t *connection, u8 the_error)
+static void gdb_send_error(struct connection *connection, uint8_t the_error)
 {
        char err[4];
-       snprintf(err, 4, "E%2.2X", the_error );
+       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)
+static int gdb_last_signal_packet(struct connection *connection,
+               struct target *target, char* packet, int packet_size)
 {
        char sig_reply[4];
        int signal;
@@ -865,7 +955,7 @@ int gdb_last_signal_packet(connection_t *connection, target_t *target, char* pac
        return ERROR_OK;
 }
 
-static int gdb_reg_pos(target_t *target, int pos, int len)
+static int gdb_reg_pos(struct target *target, int pos, int len)
 {
        if (target->endianness == TARGET_LITTLE_ENDIAN)
                return pos;
@@ -877,35 +967,36 @@ static int gdb_reg_pos(target_t *target, int pos, int len)
  * register might be non-divisible by 8(a byte), in which
  * case an entire byte is shown.
  *
- * NB! the format on the wire is the target endianess
+ * NB! the format on the wire is the target endianness
  *
  * The format of reg->value is little endian
  *
  */
-void gdb_str_to_target(target_t *target, char *tstr, reg_t *reg)
+static void gdb_str_to_target(struct target *target,
+               char *tstr, struct reg *reg)
 {
        int i;
 
-       u8 *buf;
+       uint8_t *buf;
        int buf_len;
        buf = reg->value;
-       buf_len = CEIL(reg->size, 8);
+       buf_len = DIV_ROUND_UP(reg->size, 8);
 
        for (i = 0; i < buf_len; i++)
        {
                int j = gdb_reg_pos(target, i, buf_len);
                tstr[i*2]   = DIGITS[(buf[j]>>4) & 0xf];
-               tstr[i*2+1] = DIGITS[buf[j]&0xf];
+               tstr[i*2 + 1] = DIGITS[buf[j]&0xf];
        }
 }
 
-static int hextoint(char c)
+static int hextoint(int c)
 {
        if (c>='0'&&c<='9')
        {
                return c-'0';
        }
-       c=toupper(c);
+       c = toupper(c);
        if (c>='A'&&c<='F')
        {
                return c-'A'+10;
@@ -915,7 +1006,8 @@ static int hextoint(char c)
 }
 
 /* copy over in register buffer */
-void gdb_target_to_reg(target_t *target, char *tstr, int str_len, u8 *bin)
+static void gdb_target_to_reg(struct target *target,
+               char *tstr, int str_len, uint8_t *bin)
 {
        if (str_len % 2)
        {
@@ -924,19 +1016,20 @@ void gdb_target_to_reg(target_t *target, char *tstr, int str_len, u8 *bin)
        }
 
        int i;
-       for (i = 0; i < str_len; i+=2)
+       for (i = 0; i < str_len; i += 2)
        {
-               u8 t = hextoint(tstr[i])<<4;
-               t |= hextoint(tstr[i+1]);
+               uint8_t t = hextoint(tstr[i]) << 4;
+               t |= hextoint(tstr[i + 1]);
 
                int j = gdb_reg_pos(target, i/2, str_len/2);
                bin[j] = t;
        }
 }
 
-int gdb_get_registers_packet(connection_t *connection, target_t *target, char* packet, int packet_size)
+static int gdb_get_registers_packet(struct connection *connection,
+               struct target *target, char* packet, int packet_size)
 {
-       reg_t **reg_list;
+       struct reg **reg_list;
        int reg_list_size;
        int retval;
        int reg_packet_size = 0;
@@ -948,7 +1041,7 @@ int gdb_get_registers_packet(connection_t *connection, target_t *target, char* p
        LOG_DEBUG("-");
 #endif
 
-       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
+       if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
        {
                return gdb_error(connection, retval);
        }
@@ -958,25 +1051,25 @@ int gdb_get_registers_packet(connection_t *connection, target_t *target, char* p
                reg_packet_size += reg_list[i]->size;
        }
 
-       reg_packet = malloc(CEIL(reg_packet_size, 8) * 2);
+       reg_packet = malloc(DIV_ROUND_UP(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;
+               reg_packet_p += DIV_ROUND_UP(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);
+               reg_packet_p = strndup(reg_packet, DIV_ROUND_UP(reg_packet_size, 8) * 2);
                LOG_DEBUG("reg_packet: %s", reg_packet_p);
                free(reg_packet_p);
        }
 #endif
 
-       gdb_put_packet(connection, reg_packet, CEIL(reg_packet_size, 8) * 2);
+       gdb_put_packet(connection, reg_packet, DIV_ROUND_UP(reg_packet_size, 8) * 2);
        free(reg_packet);
 
        free(reg_list);
@@ -984,10 +1077,11 @@ int gdb_get_registers_packet(connection_t *connection, target_t *target, char* p
        return ERROR_OK;
 }
 
-int gdb_set_registers_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+static int gdb_set_registers_packet(struct connection *connection,
+               struct target *target, char *packet, int packet_size)
 {
        int i;
-       reg_t **reg_list;
+       struct reg **reg_list;
        int reg_list_size;
        int retval;
        char *packet_p;
@@ -1006,7 +1100,7 @@ int gdb_set_registers_packet(connection_t *connection, target_t *target, char *p
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
+       if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
        {
                return gdb_error(connection, retval);
        }
@@ -1014,22 +1108,18 @@ int gdb_set_registers_packet(connection_t *connection, target_t *target, char *p
        packet_p = packet;
        for (i = 0; i < reg_list_size; i++)
        {
-               u8 *bin_buf;
-               int chars = (CEIL(reg_list[i]->size, 8) * 2);
+               uint8_t *bin_buf;
+               int chars = (DIV_ROUND_UP(reg_list[i]->size, 8) * 2);
 
                if (packet_p + chars > packet + packet_size)
                {
                        LOG_ERROR("BUG: register packet is too small for registers");
                }
 
-               reg_arch_type_t *arch_type;
-               bin_buf = malloc(CEIL(reg_list[i]->size, 8));
+               bin_buf = malloc(DIV_ROUND_UP(reg_list[i]->size, 8));
                gdb_target_to_reg(target, packet_p, chars, bin_buf);
 
-               /* get register arch_type, and call set method */
-               arch_type = register_get_arch_type(reg_list[i]->arch_type);
-
-               arch_type->set(reg_list[i], bin_buf);
+               reg_list[i]->type->set(reg_list[i], bin_buf);
 
                /* advance packet pointer */
                packet_p += chars;
@@ -1038,7 +1128,7 @@ int gdb_set_registers_packet(connection_t *connection, target_t *target, char *p
                free(bin_buf);
        }
 
-       /* free reg_t *reg_list[] array allocated by get_gdb_reg_list */
+       /* free struct reg *reg_list[] array allocated by get_gdb_reg_list */
        free(reg_list);
 
        gdb_put_packet(connection, "OK", 2);
@@ -1046,11 +1136,12 @@ int gdb_set_registers_packet(connection_t *connection, target_t *target, char *p
        return ERROR_OK;
 }
 
-int gdb_get_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+static int gdb_get_register_packet(struct connection *connection,
+               struct target *target, char *packet, int packet_size)
 {
        char *reg_packet;
        int reg_num = strtoul(packet + 1, NULL, 16);
-       reg_t **reg_list;
+       struct reg **reg_list;
        int reg_list_size;
        int retval;
 
@@ -1058,7 +1149,7 @@ int gdb_get_register_packet(connection_t *connection, target_t *target, char *pa
        LOG_DEBUG("-");
 #endif
 
-       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
+       if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
        {
                return gdb_error(connection, retval);
        }
@@ -1069,11 +1160,11 @@ int gdb_get_register_packet(connection_t *connection, target_t *target, char *pa
                exit(-1);
        }
 
-       reg_packet = malloc(CEIL(reg_list[reg_num]->size, 8) * 2);
+       reg_packet = malloc(DIV_ROUND_UP(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);
+       gdb_put_packet(connection, reg_packet, DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
 
        free(reg_list);
        free(reg_packet);
@@ -1081,19 +1172,19 @@ int gdb_get_register_packet(connection_t *connection, target_t *target, char *pa
        return ERROR_OK;
 }
 
-int gdb_set_register_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+static int gdb_set_register_packet(struct connection *connection,
+               struct target *target, char *packet, int packet_size)
 {
        char *separator;
-       u8 *bin_buf;
+       uint8_t *bin_buf;
        int reg_num = strtoul(packet + 1, &separator, 16);
-       reg_t **reg_list;
+       struct reg **reg_list;
        int reg_list_size;
        int retval;
-       reg_arch_type_t *arch_type;
 
        LOG_DEBUG("-");
 
-       if ((retval = target->type->get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
+       if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
        {
                return gdb_error(connection, retval);
        }
@@ -1111,16 +1202,14 @@ int gdb_set_register_packet(connection_t *connection, target_t *target, char *pa
        }
 
        /* convert from GDB-string (target-endian) to hex-string (big-endian) */
-       bin_buf = malloc(CEIL(reg_list[reg_num]->size, 8));
-       int chars = (CEIL(reg_list[reg_num]->size, 8) * 2);
+       bin_buf = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8));
+       int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
 
        /* fix!!! add some sanity checks on packet size here */
 
        gdb_target_to_reg(target, separator + 1, chars, bin_buf);
 
-               /* get register arch_type, and call set method */
-       arch_type = register_get_arch_type(reg_list[reg_num]->arch_type);
-       arch_type->set(reg_list[reg_num], bin_buf);
+       reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf);
 
        gdb_put_packet(connection, "OK", 2);
 
@@ -1130,7 +1219,7 @@ int gdb_set_register_packet(connection_t *connection, target_t *target, char *pa
        return ERROR_OK;
 }
 
-int gdb_error(connection_t *connection, int retval)
+static int gdb_error(struct connection *connection, int retval)
 {
        switch (retval)
        {
@@ -1161,13 +1250,14 @@ int gdb_error(connection_t *connection, int retval)
  *
  * 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)
+static int gdb_read_memory_packet(struct connection *connection,
+               struct target *target, char *packet, int packet_size)
 {
        char *separator;
-       u32 addr = 0;
-       u32 len = 0;
+       uint32_t addr = 0;
+       uint32_t len = 0;
 
-       u8 *buffer;
+       uint8_t *buffer;
        char *hex_buffer;
 
        int retval = ERROR_OK;
@@ -1183,15 +1273,15 @@ int gdb_read_memory_packet(connection_t *connection, target_t *target, char *pac
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       len = strtoul(separator+1, NULL, 16);
+       len = strtoul(separator + 1, NULL, 16);
 
        buffer = malloc(len);
 
-       LOG_DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
+       LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
 
        retval = target_read_buffer(target, addr, len, buffer);
 
-       if ((retval!=ERROR_OK)&&!gdb_report_data_abort)
+       if ((retval != ERROR_OK)&&!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.
@@ -1200,7 +1290,7 @@ int gdb_read_memory_packet(connection_t *connection, target_t *target, char *pac
                 * 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
+                * 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.
@@ -1213,10 +1303,10 @@ int gdb_read_memory_packet(connection_t *connection, target_t *target, char *pac
        {
                hex_buffer = malloc(len * 2 + 1);
 
-               int i;
+               uint32_t i;
                for (i = 0; i < len; i++)
                {
-                       u8 t = buffer[i];
+                       uint8_t t = buffer[i];
                        hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf];
                        hex_buffer[2 * i + 1] = DIGITS[t & 0xf];
                }
@@ -1235,15 +1325,16 @@ int gdb_read_memory_packet(connection_t *connection, target_t *target, char *pac
        return retval;
 }
 
-int gdb_write_memory_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+static int gdb_write_memory_packet(struct connection *connection,
+               struct target *target, char *packet, int packet_size)
 {
        char *separator;
-       u32 addr = 0;
-       u32 len = 0;
+       uint32_t addr = 0;
+       uint32_t len = 0;
 
-       u8 *buffer;
+       uint8_t *buffer;
 
-       int i;
+       uint32_t i;
        int retval;
 
        /* skip command character */
@@ -1257,7 +1348,7 @@ int gdb_write_memory_packet(connection_t *connection, target_t *target, char *pa
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       len = strtoul(separator+1, &separator, 16);
+       len = strtoul(separator + 1, &separator, 16);
 
        if (*(separator++) != ':')
        {
@@ -1267,12 +1358,12 @@ int gdb_write_memory_packet(connection_t *connection, target_t *target, char *pa
 
        buffer = malloc(len);
 
-       LOG_DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
+       LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
 
-       for (i=0; i<len; i++)
+       for (i = 0; i < len; i++)
        {
-               u32 tmp;
-               sscanf(separator + 2*i, "%2x", &tmp);
+               uint32_t tmp;
+               sscanf(separator + 2*i, "%2" SCNx32 , &tmp);
                buffer[i] = tmp;
        }
 
@@ -1292,13 +1383,14 @@ int gdb_write_memory_packet(connection_t *connection, target_t *target, char *pa
        return retval;
 }
 
-int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+static int gdb_write_memory_binary_packet(struct connection *connection,
+               struct target *target, char *packet, int packet_size)
 {
        char *separator;
-       u32 addr = 0;
-       u32 len = 0;
+       uint32_t addr = 0;
+       uint32_t len = 0;
 
-       int retval;
+       int retval = ERROR_OK;
 
        /* skip command character */
        packet++;
@@ -1311,7 +1403,7 @@ int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, c
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       len = strtoul(separator+1, &separator, 16);
+       len = strtoul(separator + 1, &separator, 16);
 
        if (*(separator++) != ':')
        {
@@ -1319,14 +1411,18 @@ int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, c
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       retval = ERROR_OK;
-       if (len)
-       {
-               LOG_DEBUG("addr: 0x%8.8x, len: 0x%8.8x", addr, len);
+       struct gdb_connection *gdb_connection = connection->priv;
 
-               retval = target_write_buffer(target, addr, len, (u8*)separator);
+       if (gdb_connection->mem_write_error)
+       {
+               retval = ERROR_FAIL;
+               /* now that we have reported the memory write error, we can clear the condition */
+               gdb_connection->mem_write_error = false;
        }
 
+       /* By replying the packet *immediately* GDB will send us a new packet
+        * while we write the last one to the target.
+        */
        if (retval == ERROR_OK)
        {
                gdb_put_packet(connection, "OK", 2);
@@ -1337,14 +1433,26 @@ int gdb_write_memory_binary_packet(connection_t *connection, target_t *target, c
                        return retval;
        }
 
+       if (len)
+       {
+               LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
+
+               retval = target_write_buffer(target, addr, len, (uint8_t*)separator);
+               if (retval != ERROR_OK)
+               {
+                       gdb_connection->mem_write_error = true;
+               }
+       }
+
        return ERROR_OK;
 }
 
-int gdb_step_continue_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+static int gdb_step_continue_packet(struct connection *connection,
+               struct target *target, char *packet, int packet_size)
 {
        int current = 0;
-       u32 address = 0x0;
-       int retval=ERROR_OK;
+       uint32_t address = 0x0;
+       int retval = ERROR_OK;
 
        LOG_DEBUG("-");
 
@@ -1361,24 +1469,26 @@ int gdb_step_continue_packet(connection_t *connection, target_t *target, char *p
        if (packet[0] == 'c')
        {
                LOG_DEBUG("continue");
-               target_handle_event( target, TARGET_EVENT_OLD_pre_resume );
-               retval=target_resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */
+               target_handle_event(target, TARGET_EVENT_OLD_pre_resume);
+               retval = target_resume(target, current, address, 0, 0); /* resume at current address, don't handle breakpoints, not debugging */
        }
        else if (packet[0] == 's')
        {
                LOG_DEBUG("step");
-               retval=target->type->step(target, current, address, 0); /* step at current or address, don't handle breakpoints */
+               /* step at current or address, don't handle breakpoints */
+               retval = target_step(target, current, address, 0);
        }
        return retval;
 }
 
-int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
+               struct target *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;
+       enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */;
+       uint32_t address;
+       uint32_t size;
        char *separator;
        int retval;
 
@@ -1396,10 +1506,16 @@ int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target,
                wp_type = WPT_READ;
        else if (type == 4) /* access watchpoint */
                wp_type = WPT_ACCESS;
+       else
+       {
+               LOG_ERROR("invalid gdb watch/breakpoint type(%d), dropping connection", type);
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
+
 
-       if (gdb_breakpoint_override&&((bp_type==BKPT_SOFT)||(bp_type==BKPT_HARD)))
+       if (gdb_breakpoint_override && ((bp_type == BKPT_SOFT)||(bp_type == BKPT_HARD)))
        {
-               bp_type=gdb_breakpoint_override_type;
+               bp_type = gdb_breakpoint_override_type;
        }
 
        if (*separator != ',')
@@ -1408,7 +1524,7 @@ int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target,
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       address = strtoul(separator+1, &separator, 16);
+       address = strtoul(separator + 1, &separator, 16);
 
        if (*separator != ',')
        {
@@ -1416,7 +1532,7 @@ int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target,
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       size = strtoul(separator+1, &separator, 16);
+       size = strtoul(separator + 1, &separator, 16);
 
        switch (type)
        {
@@ -1446,7 +1562,7 @@ int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target,
                {
                        if (packet[0] == 'Z')
                        {
-                               if ((retval = watchpoint_add(target, address, size, type-2, 0, 0xffffffffu)) != ERROR_OK)
+                               if ((retval = watchpoint_add(target, address, size, wp_type, 0, 0xffffffffu)) != ERROR_OK)
                                {
                                        if ((retval = gdb_error(connection, retval)) != ERROR_OK)
                                                return retval;
@@ -1470,8 +1586,11 @@ int gdb_breakpoint_watchpoint_packet(connection_t *connection, target_t *target,
        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, ...)
+/* print out a string and allocate more space as needed,
+ * mainly used for XML at this point
+ */
+static void xml_printf(int *retval, char **xml, int *pos, int *size,
+               const char *fmt, ...)
 {
        if (*retval != ERROR_OK)
        {
@@ -1533,37 +1652,21 @@ static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len
        if (*separator != ',')
                return -1;
 
-       *len = strtoul(separator+1, NULL, 16);
+       *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;
-}
-
 static int compare_bank (const void * a, const void * b)
 {
-       flash_bank_t *b1, *b2;
-       b1=*((flash_bank_t **)a);
-       b2=*((flash_bank_t **)b);
+       struct flash_bank *b1, *b2;
+       b1=*((struct flash_bank **)a);
+       b2=*((struct flash_bank **)b);
 
-       if (b1->base==b2->base)
+       if (b1->base == b2->base)
        {
                return 0;
-       } else if (b1->base>b2->base)
+       } else if (b1->base > b2->base)
        {
                return 1;
        } else
@@ -1572,10 +1675,154 @@ static int compare_bank (const void * a, const void * b)
        }
 }
 
-int gdb_query_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+static int gdb_memory_map(struct connection *connection,
+               struct target *target, char *packet, int packet_size)
+{
+       /* 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.
+        */
+
+       struct flash_bank *p;
+       char *xml = NULL;
+       int size = 0;
+       int pos = 0;
+       int retval = ERROR_OK;
+       struct flash_bank **banks;
+       int offset;
+       int length;
+       char *separator;
+       uint32_t ram_start = 0;
+       int i;
+
+       /* 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");
+
+       /* Sort banks in ascending order.  We need to report non-flash
+        * memory as ram (or rather read/write) by default for GDB, since
+        * it has no concept of non-cacheable read/write memory (i/o etc).
+        *
+        * FIXME Most non-flash addresses are *NOT* RAM!  Don't lie.
+        * Current versions of GDB assume unlisted addresses are RAM...
+        */
+       banks = malloc(sizeof(struct flash_bank *)*flash_get_bank_count());
+
+       for (i = 0; i < flash_get_bank_count(); i++) {
+               retval = get_flash_bank_by_num(i, &p);
+               if (retval != ERROR_OK)
+               {
+                       free(banks);
+                       gdb_send_error(connection, retval);
+                       return retval;
+               }
+               banks[i] = p;
+       }
+
+       qsort(banks, flash_get_bank_count(), sizeof(struct flash_bank *),
+                       compare_bank);
+
+       for (i = 0; i < flash_get_bank_count(); i++) {
+               int j;
+               unsigned sector_size = 0;
+               uint32_t start, end;
+
+               p = banks[i];
+               start = p->base;
+               end = p->base + p->size;
+
+               if (ram_start < p->base)
+                       xml_printf(&retval, &xml, &pos, &size,
+                               "<memory type=\"ram\" start=\"0x%x\" "
+                                       "length=\"0x%x\"/>\n",
+                               ram_start, p->base - ram_start);
+
+               /* Report adjacent groups of same-size sectors.  So for
+                * example top boot CFI flash will list an initial region
+                * with several large sectors (maybe 128KB) and several
+                * smaller ones at the end (maybe 32KB).  STR7 will have
+                * regions with 8KB, 32KB, and 64KB sectors; etc.
+                */
+               for (j = 0; j < p->num_sectors; j++) {
+                       unsigned group_len;
+
+                       /* Maybe start a new group of sectors. */
+                       if (sector_size == 0) {
+                               start = p->base + p->sectors[j].offset;
+                               xml_printf(&retval, &xml, &pos, &size,
+                                       "<memory type=\"flash\" "
+                                               "start=\"0x%x\" ",
+                                       start);
+                               sector_size = p->sectors[j].size;
+                       }
+
+                       /* Does this finish a group of sectors?
+                        * If not, continue an already-started group.
+                        */
+                       if (j == p->num_sectors -1)
+                               group_len = (p->base + p->size) - start;
+                       else if (p->sectors[j + 1].size != sector_size)
+                               group_len = p->base + p->sectors[j + 1].offset
+                                               - start;
+                       else
+                               continue;
+
+                       xml_printf(&retval, &xml, &pos, &size,
+                               "length=\"0x%x\">\n"
+                               "<property name=\"blocksize\">"
+                                       "0x%x</property>\n"
+                               "</memory>\n",
+                               group_len,
+                               sector_size);
+                       sector_size = 0;
+               }
+
+               ram_start = p->base + p->size;
+       }
+
+       if (ram_start != 0)
+               xml_printf(&retval, &xml, &pos, &size,
+                       "<memory type=\"ram\" start=\"0x%x\" "
+                               "length=\"0x%x\"/>\n",
+                       ram_start, 0-ram_start);
+       /* ELSE a flash chip could be at the very end of the 32 bit address
+        * space, in which case ram_start will be precisely 0
+        */
+
+       free(banks);
+       banks = NULL;
+
+       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;
+}
+
+static int gdb_query_packet(struct connection *connection,
+       struct target *target, char *packet, int packet_size)
 {
-       command_context_t *cmd_ctx = connection->cmd_ctx;
-       gdb_connection_t *gdb_connection = connection->priv;
+       struct command_context *cmd_ctx = connection->cmd_ctx;
+       struct gdb_connection *gdb_connection = connection->priv;
 
        if (strstr(packet, "qRcmd,"))
        {
@@ -1584,10 +1831,10 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
                        char *cmd;
                        int i;
                        cmd = malloc((packet_size - 6)/2 + 1);
-                       for (i=0; i < (packet_size - 6)/2; i++)
+                       for (i = 0; i < (packet_size - 6)/2; i++)
                        {
-                               u32 tmp;
-                               sscanf(packet + 6 + 2*i, "%2x", &tmp);
+                               uint32_t tmp;
+                               sscanf(packet + 6 + 2*i, "%2" SCNx32 , &tmp);
                                cmd[i] = tmp;
                        }
                        cmd[(packet_size - 6)/2] = 0x0;
@@ -1595,7 +1842,11 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
                        /* We want to print all debug output to GDB connection */
                        log_add_callback(gdb_log_callback, connection);
                        target_call_timer_callbacks_now();
+                       /* some commands need to know the GDB connection, make note of current
+                        * GDB connection. */
+                       current_gdb_connection = gdb_connection;
                        command_run_line(cmd_ctx, cmd);
+                       current_gdb_connection = NULL;
                        target_call_timer_callbacks_now();
                        log_remove_callback(gdb_log_callback, connection);
                        free(cmd);
@@ -1610,9 +1861,9 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
                        int retval;
                        char gdb_reply[10];
                        char *separator;
-                       u32 checksum;
-                       u32 addr = 0;
-                       u32 len = 0;
+                       uint32_t checksum;
+                       uint32_t addr = 0;
+                       uint32_t len = 0;
 
                        /* skip command character */
                        packet += 5;
@@ -1631,7 +1882,7 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
 
                        if (retval == ERROR_OK)
                        {
-                               snprintf(gdb_reply, 10, "C%8.8x", checksum);
+                               snprintf(gdb_reply, 10, "C%8.8" PRIx32 "", checksum);
                                gdb_put_packet(connection, gdb_reply, 9);
                        }
                        else
@@ -1654,7 +1905,7 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
 
                xml_printf(&retval, &buffer, &pos, &size,
                                "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-;QStartNoAckMode+",
-                               (GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1)&&(flash_get_bank_count()>0)) ? '+' : '-');
+                               (GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-');
 
                if (retval != ERROR_OK)
                {
@@ -1667,112 +1918,9 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
 
                return ERROR_OK;
        }
-       else if (strstr(packet, "qXfer:memory-map:read::")&&(flash_get_bank_count()>0))
-       {
-               /* 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");
-
-               /*
-               sort banks in ascending order, we need to make non-flash memory be ram(or rather
-               read/write) by default for GDB.
-               GDB does not have a concept of non-cacheable read/write memory.
-                */
-               flash_bank_t **banks=malloc(sizeof(flash_bank_t *)*flash_get_bank_count());
-               int i;
-
-               for (i=0; i<flash_get_bank_count(); i++)
-               {
-                       p = get_flash_bank_by_num(i);
-                       if (p == NULL)
-                       {
-                               free(banks);
-                               retval = ERROR_FAIL;
-                               gdb_send_error(connection, retval);
-                               return retval;
-                       }
-                       banks[i]=p;
-               }
-
-               qsort(banks, flash_get_bank_count(), sizeof(flash_bank_t *), compare_bank);
-
-               u32 ram_start=0;
-               for (i=0; i<flash_get_bank_count(); i++)
-               {
-                       p = banks[i];
-
-                       if (ram_start<p->base)
-                       {
-                               xml_printf(&retval, &xml, &pos, &size, "<memory type=\"ram\" start=\"0x%x\" length=\"0x%x\"/>\n",
-                                       ram_start, p->base-ram_start);
-                       }
-
-                       /* 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);
-                       ram_start=p->base+p->size;
-               }
-               if (ram_start!=0)
-               {
-                       xml_printf(&retval, &xml, &pos, &size, "<memory type=\"ram\" start=\"0x%x\" length=\"0x%x\"/>\n",
-                               ram_start, 0-ram_start);
-               } else
-               {
-                       /* a flash chip could be at the very end of the 32 bit address space, in which case
-                       ram_start will be precisely 0 */
-               }
-
-               free(banks);
-               banks = NULL;
-
-               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:memory-map:read::")
+                       && (flash_get_bank_count() > 0))
+               return gdb_memory_map(connection, target, packet, packet_size);
        else if (strstr(packet, "qXfer:features:read:"))
        {
                char *xml = NULL;
@@ -1800,7 +1948,7 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
                }
 
                xml_printf(&retval, &xml, &pos, &size, \
-                       "l<target version=\"1.0\">\n<architecture>arm</architecture>\n</target>\n");
+                       "l < target version=\"1.0\">\n < architecture > arm</architecture>\n</target>\n");
 
                if (retval != ERROR_OK)
                {
@@ -1824,10 +1972,11 @@ int gdb_query_packet(connection_t *connection, target_t *target, char *packet, i
        return ERROR_OK;
 }
 
-int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int packet_size)
+static int gdb_v_packet(struct connection *connection,
+               struct target *target, char *packet, int packet_size)
 {
-       gdb_connection_t *gdb_connection = connection->priv;
-       gdb_service_t *gdb_service = connection->service->priv;
+       struct gdb_connection *gdb_connection = connection->priv;
+       struct gdb_service *gdb_service = connection->service->priv;
        int result;
 
        /* if flash programming disabled - send a empty reply */
@@ -1871,9 +2020,19 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
                flash_set_dirty();
 
                /* perform any target specific operations before the erase */
-               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_START);
-               result = flash_erase_address_range(gdb_service->target, addr, length );
-               target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_END);
+               target_call_event_callbacks(gdb_service->target,
+                               TARGET_EVENT_GDB_FLASH_ERASE_START);
+
+               /* vFlashErase:addr,length messages require region start and
+                * end to be "block" aligned ... if padding is ever needed,
+                * GDB will have become dangerously confused.
+                */
+               result = flash_erase_address_range(gdb_service->target,
+                               false, addr, length);
+
+               /* perform any target specific operations after the erase */
+               target_call_event_callbacks(gdb_service->target,
+                               TARGET_EVENT_GDB_FLASH_ERASE_END);
 
                /* perform erase */
                if (result != ERROR_OK)
@@ -1913,12 +2072,12 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
                /* create a new image if there isn't already one */
                if (gdb_connection->vflash_image == NULL)
                {
-                       gdb_connection->vflash_image = malloc(sizeof(image_t));
+                       gdb_connection->vflash_image = malloc(sizeof(struct image));
                        image_open(gdb_connection->vflash_image, "", "build");
                }
 
                /* create new section with content from packet buffer */
-               if((retval = image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (u8*)parse)) != ERROR_OK)
+               if ((retval = image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (uint8_t*)parse)) != ERROR_OK)
                {
                        return retval;
                }
@@ -1930,14 +2089,14 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
 
        if (!strcmp(packet, "vFlashDone"))
        {
-               u32 written;
+               uint32_t written;
 
                /* process the flashing buffer. No need to erase as GDB
                 * always issues a vFlashErase first. */
                target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_START);
                result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0);
                target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END);
-               if ( result != ERROR_OK)
+               if (result != ERROR_OK)
                {
                        if (result == ERROR_FLASH_DST_OUT_OF_BANK)
                                gdb_put_packet(connection, "E.memtype", 9);
@@ -1946,7 +2105,7 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
                        }
                else
                {
-                       LOG_DEBUG("wrote %u bytes from vFlash image to flash", written);
+                       LOG_DEBUG("wrote %u bytes from vFlash image to flash", (unsigned)written);
                        gdb_put_packet(connection, "OK", 2);
                }
 
@@ -1961,38 +2120,21 @@ int gdb_v_packet(connection_t *connection, target_t *target, char *packet, int p
        return ERROR_OK;
 }
 
-int gdb_detach(connection_t *connection, target_t *target)
+static int gdb_detach(struct connection *connection, struct target *target)
 {
+       struct gdb_service *gdb_service = connection->service->priv;
 
-       switch( detach_mode )
-       {
-               case GDB_DETACH_RESUME:
-                       target_handle_event( target, TARGET_EVENT_OLD_pre_resume );
-                       target_resume(target, 1, 0, 1, 0);
-                       break;
-
-               case GDB_DETACH_RESET:
-                       /* FIX?? make this configurable?? */
-                       target_process_reset(connection->cmd_ctx, RESET_HALT);
-                       break;
+       target_call_event_callbacks(gdb_service->target,
+                       TARGET_EVENT_GDB_DETACH);
 
-               case GDB_DETACH_HALT:
-                       target_halt(target);
-                       break;
-
-               case GDB_DETACH_NOTHING:
-                       break;
-       }
-
-       gdb_put_packet(connection, "OK", 2);
-       return ERROR_OK;
+       return gdb_put_packet(connection, "OK", 2);
 }
 
-static void gdb_log_callback(void *priv, const char *file, int line,
+static void gdb_log_callback(void *priv, const char *file, unsigned line,
                const char *function, const char *string)
 {
-       connection_t *connection = priv;
-       gdb_connection_t *gdb_con = connection->priv;
+       struct connection *connection = priv;
+       struct gdb_connection *gdb_con = connection->priv;
 
        if (gdb_con->busy)
        {
@@ -2003,10 +2145,7 @@ static void gdb_log_callback(void *priv, const char *file, int line,
        gdb_output_con(connection, string);
 }
 
-/* Do not allocate this on the stack */
-char gdb_packet_buffer[GDB_BUFFER_SIZE];
-
-static void gdb_sig_halted(connection_t *connection)
+static void gdb_sig_halted(struct connection *connection)
 {
        char sig_reply[4];
        snprintf(sig_reply, 4, "T%2.2x", 2);
@@ -2014,40 +2153,42 @@ static void gdb_sig_halted(connection_t *connection)
 
 }
 
-int gdb_input_inner(connection_t *connection)
+static int gdb_input_inner(struct connection *connection)
 {
-       gdb_service_t *gdb_service = connection->service->priv;
-       target_t *target = gdb_service->target;
-       char *packet=gdb_packet_buffer;
+       /* Do not allocate this on the stack */
+       static char gdb_packet_buffer[GDB_BUFFER_SIZE];
+
+       struct gdb_service *gdb_service = connection->service->priv;
+       struct target *target = gdb_service->target;
+       char *packet = gdb_packet_buffer;
        int packet_size;
        int retval;
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *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)
-               {
+               retval = gdb_get_packet(connection, packet, &packet_size);
+               if (retval != ERROR_OK)
                        return retval;
-               }
 
                /* terminate with zero */
                packet[packet_size] = 0;
 
-               if( LOG_LEVEL_IS( LOG_LVL_DEBUG ) ){
-                       if( packet[0] == 'X' ){
+               if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) {
+                       if (packet[0] == 'X') {
                                // binary packets spew junk into the debug log stream
                                char buf[ 50 ];
                                int x;
-                               for( x = 0 ; (x < 49) && (packet[x] != ':') ; x++ ){
+                               for (x = 0 ; (x < 49) && (packet[x] != ':') ; x++) {
                                        buf[x] = packet[x];
                                }
                                buf[x] = 0;
-                               LOG_DEBUG("received packet: '%s:<binary-data>'", buf );
+                               LOG_DEBUG("received packet: '%s:<binary-data>'", buf);
                        } else {
-                               LOG_DEBUG("received packet: '%s'", packet );
+                               LOG_DEBUG("received packet: '%s'", packet);
                        }
                }
 
@@ -2063,69 +2204,135 @@ int gdb_input_inner(connection_t *connection)
                                        break;
                                case 'q':
                                case 'Q':
-                                       retval = gdb_query_packet(connection, target, packet, packet_size);
+                                       retval = gdb_query_packet(connection,
+                                                       target, packet,
+                                                       packet_size);
                                        break;
                                case 'g':
-                                       retval = gdb_get_registers_packet(connection, target, packet, packet_size);
+                                       retval = gdb_get_registers_packet(
+                                                       connection, target,
+                                                       packet, packet_size);
                                        break;
                                case 'G':
-                                       retval = gdb_set_registers_packet(connection, target, packet, packet_size);
+                                       retval = gdb_set_registers_packet(
+                                                       connection, target,
+                                                       packet, packet_size);
                                        break;
                                case 'p':
-                                       retval = gdb_get_register_packet(connection, target, packet, packet_size);
+                                       retval = gdb_get_register_packet(
+                                                       connection, target,
+                                                       packet, packet_size);
                                        break;
                                case 'P':
-                                       retval = gdb_set_register_packet(connection, target, packet, packet_size);
+                                       retval = gdb_set_register_packet(
+                                                       connection, target,
+                                                       packet, packet_size);
                                        break;
                                case 'm':
-                                       retval = gdb_read_memory_packet(connection, target, packet, packet_size);
+                                       retval = gdb_read_memory_packet(
+                                                       connection, target,
+                                                       packet, packet_size);
                                        break;
                                case 'M':
-                                       retval = gdb_write_memory_packet(connection, target, packet, packet_size);
+                                       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);
+                                       gdb_last_signal_packet(
+                                                       connection, target,
+                                                       packet, packet_size);
                                        break;
                                case 'c':
                                case 's':
                                        {
-                                               if (target->state != TARGET_HALTED)
+                                               int retval = ERROR_OK;
+
+                                               struct gdb_connection *gdb_con = connection->priv;
+                                               log_add_callback(gdb_log_callback, connection);
+
+                                               if (gdb_con->mem_write_error)
+                                               {
+                                                       LOG_ERROR("Memory write failure!");
+
+                                                       /* now that we have reported the memory write error, we can clear the condition */
+                                                       gdb_con->mem_write_error = false;
+                                               }
+
+                                               bool nostep = false;
+                                               bool already_running = false;
+                                               if (target->state == TARGET_RUNNING)
+                                               {
+                                                       LOG_WARNING("WARNING! The target is already running. "
+                                                                       "All changes GDB did to registers will be discarded! "
+                                                                       "Waiting for target to halt.");
+                                                       already_running = true;
+                                               } else if (target->state != TARGET_HALTED)
+                                               {
+                                                       LOG_WARNING("The target is not in the halted nor running stated, stepi/continue ignored.");
+                                                       nostep = true;
+                                               } else if ((packet[0] == 's') && gdb_con->sync)
+                                               {
+                                                       /* Hmm..... when you issue a continue in GDB, then a "stepi" is
+                                                        * sent by GDB first to OpenOCD, thus defeating the check to
+                                                        * make only the single stepping have the sync feature...
+                                                        */
+                                                       nostep = true;
+                                                       LOG_WARNING("stepi ignored. GDB will now fetch the register state from the target.");
+                                               }
+                                               gdb_con->sync = false;
+
+                                               if ((retval!=ERROR_OK) || (!already_running && nostep))
                                                {
-                                                       /* If the target isn't in the halted state, then we can't
+                                                       /* Either the target isn't in the halted state, then we can't
                                                         * step/continue. This might be early setup, etc.
+                                                        *
+                                                        * Or we want to allow GDB to pick up a fresh set of
+                                                        * register values without modifying the target state.
+                                                        *
                                                         */
                                                        gdb_sig_halted(connection);
+
+                                                       /* stop forwarding log packets! */
+                                                       log_remove_callback(gdb_log_callback, connection);
                                                } else
                                                {
                                                        /* 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_add_callback(gdb_log_callback, connection);
                                                        target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
-                                                       int retval=gdb_step_continue_packet(connection, target, packet, packet_size);
-                                                       if (retval!=ERROR_OK)
+
+                                                       if (!already_running)
                                                        {
-                                                               /* we'll never receive a halted condition... issue a false one.. */
-                                                               gdb_frontend_halted(target, connection);
+                                                               int retval = gdb_step_continue_packet(connection, target, packet, packet_size);
+                                                               if (retval != ERROR_OK)
+                                                               {
+                                                                       /* we'll never receive a halted condition... issue a false one.. */
+                                                                       gdb_frontend_halted(target, connection);
+                                                               }
                                                        }
                                                }
                                        }
                                        break;
                                case 'v':
-                                       retval = gdb_v_packet(connection, target, packet, packet_size);
+                                       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)
+                                       retval = gdb_write_memory_binary_packet(
+                                                       connection, target,
+                                                       packet, packet_size);
+                                       if (retval != ERROR_OK)
                                                return retval;
                                        break;
                                case 'k':
@@ -2142,10 +2349,12 @@ int gdb_input_inner(connection_t *connection)
                                        /* handle extended restart packet */
                                        breakpoint_clear_target(gdb_service->target);
                                        watchpoint_clear_target(gdb_service->target);
-                                       command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %d", get_num_by_target(target));
+                                       command_run_linef(connection->cmd_ctx,
+                                                       "ocd_gdb_restart %s",
+                                                       target_name(target));
                                        break;
                                default:
-                                       /* ignore unkown packets */
+                                       /* ignore unknown packets */
                                        LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]);
                                        gdb_put_packet(connection, NULL, 0);
                                        break;
@@ -2160,8 +2369,16 @@ int gdb_input_inner(connection_t *connection)
                {
                        if (target->state == TARGET_RUNNING)
                        {
-                               target_halt(target);
+                               retval = target_halt(target);
+                               if (retval != ERROR_OK)
+                               {
+                                       target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
+                               }
                                gdb_con->ctrl_c = 0;
+                       } else
+                       {
+                               LOG_INFO("The target is not running when halt was requested, stopping GDB.");
+                               target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
                        }
                }
 
@@ -2170,10 +2387,10 @@ int gdb_input_inner(connection_t *connection)
        return ERROR_OK;
 }
 
-int gdb_input(connection_t *connection)
+static int gdb_input(struct connection *connection)
 {
        int retval = gdb_input_inner(connection);
-       gdb_connection_t *gdb_con = connection->priv;
+       struct gdb_connection *gdb_con = connection->priv;
        if (retval == ERROR_SERVER_REMOTE_CLOSED)
                return retval;
 
@@ -2185,177 +2402,148 @@ int gdb_input(connection_t *connection)
        return ERROR_OK;
 }
 
-int gdb_init(void)
+static int gdb_target_start(struct target *target, uint16_t port)
 {
-       gdb_service_t *gdb_service;
-       target_t *target = all_targets;
+       bool use_pipes = 0 == port;
+       struct gdb_service *gdb_service = malloc(sizeof(struct gdb_service));
+       if (NULL == gdb_service)
+               return -ENOMEM;
 
-       if (!target)
-       {
-               LOG_WARNING("no gdb ports allocated as no target has been specified");
-               return ERROR_OK;
-       }
+       gdb_service->target = target;
+
+       add_service("gdb", use_pipes ? CONNECTION_PIPE : CONNECTION_TCP,
+                       port, 1, &gdb_new_connection, &gdb_input,
+                       &gdb_connection_closed, gdb_service);
 
+       const char *name = target_name(target);
+       if (use_pipes)
+               LOG_DEBUG("gdb service for target '%s' using pipes", name);
+       else
+               LOG_DEBUG("gdb service for target '%s' on TCP port %u", name, port);
+       return ERROR_OK;
+}
+
+static int gdb_target_add_one(struct target *target)
+{
        if (gdb_port == 0 && server_use_pipes == 0)
        {
-               LOG_WARNING("no gdb port specified, using default port 3333");
-               gdb_port = 3333;
+               LOG_INFO("gdb port disabled");
+               return ERROR_OK;
        }
+       if (0 == gdb_port_next)
+               gdb_port_next = gdb_port;
 
-       if (server_use_pipes)
+       bool use_pipes = server_use_pipes;
+       static bool server_started_with_pipes = false;
+       if (server_started_with_pipes)
        {
-               /* only a single gdb connection when using a pipe */
-               
-               gdb_service = malloc(sizeof(gdb_service_t));
-               gdb_service->target = target;
-
-               add_service("gdb", CONNECTION_PIPE, 0, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
+               LOG_WARNING("gdb service permits one target when using pipes");
+               if (0 == gdb_port)
+                       return ERROR_OK;
 
-               LOG_DEBUG("gdb service for target %s using pipes", target->type->name);
+               use_pipes = false;
        }
-       else
-       {
-               while (target)
-               {
-                       gdb_service = malloc(sizeof(gdb_service_t));
-                       gdb_service->target = target;
 
-                       add_service("gdb", CONNECTION_TCP, gdb_port + target->target_number, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
-                       
-                       LOG_DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + target->target_number);
-                       target = target->next;
-               }
+       int e = gdb_target_start(target, use_pipes ? 0 : gdb_port_next);
+       if (ERROR_OK == e)
+       {
+               server_started_with_pipes |= use_pipes;
+               gdb_port_next++;
        }
-       
-       return ERROR_OK;
+       return e;
 }
 
-/* daemon configuration command gdb_port */
-int handle_gdb_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+int gdb_target_add_all(struct target *target)
 {
-       if (argc == 0)
+       if (NULL == target)
        {
-               command_print(cmd_ctx, "%d", gdb_port);
+               LOG_WARNING("gdb services need one or more targets defined");
                return ERROR_OK;
        }
 
-       /* only if the port wasn't overwritten by cmdline */
-       if (gdb_port == 0)
-               gdb_port = strtoul(args[0], NULL, 0);
+       while (NULL != target)
+       {
+               int retval = gdb_target_add_one(target);
+               if (ERROR_OK != retval)
+                       return retval;
+
+               target = target->next;
+       }
 
        return ERROR_OK;
 }
 
-int handle_gdb_detach_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+COMMAND_HANDLER(handle_gdb_sync_command)
 {
-       if (argc == 1)
+       if (CMD_ARGC != 0)
        {
-               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;
-               }
-               else
-                       LOG_WARNING("invalid gdb_detach configuration directive: %s", args[0]);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (current_gdb_connection == NULL)
+       {
+               command_print(CMD_CTX,
+                               "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\"");
+               return ERROR_FAIL;
        }
 
-       return ERROR_COMMAND_SYNTAX_ERROR;
+       current_gdb_connection->sync = true;
+
+       return ERROR_OK;
 }
 
-int handle_gdb_memory_map_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+/* daemon configuration command gdb_port */
+COMMAND_HANDLER(handle_gdb_port_command)
 {
-       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;
-               }
-               else
-                       LOG_WARNING("invalid gdb_memory_map configuration directive %s", args[0]);
-       }
+       int retval = CALL_COMMAND_HANDLER(server_port_command, &gdb_port);
+       if (ERROR_OK == retval)
+               gdb_port_next = gdb_port;
+       return retval;
+}
 
-       return ERROR_COMMAND_SYNTAX_ERROR;
+COMMAND_HANDLER(handle_gdb_memory_map_command)
+{
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_memory_map);
+       return ERROR_OK;
 }
 
-int handle_gdb_flash_program_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+COMMAND_HANDLER(handle_gdb_flash_program_command)
 {
-       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;
-               }
-               else
-                       LOG_WARNING("invalid gdb_flash_program configuration directive: %s", args[0]);
-       }
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
 
-       return ERROR_COMMAND_SYNTAX_ERROR;
+       COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_flash_program);
+       return ERROR_OK;
 }
 
-int handle_gdb_report_data_abort_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+COMMAND_HANDLER(handle_gdb_report_data_abort_command)
 {
-       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;
-               }
-               else
-                       LOG_WARNING("invalid gdb_report_data_abort configuration directive: %s", args[0]);
-       }
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
 
-       return ERROR_COMMAND_SYNTAX_ERROR;
+       COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_data_abort);
+       return ERROR_OK;
 }
 
 /* gdb_breakpoint_override */
-int handle_gdb_breakpoint_override_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+COMMAND_HANDLER(handle_gdb_breakpoint_override_command)
 {
-       if (argc == 0)
+       if (CMD_ARGC == 0)
        {
 
-       } else if (argc==1)
+       } else if (CMD_ARGC == 1)
        {
                gdb_breakpoint_override = 1;
-               if (strcmp(args[0], "hard")==0)
+               if (strcmp(CMD_ARGV[0], "hard") == 0)
                {
-                       gdb_breakpoint_override_type=BKPT_HARD;
-               } else if (strcmp(args[0], "soft")==0)
+                       gdb_breakpoint_override_type = BKPT_HARD;
+               } else if (strcmp(CMD_ARGV[0], "soft") == 0)
                {
-                       gdb_breakpoint_override_type=BKPT_SOFT;
-               } else if (strcmp(args[0], "disable") == 0)
+                       gdb_breakpoint_override_type = BKPT_SOFT;
+               } else if (strcmp(CMD_ARGV[0], "disable") == 0)
                {
                        gdb_breakpoint_override = 0;
                }
@@ -2365,31 +2553,66 @@ int handle_gdb_breakpoint_override_command(struct command_context_s *cmd_ctx, ch
        }
        if (gdb_breakpoint_override)
        {
-               LOG_USER("force %s breakpoints", (gdb_breakpoint_override_type==BKPT_HARD)?"hard":"soft");
+               LOG_USER("force %s breakpoints", (gdb_breakpoint_override_type == BKPT_HARD)?"hard":"soft");
        } else
        {
-               LOG_USER("breakpoint type is not overriden");
+               LOG_USER("breakpoint type is not overridden");
        }
 
        return ERROR_OK;
 }
 
-int gdb_register_commands(command_context_t *command_context)
+static const struct command_registration gdb_command_handlers[] = {
+       {
+               .name = "gdb_sync",
+               .handler = handle_gdb_sync_command,
+               .mode = COMMAND_ANY,
+               .help = "next stepi will return immediately allowing "
+                       "GDB to fetch register state without affecting "
+                       "target state",
+       },
+       {
+               .name = "gdb_port",
+               .handler = handle_gdb_port_command,
+               .mode = COMMAND_ANY,
+               .help = "Display or specify base port on which to listen "
+                       "for incoming GDB connections.  "
+                       "No arguments reports GDB port; zero disables.",
+               .usage = "[port_num]",
+       },
+       {
+               .name = "gdb_memory_map",
+               .handler = handle_gdb_memory_map_command,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable memory map",
+               .usage = "('enable'|'disable')"
+       },
+       {
+               .name = "gdb_flash_program",
+               .handler = handle_gdb_flash_program_command,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable flash program",
+               .usage = "('enable'|'disable')"
+       },
+       {
+               .name = "gdb_report_data_abort",
+               .handler = handle_gdb_report_data_abort_command,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable reporting data aborts",
+               .usage = "('enable'|'disable')"
+       },
+       {
+               .name = "gdb_breakpoint_override",
+               .handler = handle_gdb_breakpoint_override_command,
+               .mode = COMMAND_ANY,
+               .help = "Display or specify type of breakpoint "
+                       "to be used by gdb 'break' commands.",
+               .usage = "('hard'|'soft'|'disable')"
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+int gdb_register_commands(struct command_context *cmd_ctx)
 {
-       register_command(command_context, NULL, "gdb_port", handle_gdb_port_command,
-                       COMMAND_CONFIG, "daemon configuration command gdb_port");
-       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, "enable or disable memory map");
-       register_command(command_context, NULL, "gdb_flash_program", handle_gdb_flash_program_command,
-                       COMMAND_CONFIG, "enable or disable flash program");
-       register_command(command_context, NULL, "gdb_report_data_abort", handle_gdb_report_data_abort_command,
-                       COMMAND_CONFIG, "enable or disable report data");
-       register_command(command_context, NULL, "gdb_breakpoint_override", handle_gdb_breakpoint_override_command,
-                       COMMAND_EXEC, "hard/soft/disabled - force breakpoint type for gdb 'break' commands."
-                       "The raison d'etre for this option is to support GDB GUI's without "
-                       "a hard/soft breakpoint concept where the default OpenOCD behaviour "
-                       "is not sufficient");
-       return ERROR_OK;
+       return register_commands(cmd_ctx, NULL, gdb_command_handlers);
 }

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)