gdb_server: fix 'null' pointer passed as 'nonnull' parameter
[openocd.git] / src / server / gdb_server.c
index a15c5bb810499ce0c285924e3de9ef2429fa9ef0..54cf9aff8e06f9637bbdfac61bae4177a8d67e3d 100644 (file)
@@ -130,6 +130,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 +153,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:
@@ -732,7 +737,6 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
        } else {
                if (gdb_connection->ctrl_c) {
                        signal_var = 0x2;
-                       gdb_connection->ctrl_c = 0;
                } else
                        signal_var = gdb_last_signal(target);
 
@@ -769,11 +773,14 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
                                        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);
+                       if (!gdb_connection->ctrl_c)
+                               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 = 0;
        }
 
        gdb_put_packet(connection, sig_reply, sig_reply_len);
@@ -788,64 +795,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_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_3,
                                target->fileio_info->param_4);
        else if (strcmp(target->fileio_info->identifier, "unlink") == 0)
-               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
+               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, "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);
        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);
 
@@ -931,6 +938,7 @@ 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;
@@ -1173,8 +1181,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 +1196,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 +1267,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,6 +1303,9 @@ static int gdb_get_register_packet(struct connection *connection,
        LOG_DEBUG("-");
 #endif
 
+       if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg(connection, reg_num)))
+               return ERROR_OK;
+
        retval = target_get_gdb_reg_list(target, &reg_list, &reg_list_size,
                        REG_CLASS_ALL);
        if (retval != ERROR_OK)
@@ -1287,8 +1316,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 */
 
@@ -1335,14 +1370,21 @@ static int gdb_set_register_packet(struct connection *connection,
        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");
+               LOG_ERROR("gdb sent %zu bits for a %d-bit register (%s)",
+                               strlen(separator + 1) * 4, chars * 4, reg_list[reg_num]->name);
                free(bin_buf);
                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);
 
@@ -1395,7 +1437,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;
        }
 
@@ -1778,7 +1820,7 @@ static int gdb_memory_map(struct connection *connection,
        int offset;
        int length;
        char *separator;
-       uint32_t ram_start = 0;
+       target_addr_t ram_start = 0;
        int i;
        int target_flash_banks = 0;
 
@@ -1793,9 +1835,6 @@ 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());
 
@@ -1818,14 +1857,13 @@ static int gdb_memory_map(struct connection *connection,
        for (i = 0; i < target_flash_banks; i++) {
                int j;
                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\" "
+                               "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" "
                                "length=\"0x%x\"/>\n",
                                ram_start, p->base - ram_start);
 
@@ -1836,27 +1874,35 @@ static int gdb_memory_map(struct connection *connection,
                 * regions with 8KB, 32KB, and 64KB sectors; etc.
                 */
                for (j = 0; j < p->num_sectors; j++) {
-                       unsigned group_len;
 
                        /* Maybe start a new group of sectors. */
                        if (sector_size == 0) {
+                               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,7 +1920,7 @@ static int gdb_memory_map(struct connection *connection,
 
        if (ram_start != 0)
                xml_printf(&retval, &xml, &pos, &size,
-                       "<memory type=\"ram\" start=\"0x%x\" "
+                       "<memory type=\"ram\" start=\"" TARGET_ADDR_FMT "\" "
                        "length=\"0x%x\"/>\n",
                        ram_start, 0-ram_start);
        /* ELSE a flash chip could be at the very end of the 32 bit address
@@ -1882,11 +1928,11 @@ static int gdb_memory_map(struct connection *connection,
         */
 
        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 +1953,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 +1967,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:
@@ -1946,12 +1996,45 @@ static const char *gdb_get_reg_type_name(enum reg_type type)
        return "int"; /* "int" as default value */
 }
 
+static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], const char *type_id,
+                                       int *num_arch_defined_types)
+{
+       int tbl_sz = *num_arch_defined_types;
+
+       if (type_id != NULL && (strcmp(type_id, ""))) {
+               for (int j = 0; j < (tbl_sz + 1); j++) {
+                       if (!((*arch_defined_types_list)[j])) {
+                               (*arch_defined_types_list)[tbl_sz++] = type_id;
+                               *arch_defined_types_list = realloc(*arch_defined_types_list,
+                                                               sizeof(char *) * (tbl_sz + 1));
+                               (*arch_defined_types_list)[tbl_sz] = NULL;
+                               *num_arch_defined_types = tbl_sz;
+                               return 1;
+                       } else {
+                               if (!strcmp((*arch_defined_types_list)[j], type_id))
+                                       return 0;
+                       }
+               }
+       }
+
+       return -1;
+}
+
 static int gdb_generate_reg_type_description(struct target *target,
-               char **tdesc, int *pos, int *size, struct reg_data_type *type)
+               char **tdesc, int *pos, int *size, struct reg_data_type *type,
+               char const **arch_defined_types_list[], int * num_arch_defined_types)
 {
        int retval = ERROR_OK;
 
        if (type->type_class == REG_TYPE_CLASS_VECTOR) {
+               struct reg_data_type *data_type = type->reg_type_vector->type;
+               if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+                       if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+                                                       num_arch_defined_types))
+                               gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+                                                               arch_defined_types_list,
+                                                               num_arch_defined_types);
+               }
                /* <vector id="id" type="type" count="count"/> */
                xml_printf(&retval, tdesc, pos, size,
                                "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
@@ -1959,6 +2042,20 @@ static int gdb_generate_reg_type_description(struct target *target,
                                type->reg_type_vector->count);
 
        } else if (type->type_class == REG_TYPE_CLASS_UNION) {
+               struct reg_data_type_union_field *field;
+               field = type->reg_type_union->fields;
+               while (field != NULL) {
+                       struct reg_data_type *data_type = field->type;
+                       if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+                               if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+                                                               num_arch_defined_types))
+                                       gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+                                                                       arch_defined_types_list,
+                                                                       num_arch_defined_types);
+                       }
+
+                       field = field->next;
+               }
                /* <union id="id">
                 *  <field name="name" type="type"/> ...
                 * </union> */
@@ -1966,7 +2063,6 @@ static int gdb_generate_reg_type_description(struct target *target,
                                "<union id=\"%s\">\n",
                                type->id);
 
-               struct reg_data_type_union_field *field;
                field = type->reg_type_union->fields;
                while (field != NULL) {
                        xml_printf(&retval, tdesc, pos, size,
@@ -1992,13 +2088,24 @@ 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;
                        }
                } else {
+                       while (field != NULL) {
+                               struct reg_data_type *data_type = field->type;
+                               if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+                                       if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+                                                                       num_arch_defined_types))
+                                               gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+                                                                               arch_defined_types_list,
+                                                                               num_arch_defined_types);
+                               }
+                       }
+
                        /* <struct id="id">
                         *  <field name="name" type="type"/> ...
                         * </struct> */
@@ -2029,8 +2136,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;
                }
@@ -2090,12 +2198,17 @@ 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,
                        &reg_list_size, REG_CLASS_ALL);
 
@@ -2127,6 +2240,12 @@ 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]) {
@@ -2148,8 +2267,13 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
                                if (reg_list[i]->reg_data_type != NULL) {
                                        if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) {
                                                /* generate <type... first, if there are architecture-defined types. */
-                                               gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
-                                                               reg_list[i]->reg_data_type);
+                                               if (lookup_add_arch_defined_types(&arch_defined_types,
+                                                                               reg_list[i]->reg_data_type->id,
+                                                                               &num_arch_defined_types))
+                                                       gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
+                                                                                       reg_list[i]->reg_data_type,
+                                                                                       &arch_defined_types,
+                                                                                       &num_arch_defined_types);
 
                                                type_str = reg_list[i]->reg_data_type->id;
                                        } else {
@@ -2199,6 +2323,7 @@ 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;
@@ -2270,6 +2395,8 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        char const **features = NULL;
        int feature_list_size = 0;
 
+       char const *architecture = target_get_gdb_arch(target);
+
        retval = target_get_gdb_reg_list(target, &reg_list,
                        &reg_list_size, REG_CLASS_ALL);
        if (retval != ERROR_OK) {
@@ -2291,7 +2418,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;
@@ -2375,7 +2502,11 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
        else
                transfer_type = 'l';
 
-       *chunk = malloc(length + 2);
+       *chunk = malloc(length + 2 + 3);
+    /* 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 */
        if (*chunk == NULL) {
                LOG_ERROR("Unable to allocate memory");
                return ERROR_FAIL;
@@ -2596,6 +2727,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);
@@ -2622,6 +2754,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;
@@ -2637,9 +2772,20 @@ 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;
@@ -2673,15 +2819,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);
@@ -2868,9 +3037,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);
 }
 
@@ -3062,7 +3234,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;
@@ -3165,7 +3337,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;
                        }
 
@@ -3220,6 +3392,8 @@ 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);
+
        gdb_service->target = target;
        gdb_service->core[0] = -1;
        gdb_service->core[1] = -1;
@@ -3245,16 +3419,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.
@@ -3279,11 +3473,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;
@@ -3354,6 +3543,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)
 {
@@ -3475,6 +3673,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,
@@ -3505,3 +3710,9 @@ int gdb_register_commands(struct command_context *cmd_ctx)
        gdb_port_next = strdup("3333");
        return register_commands(cmd_ctx, NULL, gdb_command_handlers);
 }
+
+void gdb_service_free(void)
+{
+       free(gdb_port);
+       free(gdb_port_next);
+}

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)