]> git.sur5r.net Git - openocd/blobdiff - src/server/gdb_server.c
server: gdb: always print target information in multi-target setups
[openocd] / src / server / gdb_server.c
index 97cf26f2f25cc0e55c265991ff9be7113615da5f..fc0868b0a3d56d7ae1c27db014fb68c15d904186 100644 (file)
@@ -31,9 +31,7 @@
  *   GNU General Public License for more details.                          *
  *                                                                         *
  *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -73,8 +71,8 @@ struct gdb_connection {
        int ctrl_c;
        enum target_state frontend_state;
        struct image *vflash_image;
-       int closed;
-       int busy;
+       bool closed;
+       bool busy;
        int noack_mode;
        /* 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
@@ -92,6 +90,8 @@ struct gdb_connection {
        bool attached;
        /* temporarily used for target description support */
        struct target_desc_format target_desc;
+       /* temporarily used for thread list support */
+       char *thread_list;
 };
 
 #if 0
@@ -104,8 +104,8 @@ static int gdb_breakpoint_override;
 static enum breakpoint_type gdb_breakpoint_override_type;
 
 static int gdb_error(struct connection *connection, int retval);
-static const char *gdb_port;
-static const char *gdb_port_next;
+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);
@@ -215,7 +215,7 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char)
                if (gdb_con->buf_cnt > 0)
                        break;
                if (gdb_con->buf_cnt == 0) {
-                       gdb_con->closed = 1;
+                       gdb_con->closed = true;
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
 
@@ -227,10 +227,10 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char)
                                usleep(1000);
                                break;
                        case WSAECONNABORTED:
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        case WSAECONNRESET:
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        default:
                                LOG_ERROR("read: %d", errno);
@@ -242,14 +242,14 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char)
                                usleep(1000);
                                break;
                        case ECONNABORTED:
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        case ECONNRESET:
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        default:
                                LOG_ERROR("read: %s", strerror(errno));
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                }
 #endif
@@ -341,7 +341,7 @@ static int gdb_write(struct connection *connection, void *data, int len)
 
        if (connection_write(connection, data, len) == len)
                return ERROR_OK;
-       gdb_con->closed = 1;
+       gdb_con->closed = true;
        return ERROR_SERVER_REMOTE_CLOSED;
 }
 
@@ -448,7 +448,7 @@ static int gdb_put_packet_inner(struct connection *connection,
                                return ERROR_OK;
                        } else {
                                LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply);
-                               gdb_con->closed = 1;
+                               gdb_con->closed = true;
                                return ERROR_SERVER_REMOTE_CLOSED;
                        }
                } else if (reply == '$') {
@@ -458,7 +458,7 @@ static int gdb_put_packet_inner(struct connection *connection,
                } else {
                        LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection",
                                reply);
-                       gdb_con->closed = 1;
+                       gdb_con->closed = true;
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
        }
@@ -471,9 +471,9 @@ static int gdb_put_packet_inner(struct connection *connection,
 int gdb_put_packet(struct connection *connection, char *buffer, int len)
 {
        struct gdb_connection *gdb_con = connection->priv;
-       gdb_con->busy = 1;
+       gdb_con->busy = true;
        int retval = gdb_put_packet_inner(connection, buffer, len);
-       gdb_con->busy = 0;
+       gdb_con->busy = false;
 
        /* we sent some data, reset timer for keep alive messages */
        kept_alive();
@@ -617,11 +617,21 @@ static int gdb_get_packet_inner(struct connection *connection,
                                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 if (gdb_con->noack_mode) {
+                                               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");
@@ -669,9 +679,9 @@ static int gdb_get_packet_inner(struct connection *connection,
 static int gdb_get_packet(struct connection *connection, char *buffer, int *len)
 {
        struct gdb_connection *gdb_con = connection->priv;
-       gdb_con->busy = 1;
+       gdb_con->busy = true;
        int retval = gdb_get_packet_inner(connection, buffer, len);
-       gdb_con->busy = 0;
+       gdb_con->busy = false;
        return retval;
 }
 
@@ -687,7 +697,8 @@ static int gdb_output_con(struct connection *connection, const char *line)
                return ERROR_GDB_BUFFER_TOO_SMALL;
 
        hex_buffer[0] = 'O';
-       int pkt_len = hexify(hex_buffer + 1, line, bin_size, bin_size * 2 + 1);
+       size_t pkt_len = hexify(hex_buffer + 1, (const uint8_t *)line, bin_size,
+               bin_size * 2 + 1);
        int retval = gdb_put_packet(connection, hex_buffer, pkt_len + 1);
 
        free(hex_buffer);
@@ -704,11 +715,14 @@ static int gdb_output(struct command_context *context, const char *line)
 static void gdb_signal_reply(struct target *target, struct connection *connection)
 {
        struct gdb_connection *gdb_connection = connection->priv;
-       char sig_reply[20];
+       char sig_reply[45];
        char stop_reason[20];
+       char current_thread[25];
        int sig_reply_len;
        int signal_var;
 
+       rtos_update_threads(target);
+
        if (target->debug_reason == DBG_REASON_EXIT) {
                sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00");
        } else {
@@ -721,22 +735,22 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
                stop_reason[0] = '\0';
                if (target->debug_reason == DBG_REASON_WATCHPOINT) {
                        enum watchpoint_rw hit_wp_type;
-                       uint32_t hit_wp_address;
+                       target_addr_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:%08x;", hit_wp_address);
+                                                               "watch:%08" TARGET_PRIxADDR ";", hit_wp_address);
                                                break;
                                        case WPT_READ:
                                                snprintf(stop_reason, sizeof(stop_reason),
-                                                               "rwatch:%08x;", hit_wp_address);
+                                                               "rwatch:%08" TARGET_PRIxADDR ";", hit_wp_address);
                                                break;
                                        case WPT_ACCESS:
                                                snprintf(stop_reason, sizeof(stop_reason),
-                                                               "awatch:%08x;", hit_wp_address);
+                                                               "awatch:%08" TARGET_PRIxADDR ";", hit_wp_address);
                                                break;
                                        default:
                                                break;
@@ -744,13 +758,18 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
                        }
                }
 
-               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s",
-                               signal_var, stop_reason);
+               current_thread[0] = '\0';
+               if (target->rtos != NULL) {
+                       snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", target->rtos->current_thread);
+                       target->rtos->current_threadid = target->rtos->current_thread;
+               }
+
+               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s",
+                               signal_var, stop_reason, current_thread);
        }
 
        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)
@@ -761,64 +780,64 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
        bool program_exited = false;
 
        if (strcmp(target->fileio_info->identifier, "open") == 0)
-               sprintf(fileio_command, "F%s,%x/%x,%x,%x", target->fileio_info->identifier,
+               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,%x", target->fileio_info->identifier,
+               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,%x,%x,%x", target->fileio_info->identifier,
+               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,%x,%x,%x", target->fileio_info->identifier,
+               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,%x,%x,%x", target->fileio_info->identifier,
+               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,%x/%x,%x/%x", target->fileio_info->identifier,
+               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,%x/%x", target->fileio_info->identifier,
+               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,%x/%x,%x", target->fileio_info->identifier,
+               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,%x,%x", target->fileio_info->identifier,
+               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,%x,%x", target->fileio_info->identifier,
+               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,%x", target->fileio_info->identifier,
+               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,%x/%x", target->fileio_info->identifier,
+               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%02x", target->fileio_info->param_1);
+               sprintf(fileio_command, "W%02" PRIx32, target->fileio_info->param_1);
        } else {
                LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier);
 
@@ -898,10 +917,11 @@ static int gdb_target_callback_event_handler(struct target *target,
 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;
+       struct target *target;
        int retval;
        int initial_ack;
 
+       target = get_target_from_connection(connection);
        connection->priv = gdb_connection;
 
        /* initialize gdb connection information */
@@ -910,14 +930,15 @@ static int gdb_new_connection(struct connection *connection)
        gdb_connection->ctrl_c = 0;
        gdb_connection->frontend_state = TARGET_HALTED;
        gdb_connection->vflash_image = NULL;
-       gdb_connection->closed = 0;
-       gdb_connection->busy = 0;
+       gdb_connection->closed = false;
+       gdb_connection->busy = false;
        gdb_connection->noack_mode = 0;
        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;
+       gdb_connection->thread_list = NULL;
 
        /* send ACK to GDB for debug request */
        gdb_write(connection, "+", 1);
@@ -929,12 +950,12 @@ static int gdb_new_connection(struct connection *connection)
         * GDB session could leave dangling breakpoints if e.g. communication
         * timed out.
         */
-       breakpoint_clear_target(gdb_service->target);
-       watchpoint_clear_target(gdb_service->target);
+       breakpoint_clear_target(target);
+       watchpoint_clear_target(target);
 
        /* 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);
+       if ((target->rtos) && (target->rtos->type->clean))
+               target->rtos->type->clean(target);
 
        /* remove the initial ACK from the incoming buffer */
        retval = gdb_get_char(connection, &initial_ack);
@@ -946,7 +967,7 @@ static int gdb_new_connection(struct connection *connection)
         */
        if (initial_ack != '+')
                gdb_putback_char(connection, initial_ack);
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH);
+       target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH);
 
        if (gdb_use_memory_map) {
                /* Connect must fail if the memory map can't be set up correctly.
@@ -957,6 +978,9 @@ static int gdb_new_connection(struct connection *connection)
                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 != 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 " \
@@ -967,10 +991,12 @@ static int gdb_new_connection(struct connection *connection)
        }
 
        gdb_actual_connections++;
-       LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s",
+       log_printf_lf(all_targets->next != NULL ? LOG_LVL_INFO : LOG_LVL_DEBUG,
+                       __FILE__, __LINE__, __func__,
+                       "New GDB Connection: %d, Target %s, state: %s",
                        gdb_actual_connections,
-                       target_name(gdb_service->target),
-                       target_state_name(gdb_service->target));
+                       target_name(target),
+                       target_state_name(target));
 
        /* DANGER! If we fail subsequently, we must remove this handler,
         * otherwise we occasionally see crashes as the timer can invoke the
@@ -984,9 +1010,11 @@ static int gdb_new_connection(struct connection *connection)
 
 static int gdb_connection_closed(struct connection *connection)
 {
-       struct gdb_service *gdb_service = connection->service->priv;
+       struct target *target;
        struct gdb_connection *gdb_connection = connection->priv;
 
+       target = get_target_from_connection(connection);
+
        /* we're done forwarding messages. Tear down callback before
         * cleaning up connection.
         */
@@ -994,8 +1022,8 @@ static 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),
+               target_name(target),
+               target_state_name(target),
                gdb_actual_connections);
 
        /* see if an image built with vFlash commands is left */
@@ -1006,7 +1034,7 @@ static 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);
+       delete_debug_msg_receiver(connection->cmd_ctx, target);
 
        if (connection->priv) {
                free(connection->priv);
@@ -1016,9 +1044,9 @@ static int gdb_connection_closed(struct connection *connection)
 
        target_unregister_event_callback(gdb_target_callback_event_handler, connection);
 
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_END);
+       target_call_event_callbacks(target, TARGET_EVENT_GDB_END);
 
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH);
+       target_call_event_callbacks(target, TARGET_EVENT_GDB_DETACH);
 
        return ERROR_OK;
 }
@@ -1031,7 +1059,7 @@ static void gdb_send_error(struct connection *connection, uint8_t the_error)
 }
 
 static int gdb_last_signal_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        struct gdb_connection *gdb_con = connection->priv;
@@ -1088,7 +1116,7 @@ static void gdb_str_to_target(struct target *target,
 
 /* copy over in register buffer */
 static void gdb_target_to_reg(struct target *target,
-               char *tstr, int str_len, uint8_t *bin)
+               char const *tstr, int str_len, uint8_t *bin)
 {
        if (str_len % 2) {
                LOG_ERROR("BUG: gdb value with uneven number of characters encountered");
@@ -1109,7 +1137,7 @@ static void gdb_target_to_reg(struct target *target,
 }
 
 static int gdb_get_registers_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        struct reg **reg_list;
@@ -1138,6 +1166,9 @@ static int gdb_get_registers_packet(struct connection *connection,
        assert(reg_packet_size > 0);
 
        reg_packet = malloc(reg_packet_size + 1); /* plus one for string termination null */
+       if (reg_packet == NULL)
+               return ERROR_FAIL;
+
        reg_packet_p = reg_packet;
 
        for (i = 0; i < reg_list_size; i++) {
@@ -1165,14 +1196,14 @@ static int gdb_get_registers_packet(struct connection *connection,
 }
 
 static int gdb_set_registers_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        int i;
        struct reg **reg_list;
        int reg_list_size;
        int retval;
-       char *packet_p;
+       char const *packet_p;
 
 #ifdef _DEBUG_GDB_IO_
        LOG_DEBUG("-");
@@ -1220,7 +1251,7 @@ static int gdb_set_registers_packet(struct connection *connection,
 }
 
 static int gdb_get_register_packet(struct connection *connection,
-       char *packet, int packet_size)
+       char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *reg_packet;
@@ -1259,7 +1290,7 @@ static int gdb_get_register_packet(struct connection *connection,
 }
 
 static int gdb_set_register_packet(struct connection *connection,
-       char *packet, int packet_size)
+       char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
@@ -1325,11 +1356,11 @@ static int gdb_error(struct connection *connection, int retval)
  * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????
  */
 static int gdb_read_memory_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
-       uint32_t addr = 0;
+       uint64_t addr = 0;
        uint32_t len = 0;
 
        uint8_t *buffer;
@@ -1340,7 +1371,7 @@ static int gdb_read_memory_packet(struct connection *connection,
        /* skip command character */
        packet++;
 
-       addr = strtoul(packet, &separator, 16);
+       addr = strtoull(packet, &separator, 16);
 
        if (*separator != ',') {
                LOG_ERROR("incomplete read memory packet received, dropping connection");
@@ -1349,9 +1380,15 @@ static int gdb_read_memory_packet(struct connection *connection,
 
        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);
+       LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
 
        retval = target_read_buffer(target, addr, len, buffer);
 
@@ -1376,7 +1413,7 @@ static int gdb_read_memory_packet(struct connection *connection,
        if (retval == ERROR_OK) {
                hex_buffer = malloc(len * 2 + 1);
 
-               int pkt_len = hexify(hex_buffer, (char *)buffer, len, len * 2 + 1);
+               size_t pkt_len = hexify(hex_buffer, buffer, len, len * 2 + 1);
 
                gdb_put_packet(connection, hex_buffer, pkt_len);
 
@@ -1390,11 +1427,11 @@ static int gdb_read_memory_packet(struct connection *connection,
 }
 
 static int gdb_write_memory_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
-       uint32_t addr = 0;
+       uint64_t addr = 0;
        uint32_t len = 0;
 
        uint8_t *buffer;
@@ -1403,7 +1440,7 @@ static int gdb_write_memory_packet(struct connection *connection,
        /* skip command character */
        packet++;
 
-       addr = strtoul(packet, &separator, 16);
+       addr = strtoull(packet, &separator, 16);
 
        if (*separator != ',') {
                LOG_ERROR("incomplete write memory packet received, dropping connection");
@@ -1419,9 +1456,9 @@ static int gdb_write_memory_packet(struct connection *connection,
 
        buffer = malloc(len);
 
-       LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
+       LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len);
 
-       if (unhexify((char *)buffer, separator, len) != (int)len)
+       if (unhexify(buffer, separator, len) != len)
                LOG_ERROR("unable to decode memory packet");
 
        retval = target_write_buffer(target, addr, len, buffer);
@@ -1437,19 +1474,23 @@ static int gdb_write_memory_packet(struct connection *connection,
 }
 
 static int gdb_write_memory_binary_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
-       uint32_t addr = 0;
+       uint64_t addr = 0;
        uint32_t len = 0;
 
        int retval = ERROR_OK;
+       /* Packets larger than fast_limit bytes will be acknowledged instantly on
+        * the assumption that we're in a download and it's important to go as fast
+        * as possible. */
+       uint32_t fast_limit = 8;
 
        /* skip command character */
        packet++;
 
-       addr = strtoul(packet, &separator, 16);
+       addr = strtoull(packet, &separator, 16);
 
        if (*separator != ',') {
                LOG_ERROR("incomplete write memory binary packet received, dropping connection");
@@ -1465,48 +1506,60 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
 
        struct gdb_connection *gdb_connection = connection->priv;
 
-       if (gdb_connection->mem_write_error) {
+       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 == ERROR_OK) {
+               if (len >= fast_limit) {
+                       /* By replying the packet *immediately* GDB will send us a new packet
+                        * while we write the last one to the target.
+                        * We only do this for larger writes, so that users who do something like:
+                        * p *((int*)0xdeadbeef)=8675309
+                        * will get immediate feedback that that write failed.
+                        */
+                       gdb_put_packet(connection, "OK", 2);
+               }
+       } else {
                retval = gdb_error(connection, retval);
+               /* now that we have reported the memory write error, we can clear the condition */
+               gdb_connection->mem_write_error = false;
                if (retval != ERROR_OK)
                        return retval;
        }
 
        if (len) {
-               LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
+               LOG_DEBUG("addr: 0x%" PRIx64 ", 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;
        }
 
+       if (len < fast_limit) {
+               if (retval != ERROR_OK) {
+                       gdb_error(connection, retval);
+                       gdb_connection->mem_write_error = false;
+               } else {
+                       gdb_put_packet(connection, "OK", 2);
+               }
+       }
+
        return ERROR_OK;
 }
 
 static int gdb_step_continue_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        int current = 0;
-       uint32_t address = 0x0;
+       uint64_t address = 0x0;
        int retval = ERROR_OK;
 
        LOG_DEBUG("-");
 
-       if (packet_size > 1) {
-               packet[packet_size] = 0;
-               address = strtoul(packet + 1, NULL, 16);
-       } else
+       if (packet_size > 1)
+               address = strtoull(packet + 1, NULL, 16);
+       else
                current = 1;
 
        gdb_running_type = packet[0];
@@ -1523,13 +1576,13 @@ static int gdb_step_continue_packet(struct connection *connection,
 }
 
 static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *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 */;
-       uint32_t address;
+       uint64_t address;
        uint32_t size;
        char *separator;
        int retval;
@@ -1561,7 +1614,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       address = strtoul(separator + 1, &separator, 16);
+       address = strtoull(separator + 1, &separator, 16);
 
        if (*separator != ',') {
                LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection");
@@ -1651,29 +1704,31 @@ static void xml_printf(int *retval, char **xml, int *pos, int *size,
        }
 }
 
-static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len)
+static int decode_xfer_read(char const *buf, char **annex, int *ofs, unsigned int *len)
 {
-       char *separator;
-
-       /* Extract and NUL-terminate the annex. */
-       *annex = buf;
-       while (*buf && *buf != ':')
-               buf++;
-       if (*buf == '\0')
-               return -1;
-       *buf++ = 0;
+       /* Locate the annex. */
+       const char *annex_end = strchr(buf, ':');
+       if (annex_end == NULL)
+               return ERROR_FAIL;
 
        /* After the read marker and annex, qXfer looks like a
         * traditional 'm' packet. */
-
-       *ofs = strtoul(buf, &separator, 16);
+       char *separator;
+       *ofs = strtoul(annex_end + 1, &separator, 16);
 
        if (*separator != ',')
-               return -1;
+               return ERROR_FAIL;
 
        *len = strtoul(separator + 1, NULL, 16);
 
-       return 0;
+       /* Extract the annex if needed */
+       if (annex != NULL) {
+               *annex = strndup(buf, annex_end - buf);
+               if (*annex == NULL)
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
 }
 
 static int compare_bank(const void *a, const void *b)
@@ -1691,7 +1746,7 @@ static int compare_bank(const void *a, const void *b)
 }
 
 static int gdb_memory_map(struct connection *connection,
-               char *packet, int packet_size)
+               char const *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
@@ -1732,14 +1787,16 @@ static int gdb_memory_map(struct connection *connection,
        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;
                }
-               if (p->target == target)
-                       banks[target_flash_banks++] = p;
+               banks[target_flash_banks++] = p;
        }
 
        qsort(banks, target_flash_banks, sizeof(struct flash_bank *),
@@ -1976,7 +2033,7 @@ static int gdb_generate_reg_type_description(struct target *target,
 /* 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,
+static int get_reg_features_list(struct target *target, char const **feature_list[], int *feature_list_size,
                struct reg **reg_list, int reg_list_size)
 {
        int tbl_sz = 0;
@@ -1988,7 +2045,8 @@ static int get_reg_features_list(struct target *target, char **feature_list[], i
                if (reg_list[i]->exist == false)
                        continue;
 
-               if ((reg_list[i]->feature->name != NULL)
+               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
@@ -1996,7 +2054,7 @@ static int get_reg_features_list(struct target *target, char **feature_list[], i
                         */
                        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)[tbl_sz++] = reg_list[i]->feature->name;
                                        *feature_list = realloc(*feature_list, sizeof(char *) * (tbl_sz + 1));
                                        (*feature_list)[tbl_sz] = NULL;
                                        break;
@@ -2014,46 +2072,53 @@ static int get_reg_features_list(struct target *target, char **feature_list[], i
        return ERROR_OK;
 }
 
-static int gdb_generate_target_description(struct target *target, char **tdesc)
+static int gdb_generate_target_description(struct target *target, char **tdesc_out)
 {
        int retval = ERROR_OK;
-       struct reg **reg_list;
+       struct reg **reg_list = NULL;
        int reg_list_size;
+       char const **features = NULL;
+       int feature_list_size = 0;
+       char *tdesc = NULL;
        int pos = 0;
        int size = 0;
 
-       xml_printf(&retval, tdesc, &pos, &size,
-                       "<?xml version=\"1.0\"?>\n"
-                       "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n"
-                       "<target version=\"1.0\">\n");
-
        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;
+               retval = ERROR_FAIL;
+               goto error;
        }
 
-       if (reg_list_size <= 0)
-               return ERROR_FAIL;
+       if (reg_list_size <= 0) {
+               LOG_ERROR("get register list failed");
+               retval = ERROR_FAIL;
+               goto error;
+       }
 
-       char **features = NULL;
        /* Get a list of available target registers features */
-       retval = get_reg_features_list(target, &features, NULL, reg_list, reg_list_size);
+       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");
-               return ERROR_FAIL;
+               retval = ERROR_FAIL;
+               goto error;
        }
 
        /* 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,
+                       xml_printf(&retval, &tdesc, &pos, &size,
                                        "<feature name=\"%s\">\n",
                                        features[current_feature]);
 
@@ -2070,7 +2135,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc)
                                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,
+                                               gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
                                                                reg_list[i]->reg_data_type);
 
                                                type_str = reg_list[i]->reg_data_type->id;
@@ -2084,47 +2149,50 @@ static int gdb_generate_target_description(struct target *target, char **tdesc)
                                        type_str = "int";
                                }
 
-                               xml_printf(&retval, tdesc, &pos, &size,
+                               xml_printf(&retval, &tdesc, &pos, &size,
                                                "<reg name=\"%s\"", reg_list[i]->name);
-                               xml_printf(&retval, tdesc, &pos, &size,
+                               xml_printf(&retval, &tdesc, &pos, &size,
                                                " bitsize=\"%d\"", reg_list[i]->size);
-                               xml_printf(&retval, tdesc, &pos, &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,
+                                       xml_printf(&retval, &tdesc, &pos, &size,
                                                        " save-restore=\"yes\"");
                                else
-                                       xml_printf(&retval, tdesc, &pos, &size,
+                                       xml_printf(&retval, &tdesc, &pos, &size,
                                                        " save-restore=\"no\"");
 
-                               xml_printf(&retval, tdesc, &pos, &size,
+                               xml_printf(&retval, &tdesc, &pos, &size,
                                                " type=\"%s\"", type_str);
 
                                if (reg_list[i]->group != NULL)
-                                       xml_printf(&retval, tdesc, &pos, &size,
+                                       xml_printf(&retval, &tdesc, &pos, &size,
                                                        " group=\"%s\"", reg_list[i]->group);
 
-                               xml_printf(&retval, tdesc, &pos, &size,
+                               xml_printf(&retval, &tdesc, &pos, &size,
                                                "/>\n");
                        }
 
-                       xml_printf(&retval, tdesc, &pos, &size,
+                       xml_printf(&retval, &tdesc, &pos, &size,
                                        "</feature>\n");
 
                        current_feature++;
                }
        }
 
-       xml_printf(&retval, tdesc, &pos, &size,
+       xml_printf(&retval, &tdesc, &pos, &size,
                        "</target>\n");
 
-       if (reg_list != NULL)
-               free(reg_list);
+error:
+       free(features);
+       free(reg_list);
 
-       if (features != NULL)
-               free(features);
+       if (retval == ERROR_OK)
+               *tdesc_out = tdesc;
+       else
+               free(tdesc);
 
-       return ERROR_OK;
+       return retval;
 }
 
 static int gdb_get_target_description_chunk(struct target *target, struct target_desc_format *target_desc,
@@ -2186,6 +2254,7 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        int retval = ERROR_OK;
        struct reg **reg_list = NULL;
        int reg_list_size = 0;
+       char const **features = NULL;
        int feature_list_size = 0;
 
        retval = target_get_gdb_reg_list(target, &reg_list,
@@ -2196,11 +2265,11 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        }
 
        if (reg_list_size <= 0) {
+               LOG_ERROR("get register list failed");
                retval = ERROR_FAIL;
                goto error;
        }
 
-       char **features = NULL;
        /* 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) {
@@ -2216,17 +2285,104 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        }
 
 error:
-       if (reg_list != NULL)
-               free(reg_list);
+       free(features);
+
+       free(reg_list);
+
+       return retval;
+}
+
+static int gdb_generate_thread_list(struct target *target, char **thread_list_out)
+{
+       struct rtos *rtos = target->rtos;
+       int retval = ERROR_OK;
+       char *thread_list = NULL;
+       int pos = 0;
+       int size = 0;
 
-       if (features != NULL)
-               free(features);
+       xml_printf(&retval, &thread_list, &pos, &size,
+                  "<?xml version=\"1.0\"?>\n"
+                  "<threads>\n");
+
+       if (rtos != NULL) {
+               for (int i = 0; i < rtos->thread_count; i++) {
+                       struct thread_detail *thread_detail = &rtos->thread_details[i];
+
+                       if (!thread_detail->exists)
+                               continue;
+
+                       xml_printf(&retval, &thread_list, &pos, &size,
+                                  "<thread id=\"%" PRIx64 "\">", thread_detail->threadid);
+
+                       if (thread_detail->thread_name_str != NULL)
+                               xml_printf(&retval, &thread_list, &pos, &size,
+                                          "Name: %s", thread_detail->thread_name_str);
+
+                       if (thread_detail->extra_info_str != NULL) {
+                               if (thread_detail->thread_name_str != NULL)
+                                       xml_printf(&retval, &thread_list, &pos, &size,
+                                                  ", ");
+                               xml_printf(&retval, &thread_list, &pos, &size,
+                                          thread_detail->extra_info_str);
+                       }
+
+                       xml_printf(&retval, &thread_list, &pos, &size,
+                                  "</thread>\n");
+               }
+       }
+
+       xml_printf(&retval, &thread_list, &pos, &size,
+                  "</threads>\n");
+
+       if (retval == ERROR_OK)
+               *thread_list_out = thread_list;
+       else
+               free(thread_list);
 
        return retval;
 }
 
+static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
+               char **chunk, int32_t offset, uint32_t length)
+{
+       if (*thread_list == NULL) {
+               int retval = gdb_generate_thread_list(target, thread_list);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Unable to Generate Thread List");
+                       return ERROR_FAIL;
+               }
+       }
+
+       size_t thread_list_length = strlen(*thread_list);
+       char transfer_type;
+
+       length = MIN(length, thread_list_length - offset);
+       if (length < (thread_list_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;
+       strncpy((*chunk) + 1, (*thread_list) + offset, length);
+       (*chunk)[1 + length] = '\0';
+
+       /* After gdb-server sends out last chunk, invalidate thread list. */
+       if (transfer_type == 'l') {
+               free(*thread_list);
+               *thread_list = NULL;
+       }
+
+       return ERROR_OK;
+}
+
 static int gdb_query_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct command_context *cmd_ctx = connection->cmd_ctx;
        struct gdb_connection *gdb_connection = connection->priv;
@@ -2236,7 +2392,7 @@ static int gdb_query_packet(struct connection *connection,
                if (packet_size > 6) {
                        char *cmd;
                        cmd = malloc((packet_size - 6) / 2 + 1);
-                       int len = unhexify(cmd, packet + 6, (packet_size - 6) / 2);
+                       size_t len = unhexify((uint8_t *)cmd, packet + 6, (packet_size - 6) / 2);
                        cmd[len] = 0;
 
                        /* We want to print all debug output to GDB connection */
@@ -2314,7 +2470,7 @@ static int gdb_query_packet(struct connection *connection,
                        &buffer,
                        &pos,
                        &size,
-                       "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;QStartNoAckMode+",
+                       "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+",
                        (GDB_BUFFER_SIZE - 1),
                        ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-',
                        (gdb_target_desc_supported == 1) ? '+' : '-');
@@ -2337,12 +2493,11 @@ static int gdb_query_packet(struct connection *connection,
 
                int offset;
                unsigned int length;
-               char *annex;
 
                /* skip command character */
                packet += 20;
 
-               if (decode_xfer_read(packet, &annex, &offset, &length) < 0) {
+               if (decode_xfer_read(packet, NULL, &offset, &length) < 0) {
                        gdb_send_error(connection, 01);
                        return ERROR_OK;
                }
@@ -2361,6 +2516,37 @@ static int gdb_query_packet(struct connection *connection,
 
                gdb_put_packet(connection, xml, strlen(xml));
 
+               free(xml);
+               return ERROR_OK;
+       } else if (strncmp(packet, "qXfer:threads:read:", 19) == 0) {
+               char *xml = NULL;
+               int retval = ERROR_OK;
+
+               int offset;
+               unsigned int length;
+
+               /* skip command character */
+               packet += 19;
+
+               if (decode_xfer_read(packet, NULL, &offset, &length) < 0) {
+                       gdb_send_error(connection, 01);
+                       return ERROR_OK;
+               }
+
+               /* Target should prepare correct thread list 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_thread_list_chunk(target, &gdb_connection->thread_list,
+                                                  &xml, offset, length);
+               if (retval != ERROR_OK) {
+                       gdb_error(connection, retval);
+                       return retval;
+               }
+
+               gdb_put_packet(connection, xml, strlen(xml));
+
                free(xml);
                return ERROR_OK;
        } else if (strncmp(packet, "QStartNoAckMode", 15) == 0) {
@@ -2374,12 +2560,14 @@ static int gdb_query_packet(struct connection *connection,
 }
 
 static int gdb_v_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct gdb_connection *gdb_connection = connection->priv;
-       struct gdb_service *gdb_service = connection->service->priv;
+       struct target *target;
        int result;
 
+       target = get_target_from_connection(connection);
+
        /* if flash programming disabled - send a empty reply */
 
        if (gdb_flash_program == 0) {
@@ -2391,20 +2579,20 @@ static int gdb_v_packet(struct connection *connection,
                unsigned long addr;
                unsigned long length;
 
-               char *parse = packet + 12;
+               char const *parse = packet + 12;
                if (*parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
 
-               addr = strtoul(parse, &parse, 16);
+               addr = strtoul(parse, (char **)&parse, 16);
 
                if (*(parse++) != ',' || *parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
 
-               length = strtoul(parse, &parse, 16);
+               length = strtoul(parse, (char **)&parse, 16);
 
                if (*parse != '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
@@ -2416,18 +2604,18 @@ static int gdb_v_packet(struct connection *connection,
                flash_set_dirty();
 
                /* perform any target specific operations before the erase */
-               target_call_event_callbacks(gdb_service->target,
+               target_call_event_callbacks(target,
                        TARGET_EVENT_GDB_FLASH_ERASE_START);
 
                /* vFlashErase:addr,length messages require region start and
                 * end to be "block" aligned ... if padding is ever needed,
                 * GDB will have become dangerously confused.
                 */
-               result = flash_erase_address_range(gdb_service->target,
-                               false, addr, length);
+               result = flash_erase_address_range(target, false, addr,
+                       length);
 
                /* perform any target specific operations after the erase */
-               target_call_event_callbacks(gdb_service->target,
+               target_call_event_callbacks(target,
                        TARGET_EVENT_GDB_FLASH_ERASE_END);
 
                /* perform erase */
@@ -2447,13 +2635,13 @@ static int gdb_v_packet(struct connection *connection,
                int retval;
                unsigned long addr;
                unsigned long length;
-               char *parse = packet + 12;
+               char const *parse = packet + 12;
 
                if (*parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
-               addr = strtoul(parse, &parse, 16);
+               addr = strtoul(parse, (char **)&parse, 16);
                if (*(parse++) != ':') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
@@ -2468,7 +2656,7 @@ static int gdb_v_packet(struct connection *connection,
 
                /* create new section with content from packet buffer */
                retval = image_add_section(gdb_connection->vflash_image,
-                               addr, length, 0x0, (uint8_t *)parse);
+                               addr, length, 0x0, (uint8_t const *)parse);
                if (retval != ERROR_OK)
                        return retval;
 
@@ -2482,10 +2670,12 @@ static int gdb_v_packet(struct connection *connection,
 
                /* process the flashing buffer. No need to erase as GDB
                 * always issues a vFlashErase first. */
-               target_call_event_callbacks(gdb_service->target,
+               target_call_event_callbacks(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);
+               result = flash_write(target, gdb_connection->vflash_image,
+                       &written, 0);
+               target_call_event_callbacks(target,
+                       TARGET_EVENT_GDB_FLASH_WRITE_END);
                if (result != ERROR_OK) {
                        if (result == ERROR_FLASH_DST_OUT_OF_BANK)
                                gdb_put_packet(connection, "E.memtype", 9);
@@ -2509,9 +2699,8 @@ static int gdb_v_packet(struct connection *connection,
 
 static int gdb_detach(struct connection *connection)
 {
-       struct gdb_service *gdb_service = connection->service->priv;
-
-       target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH);
+       target_call_event_callbacks(get_target_from_connection(connection),
+               TARGET_EVENT_GDB_DETACH);
 
        return gdb_put_packet(connection, "OK", 2);
 }
@@ -2520,7 +2709,7 @@ static int gdb_detach(struct connection *connection)
  * Fretcode,errno,Ctrl-C flag;call-specific attachment
  */
 static int gdb_fileio_response_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
@@ -2590,14 +2779,15 @@ 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;
+       struct target *target;
+       char const *packet = gdb_packet_buffer;
        int packet_size;
        int retval;
        struct gdb_connection *gdb_con = connection->priv;
        static int extended_protocol;
 
+       target = get_target_from_connection(connection);
+
        /* drain input buffer. If one of the packets fail, then an error
         * packet is replied, if applicable.
         *
@@ -2611,12 +2801,12 @@ static int gdb_input_inner(struct connection *connection)
         */
        do {
                packet_size = GDB_BUFFER_SIZE-1;
-               retval = gdb_get_packet(connection, packet, &packet_size);
+               retval = gdb_get_packet(connection, gdb_packet_buffer, &packet_size);
                if (retval != ERROR_OK)
                        return retval;
 
                /* terminate with zero */
-               packet[packet_size] = 0;
+               gdb_packet_buffer[packet_size] = '\0';
 
                if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) {
                        if (packet[0] == 'X') {
@@ -2767,8 +2957,8 @@ static int gdb_input_inner(struct connection *connection)
                                        break;
                                case 'R':
                                        /* handle extended restart packet */
-                                       breakpoint_clear_target(gdb_service->target);
-                                       watchpoint_clear_target(gdb_service->target);
+                                       breakpoint_clear_target(target);
+                                       watchpoint_clear_target(target);
                                        command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s",
                                                        target_name(target));
                                        /* set connection as attached after reset */
@@ -2881,6 +3071,11 @@ static int gdb_target_start(struct target *target, const char *port)
 
 static int gdb_target_add_one(struct target *target)
 {
+       if (strcmp(gdb_port, "disabled") == 0) {
+               LOG_INFO("gdb port disabled");
+               return ERROR_OK;
+       }
+
        /*  one gdb instance per smp list */
        if ((target->smp) && (target->gdb_service))
                return ERROR_OK;
@@ -2894,7 +3089,7 @@ static int gdb_target_add_one(struct target *target)
                portnumber = strtol(gdb_port_next, &end, 0);
                if (!*end) {
                        if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) {
-                               free((void *)gdb_port_next);
+                               free(gdb_port_next);
                                gdb_port_next = alloc_printf("%d", portnumber+1);
                        }
                }
@@ -2904,6 +3099,11 @@ static int gdb_target_add_one(struct target *target)
 
 int gdb_target_add_all(struct target *target)
 {
+       if (strcmp(gdb_port, "disabled") == 0) {
+               LOG_INFO("gdb server disabled");
+               return ERROR_OK;
+       }
+
        if (NULL == target) {
                LOG_WARNING("gdb services need one or more targets defined");
                return ERROR_OK;
@@ -2941,7 +3141,7 @@ COMMAND_HANDLER(handle_gdb_port_command)
 {
        int retval = CALL_COMMAND_HANDLER(server_pipe_command, &gdb_port);
        if (ERROR_OK == retval) {
-               free((void *)gdb_port_next);
+               free(gdb_port_next);
                gdb_port_next = strdup(gdb_port);
        }
        return retval;
@@ -3012,7 +3212,6 @@ COMMAND_HANDLER(handle_gdb_save_tdesc_command)
        char *tdesc;
        uint32_t tdesc_length;
        struct target *target = get_current_target(CMD_CTX);
-       char *tdesc_filename;
 
        int retval = gdb_generate_target_description(target, &tdesc);
        if (retval != ERROR_OK) {
@@ -3022,37 +3221,34 @@ COMMAND_HANDLER(handle_gdb_save_tdesc_command)
 
        tdesc_length = strlen(tdesc);
 
-       if (tdesc_length == 0) {
-               LOG_ERROR("Unable to Generate Target Description");
-               return ERROR_FAIL;
-       }
-
-       struct fileio fileio;
+       struct fileio *fileio;
        size_t size_written;
 
-       tdesc_filename = malloc(strlen(target_type_name(target)) + 5);
-       sprintf(tdesc_filename, "%s.xml", target_type_name(target));
+       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_WARNING("Can't open %s for writing", tdesc_filename);
-               free(tdesc_filename);
-               return ERROR_FAIL;
+               LOG_ERROR("Can't open %s for writing", tdesc_filename);
+               goto out;
        }
 
-       retval = fileio_write(&fileio, tdesc_length, tdesc, &size_written);
+       retval = fileio_write(fileio, tdesc_length, tdesc, &size_written);
+
+       fileio_close(fileio);
 
-       fileio_close(&fileio);
+       if (retval != ERROR_OK)
+               LOG_ERROR("Error while writing the tdesc file");
+
+out:
        free(tdesc_filename);
        free(tdesc);
 
-       if (retval != ERROR_OK) {
-               LOG_WARNING("Error while writing the tdesc file");
-               return ERROR_FAIL;
-       }
-
-       return ERROR_OK;
+       return retval;
 }
 
 static const struct command_registration gdb_command_handlers[] = {
@@ -3073,7 +3269,7 @@ static const struct command_registration gdb_command_handlers[] = {
                        "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 "
+                       "output to stdout, an integer is base port number, \"disabled\" 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]",