gdb_server: Don't modify "buf" argument in decode_xfer_read()
[openocd.git] / src / server / gdb_server.c
index 660e05ef949c3be64c0e38955bfd49ffa921ca22..0b28287d80a7c8ee22f69a7f18d72ad3e69f0162 100644 (file)
@@ -104,8 +104,8 @@ static int gdb_breakpoint_override;
 static enum breakpoint_type gdb_breakpoint_override_type;
 
 static int gdb_error(struct connection *connection, int retval);
-static const char *gdb_port;
-static const char *gdb_port_next;
+static char *gdb_port;
+static char *gdb_port_next;
 
 static void gdb_log_callback(void *priv, const char *file, unsigned line,
                const char *function, const char *string);
@@ -617,11 +617,21 @@ static int gdb_get_packet_inner(struct connection *connection,
                                case '$':
                                        break;
                                case '+':
-                                       /* gdb sends a dummy ack '+' at every remote connect - see
-                                        * remote_start_remote (remote.c)
-                                        * in case anyone tries to debug why they receive this
-                                        * warning every time */
-                                       LOG_WARNING("acknowledgment received, but no packet pending");
+                                       /* According to the GDB documentation
+                                        * (https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html):
+                                        * "gdb sends a final `+` acknowledgment of the stub's `OK`
+                                        * response, which can be safely ignored by the stub."
+                                        * However OpenOCD server already is in noack mode at this
+                                        * point and instead of ignoring this it was emitting a
+                                        * warning. This code makes server ignore the first ACK
+                                        * that will be received after going into noack mode,
+                                        * warning only about subsequent ACK's. */
+                                       if (gdb_con->noack_mode > 1) {
+                                               LOG_WARNING("acknowledgment received, but no packet pending");
+                                       } else {
+                                               LOG_DEBUG("Received first acknowledgment after entering noack mode. Ignoring it.");
+                                               gdb_con->noack_mode = 2;
+                                       }
                                        break;
                                case '-':
                                        LOG_WARNING("negative acknowledgment, but no packet pending");
@@ -728,15 +738,15 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
                                switch (hit_wp_type) {
                                        case WPT_WRITE:
                                                snprintf(stop_reason, sizeof(stop_reason),
-                                                               "watch:%08x;", hit_wp_address);
+                                                               "watch:%08" PRIx32 ";", hit_wp_address);
                                                break;
                                        case WPT_READ:
                                                snprintf(stop_reason, sizeof(stop_reason),
-                                                               "rwatch:%08x;", hit_wp_address);
+                                                               "rwatch:%08" PRIx32 ";", hit_wp_address);
                                                break;
                                        case WPT_ACCESS:
                                                snprintf(stop_reason, sizeof(stop_reason),
-                                                               "awatch:%08x;", hit_wp_address);
+                                                               "awatch:%08" PRIx32 ";", hit_wp_address);
                                                break;
                                        default:
                                                break;
@@ -761,64 +771,64 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
        bool program_exited = false;
 
        if (strcmp(target->fileio_info->identifier, "open") == 0)
-               sprintf(fileio_command, "F%s,%x/%x,%x,%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2,
                                target->fileio_info->param_3,
                                target->fileio_info->param_4);
        else if (strcmp(target->fileio_info->identifier, "close") == 0)
-               sprintf(fileio_command, "F%s,%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1);
        else if (strcmp(target->fileio_info->identifier, "read") == 0)
-               sprintf(fileio_command, "F%s,%x,%x,%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2,
                                target->fileio_info->param_3);
        else if (strcmp(target->fileio_info->identifier, "write") == 0)
-               sprintf(fileio_command, "F%s,%x,%x,%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2,
                                target->fileio_info->param_3);
        else if (strcmp(target->fileio_info->identifier, "lseek") == 0)
-               sprintf(fileio_command, "F%s,%x,%x,%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2,
                                target->fileio_info->param_3);
        else if (strcmp(target->fileio_info->identifier, "rename") == 0)
-               sprintf(fileio_command, "F%s,%x/%x,%x/%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2,
                                target->fileio_info->param_3,
                                target->fileio_info->param_4);
        else if (strcmp(target->fileio_info->identifier, "unlink") == 0)
-               sprintf(fileio_command, "F%s,%x/%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2);
        else if (strcmp(target->fileio_info->identifier, "stat") == 0)
-               sprintf(fileio_command, "F%s,%x/%x,%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2,
                                target->fileio_info->param_3);
        else if (strcmp(target->fileio_info->identifier, "fstat") == 0)
-               sprintf(fileio_command, "F%s,%x,%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2);
        else if (strcmp(target->fileio_info->identifier, "gettimeofday") == 0)
-               sprintf(fileio_command, "F%s,%x,%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2);
        else if (strcmp(target->fileio_info->identifier, "isatty") == 0)
-               sprintf(fileio_command, "F%s,%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1);
        else if (strcmp(target->fileio_info->identifier, "system") == 0)
-               sprintf(fileio_command, "F%s,%x/%x", target->fileio_info->identifier,
+               sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
                                target->fileio_info->param_1,
                                target->fileio_info->param_2);
        else if (strcmp(target->fileio_info->identifier, "exit") == 0) {
                /* If target hits exit syscall, report to GDB the program is terminated.
                 * In addition, let target run its own exit syscall handler. */
                program_exited = true;
-               sprintf(fileio_command, "W%02x", target->fileio_info->param_1);
+               sprintf(fileio_command, "W%02" PRIx32, target->fileio_info->param_1);
        } else {
                LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier);
 
@@ -957,6 +967,9 @@ static int gdb_new_connection(struct connection *connection)
                int i;
                for (i = 0; i < flash_get_bank_count(); i++) {
                        struct flash_bank *p;
+                       p = get_flash_bank_by_num_noprobe(i);
+                       if (p->target != gdb_service->target)
+                               continue;
                        retval = get_flash_bank_by_num(i, &p);
                        if (retval != ERROR_OK) {
                                LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target " \
@@ -1349,6 +1362,12 @@ static int gdb_read_memory_packet(struct connection *connection,
 
        len = strtoul(separator + 1, NULL, 16);
 
+       if (!len) {
+               LOG_WARNING("invalid read memory packet received (len == 0)");
+               gdb_put_packet(connection, NULL, 0);
+               return ERROR_OK;
+       }
+
        buffer = malloc(len);
 
        LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
@@ -1503,10 +1522,9 @@ static int gdb_step_continue_packet(struct connection *connection,
 
        LOG_DEBUG("-");
 
-       if (packet_size > 1) {
-               packet[packet_size] = 0;
+       if (packet_size > 1)
                address = strtoul(packet + 1, NULL, 16);
-       else
+       else
                current = 1;
 
        gdb_running_type = packet[0];
@@ -1651,29 +1669,41 @@ static void xml_printf(int *retval, char **xml, int *pos, int *size,
        }
 }
 
-static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len)
+static int decode_xfer_read(char *_buf, char **annex, int *ofs, unsigned int *len)
 {
+       int ret = 0;
+       char *buf = strdup(_buf);
+       char *_annex;
        char *separator;
 
        /* Extract and NUL-terminate the annex. */
-       *annex = buf;
+       _annex = buf;
        while (*buf && *buf != ':')
                buf++;
-       if (*buf == '\0')
-               return -1;
+       if (*buf == '\0') {
+               ret = -1;
+               goto out;
+       }
        *buf++ = 0;
 
+       /* Return annex as copy because "buf" will be freed in this function */
+       *annex = strdup(_annex);
+
        /* After the read marker and annex, qXfer looks like a
         * traditional 'm' packet. */
 
        *ofs = strtoul(buf, &separator, 16);
 
-       if (*separator != ',')
-               return -1;
+       if (*separator != ',') {
+               ret = -1;
+               goto out;
+       }
 
        *len = strtoul(separator + 1, NULL, 16);
 
-       return 0;
+out:
+       free(buf);
+       return ret;
 }
 
 static int compare_bank(const void *a, const void *b)
@@ -1732,14 +1762,16 @@ static int gdb_memory_map(struct connection *connection,
        banks = malloc(sizeof(struct flash_bank *)*flash_get_bank_count());
 
        for (i = 0; i < flash_get_bank_count(); i++) {
+               p = get_flash_bank_by_num_noprobe(i);
+               if (p->target != target)
+                       continue;
                retval = get_flash_bank_by_num(i, &p);
                if (retval != ERROR_OK) {
                        free(banks);
                        gdb_error(connection, retval);
                        return retval;
                }
-               if (p->target == target)
-                       banks[target_flash_banks++] = p;
+               banks[target_flash_banks++] = p;
        }
 
        qsort(banks, target_flash_banks, sizeof(struct flash_bank *),
@@ -1988,7 +2020,8 @@ static int get_reg_features_list(struct target *target, char **feature_list[], i
                if (reg_list[i]->exist == false)
                        continue;
 
-               if ((reg_list[i]->feature->name != NULL)
+               if (reg_list[i]->feature != NULL
+                       && reg_list[i]->feature->name != NULL
                        && (strcmp(reg_list[i]->feature->name, ""))) {
                        /* We found a feature, check if the feature is already in the
                         * table. If not, allocate a new entry for the table and
@@ -2193,6 +2226,7 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        struct reg **reg_list = NULL;
        int reg_list_size = 0;
        int feature_list_size = 0;
+       char **features = NULL;
 
        retval = target_get_gdb_reg_list(target, &reg_list,
                        &reg_list_size, REG_CLASS_ALL);
@@ -2206,7 +2240,6 @@ static int gdb_target_description_supported(struct target *target, int *supporte
                goto error;
        }
 
-       char **features = NULL;
        /* Get a list of available target registers features */
        retval = get_reg_features_list(target, &features, &feature_list_size, reg_list, reg_list_size);
        if (retval != ERROR_OK) {
@@ -2343,7 +2376,7 @@ static int gdb_query_packet(struct connection *connection,
 
                int offset;
                unsigned int length;
-               char *annex;
+               char *annex = NULL;
 
                /* skip command character */
                packet += 20;
@@ -2352,6 +2385,7 @@ static int gdb_query_packet(struct connection *connection,
                        gdb_send_error(connection, 01);
                        return ERROR_OK;
                }
+               free(annex);
 
                /* Target should prepare correct target description for annex.
                 * The first character of returned xml is 'm' or 'l'. 'm' for
@@ -2900,7 +2934,7 @@ static int gdb_target_add_one(struct target *target)
                portnumber = strtol(gdb_port_next, &end, 0);
                if (!*end) {
                        if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) {
-                               free((void *)gdb_port_next);
+                               free(gdb_port_next);
                                gdb_port_next = alloc_printf("%d", portnumber+1);
                        }
                }
@@ -2947,7 +2981,7 @@ COMMAND_HANDLER(handle_gdb_port_command)
 {
        int retval = CALL_COMMAND_HANDLER(server_pipe_command, &gdb_port);
        if (ERROR_OK == retval) {
-               free((void *)gdb_port_next);
+               free(gdb_port_next);
                gdb_port_next = strdup(gdb_port);
        }
        return retval;

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)