gdb_server: fix HW thread status at gdb attach
[fw/openocd] / src / server / gdb_server.c
index 0370fcd5bbe1c979e3518cab92e87857e8b3076d..9e44287fd768be72b1c6a710bd120af75ea9b255 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 + 1]; /* Extra byte for nul-termination */
+       char buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for null-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 */
@@ -274,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
@@ -299,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);
@@ -441,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;
@@ -646,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:
@@ -782,7 +785,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
                sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s",
                                signal_var, stop_reason, current_thread);
 
-               gdb_connection->ctrl_c = 0;
+               gdb_connection->ctrl_c = false;
        }
 
        gdb_put_packet(connection, sig_reply, sig_reply_len);
@@ -799,7 +802,7 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
        if (strcmp(target->fileio_info->identifier, "open") == 0)
                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)
@@ -823,13 +826,13 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
        else if (strcmp(target->fileio_info->identifier, "rename") == 0)
                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,%" 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,%" PRIx64 "/%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
                                target->fileio_info->param_1,
@@ -849,7 +852,7 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
        else if (strcmp(target->fileio_info->identifier, "system") == 0)
                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. */
@@ -939,7 +942,7 @@ static int gdb_new_connection(struct connection *connection)
        /* 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;
@@ -948,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;
@@ -965,15 +969,6 @@ static int gdb_new_connection(struct connection *connection)
        breakpoint_clear_target(target);
        watchpoint_clear_target(target);
 
-       if (target->rtos) {
-               /* clean previous rtos session if supported*/
-               if (target->rtos->type->clean)
-                       target->rtos->type->clean(target);
-
-               /* update threads */
-               rtos_update_threads(target);
-       }
-
        /* remove the initial ACK from the incoming buffer */
        retval = gdb_get_char(connection, &initial_ack);
        if (retval != ERROR_OK)
@@ -986,21 +981,29 @@ static int gdb_new_connection(struct connection *connection)
                gdb_putback_char(connection, initial_ack);
        target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH);
 
+       if (target->rtos) {
+               /* clean previous rtos session if supported*/
+               if (target->rtos->type->clean)
+                       target->rtos->type->clean(target);
+
+               /* update threads */
+               rtos_update_threads(target);
+       }
+
        if (gdb_use_memory_map) {
                /* Connect must fail if the memory map can't be set up correctly.
                 *
                 * This will cause an auto_probe to be invoked, which is either
                 * a no-op or it will fail when the target isn't ready(e.g. not halted).
                 */
-               int i;
-               for (i = 0; i < flash_get_bank_count(); i++) {
+               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;
                        }
@@ -1015,6 +1018,17 @@ static int gdb_new_connection(struct connection *connection)
                        target_name(target),
                        target_state_name(target));
 
+       if (!target_was_examined(target)) {
+               LOG_ERROR("Target %s not examined yet, refuse gdb connection %d!",
+                                 target_name(target), gdb_actual_connections);
+               gdb_actual_connections--;
+               return ERROR_TARGET_NOT_EXAMINED;
+       }
+
+       if (target->state != TARGET_HALTED)
+               LOG_WARNING("GDB connection %d on target %s not halted",
+                                       gdb_actual_connections, target_name(target));
+
        /* DANGER! If we fail subsequently, we must remove this handler,
         * otherwise we occasionally see crashes as the timer can invoke the
         * callback fn.
@@ -1053,11 +1067,8 @@ 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, target);
 
-       if (connection->priv) {
-               free(connection->priv);
-               connection->priv = NULL;
-       } else
-               LOG_ERROR("BUG: connection->priv == NULL");
+       free(connection->priv);
+       connection->priv = NULL;
 
        target_unregister_event_callback(gdb_target_callback_event_handler, connection);
 
@@ -1178,7 +1189,7 @@ static int gdb_get_registers_packet(struct connection *connection,
                return gdb_error(connection, retval);
 
        for (i = 0; i < reg_list_size; i++) {
-               if (reg_list[i] == NULL || reg_list[i]->exist == false)
+               if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
                        continue;
                reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
        }
@@ -1192,7 +1203,7 @@ 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] == NULL || reg_list[i]->exist == false)
+               if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
                        continue;
                if (!reg_list[i]->valid) {
                        retval = reg_list[i]->type->get(reg_list[i]);
@@ -1321,7 +1332,7 @@ static int gdb_get_register_packet(struct connection *connection,
                }
        }
 
-       reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */
+       reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */
 
        gdb_str_to_target(target, reg_packet, reg_list[reg_num]);
 
@@ -1377,8 +1388,8 @@ static int gdb_set_register_packet(struct connection *connection,
        }
 
        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);
+               LOG_ERROR("gdb sent %zu bits for a %" PRIu32 "-bit register (%s)",
+                               chars * 4, reg_list[reg_num]->size, reg_list[reg_num]->name);
                free(bin_buf);
                free(reg_list);
                return ERROR_SERVER_REMOTE_CLOSED;
@@ -1728,8 +1739,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;
@@ -1744,8 +1755,7 @@ static void xml_printf(int *retval, char **xml, int *pos, int *size,
                        char *t = *xml;
                        *xml = realloc(*xml, *size);
                        if (*xml == NULL) {
-                               if (t)
-                                       free(t);
+                               free(t);
                                *retval = ERROR_SERVER_REMOTE_CLOSED;
                                return;
                        }
@@ -1827,8 +1837,7 @@ static int gdb_memory_map(struct connection *connection,
        int length;
        char *separator;
        target_addr_t ram_start = 0;
-       int i;
-       int target_flash_banks = 0;
+       unsigned int target_flash_banks = 0;
 
        /* skip command character */
        packet += 23;
@@ -1844,7 +1853,7 @@ 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++) {
+       for (unsigned int i = 0; i < flash_get_bank_count(); i++) {
                p = get_flash_bank_by_num_noprobe(i);
                if (p->target != target)
                        continue;
@@ -1860,8 +1869,7 @@ 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;
                unsigned group_len = 0;
 
@@ -1870,7 +1878,7 @@ static int gdb_memory_map(struct connection *connection,
                if (ram_start < p->base)
                        xml_printf(&retval, &xml, &pos, &size,
                                "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" "
-                               "length=\"0x%x\"/>\n",
+                               "length=\"" TARGET_ADDR_FMT "\"/>\n",
                                ram_start, p->base - ram_start);
 
                /* Report adjacent groups of same-size sectors.  So for
@@ -1879,7 +1887,7 @@ 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++) {
+               for (unsigned int j = 0; j < p->num_sectors; j++) {
 
                        /* Maybe start a new group of sectors. */
                        if (sector_size == 0) {
@@ -2027,7 +2035,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;
 
@@ -2042,7 +2050,7 @@ static int gdb_generate_reg_type_description(struct target *target,
                }
                /* <vector id="id" type="type" count="count"/> */
                xml_printf(&retval, tdesc, pos, size,
-                               "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
+                               "<vector id=\"%s\" type=\"%s\" count=\"%" PRIu32 "\"/>\n",
                                type->id, type->reg_type_vector->type->id,
                                type->reg_type_vector->count);
 
@@ -2089,11 +2097,11 @@ static int gdb_generate_reg_type_description(struct target *target,
                         *  <field name="name" start="start" end="end"/> ...
                         * </struct> */
                        xml_printf(&retval, tdesc, pos, size,
-                                       "<struct id=\"%s\" size=\"%d\">\n",
+                                       "<struct id=\"%s\" size=\"%" PRIu32 "\">\n",
                                        type->id, type->reg_type_struct->size);
                        while (field != NULL) {
                                xml_printf(&retval, tdesc, pos, size,
-                                               "<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+                                               "<field name=\"%s\" start=\"%" PRIu32 "\" end=\"%" PRIu32 "\" type=\"%s\" />\n",
                                                field->name, field->bitfield->start, field->bitfield->end,
                                                gdb_get_reg_type_name(field->bitfield->type));
 
@@ -2134,14 +2142,14 @@ static int gdb_generate_reg_type_description(struct target *target,
                 *  <field name="name" start="start" end="end"/> ...
                 * </flags> */
                xml_printf(&retval, tdesc, pos, size,
-                               "<flags id=\"%s\" size=\"%d\">\n",
+                               "<flags id=\"%s\" size=\"%" PRIu32 "\">\n",
                                type->id, type->reg_type_flags->size);
 
                struct reg_data_type_flags_field *field;
                field = type->reg_type_flags->fields;
                while (field != NULL) {
                        xml_printf(&retval, tdesc, pos, size,
-                                       "<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+                                       "<field name=\"%s\" start=\"%" PRIu32 "\" end=\"%" PRIu32 "\" type=\"%s\" />\n",
                                        field->name, field->bitfield->start, field->bitfield->end,
                                        gdb_get_reg_type_name(field->bitfield->type));
 
@@ -2168,7 +2176,7 @@ static int get_reg_features_list(struct target *target, char const **feature_lis
        *feature_list = calloc(1, sizeof(char *));
 
        for (int i = 0; i < reg_list_size; i++) {
-               if (reg_list[i]->exist == false)
+               if (reg_list[i]->exist == false || reg_list[i]->hidden)
                        continue;
 
                if (reg_list[i]->feature != NULL
@@ -2262,7 +2270,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                        int i;
                        for (i = 0; i < reg_list_size; i++) {
 
-                               if (reg_list[i]->exist == false)
+                               if (reg_list[i]->exist == false || reg_list[i]->hidden)
                                        continue;
 
                                if (strcmp(reg_list[i]->feature->name, features[current_feature]))
@@ -2294,9 +2302,9 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                                xml_printf(&retval, &tdesc, &pos, &size,
                                                "<reg name=\"%s\"", reg_list[i]->name);
                                xml_printf(&retval, &tdesc, &pos, &size,
-                                               " bitsize=\"%d\"", reg_list[i]->size);
+                                               " bitsize=\"%" PRIu32 "\"", reg_list[i]->size);
                                xml_printf(&retval, &tdesc, &pos, &size,
-                                               " regnum=\"%d\"", reg_list[i]->number);
+                                               " regnum=\"%" PRIu32 "\"", reg_list[i]->number);
                                if (reg_list[i]->caller_save)
                                        xml_printf(&retval, &tdesc, &pos, &size,
                                                        " save-restore=\"yes\"");
@@ -2468,7 +2476,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,
@@ -2508,7 +2516,7 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
                transfer_type = 'l';
 
        *chunk = malloc(length + 2 + 3);
-    /* Allocating extra 3 bytes prevents false positive valgrind report
+       /* Allocating extra 3 bytes prevents false positive valgrind report
         * of strlen(chunk) word access:
         * Invalid read of size 4
         * Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */
@@ -2853,7 +2861,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
                        if (gdb_connection->sync) {
                                gdb_connection->sync = false;
                                if (ct->state == TARGET_HALTED) {
-                                       LOG_DEBUG("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);
@@ -2887,6 +2895,96 @@ 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)
 {
@@ -2908,6 +3006,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) {
@@ -3013,7 +3121,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) {
@@ -3120,14 +3228,14 @@ 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 + 1]; /* Extra byte for nul-termination */
+       static char gdb_packet_buffer[GDB_BUFFER_SIZE + 1]; /* Extra byte for null-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;
+       static bool warn_use_ext;
 
        target = get_target_from_connection(connection);
 
@@ -3204,6 +3312,12 @@ static int gdb_input_inner(struct connection *connection)
                                        break;
                                case '?':
                                        gdb_last_signal_packet(connection, packet, packet_size);
+                                       /* '?' is sent after the eventual '!' */
+                                       if (!warn_use_ext && !gdb_con->extended_protocol) {
+                                               warn_use_ext = true;
+                                               LOG_WARNING("Prefer GDB command \"target extended-remote %s\" instead of \"target remote %s\"",
+                                                                       connection->service->port, connection->service->port);
+                                       }
                                        break;
                                case 'c':
                                case 's':
@@ -3227,7 +3341,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) {
@@ -3236,7 +3350,7 @@ static int gdb_input_inner(struct connection *connection)
                                                 * make only the single stepping have the sync feature...
                                                 */
                                                nostep = true;
-                                               LOG_DEBUG("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;
@@ -3279,7 +3393,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);
@@ -3287,7 +3400,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;
                                        }
@@ -3295,19 +3408,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':
@@ -3358,7 +3464,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);
@@ -3394,7 +3500,7 @@ static int gdb_target_start(struct target *target, const char *port)
        if (NULL == gdb_service)
                return -ENOMEM;
 
-       LOG_DEBUG("starting gdb server for %s on %s", target_name(target), port);
+       LOG_INFO("starting gdb server for %s on %s", target_name(target), port);
 
        gdb_service->target = target;
        gdb_service->core[0] = -1;
@@ -3402,9 +3508,9 @@ static int gdb_target_start(struct target *target, const char *port)
        target->gdb_service = gdb_service;
 
        ret = add_service("gdb",
-                       port, 1, &gdb_new_connection, &gdb_input,
-                       &gdb_connection_closed, gdb_service);
-       /* initialialize all targets gdb service with the same pointer */
+                       port, target->gdb_max_connections, &gdb_new_connection, &gdb_input,
+                       &gdb_connection_closed, gdb_service, NULL);
+       /* initialize all targets gdb service with the same pointer */
        {
                struct target_list *head;
                struct target *curr;
@@ -3461,7 +3567,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. */
@@ -3644,7 +3750,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. "