flash/nor: Use proper data types in driver API
[fw/openocd] / src / server / gdb_server.c
index 2acebe83968eb0d224b7e6273a30509d72724967..0e0b595c6982cccd1e20e9fe5e34a22709526715 100644 (file)
@@ -43,6 +43,7 @@
 #include <target/register.h>
 #include <target/target.h>
 #include <target/target_type.h>
+#include <target/semihosting_common.h>
 #include "server.h"
 #include <flash/nor/core.h>
 #include "gdb_server.h"
@@ -67,10 +68,10 @@ struct target_desc_format {
 
 /* private connection data for GDB */
 struct gdb_connection {
-       char buffer[GDB_BUFFER_SIZE];
+       char buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for nul-termination */
        char *buf_p;
        int buf_cnt;
-       int ctrl_c;
+       bool ctrl_c;
        enum target_state frontend_state;
        struct image *vflash_image;
        bool closed;
@@ -90,6 +91,8 @@ struct gdb_connection {
         * 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;
+       /* set when extended protocol is used */
+       bool extended_protocol;
        /* temporarily used for target description support */
        struct target_desc_format target_desc;
        /* temporarily used for thread list support */
@@ -130,6 +133,9 @@ static int gdb_flash_program = 1;
  * Disabled by default.
  */
 static int gdb_report_data_abort;
+/* If set, errors when accessing registers are reported to gdb. Disabled by
+ * default. */
+static int gdb_report_register_access_error;
 
 /* set if we are sending target descriptions to gdb
  * via qXfer:features:read packet */
@@ -150,6 +156,8 @@ static int gdb_last_signal(struct target *target)
                        return 0x05;    /* SIGTRAP */
                case DBG_REASON_SINGLESTEP:
                        return 0x05;    /* SIGTRAP */
+               case DBG_REASON_EXC_CATCH:
+                       return 0x05;
                case DBG_REASON_NOTHALTED:
                        return 0x0;             /* no signal... shouldn't happen */
                default:
@@ -269,9 +277,9 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char)
        gdb_con->buf_cnt--;
        *next_char = *(gdb_con->buf_p++);
        if (gdb_con->buf_cnt > 0)
-               connection->input_pending = 1;
+               connection->input_pending = true;
        else
-               connection->input_pending = 0;
+               connection->input_pending = false;
 #ifdef _DEBUG_GDB_IO_
        LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
 #endif
@@ -294,9 +302,9 @@ static inline int gdb_get_char_fast(struct connection *connection,
                *next_char = **buf_p;
                (*buf_p)++;
                if (*buf_cnt > 0)
-                       connection->input_pending = 1;
+                       connection->input_pending = true;
                else
-                       connection->input_pending = 0;
+                       connection->input_pending = false;
 
 #ifdef _DEBUG_GDB_IO_
                LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char);
@@ -436,7 +444,7 @@ static int gdb_put_packet_inner(struct connection *connection,
                        log_remove_callback(gdb_log_callback, connection);
                        LOG_WARNING("negative reply, retrying");
                } else if (reply == 0x3) {
-                       gdb_con->ctrl_c = 1;
+                       gdb_con->ctrl_c = true;
                        retval = gdb_get_char(connection, &reply);
                        if (retval != ERROR_OK)
                                return retval;
@@ -641,7 +649,7 @@ static int gdb_get_packet_inner(struct connection *connection,
                                        LOG_WARNING("negative acknowledgment, but no packet pending");
                                        break;
                                case 0x3:
-                                       gdb_con->ctrl_c = 1;
+                                       gdb_con->ctrl_c = true;
                                        *len = 0;
                                        return ERROR_OK;
                                default:
@@ -719,7 +727,7 @@ 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[45];
+       char sig_reply[65];
        char stop_reason[20];
        char current_thread[25];
        int sig_reply_len;
@@ -730,18 +738,25 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
        if (target->debug_reason == DBG_REASON_EXIT) {
                sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00");
        } else {
+               struct target *ct;
+               if (target->rtos != NULL) {
+                       target->rtos->current_threadid = target->rtos->current_thread;
+                       target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct);
+               } else {
+                       ct = target;
+               }
+
                if (gdb_connection->ctrl_c) {
                        signal_var = 0x2;
-                       gdb_connection->ctrl_c = 0;
                } else
-                       signal_var = gdb_last_signal(target);
+                       signal_var = gdb_last_signal(ct);
 
                stop_reason[0] = '\0';
-               if (target->debug_reason == DBG_REASON_WATCHPOINT) {
+               if (ct->debug_reason == DBG_REASON_WATCHPOINT) {
                        enum watchpoint_rw hit_wp_type;
                        target_addr_t hit_wp_address;
 
-                       if (watchpoint_hit(target, &hit_wp_type, &hit_wp_address) == ERROR_OK) {
+                       if (watchpoint_hit(ct, &hit_wp_type, &hit_wp_address) == ERROR_OK) {
 
                                switch (hit_wp_type) {
                                        case WPT_WRITE:
@@ -763,17 +778,14 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
                }
 
                current_thread[0] = '\0';
-               if (target->rtos != NULL) {
-                       struct target *ct;
-                       snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";",
+               if (target->rtos != NULL)
+                       snprintf(current_thread, sizeof(current_thread), "thread:%" PRIx64 ";",
                                        target->rtos->current_thread);
-                       target->rtos->current_threadid = target->rtos->current_thread;
-                       target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct);
-                       signal_var = gdb_last_signal(ct);
-               }
 
                sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s",
                                signal_var, stop_reason, current_thread);
+
+               gdb_connection->ctrl_c = false;
        }
 
        gdb_put_packet(connection, sig_reply, sig_reply_len);
@@ -788,64 +800,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,%" PRIx32 "/%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
                                target->fileio_info->param_1,
-                               target->fileio_info->param_2,
+                               target->fileio_info->param_2 + 1,       /* len + trailing zero */
                                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,
+               sprintf(fileio_command, "F%s,%" PRIx64, 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,
+               sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, 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,
+               sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, 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,
+               sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, 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,
+               sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
                                target->fileio_info->param_1,
-                               target->fileio_info->param_2,
+                               target->fileio_info->param_2 + 1,       /* len + trailing zero */
                                target->fileio_info->param_3,
-                               target->fileio_info->param_4);
+                               target->fileio_info->param_4 + 1);      /* len + trailing zero */
        else if (strcmp(target->fileio_info->identifier, "unlink") == 0)
-               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
                                target->fileio_info->param_1,
-                               target->fileio_info->param_2);
+                               target->fileio_info->param_2 + 1);      /* len + trailing zero */
        else if (strcmp(target->fileio_info->identifier, "stat") == 0)
-               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64, 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,
+               sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, 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,
+               sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, 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,
+               sprintf(fileio_command, "F%s,%" PRIx64, 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,
+               sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
                                target->fileio_info->param_1,
-                               target->fileio_info->param_2);
+                               target->fileio_info->param_2 + 1);      /* len + trailing zero */
        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);
+               sprintf(fileio_command, "W%02" PRIx64, target->fileio_info->param_1);
        } else {
                LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier);
 
@@ -896,7 +908,6 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec
 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;
 
@@ -910,11 +921,6 @@ static int gdb_target_callback_event_handler(struct target *target,
                case TARGET_EVENT_HALTED:
                        target_call_event_callbacks(target, TARGET_EVENT_GDB_END);
                        break;
-               case TARGET_EVENT_GDB_FLASH_ERASE_START:
-                       retval = jtag_execute_queue();
-                       if (retval != ERROR_OK)
-                               return retval;
-                       break;
                default:
                        break;
        }
@@ -931,11 +937,12 @@ static int gdb_new_connection(struct connection *connection)
 
        target = get_target_from_connection(connection);
        connection->priv = gdb_connection;
+       connection->cmd_ctx->current_target = target;
 
        /* initialize gdb connection information */
        gdb_connection->buf_p = gdb_connection->buffer;
        gdb_connection->buf_cnt = 0;
-       gdb_connection->ctrl_c = 0;
+       gdb_connection->ctrl_c = false;
        gdb_connection->frontend_state = TARGET_HALTED;
        gdb_connection->vflash_image = NULL;
        gdb_connection->closed = false;
@@ -944,6 +951,7 @@ static int gdb_new_connection(struct connection *connection)
        gdb_connection->sync = false;
        gdb_connection->mem_write_error = false;
        gdb_connection->attached = true;
+       gdb_connection->extended_protocol = false;
        gdb_connection->target_desc.tdesc = NULL;
        gdb_connection->target_desc.tdesc_length = 0;
        gdb_connection->thread_list = NULL;
@@ -988,15 +996,14 @@ static int gdb_new_connection(struct connection *connection)
                 * 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++) {
+               for (unsigned int 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 " \
+                               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;
                        }
@@ -1173,8 +1180,11 @@ static int gdb_get_registers_packet(struct connection *connection,
        if (retval != ERROR_OK)
                return gdb_error(connection, retval);
 
-       for (i = 0; i < reg_list_size; i++)
+       for (i = 0; i < reg_list_size; i++) {
+               if (reg_list[i] == NULL || reg_list[i]->exist == false)
+                       continue;
                reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
+       }
 
        assert(reg_packet_size > 0);
 
@@ -1185,8 +1195,17 @@ static int gdb_get_registers_packet(struct connection *connection,
        reg_packet_p = reg_packet;
 
        for (i = 0; i < reg_list_size; i++) {
-               if (!reg_list[i]->valid)
-                       reg_list[i]->type->get(reg_list[i]);
+               if (reg_list[i] == NULL || reg_list[i]->exist == false)
+                       continue;
+               if (!reg_list[i]->valid) {
+                       retval = reg_list[i]->type->get(reg_list[i]);
+                       if (retval != ERROR_OK && gdb_report_register_access_error) {
+                               LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name);
+                               free(reg_packet);
+                               free(reg_list);
+                               return gdb_error(connection, retval);
+                       }
+               }
                gdb_str_to_target(target, reg_packet_p, reg_list[i]);
                reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
        }
@@ -1247,7 +1266,13 @@ static int gdb_set_registers_packet(struct connection *connection,
                bin_buf = malloc(DIV_ROUND_UP(reg_list[i]->size, 8));
                gdb_target_to_reg(target, packet_p, chars, bin_buf);
 
-               reg_list[i]->type->set(reg_list[i], bin_buf);
+               retval = reg_list[i]->type->set(reg_list[i], bin_buf);
+               if (retval != ERROR_OK && gdb_report_register_access_error) {
+                       LOG_DEBUG("Couldn't set register %s.", reg_list[i]->name);
+                       free(reg_list);
+                       free(bin_buf);
+                       return gdb_error(connection, retval);
+               }
 
                /* advance packet pointer */
                packet_p += chars;
@@ -1277,7 +1302,10 @@ static int gdb_get_register_packet(struct connection *connection,
        LOG_DEBUG("-");
 #endif
 
-       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+       if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg(connection, reg_num)))
+               return ERROR_OK;
+
+       retval = target_get_gdb_reg_list_noread(target, &reg_list, &reg_list_size,
                        REG_CLASS_ALL);
        if (retval != ERROR_OK)
                return gdb_error(connection, retval);
@@ -1287,8 +1315,14 @@ static int gdb_get_register_packet(struct connection *connection,
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       if (!reg_list[reg_num]->valid)
-               reg_list[reg_num]->type->get(reg_list[reg_num]);
+       if (!reg_list[reg_num]->valid) {
+               retval = reg_list[reg_num]->type->get(reg_list[reg_num]);
+               if (retval != ERROR_OK && gdb_report_register_access_error) {
+                       LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name);
+                       free(reg_list);
+                       return gdb_error(connection, retval);
+               }
+       }
 
        reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */
 
@@ -1307,42 +1341,61 @@ static int gdb_set_register_packet(struct connection *connection,
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
-       uint8_t *bin_buf;
        int reg_num = strtoul(packet + 1, &separator, 16);
        struct reg **reg_list;
        int reg_list_size;
        int retval;
 
+#ifdef _DEBUG_GDB_IO_
        LOG_DEBUG("-");
+#endif
 
-       retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
+       if (*separator != '=') {
+               LOG_ERROR("GDB 'set register packet', but no '=' following the register number");
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
+       size_t chars = strlen(separator + 1);
+       uint8_t *bin_buf = malloc(chars / 2);
+       gdb_target_to_reg(target, separator + 1, chars, bin_buf);
+
+       if ((target->rtos != NULL) &&
+                       (ERROR_OK == rtos_set_reg(connection, reg_num, bin_buf))) {
+               free(bin_buf);
+               gdb_put_packet(connection, "OK", 2);
+               return ERROR_OK;
+       }
+
+       retval = target_get_gdb_reg_list_noread(target, &reg_list, &reg_list_size,
                        REG_CLASS_ALL);
-       if (retval != ERROR_OK)
+       if (retval != ERROR_OK) {
+               free(bin_buf);
                return gdb_error(connection, retval);
+       }
 
        if (reg_list_size <= reg_num) {
                LOG_ERROR("gdb requested a non-existing register");
+               free(bin_buf);
+               free(reg_list);
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
-       if (*separator != '=') {
-               LOG_ERROR("GDB 'set register packet', but no '=' following the register number");
-               return ERROR_SERVER_REMOTE_CLOSED;
-       }
-
-       /* convert from GDB-string (target-endian) to hex-string (big-endian) */
-       bin_buf = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8));
-       int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2);
-
-       if ((unsigned int)chars != strlen(separator + 1)) {
-               LOG_ERROR("gdb sent a packet with wrong register size");
+       if (chars != (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2)) {
+               LOG_ERROR("gdb sent %d bits for a %d-bit register (%s)",
+                               (int) chars * 4, reg_list[reg_num]->size, reg_list[reg_num]->name);
                free(bin_buf);
+               free(reg_list);
                return ERROR_SERVER_REMOTE_CLOSED;
        }
 
        gdb_target_to_reg(target, separator + 1, chars, bin_buf);
 
-       reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf);
+       retval = reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf);
+       if (retval != ERROR_OK && gdb_report_register_access_error) {
+               LOG_DEBUG("Couldn't set register %s.", reg_list[reg_num]->name);
+               free(bin_buf);
+               free(reg_list);
+               return gdb_error(connection, retval);
+       }
 
        gdb_put_packet(connection, "OK", 2);
 
@@ -1365,8 +1418,6 @@ static int gdb_error(struct connection *connection, int retval)
 
 /* We don't have to worry about the default 2 second timeout for GDB packets,
  * because GDB breaks up large memory reads into smaller reads.
- *
- * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????
  */
 static int gdb_read_memory_packet(struct connection *connection,
                char const *packet, int packet_size)
@@ -1395,7 +1446,7 @@ static int gdb_read_memory_packet(struct connection *connection,
 
        if (!len) {
                LOG_WARNING("invalid read memory packet received (len == 0)");
-               gdb_put_packet(connection, NULL, 0);
+               gdb_put_packet(connection, "", 0);
                return ERROR_OK;
        }
 
@@ -1600,7 +1651,7 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
        char *separator;
        int retval;
 
-       LOG_DEBUG("-");
+       LOG_DEBUG("[%s]", target_name(target));
 
        type = strtoul(packet + 1, &separator, 16);
 
@@ -1680,8 +1731,8 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
 /* 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, ...)
+static __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))) void xml_printf(int *retval,
+               char **xml, int *pos, int *size, const char *fmt, ...)
 {
        if (*retval != ERROR_OK)
                return;
@@ -1778,9 +1829,8 @@ static int gdb_memory_map(struct connection *connection,
        int offset;
        int length;
        char *separator;
-       uint32_t ram_start = 0;
-       int i;
-       int target_flash_banks = 0;
+       target_addr_t ram_start = 0;
+       unsigned int target_flash_banks = 0;
 
        /* skip command character */
        packet += 23;
@@ -1793,13 +1843,10 @@ static int gdb_memory_map(struct connection *connection,
        /* 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++) {
+       for (unsigned int i = 0; i < flash_get_bank_count(); i++) {
                p = get_flash_bank_by_num_noprobe(i);
                if (p->target != target)
                        continue;
@@ -1815,18 +1862,16 @@ static int gdb_memory_map(struct connection *connection,
        qsort(banks, target_flash_banks, sizeof(struct flash_bank *),
                compare_bank);
 
-       for (i = 0; i < target_flash_banks; i++) {
-               int j;
+       for (unsigned int i = 0; i < target_flash_banks; i++) {
                unsigned sector_size = 0;
-               uint32_t start;
+               unsigned group_len = 0;
 
                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",
+                               "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" "
+                               "length=\"" TARGET_ADDR_FMT "\"/>\n",
                                ram_start, p->base - ram_start);
 
                /* Report adjacent groups of same-size sectors.  So for
@@ -1835,28 +1880,36 @@ static int gdb_memory_map(struct connection *connection,
                 * 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;
+               for (unsigned int j = 0; j < p->num_sectors; j++) {
 
                        /* Maybe start a new group of sectors. */
                        if (sector_size == 0) {
+                               if (p->sectors[j].offset + p->sectors[j].size > p->size) {
+                                       LOG_WARNING("The flash sector at offset 0x%08" PRIx32
+                                               " overflows the end of %s bank.",
+                                               p->sectors[j].offset, p->name);
+                                       LOG_WARNING("The rest of bank will not show in gdb memory map.");
+                                       break;
+                               }
+                               target_addr_t start;
                                start = p->base + p->sectors[j].offset;
                                xml_printf(&retval, &xml, &pos, &size,
                                        "<memory type=\"flash\" "
-                                       "start=\"0x%x\" ",
+                                       "start=\"" TARGET_ADDR_FMT "\" ",
                                        start);
                                sector_size = p->sectors[j].size;
+                               group_len = sector_size;
+                       } else {
+                               group_len += sector_size; /* equal to 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
+                       if (j < p->num_sectors - 1
+                                       && p->sectors[j + 1].size == sector_size
+                                       && p->sectors[j + 1].offset == p->sectors[j].offset + sector_size
+                                       && p->sectors[j + 1].offset + p->sectors[j + 1].size <= p->size)
                                continue;
 
                        xml_printf(&retval, &xml, &pos, &size,
@@ -1874,19 +1927,18 @@ static int gdb_memory_map(struct connection *connection,
 
        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
-        */
+                       "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" "
+                       "length=\"" TARGET_ADDR_FMT "\"/>\n",
+                       ram_start, target_address_max(target) - ram_start + 1);
+       /* ELSE a flash chip could be at the very end of the 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) {
+               free(xml);
                gdb_error(connection, retval);
                return retval;
        }
@@ -1907,6 +1959,8 @@ static int gdb_memory_map(struct connection *connection,
 static const char *gdb_get_reg_type_name(enum reg_type type)
 {
        switch (type) {
+               case REG_TYPE_BOOL:
+                       return "bool";
                case REG_TYPE_INT:
                        return "int";
                case REG_TYPE_INT8:
@@ -1919,6 +1973,8 @@ static const char *gdb_get_reg_type_name(enum reg_type type)
                        return "int64";
                case REG_TYPE_INT128:
                        return "int128";
+               case REG_TYPE_UINT:
+                       return "uint";
                case REG_TYPE_UINT8:
                        return "uint8";
                case REG_TYPE_UINT16:
@@ -1972,7 +2028,7 @@ static int lookup_add_arch_defined_types(char const **arch_defined_types_list[],
 
 static int gdb_generate_reg_type_description(struct target *target,
                char **tdesc, int *pos, int *size, struct reg_data_type *type,
-               char const **arch_defined_types_list[], int * num_arch_defined_types)
+               char const **arch_defined_types_list[], int *num_arch_defined_types)
 {
        int retval = ERROR_OK;
 
@@ -2038,9 +2094,9 @@ static int gdb_generate_reg_type_description(struct target *target,
                                        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 name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+                                               field->name, field->bitfield->start, field->bitfield->end,
+                                               gdb_get_reg_type_name(field->bitfield->type));
 
                                field = field->next;
                        }
@@ -2086,8 +2142,9 @@ static int gdb_generate_reg_type_description(struct target *target,
                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 name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+                                       field->name, field->bitfield->start, field->bitfield->end,
+                                       gdb_get_reg_type_name(field->bitfield->type));
 
                        field = field->next;
                }
@@ -2147,17 +2204,15 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
        int retval = ERROR_OK;
        struct reg **reg_list = NULL;
        int reg_list_size;
+       char const *architecture;
        char const **features = NULL;
-       char const **arch_defined_types = NULL;
        int feature_list_size = 0;
-       int num_arch_defined_types = 0;
        char *tdesc = NULL;
        int pos = 0;
        int size = 0;
 
-       arch_defined_types = calloc(1, sizeof(char *));
 
-       retval = target_get_gdb_reg_list(target, &reg_list,
+       retval = target_get_gdb_reg_list_noread(target, &reg_list,
                        &reg_list_size, REG_CLASS_ALL);
 
        if (retval != ERROR_OK) {
@@ -2188,10 +2243,19 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                        "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n"
                        "<target version=\"1.0\">\n");
 
+       /* generate architecture element if supported by target */
+       architecture = target_get_gdb_arch(target);
+       if (architecture != NULL)
+               xml_printf(&retval, &tdesc, &pos, &size,
+                               "<architecture>%s</architecture>\n", architecture);
+
        /* generate target description according to register list */
        if (features != NULL) {
                while (features[current_feature]) {
+                       char const **arch_defined_types = NULL;
+                       int num_arch_defined_types = 0;
 
+                       arch_defined_types = calloc(1, sizeof(char *));
                        xml_printf(&retval, &tdesc, &pos, &size,
                                        "<feature name=\"%s\">\n",
                                        features[current_feature]);
@@ -2256,6 +2320,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                                        "</feature>\n");
 
                        current_feature++;
+                       free(arch_defined_types);
                }
        }
 
@@ -2265,7 +2330,6 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
 error:
        free(features);
        free(reg_list);
-       free(arch_defined_types);
 
        if (retval == ERROR_OK)
                *tdesc_out = tdesc;
@@ -2337,7 +2401,9 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        char const **features = NULL;
        int feature_list_size = 0;
 
-       retval = target_get_gdb_reg_list(target, &reg_list,
+       char const *architecture = target_get_gdb_arch(target);
+
+       retval = target_get_gdb_reg_list_noread(target, &reg_list,
                        &reg_list_size, REG_CLASS_ALL);
        if (retval != ERROR_OK) {
                LOG_ERROR("get register list failed");
@@ -2358,7 +2424,7 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        }
 
        if (supported) {
-               if (feature_list_size)
+               if (architecture || feature_list_size)
                        *supported = 1;
                else
                        *supported = 0;
@@ -2403,7 +2469,7 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou
                                        xml_printf(&retval, &thread_list, &pos, &size,
                                                   ", ");
                                xml_printf(&retval, &thread_list, &pos, &size,
-                                          thread_detail->extra_info_str);
+                                          "%s", thread_detail->extra_info_str);
                        }
 
                        xml_printf(&retval, &thread_list, &pos, &size,
@@ -2555,7 +2621,7 @@ static int gdb_query_packet(struct connection *connection,
                        &pos,
                        &size,
                        "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+",
-                       (GDB_BUFFER_SIZE - 1),
+                       GDB_BUFFER_SIZE,
                        ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-',
                        (gdb_target_desc_supported == 1) ? '+' : '-');
 
@@ -2667,6 +2733,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
 
        /* simple case, a continue packet */
        if (parse[0] == 'c') {
+               gdb_running_type = 'c';
                LOG_DEBUG("target %s continue", target_name(target));
                log_add_callback(gdb_log_callback, connection);
                retval = target_resume(target, 1, 0, 0, 0);
@@ -2693,6 +2760,9 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
 
        /* single-step or step-over-breakpoint */
        if (parse[0] == 's') {
+               gdb_running_type = 's';
+               bool fake_step = false;
+
                if (strncmp(parse, "s:", 2) == 0) {
                        struct target *ct = target;
                        int current_pc = 1;
@@ -2708,22 +2778,31 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
                                parse = endp;
                        }
 
-                       if (target->rtos != NULL)
+                       if (target->rtos != NULL) {
+                               /* FIXME: why is this necessary? rtos state should be up-to-date here already! */
+                               rtos_update_threads(target);
+
                                target->rtos->gdb_target_for_threadid(connection, thread_id, &ct);
 
+                               /*
+                                * check if the thread to be stepped is the current rtos thread
+                                * if not, we must fake the step
+                                */
+                               if (target->rtos->current_thread != thread_id)
+                                       fake_step = true;
+                       }
+
                        if (parse[0] == ';') {
                                ++parse;
                                --packet_size;
 
                                if (parse[0] == 'c') {
                                        parse += 1;
-                                       packet_size -= 1;
 
                                        /* check if thread-id follows */
                                        if (parse[0] == ':') {
                                                int64_t tid;
                                                parse += 1;
-                                               packet_size -= 1;
 
                                                tid = strtoll(parse, &endp, 16);
                                                if (tid == thread_id) {
@@ -2744,15 +2823,38 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
                                }
                        }
 
-                       LOG_DEBUG("target %s single-step thread %"PRId64, target_name(ct), thread_id);
+                       LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id);
                        log_add_callback(gdb_log_callback, connection);
                        target_call_event_callbacks(ct, TARGET_EVENT_GDB_START);
 
+                       /*
+                        * work around an annoying gdb behaviour: when the current thread
+                        * is changed in gdb, it assumes that the target can follow and also
+                        * make the thread current. This is an assumption that cannot hold
+                        * for a real target running a multi-threading OS. We just fake
+                        * the step to not trigger an internal error in gdb. See
+                        * https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details
+                        */
+                       if (fake_step) {
+                               int sig_reply_len;
+                               char sig_reply[128];
+
+                               LOG_DEBUG("fake step thread %"PRIx64, thread_id);
+
+                               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply),
+                                                                                "T05thread:%016"PRIx64";", thread_id);
+
+                               gdb_put_packet(connection, sig_reply, sig_reply_len);
+                               log_remove_callback(gdb_log_callback, connection);
+
+                               return true;
+                       }
+
                        /* support for gdb_sync command */
                        if (gdb_connection->sync) {
                                gdb_connection->sync = false;
                                if (ct->state == TARGET_HALTED) {
-                                       LOG_WARNING("stepi ignored. GDB will now fetch the register state " \
+                                       LOG_DEBUG("stepi ignored. GDB will now fetch the register state "
                                                                        "from the target.");
                                        gdb_sig_halted(connection);
                                        log_remove_callback(gdb_log_callback, connection);
@@ -2786,14 +2888,103 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
        return false;
 }
 
+static char *next_hex_encoded_field(const char **str, char sep)
+{
+       size_t hexlen;
+       const char *hex = *str;
+       if (hex[0] == '\0')
+               return NULL;
+
+       const char *end = strchr(hex, sep);
+       if (end == NULL)
+               hexlen = strlen(hex);
+       else
+               hexlen = end - hex;
+       *str = hex + hexlen + 1;
+
+       if (hexlen % 2 != 0) {
+               /* Malformed hex data */
+               return NULL;
+       }
+
+       size_t count = hexlen / 2;
+       char *decoded = malloc(count + 1);
+       if (decoded == NULL)
+               return NULL;
+
+       size_t converted = unhexify((void *)decoded, hex, count);
+       if (converted != count) {
+               free(decoded);
+               return NULL;
+       }
+
+       decoded[count] = '\0';
+       return decoded;
+}
+
+/* handle extended restart packet */
+static void gdb_restart_inferior(struct connection *connection, const char *packet, int packet_size)
+{
+       struct gdb_connection *gdb_con = connection->priv;
+       struct target *target = get_target_from_connection(connection);
+
+       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 */
+       gdb_con->attached = true;
+       /*  info rtos parts */
+       gdb_thread_packet(connection, packet, packet_size);
+}
+
+static bool gdb_handle_vrun_packet(struct connection *connection, const char *packet, int packet_size)
+{
+       struct target *target = get_target_from_connection(connection);
+       const char *parse = packet;
+
+       /* Skip "vRun" */
+       parse += 4;
+
+       if (parse[0] != ';')
+               return false;
+       parse++;
+
+       /* Skip first field "filename"; don't know what to do with it. */
+       free(next_hex_encoded_field(&parse, ';'));
+
+       char *cmdline = next_hex_encoded_field(&parse, ';');
+       char *arg;
+       while (cmdline != NULL && (arg = next_hex_encoded_field(&parse, ';')) != NULL) {
+               char *new_cmdline = alloc_printf("%s %s", cmdline, arg);
+               free(cmdline);
+               free(arg);
+               cmdline = new_cmdline;
+       }
+
+       if (cmdline != NULL) {
+               if (target->semihosting != NULL) {
+                       LOG_INFO("GDB set inferior command line to '%s'", cmdline);
+                       free(target->semihosting->cmdline);
+                       target->semihosting->cmdline = cmdline;
+               } else {
+                       LOG_INFO("GDB set inferior command line to '%s' but semihosting is unavailable", cmdline);
+                       free(cmdline);
+               }
+       }
+
+       gdb_restart_inferior(connection, packet, packet_size);
+       gdb_put_packet(connection, "S00", 3);
+       return true;
+}
+
 static int gdb_v_packet(struct connection *connection,
                char const *packet, int packet_size)
 {
        struct gdb_connection *gdb_connection = connection->priv;
-       struct target *target;
        int result;
 
-       target = get_target_from_connection(connection);
+       struct target *target = get_target_from_connection(connection);
 
        if (strncmp(packet, "vCont", 5) == 0) {
                bool handled;
@@ -2808,6 +2999,16 @@ static int gdb_v_packet(struct connection *connection,
                return ERROR_OK;
        }
 
+       if (strncmp(packet, "vRun", 4) == 0) {
+               bool handled;
+
+               handled = gdb_handle_vrun_packet(connection, packet, packet_size);
+               if (!handled)
+                       gdb_put_packet(connection, "", 0);
+
+               return ERROR_OK;
+       }
+
        /* if flash programming disabled - send a empty reply */
 
        if (gdb_flash_program == 0) {
@@ -2913,7 +3114,7 @@ static int gdb_v_packet(struct connection *connection,
                target_call_event_callbacks(target,
                                TARGET_EVENT_GDB_FLASH_WRITE_START);
                result = flash_write(target, gdb_connection->vflash_image,
-                       &written, 0);
+                       &written, false);
                target_call_event_callbacks(target,
                        TARGET_EVENT_GDB_FLASH_WRITE_END);
                if (result != ERROR_OK) {
@@ -2939,9 +3140,12 @@ static int gdb_v_packet(struct connection *connection,
 
 static int gdb_detach(struct connection *connection)
 {
-       target_call_event_callbacks(get_target_from_connection(connection),
-               TARGET_EVENT_GDB_DETACH);
-
+       /*
+        * Only reply "OK" to GDB
+        * it will close the connection and this will trigger a call to
+        * gdb_connection_closed() that will in turn trigger the event
+        * TARGET_EVENT_GDB_DETACH
+        */
        return gdb_put_packet(connection, "OK", 2);
 }
 
@@ -3017,14 +3221,13 @@ static void gdb_sig_halted(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];
+       static char gdb_packet_buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for nul-termination */
 
        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);
 
@@ -3040,7 +3243,7 @@ static int gdb_input_inner(struct connection *connection)
         * drain the rest of the buffer.
         */
        do {
-               packet_size = GDB_BUFFER_SIZE-1;
+               packet_size = GDB_BUFFER_SIZE;
                retval = gdb_get_packet(connection, gdb_packet_buffer, &packet_size);
                if (retval != ERROR_OK)
                        return retval;
@@ -3124,7 +3327,7 @@ static int gdb_input_inner(struct connection *connection)
                                                                "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, " \
+                                               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) {
@@ -3133,7 +3336,7 @@ static int gdb_input_inner(struct connection *connection)
                                                 * make only the single stepping have the sync feature...
                                                 */
                                                nostep = true;
-                                               LOG_WARNING("stepi ignored. GDB will now fetch the register state " \
+                                               LOG_DEBUG("stepi ignored. GDB will now fetch the register state "
                                                                "from the target.");
                                        }
                                        gdb_con->sync = false;
@@ -3176,7 +3379,6 @@ static int gdb_input_inner(struct connection *connection)
                                        break;
                                case 'D':
                                        retval = gdb_detach(connection);
-                                       extended_protocol = 0;
                                        break;
                                case 'X':
                                        retval = gdb_write_memory_binary_packet(connection, packet, packet_size);
@@ -3184,7 +3386,7 @@ static int gdb_input_inner(struct connection *connection)
                                                return retval;
                                        break;
                                case 'k':
-                                       if (extended_protocol != 0) {
+                                       if (gdb_con->extended_protocol) {
                                                gdb_con->attached = false;
                                                break;
                                        }
@@ -3192,19 +3394,12 @@ static int gdb_input_inner(struct connection *connection)
                                        return ERROR_SERVER_REMOTE_CLOSED;
                                case '!':
                                        /* handle extended remote protocol */
-                                       extended_protocol = 1;
+                                       gdb_con->extended_protocol = true;
                                        gdb_put_packet(connection, "OK", 2);
                                        break;
                                case 'R':
                                        /* handle extended restart packet */
-                                       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 */
-                                       gdb_con->attached = true;
-                                       /*  info rtos parts */
-                                       gdb_thread_packet(connection, packet, packet_size);
+                                       gdb_restart_inferior(connection, packet, packet_size);
                                        break;
 
                                case 'j':
@@ -3236,7 +3431,7 @@ static int gdb_input_inner(struct connection *connection)
                                default:
                                        /* ignore unknown packets */
                                        LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]);
-                                       gdb_put_packet(connection, NULL, 0);
+                                       gdb_put_packet(connection, "", 0);
                                        break;
                        }
 
@@ -3255,7 +3450,7 @@ static int gdb_input_inner(struct connection *connection)
                                        retval = target_poll(t);
                                if (retval != ERROR_OK)
                                        target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
-                               gdb_con->ctrl_c = 0;
+                               gdb_con->ctrl_c = false;
                        } else {
                                LOG_INFO("The target is not running when halt was requested, stopping GDB.");
                                target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
@@ -3291,6 +3486,8 @@ static int gdb_target_start(struct target *target, const char *port)
        if (NULL == gdb_service)
                return -ENOMEM;
 
+       LOG_INFO("starting gdb server for %s on %s", target_name(target), port);
+
        gdb_service->target = target;
        gdb_service->core[0] = -1;
        gdb_service->core[1] = -1;
@@ -3316,16 +3513,36 @@ static int gdb_target_start(struct target *target, const char *port)
 
 static int gdb_target_add_one(struct target *target)
 {
+       /*  one gdb instance per smp list */
+       if ((target->smp) && (target->gdb_service))
+               return ERROR_OK;
+
+       /* skip targets that cannot handle a gdb connections (e.g. mem_ap) */
+       if (!target_supports_gdb_connection(target)) {
+               LOG_DEBUG("skip gdb server for target %s", target_name(target));
+               return ERROR_OK;
+       }
+
+       if (target->gdb_port_override) {
+               if (strcmp(target->gdb_port_override, "disabled") == 0) {
+                       LOG_INFO("gdb port disabled");
+                       return ERROR_OK;
+               }
+               return gdb_target_start(target, target->gdb_port_override);
+       }
+
        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;
        int retval = gdb_target_start(target, gdb_port_next);
        if (retval == ERROR_OK) {
+               /* save the port number so can be queried with
+                * $target_name cget -gdb-port
+                */
+               target->gdb_port_override = strdup(gdb_port_next);
+
                long portnumber;
                /* If we can parse the port number
                 * then we increment the port number for the next target.
@@ -3336,7 +3553,7 @@ static int gdb_target_add_one(struct target *target)
                        if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) {
                                free(gdb_port_next);
                                if (portnumber) {
-                                       gdb_port_next = alloc_printf("%d", portnumber+1);
+                                       gdb_port_next = alloc_printf("%ld", portnumber+1);
                                } else {
                                        /* Don't increment if gdb_port is 0, since we're just
                                         * trying to allocate an unused port. */
@@ -3350,11 +3567,6 @@ 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;
@@ -3377,7 +3589,7 @@ COMMAND_HANDLER(handle_gdb_sync_command)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        if (current_gdb_connection == NULL) {
-               command_print(CMD_CTX,
+               command_print(CMD,
                        "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\"");
                return ERROR_FAIL;
        }
@@ -3425,6 +3637,15 @@ COMMAND_HANDLER(handle_gdb_report_data_abort_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(handle_gdb_report_register_access_error)
+{
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_register_access_error);
+       return ERROR_OK;
+}
+
 /* gdb_breakpoint_override */
 COMMAND_HANDLER(handle_gdb_breakpoint_override_command)
 {
@@ -3515,7 +3736,7 @@ static const struct command_registration gdb_command_handlers[] = {
        {
                .name = "gdb_port",
                .handler = handle_gdb_port_command,
-               .mode = COMMAND_ANY,
+               .mode = COMMAND_CONFIG,
                .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. "
@@ -3546,6 +3767,13 @@ static const struct command_registration gdb_command_handlers[] = {
                .help = "enable or disable reporting data aborts",
                .usage = "('enable'|'disable')"
        },
+       {
+               .name = "gdb_report_register_access_error",
+               .handler = handle_gdb_report_register_access_error,
+               .mode = COMMAND_CONFIG,
+               .help = "enable or disable reporting register access errors",
+               .usage = "('enable'|'disable')"
+       },
        {
                .name = "gdb_breakpoint_override",
                .handler = handle_gdb_breakpoint_override_command,
@@ -3566,6 +3794,7 @@ static const struct command_registration gdb_command_handlers[] = {
                .handler = handle_gdb_save_tdesc_command,
                .mode = COMMAND_EXEC,
                .help = "Save the target description file",
+               .usage = "",
        },
        COMMAND_REGISTRATION_DONE
 };