gdb_server: Don't modify "buf" argument in decode_xfer_read()
[openocd.git] / src / server / gdb_server.c
index d656745405cb92005b1e51994cc25372cfe3db43..0b28287d80a7c8ee22f69a7f18d72ad3e69f0162 100644 (file)
@@ -2,12 +2,24 @@
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
- *   Copyright (C) 2007-2009 Øyvind Harboe                                 *
+ *   Copyright (C) 2007-2010 Øyvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
  *   Copyright (C) 2008 by Spencer Oliver                                  *
  *   spen@spen-soft.co.uk                                                  *
  *                                                                         *
+ *   Copyright (C) 2011 by Broadcom Corporation                            *
+ *   Evan Hunter - ehunter@broadcom.com                                    *
+ *                                                                         *
+ *   Copyright (C) ST-Ericsson SA 2011                                     *
+ *   michel.jaouen@stericsson.com : smp minimum support                    *
+ *                                                                         *
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   Copyright (C) 2013 Franck Jullien                                     *
+ *   elec4fun@gmail.com                                                    *
+ *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
  *   the Free Software Foundation; either version 2 of the License, or     *
@@ -21,8 +33,9 @@
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
  ***************************************************************************/
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -35,7 +48,8 @@
 #include "gdb_server.h"
 #include <target/image.h>
 #include <jtag/jtag.h>
-
+#include "rtos/rtos.h"
+#include "target/smp.h"
 
 /**
  * @file
  * found in most modern embedded processors.
  */
 
+struct target_desc_format {
+       char *tdesc;
+       uint32_t tdesc_length;
+};
+
 /* private connection data for GDB */
-struct gdb_connection
-{
+struct gdb_connection {
        char buffer[GDB_BUFFER_SIZE];
        char *buf_p;
        int buf_cnt;
@@ -58,13 +76,24 @@ struct gdb_connection
        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. */
-
+       /* 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. */
+       bool sync;
+       /* 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;
+       /* with extended-remote it seems we need to better emulate attach/detach.
+        * what this means is we reply with a W stop reply after a kill packet,
+        * normally we reply with a S reply via gdb_last_signal_packet.
+        * as a side note this behaviour only effects gdb > 6.8 */
+       bool attached;
+       /* temporarily used for target description support */
+       struct target_desc_format target_desc;
 };
 
-
 #if 0
 #define _DEBUG_GDB_IO_
 #endif
@@ -74,10 +103,9 @@ static struct gdb_connection *current_gdb_connection;
 static int gdb_breakpoint_override;
 static enum breakpoint_type gdb_breakpoint_override_type;
 
-extern 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 int gdb_error(struct connection *connection, int retval);
+static char *gdb_port;
+static char *gdb_port_next;
 
 static void gdb_log_callback(void *priv, const char *file, unsigned line,
                const char *function, const char *string);
@@ -89,35 +117,46 @@ 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(struct target *target)
+/* set if we are sending target descriptions to gdb
+ * via qXfer:features:read packet */
+/* enabled by default */
+static int gdb_use_target_description = 1;
+
+/* current processing free-run type, used by file-I/O */
+static char gdb_running_type;
+
+static int gdb_last_signal(struct target *target)
 {
-       switch (target->debug_reason)
-       {
+       switch (target->debug_reason) {
                case DBG_REASON_DBGRQ:
-                       return 0x2; /* SIGINT */
+                       return 0x2;             /* SIGINT */
                case DBG_REASON_BREAKPOINT:
                case DBG_REASON_WATCHPOINT:
                case DBG_REASON_WPTANDBKPT:
-                       return 0x05; /* SIGTRAP */
+                       return 0x05;    /* SIGTRAP */
                case DBG_REASON_SINGLESTEP:
-                       return 0x05; /* SIGTRAP */
+                       return 0x05;    /* SIGTRAP */
                case DBG_REASON_NOTHALTED:
-                       return 0x0; /* no signal... shouldn't happen */
+                       return 0x0;             /* no signal... shouldn't happen */
                default:
-                       LOG_USER("undefined debug reason %d - target needs reset", target->debug_reason);
+                       LOG_USER("undefined debug reason %d - target needs reset",
+                                       target->debug_reason);
                        return 0x0;
        }
 }
 
-int check_pending(struct connection *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
@@ -127,11 +166,10 @@ int check_pending(struct connection *connection, int timeout_s, int *got_data)
        struct gdb_connection *gdb_con = connection->priv;
        int t;
        if (got_data == NULL)
-               got_data=&t;
+               got_data = &t;
        *got_data = 0;
 
-       if (gdb_con->buf_cnt > 0)
-       {
+       if (gdb_con->buf_cnt > 0) {
                *got_data = 1;
                return ERROR_OK;
        }
@@ -141,48 +179,42 @@ int check_pending(struct connection *connection, int timeout_s, int *got_data)
 
        tv.tv_sec = timeout_s;
        tv.tv_usec = 0;
-       if (socket_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)
-               {
                        return ERROR_GDB_TIMEOUT;
-               } else
-               {
+               else
                        return ERROR_OK;
-               }
        }
        *got_data = FD_ISSET(connection->fd, &read_fds) != 0;
        return ERROR_OK;
 }
 
-static int gdb_get_char_inner(struct connection *connection, intnext_char)
+static int gdb_get_char_inner(struct connection *connection, int *next_char)
 {
        struct gdb_connection *gdb_con = connection->priv;
        int retval = ERROR_OK;
 
-       for (;;)
-       {
-               if (connection->service->type == CONNECTION_PIPE)
-               {
+#ifdef _DEBUG_GDB_IO_
+       char *debug_buffer;
+#endif
+       for (;; ) {
+               if (connection->service->type != CONNECTION_TCP)
                        gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
-               }
-               else
-               {
+               else {
                        retval = check_pending(connection, 1, NULL);
                        if (retval != ERROR_OK)
                                return retval;
-                       gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
+                       gdb_con->buf_cnt = read_socket(connection->fd,
+                                       gdb_con->buffer,
+                                       GDB_BUFFER_SIZE);
                }
 
                if (gdb_con->buf_cnt > 0)
-               {
                        break;
-               }
-               if (gdb_con->buf_cnt == 0)
-               {
+               if (gdb_con->buf_cnt == 0) {
                        gdb_con->closed = 1;
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
@@ -190,8 +222,7 @@ static int gdb_get_char_inner(struct connection *connection, int* next_char)
 #ifdef _WIN32
                errno = WSAGetLastError();
 
-               switch (errno)
-               {
+               switch (errno) {
                        case WSAEWOULDBLOCK:
                                usleep(1000);
                                break;
@@ -206,8 +237,7 @@ static int gdb_get_char_inner(struct connection *connection, int* next_char)
                                exit(-1);
                }
 #else
-               switch (errno)
-               {
+               switch (errno) {
                        case EAGAIN:
                                usleep(1000);
                                break;
@@ -226,9 +256,7 @@ static int gdb_get_char_inner(struct connection *connection, int* next_char)
        }
 
 #ifdef _DEBUG_GDB_IO_
-       debug_buffer = malloc(gdb_con->buf_cnt + 1);
-       memcpy(debug_buffer, gdb_con->buffer, gdb_con->buf_cnt);
-       debug_buffer[gdb_con->buf_cnt] = 0;
+       debug_buffer = strndup(gdb_con->buffer, gdb_con->buf_cnt);
        LOG_DEBUG("received '%s'", debug_buffer);
        free(debug_buffer);
 #endif
@@ -253,12 +281,12 @@ static int gdb_get_char_inner(struct connection *connection, int* next_char)
  *
  * 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)
+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)
-       {
+       if ((*buf_cnt)-- > 0) {
                *next_char = **buf_p;
                (*buf_p)++;
                if (*buf_cnt > 0)
@@ -283,27 +311,21 @@ static inline int gdb_get_char_fast(struct connection *connection, int* next_cha
        return retval;
 }
 
-
-int gdb_get_char(struct connection *connection, int* next_char)
+static int gdb_get_char(struct connection *connection, int *next_char)
 {
        struct gdb_connection *gdb_con = connection->priv;
        return gdb_get_char_fast(connection, next_char, &gdb_con->buf_p, &gdb_con->buf_cnt);
 }
 
-
-int gdb_putback_char(struct connection *connection, int last_char)
+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)
-       {
+       if (gdb_con->buf_p > gdb_con->buffer) {
                *(--gdb_con->buf_p) = last_char;
                gdb_con->buf_cnt++;
-       }
-       else
-       {
+       } else
                LOG_ERROR("BUG: couldn't put character back");
-       }
 
        return ERROR_OK;
 }
@@ -311,32 +333,20 @@ int gdb_putback_char(struct connection *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(struct connection *connection, void *data, int len)
+static int gdb_write(struct connection *connection, void *data, int len)
 {
        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 */
-               if (write(STDOUT_FILENO, data, len) == len)
-               {
-                       return ERROR_OK;
-               }
-       }
-       else
-       {
-               if (write_socket(connection->fd, data, len) == len)
-               {
-                       return ERROR_OK;
-               }
-       }
+       if (connection_write(connection, data, len) == len)
+               return ERROR_OK;
        gdb_con->closed = 1;
        return ERROR_SERVER_REMOTE_CLOSED;
 }
 
-int gdb_put_packet_inner(struct connection *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;
@@ -357,13 +367,14 @@ int gdb_put_packet_inner(struct connection *connection, char *buffer, int len)
         * an ACK (+) for everything we've sent off.
         */
        int gotdata;
-       for (;;)
-       {
-               if ((retval = check_pending(connection, 0, &gotdata)) != ERROR_OK)
+       for (;; ) {
+               retval = check_pending(connection, 0, &gotdata);
+               if (retval != ERROR_OK)
                        return retval;
                if (!gotdata)
                        break;
-               if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
+               retval = gdb_get_char(connection, &reply);
+               if (retval != ERROR_OK)
                        return retval;
                if (reply == '$') {
                        /* fix a problem with some IAR tools */
@@ -376,97 +387,77 @@ int gdb_put_packet_inner(struct connection *connection, char *buffer, int len)
        }
 #endif
 
-       while (1)
-       {
+       while (1) {
 #ifdef _DEBUG_GDB_IO_
-               debug_buffer = malloc(len + 1);
-               memcpy(debug_buffer, buffer, len);
-               debug_buffer[len] = 0;
+               debug_buffer = strndup(buffer, len);
                LOG_DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum);
                free(debug_buffer);
 #endif
 
                char local_buffer[1024];
                local_buffer[0] = '$';
-               if ((size_t)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++);
-                       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)
-                       {
+                       len += snprintf(local_buffer + len, sizeof(local_buffer) - len, "#%02x", my_checksum);
+                       retval = gdb_write(connection, local_buffer, len);
+                       if (retval != ERROR_OK)
                                return retval;
-                       }
-               }
-               else
-               {
+               } else {
                        /* larger packets are transmitted directly from caller supplied buffer
-                          by several calls to gdb_write() to avoid dynamic allocation */
-                       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)
-                       {
+                        * by several calls to gdb_write() to avoid dynamic allocation */
+                       snprintf(local_buffer + 1, sizeof(local_buffer) - 1, "#%02x", my_checksum);
+                       retval = gdb_write(connection, local_buffer, 1);
+                       if (retval != ERROR_OK)
                                return retval;
-                       }
-                       if ((retval = gdb_write(connection, buffer, len)) != ERROR_OK)
-                       {
+                       retval = gdb_write(connection, buffer, len);
+                       if (retval != ERROR_OK)
                                return retval;
-                       }
-                       if ((retval = gdb_write(connection, local_buffer + 1, 3)) != ERROR_OK)
-                       {
+                       retval = gdb_write(connection, local_buffer + 1, 3);
+                       if (retval != ERROR_OK)
                                return retval;
-                       }
                }
 
                if (gdb_con->noack_mode)
                        break;
 
-               if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
+               retval = gdb_get_char(connection, &reply);
+               if (retval != ERROR_OK)
                        return retval;
 
                if (reply == '+')
                        break;
-               else if (reply == '-')
-               {
+               else if (reply == '-') {
                        /* Stop sending output packets for now */
                        log_remove_callback(gdb_log_callback, connection);
                        LOG_WARNING("negative reply, retrying");
-               }
-               else if (reply == 0x3)
-               {
+               } else if (reply == 0x3) {
                        gdb_con->ctrl_c = 1;
-                       if ((retval = gdb_get_char(connection, &reply)) != ERROR_OK)
+                       retval = gdb_get_char(connection, &reply);
+                       if (retval != ERROR_OK)
                                return retval;
                        if (reply == '+')
                                break;
-                       else if (reply == '-')
-                       {
+                       else if (reply == '-') {
                                /* Stop sending output packets for now */
                                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);
                                return ERROR_OK;
                        } else {
-
                                LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply);
                                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);
                        return ERROR_OK;
-               }
-               else
-               {
-                       LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection", reply);
+               } else {
+                       LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection",
+                               reply);
                        gdb_con->closed = 1;
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
@@ -490,7 +481,8 @@ int gdb_put_packet(struct connection *connection, char *buffer, int len)
        return retval;
 }
 
-static __inline__ int fetch_packet(struct connection *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];
@@ -507,14 +499,12 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
        char *buf_p = gdb_con->buf_p;
        int buf_cnt = gdb_con->buf_cnt;
 
-       for (;;)
-       {
+       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 ((buf_cnt > 2) && ((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
@@ -524,21 +514,17 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
                        int run = buf_cnt - 2;
                        i = 0;
                        int done = 0;
-                       while (i < run)
-                       {
+                       while (i < run) {
                                character = *buf++;
                                i++;
-                               if (character == '#')
-                               {
+                               if (character == '#') {
                                        /* Danger! character can be '#' when esc is
-                                        * used so we need an explicit boolean for done here.
-                                        */
+                                        * used so we need an explicit boolean for done here. */
                                        done = 1;
                                        break;
                                }
 
-                               if (character == '}')
-                               {
+                               if (character == '}') {
                                        /* data transmitted in binary mode (X packet)
                                         * uses 0x7d as escape character */
                                        my_checksum += character & 0xff;
@@ -546,9 +532,7 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
                                        i++;
                                        my_checksum += character & 0xff;
                                        buffer[count++] = (character ^ 0x20) & 0xff;
-                               }
-                               else
-                               {
+                               } else {
                                        my_checksum += character & 0xff;
                                        buffer[count++] = character & 0xff;
                                }
@@ -558,8 +542,7 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
                        if (done)
                                break;
                }
-               if (count > *len)
-               {
+               if (count > *len) {
                        LOG_ERROR("packet buffer too small");
                        retval = ERROR_GDB_BUFFER_TOO_SMALL;
                        break;
@@ -572,8 +555,7 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
                if (character == '#')
                        break;
 
-               if (character == '}')
-               {
+               if (character == '}') {
                        /* data transmitted in binary mode (X packet)
                         * uses 0x7d as escape character */
                        my_checksum += character & 0xff;
@@ -584,9 +566,7 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
 
                        my_checksum += character & 0xff;
                        buffer[count++] = (character ^ 0x20) & 0xff;
-               }
-               else
-               {
+               } else {
                        my_checksum += character & 0xff;
                        buffer[count++] = character & 0xff;
                }
@@ -600,47 +580,58 @@ static __inline__ int fetch_packet(struct connection *connection, int *checksum_
 
        *len = count;
 
-       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+       retval = gdb_get_char(connection, &character);
+       if (retval != ERROR_OK)
                return retval;
        checksum[0] = character;
-       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+       retval = gdb_get_char(connection, &character);
+       if (retval != ERROR_OK)
                return retval;
        checksum[1] = character;
        checksum[2] = 0;
 
        if (!noack)
-       {
                *checksum_ok = (my_checksum == strtoul(checksum, NULL, 16));
-       }
 
        return ERROR_OK;
 }
 
-int gdb_get_packet_inner(struct connection *connection, char *buffer, int *len)
+static int gdb_get_packet_inner(struct connection *connection,
+               char *buffer, int *len)
 {
        int character;
        int retval;
        struct gdb_connection *gdb_con = connection->priv;
 
-       while (1)
-       {
-               do
-               {
-                       if ((retval = gdb_get_char(connection, &character)) != ERROR_OK)
+       while (1) {
+               do {
+                       retval = gdb_get_char(connection, &character);
+                       if (retval != ERROR_OK)
                                return retval;
 
 #ifdef _DEBUG_GDB_IO_
                        LOG_DEBUG("character: '%c'", character);
 #endif
 
-                       switch (character)
-                       {
+                       switch (character) {
                                case '$':
                                        break;
                                case '+':
-                                       /* gdb sends a dummy ack '+' at every remote connect - see remote_start_remote (remote.c)
-                                        * in case anyone tries to debug why they receive this warning every time */
-                                       LOG_WARNING("acknowledgment received, but no packet pending");
+                                       /* According to the GDB documentation
+                                        * (https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html):
+                                        * "gdb sends a final `+` acknowledgment of the stub's `OK`
+                                        * response, which can be safely ignored by the stub."
+                                        * However OpenOCD server already is in noack mode at this
+                                        * point and instead of ignoring this it was emitting a
+                                        * warning. This code makes server ignore the first ACK
+                                        * that will be received after going into noack mode,
+                                        * warning only about subsequent ACK's. */
+                                       if (gdb_con->noack_mode > 1) {
+                                               LOG_WARNING("acknowledgment received, but no packet pending");
+                                       } else {
+                                               LOG_DEBUG("Received first acknowledgment after entering noack mode. Ignoring it.");
+                                               gdb_con->noack_mode = 2;
+                                       }
                                        break;
                                case '-':
                                        LOG_WARNING("negative acknowledgment, but no packet pending");
@@ -655,33 +646,27 @@ int gdb_get_packet_inner(struct connection *connection, char *buffer, int *len)
                        }
                } while (character != '$');
 
-
-
                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)
+                * calculating checksum */
+               if (gdb_con->noack_mode) {
+                       retval = fetch_packet(connection, &checksum_ok, 1, len, buffer);
+                       if (retval != ERROR_OK)
                                return retval;
-               } else
-               {
-                       if ((retval = fetch_packet(connection, &checksum_ok, 0, len, buffer)) != ERROR_OK)
+               } else {
+                       retval = fetch_packet(connection, &checksum_ok, 0, len, buffer);
+                       if (retval != ERROR_OK)
                                return retval;
                }
 
-               if (gdb_con->noack_mode)
-               {
+               if (gdb_con->noack_mode) {
                        /* checksum is not checked in noack mode */
                        break;
                }
-               if (checksum_ok)
-               {
-                       if ((retval = gdb_write(connection, "+", 1)) != ERROR_OK)
-                       {
+               if (checksum_ok) {
+                       retval = gdb_write(connection, "+", 1);
+                       if (retval != ERROR_OK)
                                return retval;
-                       }
                        break;
                }
        }
@@ -691,7 +676,7 @@ int gdb_get_packet_inner(struct connection *connection, char *buffer, int *len)
        return ERROR_OK;
 }
 
-int gdb_get_packet(struct connection *connection, char *buffer, int *len)
+static int gdb_get_packet(struct connection *connection, char *buffer, int *len)
 {
        struct gdb_connection *gdb_con = connection->priv;
        gdb_con->busy = 1;
@@ -700,35 +685,171 @@ int gdb_get_packet(struct connection *connection, char *buffer, int *len)
        return retval;
 }
 
-int gdb_output_con(struct connection *connection, const char* line)
+static int gdb_output_con(struct connection *connection, const char *line)
 {
        char *hex_buffer;
-       int i, bin_size;
+       int bin_size;
 
        bin_size = strlen(line);
 
-       hex_buffer = malloc(bin_size*2 + 2);
+       hex_buffer = malloc(bin_size * 2 + 2);
        if (hex_buffer == NULL)
                return ERROR_GDB_BUFFER_TOO_SMALL;
 
        hex_buffer[0] = 'O';
-       for (i = 0; i < bin_size; i++)
-               snprintf(hex_buffer + 1 + i*2, 3, "%2.2x", line[i]);
-       hex_buffer[bin_size*2 + 1] = 0;
-
-       int retval = gdb_put_packet(connection, hex_buffer, bin_size*2 + 1);
+       int pkt_len = hexify(hex_buffer + 1, line, bin_size, bin_size * 2 + 1);
+       int retval = gdb_put_packet(connection, hex_buffer, pkt_len + 1);
 
        free(hex_buffer);
        return retval;
 }
 
-int gdb_output(struct command_context *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);
        return ERROR_OK;
 }
 
+static void gdb_signal_reply(struct target *target, struct connection *connection)
+{
+       struct gdb_connection *gdb_connection = connection->priv;
+       char sig_reply[20];
+       char stop_reason[20];
+       int sig_reply_len;
+       int signal_var;
+
+       if (target->debug_reason == DBG_REASON_EXIT) {
+               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00");
+       } else {
+               if (gdb_connection->ctrl_c) {
+                       signal_var = 0x2;
+                       gdb_connection->ctrl_c = 0;
+               } else
+                       signal_var = gdb_last_signal(target);
+
+               stop_reason[0] = '\0';
+               if (target->debug_reason == DBG_REASON_WATCHPOINT) {
+                       enum watchpoint_rw hit_wp_type;
+                       uint32_t hit_wp_address;
+
+                       if (watchpoint_hit(target, &hit_wp_type, &hit_wp_address) == ERROR_OK) {
+
+                               switch (hit_wp_type) {
+                                       case WPT_WRITE:
+                                               snprintf(stop_reason, sizeof(stop_reason),
+                                                               "watch:%08" PRIx32 ";", hit_wp_address);
+                                               break;
+                                       case WPT_READ:
+                                               snprintf(stop_reason, sizeof(stop_reason),
+                                                               "rwatch:%08" PRIx32 ";", hit_wp_address);
+                                               break;
+                                       case WPT_ACCESS:
+                                               snprintf(stop_reason, sizeof(stop_reason),
+                                                               "awatch:%08" PRIx32 ";", hit_wp_address);
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+
+               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s",
+                               signal_var, stop_reason);
+       }
+
+       gdb_put_packet(connection, sig_reply, sig_reply_len);
+       gdb_connection->frontend_state = TARGET_HALTED;
+       rtos_update_threads(target);
+}
+
+static void gdb_fileio_reply(struct target *target, struct connection *connection)
+{
+       struct gdb_connection *gdb_connection = connection->priv;
+       char fileio_command[256];
+       int command_len;
+       bool program_exited = false;
+
+       if (strcmp(target->fileio_info->identifier, "open") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3,
+                               target->fileio_info->param_4);
+       else if (strcmp(target->fileio_info->identifier, "close") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1);
+       else if (strcmp(target->fileio_info->identifier, "read") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3);
+       else if (strcmp(target->fileio_info->identifier, "write") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3);
+       else if (strcmp(target->fileio_info->identifier, "lseek") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3);
+       else if (strcmp(target->fileio_info->identifier, "rename") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3,
+                               target->fileio_info->param_4);
+       else if (strcmp(target->fileio_info->identifier, "unlink") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2);
+       else if (strcmp(target->fileio_info->identifier, "stat") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2,
+                               target->fileio_info->param_3);
+       else if (strcmp(target->fileio_info->identifier, "fstat") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2);
+       else if (strcmp(target->fileio_info->identifier, "gettimeofday") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2);
+       else if (strcmp(target->fileio_info->identifier, "isatty") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1);
+       else if (strcmp(target->fileio_info->identifier, "system") == 0)
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
+                               target->fileio_info->param_1,
+                               target->fileio_info->param_2);
+       else if (strcmp(target->fileio_info->identifier, "exit") == 0) {
+               /* If target hits exit syscall, report to GDB the program is terminated.
+                * In addition, let target run its own exit syscall handler. */
+               program_exited = true;
+               sprintf(fileio_command, "W%02" PRIx32, target->fileio_info->param_1);
+       } else {
+               LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier);
+
+               /* encounter unknown syscall, continue */
+               gdb_connection->frontend_state = TARGET_RUNNING;
+               target_resume(target, 1, 0x0, 0, 0);
+               return;
+       }
+
+       command_len = strlen(fileio_command);
+       gdb_put_packet(connection, fileio_command, command_len);
+
+       if (program_exited) {
+               /* Use target_resume() to let target run its own exit syscall handler. */
+               gdb_connection->frontend_state = TARGET_RUNNING;
+               target_resume(target, 1, 0x0, 0, 0);
+       } else {
+               gdb_connection->frontend_state = TARGET_HALTED;
+               rtos_update_threads(target);
+       }
+}
 
 static void gdb_frontend_halted(struct target *target, struct connection *connection)
 {
@@ -743,38 +864,29 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec
         * out of the running state so we'll see lots of TARGET_EVENT_XXX
         * that are to be ignored.
         */
-       if (gdb_connection->frontend_state == TARGET_RUNNING)
-       {
-               char sig_reply[4];
-               int signal;
-
+       if (gdb_connection->frontend_state == TARGET_RUNNING) {
                /* stop forwarding log packets! */
                log_remove_callback(gdb_log_callback, connection);
 
-               if (gdb_connection->ctrl_c)
-               {
-                       signal = 0x2;
-                       gdb_connection->ctrl_c = 0;
-               }
+               /* check fileio first */
+               if (target_get_gdb_fileio_info(target, target->fileio_info) == ERROR_OK)
+                       gdb_fileio_reply(target, connection);
                else
-               {
-                       signal = gdb_last_signal(target);
-               }
-
-               snprintf(sig_reply, 4, "T%2.2x", signal);
-               gdb_put_packet(connection, sig_reply, 3);
-               gdb_connection->frontend_state = TARGET_HALTED;
+                       gdb_signal_reply(target, connection);
        }
 }
 
-int gdb_target_callback_event_handler(struct target *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;
        struct connection *connection = priv;
+       struct gdb_service *gdb_service = connection->service->priv;
 
-       target_handle_event(target, event);
-       switch (event)
-       {
+       if (gdb_service->target != target)
+               return ERROR_OK;
+
+       switch (event) {
                case TARGET_EVENT_GDB_HALT:
                        gdb_frontend_halted(target, connection);
                        break;
@@ -782,11 +894,9 @@ int gdb_target_callback_event_handler(struct target *target, enum target_event e
                        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)
-                       {
+                       retval = jtag_execute_queue();
+                       if (retval != ERROR_OK)
                                return retval;
-                       }
                        break;
                default:
                        break;
@@ -795,7 +905,7 @@ int gdb_target_callback_event_handler(struct target *target, enum target_event e
        return ERROR_OK;
 }
 
-int gdb_new_connection(struct connection *connection)
+static int gdb_new_connection(struct connection *connection)
 {
        struct gdb_connection *gdb_connection = malloc(sizeof(struct gdb_connection));
        struct gdb_service *gdb_service = connection->service->priv;
@@ -813,7 +923,11 @@ int gdb_new_connection(struct connection *connection)
        gdb_connection->closed = 0;
        gdb_connection->busy = 0;
        gdb_connection->noack_mode = 0;
-       gdb_connection->sync = true;
+       gdb_connection->sync = false;
+       gdb_connection->mem_write_error = false;
+       gdb_connection->attached = true;
+       gdb_connection->target_desc.tdesc = NULL;
+       gdb_connection->target_desc.tdesc_length = 0;
 
        /* send ACK to GDB for debug request */
        gdb_write(connection, "+", 1);
@@ -828,11 +942,13 @@ int gdb_new_connection(struct connection *connection)
        breakpoint_clear_target(gdb_service->target);
        watchpoint_clear_target(gdb_service->target);
 
-       /* register callback to be informed about target events */
-       target_register_event_callback(gdb_target_callback_event_handler, connection);
+       /* clean previous rtos session if supported*/
+       if ((gdb_service->target->rtos) && (gdb_service->target->rtos->type->clean))
+               gdb_service->target->rtos->type->clean(gdb_service->target);
 
        /* remove the initial ACK from the incoming buffer */
-       if ((retval = gdb_get_char(connection, &initial_ack)) != ERROR_OK)
+       retval = gdb_get_char(connection, &initial_ack);
+       if (retval != ERROR_OK)
                return retval;
 
        /* FIX!!!??? would we actually ever receive a + here???
@@ -842,16 +958,44 @@ int gdb_new_connection(struct connection *connection)
                gdb_putback_char(connection, initial_ack);
        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;
+                       p = get_flash_bank_by_num_noprobe(i);
+                       if (p->target != gdb_service->target)
+                               continue;
+                       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, or use 'gdb_memory_map disable'.");
+                               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));
+                       gdb_actual_connections,
+                       target_name(gdb_service->target),
+                       target_state_name(gdb_service->target));
+
+       /* DANGER! If we fail subsequently, we must remove this handler,
+        * otherwise we occasionally see crashes as the timer can invoke the
+        * callback fn.
+        *
+        * register callback to be informed about target events */
+       target_register_event_callback(gdb_target_callback_event_handler, connection);
 
        return ERROR_OK;
 }
 
-int gdb_connection_closed(struct connection *connection)
+static int gdb_connection_closed(struct connection *connection)
 {
        struct gdb_service *gdb_service = connection->service->priv;
        struct gdb_connection *gdb_connection = connection->priv;
@@ -863,13 +1007,12 @@ int gdb_connection_closed(struct connection *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);
+               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)
-       {
+       if (gdb_connection->vflash_image) {
                image_close(gdb_connection->vflash_image);
                free(gdb_connection->vflash_image);
                gdb_connection->vflash_image = NULL;
@@ -878,16 +1021,11 @@ int gdb_connection_closed(struct connection *connection)
        /* if this connection registered a debug-message receiver delete it */
        delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target);
 
-       if (connection->priv)
-       {
+       if (connection->priv) {
                free(connection->priv);
                connection->priv = NULL;
-       }
-       else
-       {
+       } else
                LOG_ERROR("BUG: connection->priv == NULL");
-       }
-
 
        target_unregister_event_callback(gdb_target_callback_event_handler, connection);
 
@@ -898,27 +1036,37 @@ int gdb_connection_closed(struct connection *connection)
        return ERROR_OK;
 }
 
-void gdb_send_error(struct connection *connection, uint8_t 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);
        gdb_put_packet(connection, err, 3);
 }
 
-int gdb_last_signal_packet(struct connection *connection, struct target *target, char* packet, int packet_size)
+static int gdb_last_signal_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
+       struct gdb_connection *gdb_con = connection->priv;
        char sig_reply[4];
-       int signal;
+       int signal_var;
+
+       if (!gdb_con->attached) {
+               /* if we are here we have received a kill packet
+                * reply W stop reply otherwise gdb gets very unhappy */
+               gdb_put_packet(connection, "W00", 3);
+               return ERROR_OK;
+       }
 
-       signal = gdb_last_signal(target);
+       signal_var = gdb_last_signal(target);
 
-       snprintf(sig_reply, 4, "S%2.2x", signal);
+       snprintf(sig_reply, 4, "S%2.2x", signal_var);
        gdb_put_packet(connection, sig_reply, 3);
 
        return ERROR_OK;
 }
 
-static int gdb_reg_pos(struct target *target, int pos, int len)
+static inline int gdb_reg_pos(struct target *target, int pos, int len)
 {
        if (target->endianness == TARGET_LITTLE_ENDIAN)
                return pos;
@@ -935,7 +1083,8 @@ static int gdb_reg_pos(struct target *target, int pos, int len)
  * The format of reg->value is little endian
  *
  */
-void gdb_str_to_target(struct target *target, char *tstr, struct reg *reg)
+static void gdb_str_to_target(struct target *target,
+               char *tstr, struct reg *reg)
 {
        int i;
 
@@ -944,51 +1093,38 @@ void gdb_str_to_target(struct target *target, char *tstr, struct reg *reg)
        buf = reg->value;
        buf_len = DIV_ROUND_UP(reg->size, 8);
 
-       for (i = 0; i < buf_len; i++)
-       {
+       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];
-       }
-}
-
-static int hextoint(int c)
-{
-       if (c>='0'&&c<='9')
-       {
-               return c-'0';
-       }
-       c = toupper(c);
-       if (c>='A'&&c<='F')
-       {
-               return c-'A'+10;
+               tstr += sprintf(tstr, "%02x", buf[j]);
        }
-       LOG_ERROR("BUG: invalid register value %08x", c);
-       return 0;
 }
 
 /* copy over in register buffer */
-void gdb_target_to_reg(struct target *target, char *tstr, int str_len, uint8_t *bin)
+static void gdb_target_to_reg(struct target *target,
+               char *tstr, int str_len, uint8_t *bin)
 {
-       if (str_len % 2)
-       {
+       if (str_len % 2) {
                LOG_ERROR("BUG: gdb value with uneven number of characters encountered");
                exit(-1);
        }
 
        int i;
-       for (i = 0; i < str_len; i += 2)
-       {
-               uint8_t t = hextoint(tstr[i]) << 4;
-               t |= hextoint(tstr[i + 1]);
+       for (i = 0; i < str_len; i += 2) {
+               unsigned t;
+               if (sscanf(tstr + i, "%02x", &t) != 1) {
+                       LOG_ERROR("BUG: unable to convert register value");
+                       exit(-1);
+               }
 
                int j = gdb_reg_pos(target, i/2, str_len/2);
                bin[j] = t;
        }
 }
 
-int gdb_get_registers_packet(struct connection *connection, struct target *target, char* packet, int packet_size)
+static int gdb_get_registers_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
        struct reg **reg_list;
        int reg_list_size;
        int retval;
@@ -1001,35 +1137,39 @@ int gdb_get_registers_packet(struct connection *connection, struct target *targe
        LOG_DEBUG("-");
 #endif
 
-       if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
-       {
+       if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg_list(connection)))
+               return ERROR_OK;
+
+       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+                       REG_CLASS_GENERAL);
+       if (retval != ERROR_OK)
                return gdb_error(connection, retval);
-       }
 
        for (i = 0; i < reg_list_size; i++)
-       {
-               reg_packet_size += reg_list[i]->size;
-       }
+               reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
+
+       assert(reg_packet_size > 0);
 
-       reg_packet = malloc(DIV_ROUND_UP(reg_packet_size, 8) * 2);
+       reg_packet = malloc(reg_packet_size + 1); /* plus one for string termination null */
        reg_packet_p = reg_packet;
 
-       for (i = 0; i < reg_list_size; i++)
-       {
+       for (i = 0; i < reg_list_size; i++) {
+               if (!reg_list[i]->valid)
+                       reg_list[i]->type->get(reg_list[i]);
                gdb_str_to_target(target, reg_packet_p, reg_list[i]);
                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, DIV_ROUND_UP(reg_packet_size, 8) * 2);
-               LOG_DEBUG("reg_packet: %s", reg_packet_p);
-               free(reg_packet_p);
+               char *reg_packet_p_debug;
+               reg_packet_p_debug = strndup(reg_packet, reg_packet_size);
+               LOG_DEBUG("reg_packet: %s", reg_packet_p_debug);
+               free(reg_packet_p_debug);
        }
 #endif
 
-       gdb_put_packet(connection, reg_packet, DIV_ROUND_UP(reg_packet_size, 8) * 2);
+       gdb_put_packet(connection, reg_packet, reg_packet_size);
        free(reg_packet);
 
        free(reg_list);
@@ -1037,8 +1177,10 @@ int gdb_get_registers_packet(struct connection *connection, struct target *targe
        return ERROR_OK;
 }
 
-int gdb_set_registers_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_set_registers_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
        int i;
        struct reg **reg_list;
        int reg_list_size;
@@ -1053,27 +1195,23 @@ int gdb_set_registers_packet(struct connection *connection, struct target *targe
        packet++;
        packet_size--;
 
-       if (packet_size % 2)
-       {
+       if (packet_size % 2) {
                LOG_WARNING("GDB set_registers packet with uneven characters received, dropping connection");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
-       {
+       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+                       REG_CLASS_GENERAL);
+       if (retval != ERROR_OK)
                return gdb_error(connection, retval);
-       }
 
        packet_p = packet;
-       for (i = 0; i < reg_list_size; i++)
-       {
+       for (i = 0; i < reg_list_size; i++) {
                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");
-               }
 
                bin_buf = malloc(DIV_ROUND_UP(reg_list[i]->size, 8));
                gdb_target_to_reg(target, packet_p, chars, bin_buf);
@@ -1083,7 +1221,6 @@ int gdb_set_registers_packet(struct connection *connection, struct target *targe
                /* advance packet pointer */
                packet_p += chars;
 
-
                free(bin_buf);
        }
 
@@ -1095,8 +1232,10 @@ int gdb_set_registers_packet(struct connection *connection, struct target *targe
        return ERROR_OK;
 }
 
-int gdb_get_register_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_get_register_packet(struct connection *connection,
+       char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
        char *reg_packet;
        int reg_num = strtoul(packet + 1, NULL, 16);
        struct reg **reg_list;
@@ -1107,18 +1246,20 @@ int gdb_get_register_packet(struct connection *connection, struct target *target
        LOG_DEBUG("-");
 #endif
 
-       if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
-       {
+       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+                       REG_CLASS_ALL);
+       if (retval != ERROR_OK)
                return gdb_error(connection, retval);
-       }
 
-       if (reg_list_size <= reg_num)
-       {
+       if (reg_list_size <= reg_num) {
                LOG_ERROR("gdb requested a non-existing register");
-               exit(-1);
+               return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
+       if (!reg_list[reg_num]->valid)
+               reg_list[reg_num]->type->get(reg_list[reg_num]);
+
+       reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */
 
        gdb_str_to_target(target, reg_packet, reg_list[reg_num]);
 
@@ -1130,8 +1271,10 @@ int gdb_get_register_packet(struct connection *connection, struct target *target
        return ERROR_OK;
 }
 
-int gdb_set_register_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_set_register_packet(struct connection *connection,
+       char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
        char *separator;
        uint8_t *bin_buf;
        int reg_num = strtoul(packet + 1, &separator, 16);
@@ -1141,19 +1284,17 @@ int gdb_set_register_packet(struct connection *connection, struct target *target
 
        LOG_DEBUG("-");
 
-       if ((retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size)) != ERROR_OK)
-       {
+       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+                       REG_CLASS_ALL);
+       if (retval != ERROR_OK)
                return gdb_error(connection, retval);
-       }
 
-       if (reg_list_size < reg_num)
-       {
+       if (reg_list_size <= reg_num) {
                LOG_ERROR("gdb requested a non-existing register");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       if (*separator != '=')
-       {
+       if (*separator != '=') {
                LOG_ERROR("GDB 'set register packet', but no '=' following the register number");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
@@ -1162,7 +1303,11 @@ int gdb_set_register_packet(struct connection *connection, struct target *target
        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 */
+       if ((unsigned int)chars != strlen(separator + 1)) {
+               LOG_ERROR("gdb sent a packet with wrong register size");
+               free(bin_buf);
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
 
        gdb_target_to_reg(target, separator + 1, chars, bin_buf);
 
@@ -1176,29 +1321,14 @@ int gdb_set_register_packet(struct connection *connection, struct target *target
        return ERROR_OK;
 }
 
-int gdb_error(struct connection *connection, int retval)
+/* No attempt is made to translate the "retval" to
+ * GDB speak. This has to be done at the calling
+ * site as no mapping really exists.
+ */
+static int gdb_error(struct connection *connection, int retval)
 {
-       switch (retval)
-       {
-               case ERROR_TARGET_DATA_ABORT:
-                       gdb_send_error(connection, EIO);
-                       break;
-               case ERROR_TARGET_TRANSLATION_FAULT:
-                       gdb_send_error(connection, EFAULT);
-                       break;
-               case ERROR_TARGET_UNALIGNED_ACCESS:
-                       gdb_send_error(connection, EFAULT);
-                       break;
-               case ERROR_TARGET_NOT_HALTED:
-                       gdb_send_error(connection, EFAULT);
-                       break;
-               default:
-                       /* This could be that the target reset itself. */
-                       LOG_ERROR("unexpected error %i", retval);
-                       gdb_send_error(connection, EFAULT);
-                       break;
-       }
-
+       LOG_DEBUG("Reporting %i to GDB as generic error", retval);
+       gdb_send_error(connection, EFAULT);
        return ERROR_OK;
 }
 
@@ -1207,8 +1337,10 @@ int gdb_error(struct connection *connection, int retval)
  *
  * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????
  */
-int gdb_read_memory_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_read_memory_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
        char *separator;
        uint32_t addr = 0;
        uint32_t len = 0;
@@ -1223,22 +1355,26 @@ int gdb_read_memory_packet(struct connection *connection, struct target *target,
 
        addr = strtoul(packet, &separator, 16);
 
-       if (*separator != ',')
-       {
+       if (*separator != ',') {
                LOG_ERROR("incomplete read memory packet received, dropping connection");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        len = strtoul(separator + 1, NULL, 16);
 
+       if (!len) {
+               LOG_WARNING("invalid read memory packet received (len == 0)");
+               gdb_put_packet(connection, NULL, 0);
+               return ERROR_OK;
+       }
+
        buffer = malloc(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.
                 *
@@ -1246,7 +1382,8 @@ int gdb_read_memory_packet(struct connection *connection, struct target *target,
                 * 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.
@@ -1255,41 +1392,31 @@ int gdb_read_memory_packet(struct connection *connection, struct target *target,
                retval = ERROR_OK;
        }
 
-       if (retval == ERROR_OK)
-       {
+       if (retval == ERROR_OK) {
                hex_buffer = malloc(len * 2 + 1);
 
-               uint32_t i;
-               for (i = 0; i < len; i++)
-               {
-                       uint8_t t = buffer[i];
-                       hex_buffer[2 * i] = DIGITS[(t >> 4) & 0xf];
-                       hex_buffer[2 * i + 1] = DIGITS[t & 0xf];
-               }
+               int pkt_len = hexify(hex_buffer, (char *)buffer, len, len * 2 + 1);
 
-               gdb_put_packet(connection, hex_buffer, len * 2);
+               gdb_put_packet(connection, hex_buffer, pkt_len);
 
                free(hex_buffer);
-       }
-       else
-       {
+       } else
                retval = gdb_error(connection, retval);
-       }
 
        free(buffer);
 
        return retval;
 }
 
-int gdb_write_memory_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_write_memory_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
        char *separator;
        uint32_t addr = 0;
        uint32_t len = 0;
 
        uint8_t *buffer;
-
-       uint32_t i;
        int retval;
 
        /* skip command character */
@@ -1297,16 +1424,14 @@ int gdb_write_memory_packet(struct connection *connection, struct target *target
 
        addr = strtoul(packet, &separator, 16);
 
-       if (*separator != ',')
-       {
+       if (*separator != ',') {
                LOG_ERROR("incomplete write memory packet received, dropping connection");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        len = strtoul(separator + 1, &separator, 16);
 
-       if (*(separator++) != ':')
-       {
+       if (*(separator++) != ':') {
                LOG_ERROR("incomplete write memory packet received, dropping connection");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
@@ -1315,79 +1440,82 @@ int gdb_write_memory_packet(struct connection *connection, struct target *target
 
        LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
 
-       for (i = 0; i < len; i++)
-       {
-               uint32_t tmp;
-               sscanf(separator + 2*i, "%2" SCNx32 , &tmp);
-               buffer[i] = tmp;
-       }
+       if (unhexify((char *)buffer, separator, len) != (int)len)
+               LOG_ERROR("unable to decode memory packet");
 
        retval = target_write_buffer(target, addr, len, buffer);
 
        if (retval == ERROR_OK)
-       {
                gdb_put_packet(connection, "OK", 2);
-       }
        else
-       {
                retval = gdb_error(connection, retval);
-       }
 
        free(buffer);
 
        return retval;
 }
 
-int gdb_write_memory_binary_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_write_memory_binary_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
        char *separator;
        uint32_t addr = 0;
        uint32_t len = 0;
 
-       int retval;
+       int retval = ERROR_OK;
 
        /* skip command character */
        packet++;
 
        addr = strtoul(packet, &separator, 16);
 
-       if (*separator != ',')
-       {
+       if (*separator != ',') {
                LOG_ERROR("incomplete write memory binary packet received, dropping connection");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        len = strtoul(separator + 1, &separator, 16);
 
-       if (*(separator++) != ':')
-       {
+       if (*(separator++) != ':') {
                LOG_ERROR("incomplete write memory binary packet received, dropping connection");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       retval = ERROR_OK;
-       if (len)
-       {
-               LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
+       struct gdb_connection *gdb_connection = connection->priv;
 
-               retval = target_write_buffer(target, addr, len, (uint8_t*)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);
-       }
-       else
-       {
-               if ((retval = gdb_error(connection, retval)) != ERROR_OK)
+       else {
+               retval = gdb_error(connection, retval);
+               if (retval != ERROR_OK)
                        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(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_step_continue_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
        int current = 0;
        uint32_t address = 0x0;
        int retval = ERROR_OK;
@@ -1395,23 +1523,16 @@ int gdb_step_continue_packet(struct connection *connection, struct target *targe
        LOG_DEBUG("-");
 
        if (packet_size > 1)
-       {
-               packet[packet_size] = 0;
                address = strtoul(packet + 1, NULL, 16);
-       }
        else
-       {
                current = 1;
-       }
 
-       if (packet[0] == 'c')
-       {
+       gdb_running_type = packet[0];
+       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 */
-       }
-       else if (packet[0] == 's')
-       {
+               /* resume at current address, don't handle breakpoints, not debugging */
+               retval = target_resume(target, current, address, 0, 0);
+       } else if (packet[0] == 's') {
                LOG_DEBUG("step");
                /* step at current or address, don't handle breakpoints */
                retval = target_step(target, current, address, 0);
@@ -1419,8 +1540,10 @@ int gdb_step_continue_packet(struct connection *connection, struct target *targe
        return retval;
 }
 
-int gdb_breakpoint_watchpoint_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
+       struct target *target = get_target_from_connection(connection);
        int type;
        enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */;
        enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */;
@@ -1435,60 +1558,48 @@ int gdb_breakpoint_watchpoint_packet(struct connection *connection, struct targe
 
        if (type == 0)  /* memory breakpoint */
                bp_type = BKPT_SOFT;
-       else if (type == 1) /* hardware breakpoint */
+       else if (type == 1)     /* hardware breakpoint */
                bp_type = BKPT_HARD;
-       else if (type == 2) /* write watchpoint */
+       else if (type == 2)     /* write watchpoint */
                wp_type = WPT_WRITE;
-       else if (type == 3) /* read watchpoint */
+       else if (type == 3)     /* read watchpoint */
                wp_type = WPT_READ;
-       else if (type == 4) /* access watchpoint */
+       else if (type == 4)     /* access watchpoint */
                wp_type = WPT_ACCESS;
-       else
-       {
+       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;
-       }
 
-       if (*separator != ',')
-       {
+       if (*separator != ',') {
                LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        address = strtoul(separator + 1, &separator, 16);
 
-       if (*separator != ',')
-       {
+       if (*separator != ',') {
                LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        size = strtoul(separator + 1, &separator, 16);
 
-       switch (type)
-       {
+       switch (type) {
                case 0:
                case 1:
-                       if (packet[0] == 'Z')
-                       {
-                               if ((retval = breakpoint_add(target, address, size, bp_type)) != ERROR_OK)
-                               {
-                                       if ((retval = gdb_error(connection, retval)) != ERROR_OK)
+                       if (packet[0] == 'Z') {
+                               retval = breakpoint_add(target, address, size, bp_type);
+                               if (retval != ERROR_OK) {
+                                       retval = gdb_error(connection, retval);
+                                       if (retval != ERROR_OK)
                                                return retval;
-                               }
-                               else
-                               {
+                               } else
                                        gdb_put_packet(connection, "OK", 2);
-                               }
-                       }
-                       else
-                       {
+                       } else {
                                breakpoint_remove(target, address);
                                gdb_put_packet(connection, "OK", 2);
                        }
@@ -1497,20 +1608,15 @@ int gdb_breakpoint_watchpoint_packet(struct connection *connection, struct targe
                case 3:
                case 4:
                {
-                       if (packet[0] == 'Z')
-                       {
-                               if ((retval = watchpoint_add(target, address, size, wp_type, 0, 0xffffffffu)) != ERROR_OK)
-                               {
-                                       if ((retval = gdb_error(connection, retval)) != ERROR_OK)
+                       if (packet[0] == 'Z') {
+                               retval = watchpoint_add(target, address, size, wp_type, 0, 0xffffffffu);
+                               if (retval != ERROR_OK) {
+                                       retval = gdb_error(connection, retval);
+                                       if (retval != ERROR_OK)
                                                return retval;
-                               }
-                               else
-                               {
+                               } else
                                        gdb_put_packet(connection, "OK", 2);
-                               }
-                       }
-                       else
-                       {
+                       } else {
                                watchpoint_remove(target, address);
                                gdb_put_packet(connection, "OK", 2);
                        }
@@ -1523,27 +1629,25 @@ int gdb_breakpoint_watchpoint_packet(struct connection *connection, struct targe
        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)
-       {
                return;
-       }
        int first = 1;
 
-       for (;;)
-       {
-               if ((*xml == NULL) || (!first))
-               {
+       for (;; ) {
+               if ((*xml == NULL) || (!first)) {
                        /* start by 0 to exercise all the code paths.
                         * Need minimum 2 bytes to fit 1 char and 0 terminator. */
 
                        *size = *size * 2 + 2;
                        char *t = *xml;
                        *xml = realloc(*xml, *size);
-                       if (*xml == NULL)
-                       {
+                       if (*xml == NULL) {
                                if (t)
                                        free(t);
                                *retval = ERROR_SERVER_REMOTE_CLOSED;
@@ -1556,8 +1660,7 @@ void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, .
                va_start(ap, fmt);
                ret = vsnprintf(*xml + *pos, *size - *pos, fmt, ap);
                va_end(ap);
-               if ((ret > 0) && ((ret + 1) < *size - *pos))
-               {
+               if ((ret > 0) && ((ret + 1) < *size - *pos)) {
                        *pos += ret;
                        return;
                }
@@ -1566,84 +1669,614 @@ void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, .
        }
 }
 
-static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len)
+static int decode_xfer_read(char *_buf, char **annex, int *ofs, unsigned int *len)
 {
+       int ret = 0;
+       char *buf = strdup(_buf);
+       char *_annex;
        char *separator;
 
        /* Extract and NUL-terminate the annex. */
-       *annex = buf;
+       _annex = buf;
        while (*buf && *buf != ':')
                buf++;
-       if (*buf == '\0')
-               return -1;
+       if (*buf == '\0') {
+               ret = -1;
+               goto out;
+       }
        *buf++ = 0;
 
+       /* Return annex as copy because "buf" will be freed in this function */
+       *annex = strdup(_annex);
+
        /* After the read marker and annex, qXfer looks like a
         * traditional 'm' packet. */
 
        *ofs = strtoul(buf, &separator, 16);
 
-       if (*separator != ',')
-               return -1;
+       if (*separator != ',') {
+               ret = -1;
+               goto out;
+       }
 
        *len = strtoul(separator + 1, NULL, 16);
 
-       return 0;
+out:
+       free(buf);
+       return ret;
 }
 
-int gdb_calc_blocksize(struct flash_bank *bank)
+static int compare_bank(const void *a, const void *b)
 {
-       uint32_t i;
-       uint32_t block_size = 0xffffffff;
+       struct flash_bank *b1, *b2;
+       b1 = *((struct flash_bank **)a);
+       b2 = *((struct flash_bank **)b);
 
-       /* loop through all sectors and return smallest sector size */
+       if (b1->base == b2->base)
+               return 0;
+       else if (b1->base > b2->base)
+               return 1;
+       else
+               return -1;
+}
 
-       for (i = 0; i < (uint32_t)bank->num_sectors; i++)
-       {
-               if (bank->sectors[i].size < block_size)
-                       block_size = bank->sectors[i].size;
+static int gdb_memory_map(struct connection *connection,
+               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 target *target = get_target_from_connection(connection);
+       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;
+       int target_flash_banks = 0;
+
+       /* 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++) {
+               p = get_flash_bank_by_num_noprobe(i);
+               if (p->target != target)
+                       continue;
+               retval = get_flash_bank_by_num(i, &p);
+               if (retval != ERROR_OK) {
+                       free(banks);
+                       gdb_error(connection, retval);
+                       return retval;
+               }
+               banks[target_flash_banks++] = p;
+       }
+
+       qsort(banks, target_flash_banks, sizeof(struct flash_bank *),
+               compare_bank);
+
+       for (i = 0; i < target_flash_banks; i++) {
+               int j;
+               unsigned sector_size = 0;
+               uint32_t start;
+
+               p = banks[i];
+               start = p->base;
+
+               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;
        }
 
-       return block_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_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 compare_bank (const void * a, const void * b)
+static const char *gdb_get_reg_type_name(enum reg_type type)
 {
-       struct flash_bank *b1, *b2;
-       b1=*((struct flash_bank **)a);
-       b2=*((struct flash_bank **)b);
+       switch (type) {
+               case REG_TYPE_INT:
+                       return "int";
+               case REG_TYPE_INT8:
+                       return "int8";
+               case REG_TYPE_INT16:
+                       return "int16";
+               case REG_TYPE_INT32:
+                       return "int32";
+               case REG_TYPE_INT64:
+                       return "int64";
+               case REG_TYPE_INT128:
+                       return "int128";
+               case REG_TYPE_UINT8:
+                       return "uint8";
+               case REG_TYPE_UINT16:
+                       return "uint16";
+               case REG_TYPE_UINT32:
+                       return "uint32";
+               case REG_TYPE_UINT64:
+                       return "uint64";
+               case REG_TYPE_UINT128:
+                       return "uint128";
+               case REG_TYPE_CODE_PTR:
+                       return "code_ptr";
+               case REG_TYPE_DATA_PTR:
+                       return "data_ptr";
+               case REG_TYPE_FLOAT:
+                       return "float";
+               case REG_TYPE_IEEE_SINGLE:
+                       return "ieee_single";
+               case REG_TYPE_IEEE_DOUBLE:
+                       return "ieee_double";
+               case REG_TYPE_ARCH_DEFINED:
+                       return "int"; /* return arbitrary string to avoid compile warning. */
+       }
+
+       return "int"; /* "int" as default value */
+}
 
-       if (b1->base == b2->base)
-       {
-               return 0;
-       } else if (b1->base > b2->base)
-       {
-               return 1;
-       } else
-       {
-               return -1;
+static int gdb_generate_reg_type_description(struct target *target,
+               char **tdesc, int *pos, int *size, struct reg_data_type *type)
+{
+       int retval = ERROR_OK;
+
+       if (type->type_class == REG_TYPE_CLASS_VECTOR) {
+               /* <vector id="id" type="type" count="count"/> */
+               xml_printf(&retval, tdesc, pos, size,
+                               "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
+                               type->id, type->reg_type_vector->type->id,
+                               type->reg_type_vector->count);
+
+       } else if (type->type_class == REG_TYPE_CLASS_UNION) {
+               /* <union id="id">
+                *  <field name="name" type="type"/> ...
+                * </union> */
+               xml_printf(&retval, tdesc, pos, size,
+                               "<union id=\"%s\">\n",
+                               type->id);
+
+               struct reg_data_type_union_field *field;
+               field = type->reg_type_union->fields;
+               while (field != NULL) {
+                       xml_printf(&retval, tdesc, pos, size,
+                                       "<field name=\"%s\" type=\"%s\"/>\n",
+                                       field->name, field->type->id);
+
+                       field = field->next;
+               }
+
+               xml_printf(&retval, tdesc, pos, size,
+                               "</union>\n");
+
+       } else if (type->type_class == REG_TYPE_CLASS_STRUCT) {
+               struct reg_data_type_struct_field *field;
+               field = type->reg_type_struct->fields;
+
+               if (field->use_bitfields) {
+                       /* <struct id="id" size="size">
+                        *  <field name="name" start="start" end="end"/> ...
+                        * </struct> */
+                       xml_printf(&retval, tdesc, pos, size,
+                                       "<struct id=\"%s\" size=\"%d\">\n",
+                                       type->id, type->reg_type_struct->size);
+                       while (field != NULL) {
+                               xml_printf(&retval, tdesc, pos, size,
+                                               "<field name=\"%s\" start=\"%d\" end=\"%d\"/>\n",
+                                               field->name, field->bitfield->start,
+                                               field->bitfield->end);
+
+                               field = field->next;
+                       }
+               } else {
+                       /* <struct id="id">
+                        *  <field name="name" type="type"/> ...
+                        * </struct> */
+                       xml_printf(&retval, tdesc, pos, size,
+                                       "<struct id=\"%s\">\n",
+                                       type->id);
+                       while (field != NULL) {
+                               xml_printf(&retval, tdesc, pos, size,
+                                               "<field name=\"%s\" type=\"%s\"/>\n",
+                                               field->name, field->type->id);
+
+                               field = field->next;
+                       }
+               }
+
+               xml_printf(&retval, tdesc, pos, size,
+                               "</struct>\n");
+
+       } else if (type->type_class == REG_TYPE_CLASS_FLAGS) {
+               /* <flags id="id" size="size">
+                *  <field name="name" start="start" end="end"/> ...
+                * </flags> */
+               xml_printf(&retval, tdesc, pos, size,
+                               "<flags id=\"%s\" size=\"%d\">\n",
+                               type->id, type->reg_type_flags->size);
+
+               struct reg_data_type_flags_field *field;
+               field = type->reg_type_flags->fields;
+               while (field != NULL) {
+                       xml_printf(&retval, tdesc, pos, size,
+                                       "<field name=\"%s\" start=\"%d\" end=\"%d\"/>\n",
+                                       field->name, field->bitfield->start, field->bitfield->end);
+
+                       field = field->next;
+               }
+
+               xml_printf(&retval, tdesc, pos, size,
+                               "</flags>\n");
+
+       }
+
+       return ERROR_OK;
+}
+
+/* Get a list of available target registers features. feature_list must
+ * be freed by caller.
+ */
+static int get_reg_features_list(struct target *target, char **feature_list[], int *feature_list_size,
+               struct reg **reg_list, int reg_list_size)
+{
+       int tbl_sz = 0;
+
+       /* Start with only one element */
+       *feature_list = calloc(1, sizeof(char *));
+
+       for (int i = 0; i < reg_list_size; i++) {
+               if (reg_list[i]->exist == false)
+                       continue;
+
+               if (reg_list[i]->feature != NULL
+                       && reg_list[i]->feature->name != NULL
+                       && (strcmp(reg_list[i]->feature->name, ""))) {
+                       /* We found a feature, check if the feature is already in the
+                        * table. If not, allocate a new entry for the table and
+                        * put the new feature in it.
+                        */
+                       for (int j = 0; j < (tbl_sz + 1); j++) {
+                               if (!((*feature_list)[j])) {
+                                       (*feature_list)[tbl_sz++] = strdup(reg_list[i]->feature->name);
+                                       *feature_list = realloc(*feature_list, sizeof(char *) * (tbl_sz + 1));
+                                       (*feature_list)[tbl_sz] = NULL;
+                                       break;
+                               } else {
+                                       if (!strcmp((*feature_list)[j], reg_list[i]->feature->name))
+                                               break;
+                               }
+                       }
+               }
+       }
+
+       if (feature_list_size)
+               *feature_list_size = tbl_sz;
+
+       return ERROR_OK;
+}
+
+static int gdb_generate_target_description(struct target *target, char **tdesc_out)
+{
+       int retval = ERROR_OK;
+       struct reg **reg_list;
+       int reg_list_size;
+       char *tdesc = NULL;
+       int pos = 0;
+       int size = 0;
+
+       retval = target_get_gdb_reg_list(target, &reg_list,
+                       &reg_list_size, REG_CLASS_ALL);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("get register list failed");
+               return ERROR_FAIL;
+       }
+
+       if (reg_list_size <= 0) {
+               free(reg_list);
+               return ERROR_FAIL;
+       }
+
+       char **features = NULL;
+       /* Get a list of available target registers features */
+       retval = get_reg_features_list(target, &features, NULL, reg_list, reg_list_size);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Can't get the registers feature list");
+               free(reg_list);
+               return ERROR_FAIL;
+       }
+
+       /* If we found some features associated with registers, create sections */
+       int current_feature = 0;
+
+       xml_printf(&retval, &tdesc, &pos, &size,
+                       "<?xml version=\"1.0\"?>\n"
+                       "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n"
+                       "<target version=\"1.0\">\n");
+
+       /* generate target description according to register list */
+       if (features != NULL) {
+               while (features[current_feature]) {
+
+                       xml_printf(&retval, &tdesc, &pos, &size,
+                                       "<feature name=\"%s\">\n",
+                                       features[current_feature]);
+
+                       int i;
+                       for (i = 0; i < reg_list_size; i++) {
+
+                               if (reg_list[i]->exist == false)
+                                       continue;
+
+                               if (strcmp(reg_list[i]->feature->name, features[current_feature]))
+                                       continue;
+
+                               const char *type_str;
+                               if (reg_list[i]->reg_data_type != NULL) {
+                                       if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) {
+                                               /* generate <type... first, if there are architecture-defined types. */
+                                               gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
+                                                               reg_list[i]->reg_data_type);
+
+                                               type_str = reg_list[i]->reg_data_type->id;
+                                       } else {
+                                               /* predefined type */
+                                               type_str = gdb_get_reg_type_name(
+                                                               reg_list[i]->reg_data_type->type);
+                                       }
+                               } else {
+                                       /* Default type is "int" */
+                                       type_str = "int";
+                               }
+
+                               xml_printf(&retval, &tdesc, &pos, &size,
+                                               "<reg name=\"%s\"", reg_list[i]->name);
+                               xml_printf(&retval, &tdesc, &pos, &size,
+                                               " bitsize=\"%d\"", reg_list[i]->size);
+                               xml_printf(&retval, &tdesc, &pos, &size,
+                                               " regnum=\"%d\"", reg_list[i]->number);
+                               if (reg_list[i]->caller_save)
+                                       xml_printf(&retval, &tdesc, &pos, &size,
+                                                       " save-restore=\"yes\"");
+                               else
+                                       xml_printf(&retval, &tdesc, &pos, &size,
+                                                       " save-restore=\"no\"");
+
+                               xml_printf(&retval, &tdesc, &pos, &size,
+                                               " type=\"%s\"", type_str);
+
+                               if (reg_list[i]->group != NULL)
+                                       xml_printf(&retval, &tdesc, &pos, &size,
+                                                       " group=\"%s\"", reg_list[i]->group);
+
+                               xml_printf(&retval, &tdesc, &pos, &size,
+                                               "/>\n");
+                       }
+
+                       xml_printf(&retval, &tdesc, &pos, &size,
+                                       "</feature>\n");
+
+                       current_feature++;
+               }
        }
+
+       xml_printf(&retval, &tdesc, &pos, &size,
+                       "</target>\n");
+
+       free(reg_list);
+       free(features);
+
+       if (retval == ERROR_OK)
+               *tdesc_out = tdesc;
+       else
+               free(tdesc);
+
+       return retval;
 }
 
-int gdb_query_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_get_target_description_chunk(struct target *target, struct target_desc_format *target_desc,
+               char **chunk, int32_t offset, uint32_t length)
+{
+       if (target_desc == NULL) {
+               LOG_ERROR("Unable to Generate Target Description");
+               return ERROR_FAIL;
+       }
+
+       char *tdesc = target_desc->tdesc;
+       uint32_t tdesc_length = target_desc->tdesc_length;
+
+       if (tdesc == NULL) {
+               int retval = gdb_generate_target_description(target, &tdesc);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Unable to Generate Target Description");
+                       return ERROR_FAIL;
+               }
+
+               tdesc_length = strlen(tdesc);
+       }
+
+       char transfer_type;
+
+       if (length < (tdesc_length - offset))
+               transfer_type = 'm';
+       else
+               transfer_type = 'l';
+
+       *chunk = malloc(length + 2);
+       if (*chunk == NULL) {
+               LOG_ERROR("Unable to allocate memory");
+               return ERROR_FAIL;
+       }
+
+       (*chunk)[0] = transfer_type;
+       if (transfer_type == 'm') {
+               strncpy((*chunk) + 1, tdesc + offset, length);
+               (*chunk)[1 + length] = '\0';
+       } else {
+               strncpy((*chunk) + 1, tdesc + offset, tdesc_length - offset);
+               (*chunk)[1 + (tdesc_length - offset)] = '\0';
+
+               /* After gdb-server sends out last chunk, invalidate tdesc. */
+               free(tdesc);
+               tdesc = NULL;
+               tdesc_length = 0;
+       }
+
+       target_desc->tdesc = tdesc;
+       target_desc->tdesc_length = tdesc_length;
+
+       return ERROR_OK;
+}
+
+static int gdb_target_description_supported(struct target *target, int *supported)
+{
+       int retval = ERROR_OK;
+       struct reg **reg_list = NULL;
+       int reg_list_size = 0;
+       int feature_list_size = 0;
+       char **features = NULL;
+
+       retval = target_get_gdb_reg_list(target, &reg_list,
+                       &reg_list_size, REG_CLASS_ALL);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("get register list failed");
+               goto error;
+       }
+
+       if (reg_list_size <= 0) {
+               retval = ERROR_FAIL;
+               goto error;
+       }
+
+       /* Get a list of available target registers features */
+       retval = get_reg_features_list(target, &features, &feature_list_size, reg_list, reg_list_size);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Can't get the registers feature list");
+               goto error;
+       }
+
+       if (supported) {
+               if (feature_list_size)
+                       *supported = 1;
+               else
+                       *supported = 0;
+       }
+
+error:
+       if (reg_list != NULL)
+               free(reg_list);
+
+       if (features != NULL)
+               free(features);
+
+       return retval;
+}
+
+static int gdb_query_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
        struct command_context *cmd_ctx = connection->cmd_ctx;
        struct gdb_connection *gdb_connection = connection->priv;
+       struct target *target = get_target_from_connection(connection);
 
-       if (strstr(packet, "qRcmd,"))
-       {
-               if (packet_size > 6)
-               {
+       if (strncmp(packet, "qRcmd,", 6) == 0) {
+               if (packet_size > 6) {
                        char *cmd;
-                       int i;
-                       cmd = malloc((packet_size - 6)/2 + 1);
-                       for (i = 0; i < (packet_size - 6)/2; i++)
-                       {
-                               uint32_t tmp;
-                               sscanf(packet + 6 + 2*i, "%2" SCNx32 , &tmp);
-                               cmd[i] = tmp;
-                       }
-                       cmd[(packet_size - 6)/2] = 0x0;
+                       cmd = malloc((packet_size - 6) / 2 + 1);
+                       int len = unhexify(cmd, packet + 6, (packet_size - 6) / 2);
+                       cmd[len] = 0;
 
                        /* We want to print all debug output to GDB connection */
                        log_add_callback(gdb_log_callback, connection);
@@ -1659,11 +2292,8 @@ int gdb_query_packet(struct connection *connection, struct target *target, char
                }
                gdb_put_packet(connection, "OK", 2);
                return ERROR_OK;
-       }
-       else if (strstr(packet, "qCRC:"))
-       {
-               if (packet_size > 5)
-               {
+       } else if (strncmp(packet, "qCRC:", 5) == 0) {
+               if (packet_size > 5) {
                        int retval;
                        char gdb_reply[10];
                        char *separator;
@@ -1676,8 +2306,7 @@ int gdb_query_packet(struct connection *connection, struct target *target, char
 
                        addr = strtoul(packet, &separator, 16);
 
-                       if (*separator != ',')
-                       {
+                       if (*separator != ',') {
                                LOG_ERROR("incomplete read memory packet received, dropping connection");
                                return ERROR_SERVER_REMOTE_CLOSED;
                        }
@@ -1686,182 +2315,87 @@ int gdb_query_packet(struct connection *connection, struct target *target, char
 
                        retval = target_checksum_memory(target, addr, len, &checksum);
 
-                       if (retval == ERROR_OK)
-                       {
+                       if (retval == ERROR_OK) {
                                snprintf(gdb_reply, 10, "C%8.8" PRIx32 "", checksum);
                                gdb_put_packet(connection, gdb_reply, 9);
-                       }
-                       else
-                       {
-                               if ((retval = gdb_error(connection, retval)) != ERROR_OK)
+                       } else {
+                               retval = gdb_error(connection, retval);
+                               if (retval != ERROR_OK)
                                        return retval;
                        }
 
                        return ERROR_OK;
                }
-       }
-       else if (strstr(packet, "qSupported"))
-       {
+       } else if (strncmp(packet, "qSupported", 10) == 0) {
                /* we currently support packet size and qXfer:memory-map:read (if enabled)
-                * disable qXfer:features:read for the moment */
+                * qXfer:features:read is supported for some targets */
                int retval = ERROR_OK;
                char *buffer = NULL;
                int pos = 0;
                int size = 0;
+               int gdb_target_desc_supported = 0;
 
-               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)) ? '+' : '-');
-
-               if (retval != ERROR_OK)
-               {
-                       gdb_send_error(connection, 01);
-                       return ERROR_OK;
-               }
-
-               gdb_put_packet(connection, buffer, strlen(buffer));
-               free(buffer);
-
-               return ERROR_OK;
-       }
-       else if (strstr(packet, "qXfer:memory-map:read::") && (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. */
-
-               struct flash_bank *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.
-                */
-               struct flash_bank **banks = malloc(sizeof(struct flash_bank *)*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;
+               /* we need to test that the target supports target descriptions */
+               retval = gdb_target_description_supported(target, &gdb_target_desc_supported);
+               if (retval != ERROR_OK) {
+                       LOG_INFO("Failed detecting Target Description Support, disabling");
+                       gdb_target_desc_supported = 0;
                }
 
-               qsort(banks, flash_get_bank_count(), sizeof(struct flash_bank *), compare_bank);
-
-               uint32_t 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 */
+               /* support may be disabled globally */
+               if (gdb_use_target_description == 0) {
+                       if (gdb_target_desc_supported)
+                               LOG_WARNING("Target Descriptions Supported, but disabled");
+                       gdb_target_desc_supported = 0;
                }
 
-               free(banks);
-               banks = NULL;
-
-               xml_printf(&retval, &xml, &pos, &size, "</memory-map>\n");
+               xml_printf(&retval,
+                       &buffer,
+                       &pos,
+                       &size,
+                       "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;QStartNoAckMode+",
+                       (GDB_BUFFER_SIZE - 1),
+                       ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-',
+                       (gdb_target_desc_supported == 1) ? '+' : '-');
 
-               if (retval != ERROR_OK)
-               {
-                       gdb_send_error(connection, retval);
-                       return retval;
-               }
-
-               if (offset + length > pos)
-               {
-                       length = pos - offset;
+               if (retval != ERROR_OK) {
+                       gdb_send_error(connection, 01);
+                       return ERROR_OK;
                }
 
-               char *t = malloc(length + 1);
-               t[0] = 'l';
-               memcpy(t + 1, xml + offset, length);
-               gdb_put_packet(connection, t, length + 1);
+               gdb_put_packet(connection, buffer, strlen(buffer));
+               free(buffer);
 
-               free(t);
-               free(xml);
                return ERROR_OK;
-       }
-       else if (strstr(packet, "qXfer:features:read:"))
-       {
+       } else if ((strncmp(packet, "qXfer:memory-map:read::", 23) == 0)
+                  && (flash_get_bank_count() > 0))
+               return gdb_memory_map(connection, packet, packet_size);
+       else if (strncmp(packet, "qXfer:features:read:", 20) == 0) {
                char *xml = NULL;
-               int size = 0;
-               int pos = 0;
                int retval = ERROR_OK;
 
                int offset;
                unsigned int length;
-               char *annex;
+               char *annex = NULL;
 
                /* skip command character */
                packet += 20;
 
-               if (decode_xfer_read(packet, &annex, &offset, &length) < 0)
-               {
-                       gdb_send_error(connection, 01);
-                       return ERROR_OK;
-               }
-
-               if (strcmp(annex, "target.xml") != 0)
-               {
+               if (decode_xfer_read(packet, &annex, &offset, &length) < 0) {
                        gdb_send_error(connection, 01);
                        return ERROR_OK;
                }
+               free(annex);
 
-               xml_printf(&retval, &xml, &pos, &size, \
-                       "l < target version=\"1.0\">\n < architecture > arm</architecture>\n</target>\n");
-
-               if (retval != ERROR_OK)
-               {
-                       gdb_send_error(connection, retval);
+               /* Target should prepare correct target description for annex.
+                * The first character of returned xml is 'm' or 'l'. 'm' for
+                * there are *more* chunks to transfer. 'l' for it is the *last*
+                * chunk of target description.
+                */
+               retval = gdb_get_target_description_chunk(target, &gdb_connection->target_desc,
+                               &xml, offset, length);
+               if (retval != ERROR_OK) {
+                       gdb_error(connection, retval);
                        return retval;
                }
 
@@ -1869,9 +2403,7 @@ int gdb_query_packet(struct connection *connection, struct target *target, char
 
                free(xml);
                return ERROR_OK;
-       }
-       else if (strstr(packet, "QStartNoAckMode"))
-       {
+       } else if (strncmp(packet, "QStartNoAckMode", 15) == 0) {
                gdb_connection->noack_mode = 1;
                gdb_put_packet(connection, "OK", 2);
                return ERROR_OK;
@@ -1881,7 +2413,8 @@ int gdb_query_packet(struct connection *connection, struct target *target, char
        return ERROR_OK;
 }
 
-int gdb_v_packet(struct connection *connection, struct target *target, char *packet, int packet_size)
+static int gdb_v_packet(struct connection *connection,
+               char *packet, int packet_size)
 {
        struct gdb_connection *gdb_connection = connection->priv;
        struct gdb_service *gdb_service = connection->service->priv;
@@ -1889,36 +2422,31 @@ int gdb_v_packet(struct connection *connection, struct target *target, char *pac
 
        /* if flash programming disabled - send a empty reply */
 
-       if (gdb_flash_program == 0)
-       {
+       if (gdb_flash_program == 0) {
                gdb_put_packet(connection, "", 0);
                return ERROR_OK;
        }
 
-       if (strstr(packet, "vFlashErase:"))
-       {
+       if (strncmp(packet, "vFlashErase:", 12) == 0) {
                unsigned long addr;
                unsigned long length;
 
                char *parse = packet + 12;
-               if (*parse == '\0')
-               {
+               if (*parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
 
                addr = strtoul(parse, &parse, 16);
 
-               if (*(parse++) != ',' || *parse == '\0')
-               {
+               if (*(parse++) != ',' || *parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
 
                length = strtoul(parse, &parse, 16);
 
-               if (*parse != '\0')
-               {
+               if (*parse != '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
@@ -1929,7 +2457,7 @@ int gdb_v_packet(struct connection *connection, struct target *target, char *pac
 
                /* perform any target specific operations before the erase */
                target_call_event_callbacks(gdb_service->target,
-                               TARGET_EVENT_GDB_FLASH_ERASE_START);
+                       TARGET_EVENT_GDB_FLASH_ERASE_START);
 
                /* vFlashErase:addr,length messages require region start and
                 * end to be "block" aligned ... if padding is ever needed,
@@ -1940,79 +2468,70 @@ int gdb_v_packet(struct connection *connection, struct target *target, char *pac
 
                /* perform any target specific operations after the erase */
                target_call_event_callbacks(gdb_service->target,
-                               TARGET_EVENT_GDB_FLASH_ERASE_END);
+                       TARGET_EVENT_GDB_FLASH_ERASE_END);
 
                /* perform erase */
-               if (result != ERROR_OK)
-               {
+               if (result != ERROR_OK) {
                        /* GDB doesn't evaluate the actual error number returned,
                         * treat a failed erase as an I/O error
                         */
                        gdb_send_error(connection, EIO);
                        LOG_ERROR("flash_erase returned %i", result);
-               }
-               else
+               } else
                        gdb_put_packet(connection, "OK", 2);
 
                return ERROR_OK;
        }
 
-       if (strstr(packet, "vFlashWrite:"))
-       {
+       if (strncmp(packet, "vFlashWrite:", 12) == 0) {
                int retval;
                unsigned long addr;
                unsigned long length;
                char *parse = packet + 12;
 
-               if (*parse == '\0')
-               {
+               if (*parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
                addr = strtoul(parse, &parse, 16);
-               if (*(parse++) != ':')
-               {
+               if (*(parse++) != ':') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
                length = packet_size - (parse - packet);
 
                /* create a new image if there isn't already one */
-               if (gdb_connection->vflash_image == NULL)
-               {
+               if (gdb_connection->vflash_image == NULL) {
                        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, (uint8_t*)parse)) != ERROR_OK)
-               {
+               retval = image_add_section(gdb_connection->vflash_image,
+                               addr, length, 0x0, (uint8_t *)parse);
+               if (retval != ERROR_OK)
                        return retval;
-               }
 
                gdb_put_packet(connection, "OK", 2);
 
                return ERROR_OK;
        }
 
-       if (!strcmp(packet, "vFlashDone"))
-       {
+       if (strncmp(packet, "vFlashDone", 10) == 0) {
                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);
+               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);
                        else
                                gdb_send_error(connection, EIO);
-                       }
-               else
-               {
+               } else {
                        LOG_DEBUG("wrote %u bytes from vFlash image to flash", (unsigned)written);
                        gdb_put_packet(connection, "OK", 2);
                }
@@ -2028,7 +2547,7 @@ int gdb_v_packet(struct connection *connection, struct target *target, char *pac
        return ERROR_OK;
 }
 
-int gdb_detach(struct connection *connection, struct target *target)
+static int gdb_detach(struct connection *connection)
 {
        struct gdb_service *gdb_service = connection->service->priv;
 
@@ -2037,14 +2556,61 @@ int gdb_detach(struct connection *connection, struct target *target)
        return gdb_put_packet(connection, "OK", 2);
 }
 
+/* The format of 'F' response packet is
+ * Fretcode,errno,Ctrl-C flag;call-specific attachment
+ */
+static int gdb_fileio_response_packet(struct connection *connection,
+               char *packet, int packet_size)
+{
+       struct target *target = get_target_from_connection(connection);
+       char *separator;
+       char *parsing_point;
+       int fileio_retcode = strtoul(packet + 1, &separator, 16);
+       int fileio_errno = 0;
+       bool fileio_ctrl_c = false;
+       int retval;
+
+       LOG_DEBUG("-");
+
+       if (*separator == ',') {
+               parsing_point = separator + 1;
+               fileio_errno = strtoul(parsing_point, &separator, 16);
+               if (*separator == ',') {
+                       if (*(separator + 1) == 'C') {
+                               /* TODO: process ctrl-c */
+                               fileio_ctrl_c = true;
+                       }
+               }
+       }
+
+       LOG_DEBUG("File-I/O response, retcode: 0x%x, errno: 0x%x, ctrl-c: %s",
+                       fileio_retcode, fileio_errno, fileio_ctrl_c ? "true" : "false");
+
+       retval = target_gdb_fileio_end(target, fileio_retcode, fileio_errno, fileio_ctrl_c);
+       if (retval != ERROR_OK)
+               return ERROR_FAIL;
+
+       /* After File-I/O ends, keep continue or step */
+       if (gdb_running_type == 'c')
+               retval = target_resume(target, 1, 0x0, 0, 0);
+       else if (gdb_running_type == 's')
+               retval = target_step(target, 1, 0x0, 0);
+       else
+               retval = ERROR_FAIL;
+
+       if (retval != ERROR_OK)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
 static void gdb_log_callback(void *priv, const char *file, unsigned line,
                const char *function, const char *string)
 {
        struct connection *connection = priv;
        struct gdb_connection *gdb_con = connection->priv;
 
-       if (gdb_con->busy)
-       {
+       if (gdb_con->busy) {
                /* do not reply this using the O packet */
                return;
        }
@@ -2052,166 +2618,186 @@ static void gdb_log_callback(void *priv, const char *file, unsigned 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(struct connection *connection)
 {
        char sig_reply[4];
        snprintf(sig_reply, 4, "T%2.2x", 2);
        gdb_put_packet(connection, sig_reply, 3);
-
 }
 
-int gdb_input_inner(struct connection *connection)
+static int gdb_input_inner(struct connection *connection)
 {
+       /* 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;
        struct gdb_connection *gdb_con = connection->priv;
-       static int extended_protocol = 0;
+       static int extended_protocol;
 
-       /* drain input buffer */
-       do
-       {
+       /* drain input buffer. If one of the packets fail, then an error
+        * packet is replied, if applicable.
+        *
+        * This loop will terminate and the error code is returned.
+        *
+        * The calling fn will check if this error is something that
+        * can be recovered from, or if the connection must be closed.
+        *
+        * If the error is recoverable, this fn is called again to
+        * drain the rest of the 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') {
-                               // binary packets spew junk into the debug log stream
-                               char buf[ 50 ];
+                               /* 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);
-                       } else {
+                       } else
                                LOG_DEBUG("received packet: '%s'", packet);
-                       }
                }
 
-               if (packet_size > 0)
-               {
+               if (packet_size > 0) {
                        retval = ERROR_OK;
-                       switch (packet[0])
-                       {
-                               case 'H':
-                                       /* Hct... -- set thread
-                                        * we don't have threads, send empty reply */
-                                       gdb_put_packet(connection, NULL, 0);
+                       switch (packet[0]) {
+                               case 'T':       /* Is thread alive? */
+                                       gdb_thread_packet(connection, packet, packet_size);
+                                       break;
+                               case 'H':       /* Set current thread ( 'c' for step and continue,
+                                                        * 'g' for all other operations ) */
+                                       gdb_thread_packet(connection, packet, packet_size);
                                        break;
                                case 'q':
                                case 'Q':
-                                       retval = gdb_query_packet(connection, target, packet, packet_size);
+                                       retval = gdb_thread_packet(connection, packet, packet_size);
+                                       if (retval == GDB_THREAD_PACKET_NOT_CONSUMED)
+                                               retval = gdb_query_packet(connection, packet, packet_size);
                                        break;
                                case 'g':
-                                       retval = gdb_get_registers_packet(connection, target, packet, packet_size);
+                                       retval = gdb_get_registers_packet(connection, packet, packet_size);
                                        break;
                                case 'G':
-                                       retval = gdb_set_registers_packet(connection, target, packet, packet_size);
+                                       retval = gdb_set_registers_packet(connection, packet, packet_size);
                                        break;
                                case 'p':
-                                       retval = gdb_get_register_packet(connection, target, packet, packet_size);
+                                       retval = gdb_get_register_packet(connection, packet, packet_size);
                                        break;
                                case 'P':
-                                       retval = gdb_set_register_packet(connection, target, packet, packet_size);
+                                       retval = gdb_set_register_packet(connection, packet, packet_size);
                                        break;
                                case 'm':
-                                       retval = gdb_read_memory_packet(connection, target, packet, packet_size);
+                                       retval = gdb_read_memory_packet(connection, packet, packet_size);
                                        break;
                                case 'M':
-                                       retval = gdb_write_memory_packet(connection, target, packet, packet_size);
+                                       retval = gdb_write_memory_packet(connection, packet, packet_size);
                                        break;
                                case 'z':
                                case 'Z':
-                                       retval = gdb_breakpoint_watchpoint_packet(connection, target, packet, packet_size);
+                                       retval = gdb_breakpoint_watchpoint_packet(connection, packet, packet_size);
                                        break;
                                case '?':
-                                       gdb_last_signal_packet(connection, target, packet, packet_size);
+                                       gdb_last_signal_packet(connection, packet, packet_size);
                                        break;
                                case 'c':
                                case 's':
-                                       {
-                                               int retval = ERROR_OK;
-
-                                               struct gdb_connection *gdb_con = connection->priv;
-                                               log_add_callback(gdb_log_callback, connection);
-
-                                               bool nostep = false;
-                                               if (target->state == TARGET_RUNNING)
-                                               {
-                                                       LOG_WARNING("The target is already running. Halt target before stepi/continue.");
-                                                       retval = target_halt(target);
-                                                       if (retval == ERROR_OK)
-                                                               retval = target_wait_state(target, TARGET_HALTED, 100);
-                                               } 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) || nostep)
-                                               {
-                                                       /* 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_con->frontend_state = TARGET_RUNNING;
-                                                       target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
-                                                       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_thread_packet(connection, packet, packet_size);
+                                       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 (!already_running && nostep) {
+                                               /* 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_con->frontend_state = TARGET_RUNNING;
+                                               target_call_event_callbacks(target, TARGET_EVENT_GDB_START);
+
+                                               if (!already_running) {
+                                                       /* Here we don't want packet processing to stop even if this fails,
+                                                        * so we use a local variable instead of retval. */
+                                                       retval = gdb_step_continue_packet(connection, packet, packet_size);
+                                                       if (retval != ERROR_OK) {
+                                                               /* we'll never receive a halted
+                                                                * condition... issue a false one..
+                                                                */
                                                                gdb_frontend_halted(target, connection);
                                                        }
                                                }
                                        }
-                                       break;
+                               }
+                               break;
                                case 'v':
-                                       retval = gdb_v_packet(connection, target, packet, packet_size);
+                                       retval = gdb_v_packet(connection, packet, packet_size);
                                        break;
                                case 'D':
-                                       retval = gdb_detach(connection, target);
+                                       retval = gdb_detach(connection);
                                        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, packet, packet_size);
+                                       if (retval != ERROR_OK)
                                                return retval;
                                        break;
                                case 'k':
-                                       if (extended_protocol != 0)
+                                       if (extended_protocol != 0) {
+                                               gdb_con->attached = false;
                                                break;
+                                       }
                                        gdb_put_packet(connection, "OK", 2);
                                        return ERROR_SERVER_REMOTE_CLOSED;
                                case '!':
@@ -2223,10 +2809,40 @@ int gdb_input_inner(struct connection *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 %s",
+                                       command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s",
                                                        target_name(target));
+                                       /* set connection as attached after reset */
+                                       gdb_con->attached = true;
+                                       /*  info rtos parts */
+                                       gdb_thread_packet(connection, packet, packet_size);
+                                       break;
+
+                               case 'j':
+                                       /* packet supported only by smp target i.e cortex_a.c*/
+                                       /* handle smp packet replying coreid played to gbd */
+                                       gdb_read_smp_packet(connection, packet, packet_size);
+                                       break;
+
+                               case 'J':
+                                       /* packet supported only by smp target i.e cortex_a.c */
+                                       /* handle smp packet setting coreid to be played at next
+                                        * resume to gdb */
+                                       gdb_write_smp_packet(connection, packet, packet_size);
+                                       break;
+
+                               case 'F':
+                                       /* File-I/O extension */
+                                       /* After gdb uses host-side syscall to complete target file
+                                        * I/O, gdb sends host-side syscall return value to target
+                                        * by 'F' packet.
+                                        * The format of 'F' response packet is
+                                        * Fretcode,errno,Ctrl-C flag;call-specific attachment
+                                        */
+                                       gdb_con->frontend_state = TARGET_RUNNING;
+                                       log_add_callback(gdb_log_callback, connection);
+                                       gdb_fileio_response_packet(connection, packet, packet_size);
                                        break;
+
                                default:
                                        /* ignore unknown packets */
                                        LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]);
@@ -2239,18 +2855,13 @@ int gdb_input_inner(struct connection *connection)
                                return retval;
                }
 
-               if (gdb_con->ctrl_c)
-               {
-                       if (target->state == TARGET_RUNNING)
-                       {
+               if (gdb_con->ctrl_c) {
+                       if (target->state == TARGET_RUNNING) {
                                retval = target_halt(target);
                                if (retval != ERROR_OK)
-                               {
                                        target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
-                               }
                                gdb_con->ctrl_c = 0;
-                       } else
-                       {
+                       } else {
                                LOG_INFO("The target is not running when halt was requested, stopping GDB.");
                                target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
                        }
@@ -2261,7 +2872,7 @@ int gdb_input_inner(struct connection *connection)
        return ERROR_OK;
 }
 
-int gdb_input(struct connection *connection)
+static int gdb_input(struct connection *connection)
 {
        int retval = gdb_input_inner(connection);
        struct gdb_connection *gdb_con = connection->priv;
@@ -2276,68 +2887,69 @@ int gdb_input(struct connection *connection)
        return ERROR_OK;
 }
 
-static int gdb_target_start(struct target *target, uint16_t port)
+static int gdb_target_start(struct target *target, const char *port)
 {
-       bool use_pipes = 0 == port;
-       struct gdb_service *gdb_service = malloc(sizeof(struct gdb_service));
+       struct gdb_service *gdb_service;
+       int ret;
+       gdb_service = malloc(sizeof(struct gdb_service));
+
        if (NULL == gdb_service)
                return -ENOMEM;
 
        gdb_service->target = target;
+       gdb_service->core[0] = -1;
+       gdb_service->core[1] = -1;
+       target->gdb_service = gdb_service;
 
-       add_service("gdb", use_pipes ? CONNECTION_PIPE : CONNECTION_TCP,
+       ret = add_service("gdb",
                        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;
+       /* initialialize all targets gdb service with the same pointer */
+       {
+               struct target_list *head;
+               struct target *curr;
+               head = target->head;
+               while (head != (struct target_list *)NULL) {
+                       curr = head->target;
+                       if (curr != target)
+                               curr->gdb_service = gdb_service;
+                       head = head->next;
+               }
+       }
+       return ret;
 }
 
-/* FIXME static */
-int gdb_target_add_one(struct target *target)
+static int gdb_target_add_one(struct target *target)
 {
-       if (gdb_port == 0 && server_use_pipes == 0)
-       {
-               LOG_INFO("gdb port disabled");
+       /*  one gdb instance per smp list */
+       if ((target->smp) && (target->gdb_service))
                return ERROR_OK;
+       int retval = gdb_target_start(target, gdb_port_next);
+       if (retval == ERROR_OK) {
+               long portnumber;
+               /* If we can parse the port number
+                * then we increment the port number for the next target.
+                */
+               char *end;
+               portnumber = strtol(gdb_port_next, &end, 0);
+               if (!*end) {
+                       if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) {
+                               free(gdb_port_next);
+                               gdb_port_next = alloc_printf("%d", portnumber+1);
+                       }
+               }
        }
-       if (0 == gdb_port_next)
-               gdb_port_next = gdb_port;
-
-       bool use_pipes = server_use_pipes;
-       static bool server_started_with_pipes = false;
-       if (server_started_with_pipes)
-       {
-               LOG_WARNING("gdb service permits one target when using pipes");
-               if (0 == gdb_port)
-                       return ERROR_OK;
-
-               use_pipes = false;
-       }
-
-       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 e;
+       return retval;
 }
 
 int gdb_target_add_all(struct target *target)
 {
-       if (NULL == target)
-       {
+       if (NULL == target) {
                LOG_WARNING("gdb services need one or more targets defined");
                return ERROR_OK;
        }
 
-       while (NULL != target)
-       {
+       while (NULL != target) {
                int retval = gdb_target_add_one(target);
                if (ERROR_OK != retval)
                        return retval;
@@ -2351,14 +2963,11 @@ int gdb_target_add_all(struct target *target)
 COMMAND_HANDLER(handle_gdb_sync_command)
 {
        if (CMD_ARGC != 0)
-       {
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
-       if (current_gdb_connection == NULL)
-       {
+       if (current_gdb_connection == NULL) {
                command_print(CMD_CTX,
-                               "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\"");
+                       "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\"");
                return ERROR_FAIL;
        }
 
@@ -2370,70 +2979,118 @@ COMMAND_HANDLER(handle_gdb_sync_command)
 /* daemon configuration command gdb_port */
 COMMAND_HANDLER(handle_gdb_port_command)
 {
-       int retval = CALL_COMMAND_HANDLER(server_port_command, &gdb_port);
-       if (ERROR_OK == retval)
-               gdb_port_next = gdb_port;
+       int retval = CALL_COMMAND_HANDLER(server_pipe_command, &gdb_port);
+       if (ERROR_OK == retval) {
+               free(gdb_port_next);
+               gdb_port_next = strdup(gdb_port);
+       }
        return retval;
 }
 
 COMMAND_HANDLER(handle_gdb_memory_map_command)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_memory_map);
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
 
-       return ERROR_COMMAND_SYNTAX_ERROR;
+       COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_memory_map);
+       return ERROR_OK;
 }
 
 COMMAND_HANDLER(handle_gdb_flash_program_command)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_flash_program);
+       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;
 }
 
 COMMAND_HANDLER(handle_gdb_report_data_abort_command)
 {
-       if (CMD_ARGC == 1)
-               COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_data_abort);
+       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 */
 COMMAND_HANDLER(handle_gdb_breakpoint_override_command)
 {
-       if (CMD_ARGC == 0)
-       {
-
-       } else if (CMD_ARGC == 1)
-       {
+       if (CMD_ARGC == 0) {
+               /* nothing */
+       } else if (CMD_ARGC == 1) {
                gdb_breakpoint_override = 1;
                if (strcmp(CMD_ARGV[0], "hard") == 0)
-               {
                        gdb_breakpoint_override_type = BKPT_HARD;
-               } else if (strcmp(CMD_ARGV[0], "soft") == 0)
-               {
+               else if (strcmp(CMD_ARGV[0], "soft") == 0)
                        gdb_breakpoint_override_type = BKPT_SOFT;
-               } else if (strcmp(CMD_ARGV[0], "disable") == 0)
-               {
+               else if (strcmp(CMD_ARGV[0], "disable") == 0)
                        gdb_breakpoint_override = 0;
-               }
        } else
-       {
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
        if (gdb_breakpoint_override)
-       {
-               LOG_USER("force %s breakpoints", (gdb_breakpoint_override_type == BKPT_HARD)?"hard":"soft");
-       } else
-       {
+               LOG_USER("force %s breakpoints",
+                       (gdb_breakpoint_override_type == BKPT_HARD) ? "hard" : "soft");
+       else
                LOG_USER("breakpoint type is not overridden");
-       }
 
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(handle_gdb_target_description_command)
+{
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_target_description);
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_gdb_save_tdesc_command)
+{
+       char *tdesc;
+       uint32_t tdesc_length;
+       struct target *target = get_current_target(CMD_CTX);
+
+       int retval = gdb_generate_target_description(target, &tdesc);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Unable to Generate Target Description");
+               return ERROR_FAIL;
+       }
+
+       tdesc_length = strlen(tdesc);
+
+       struct fileio fileio;
+       size_t size_written;
+
+       char *tdesc_filename = alloc_printf("%s.xml", target_type_name(target));
+       if (tdesc_filename == NULL) {
+               retval = ERROR_FAIL;
+               goto out;
+       }
+
+       retval = fileio_open(&fileio, tdesc_filename, FILEIO_WRITE, FILEIO_TEXT);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Can't open %s for writing", tdesc_filename);
+               goto out;
+       }
+
+       retval = fileio_write(&fileio, tdesc_length, tdesc, &size_written);
+
+       fileio_close(&fileio);
+
+       if (retval != ERROR_OK)
+               LOG_ERROR("Error while writing the tdesc file");
+
+out:
+       free(tdesc_filename);
+       free(tdesc);
+
+       return retval;
+}
+
 static const struct command_registration gdb_command_handlers[] = {
        {
                .name = "gdb_sync",
@@ -2442,14 +3099,19 @@ static const struct command_registration gdb_command_handlers[] = {
                .help = "next stepi will return immediately allowing "
                        "GDB to fetch register state without affecting "
                        "target state",
+               .usage = ""
        },
        {
                .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.",
+               .help = "Normally gdb listens to a TCP/IP port. Each subsequent GDB "
+                       "server listens for the next port number after the "
+                       "base port number specified. "
+                       "No arguments reports GDB port. \"pipe\" means listen to stdin "
+                       "output to stdout, an integer is base port number, \"disable\" disables "
+                       "port. Any other string is are interpreted as named pipe to listen to. "
+                       "Output pipe is the same name as input pipe, but with 'o' appended.",
                .usage = "[port_num]",
        },
        {
@@ -2481,10 +3143,25 @@ static const struct command_registration gdb_command_handlers[] = {
                        "to be used by gdb 'break' commands.",
                .usage = "('hard'|'soft'|'disable')"
        },
+       {
+               .name = "gdb_target_description",
+               .handler = handle_gdb_target_description_command,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable target description",
+               .usage = "('enable'|'disable')"
+       },
+       {
+               .name = "gdb_save_tdesc",
+               .handler = handle_gdb_save_tdesc_command,
+               .mode = COMMAND_EXEC,
+               .help = "Save the target description file",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
 int gdb_register_commands(struct command_context *cmd_ctx)
 {
+       gdb_port = strdup("3333");
+       gdb_port_next = strdup("3333");
        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)