ipdbg: fix double free of virtual-ir data
[openocd.git] / src / server / gdb_server.c
index d1bcfb5406b8c3ca5b04e421b9c42b49cca85541..c1ee4aa2a18606c746cf97b7ba58d137d1955d28 100644 (file)
@@ -53,6 +53,8 @@
 enum gdb_output_flag {
        /* GDB doesn't accept 'O' packets */
        GDB_OUTPUT_NO,
+       /* GDB doesn't accept 'O' packets but accepts notifications */
+       GDB_OUTPUT_NOTIF,
        /* GDB accepts 'O' packets */
        GDB_OUTPUT_ALL,
 };
@@ -71,6 +73,8 @@ struct gdb_connection {
        enum target_state frontend_state;
        struct image *vflash_image;
        bool closed;
+       /* set to prevent re-entrance from log messages during gdb_get_packet()
+        * and gdb_put_packet(). */
        bool busy;
        int noack_mode;
        /* set flag to true if you want the next stepi to return immediately.
@@ -1001,9 +1005,6 @@ static int gdb_new_connection(struct connection *connection)
        gdb_connection->output_flag = GDB_OUTPUT_NO;
        gdb_connection->unique_index = next_unique_id++;
 
-       /* send ACK to GDB for debug request */
-       gdb_write(connection, "+", 1);
-
        /* output goes through gdb connection */
        command_set_output_handler(connection->cmd_ctx, gdb_output, connection);
 
@@ -1489,9 +1490,6 @@ static int gdb_error(struct connection *connection, int retval)
        return ERROR_OK;
 }
 
-/* We don't have to worry about the default 2 second timeout for GDB packets,
- * because GDB breaks up large memory reads into smaller reads.
- */
 static int gdb_read_memory_packet(struct connection *connection,
                char const *packet, int packet_size)
 {
@@ -3286,7 +3284,7 @@ static int gdb_v_packet(struct connection *connection,
        }
 
        if (strncmp(packet, "vFlashErase:", 12) == 0) {
-               unsigned long addr;
+               target_addr_t addr;
                unsigned long length;
 
                char const *parse = packet + 12;
@@ -3295,7 +3293,7 @@ static int gdb_v_packet(struct connection *connection,
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
 
-               addr = strtoul(parse, (char **)&parse, 16);
+               addr = strtoull(parse, (char **)&parse, 16);
 
                if (*(parse++) != ',' || *parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
@@ -3343,7 +3341,7 @@ static int gdb_v_packet(struct connection *connection,
 
        if (strncmp(packet, "vFlashWrite:", 12) == 0) {
                int retval;
-               unsigned long addr;
+               target_addr_t addr;
                unsigned long length;
                char const *parse = packet + 12;
 
@@ -3351,7 +3349,8 @@ static int gdb_v_packet(struct connection *connection,
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
-               addr = strtoul(parse, (char **)&parse, 16);
+
+               addr = strtoull(parse, (char **)&parse, 16);
                if (*(parse++) != ':') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
@@ -3378,6 +3377,13 @@ static int gdb_v_packet(struct connection *connection,
        if (strncmp(packet, "vFlashDone", 10) == 0) {
                uint32_t written;
 
+               /* GDB command 'flash-erase' does not send a vFlashWrite,
+                * so nothing to write here. */
+               if (!gdb_connection->vflash_image) {
+                       gdb_put_packet(connection, "OK", 2);
+                       return ERROR_OK;
+               }
+
                /* process the flashing buffer. No need to erase as GDB
                 * always issues a vFlashErase first. */
                target_call_event_callbacks(target,
@@ -3472,7 +3478,7 @@ static void gdb_log_callback(void *priv, const char *file, unsigned line,
        struct connection *connection = priv;
        struct gdb_connection *gdb_con = connection->priv;
 
-       if (gdb_con->output_flag == GDB_OUTPUT_NO)
+       if (gdb_con->output_flag != GDB_OUTPUT_ALL)
                /* No out allowed */
                return;
 
@@ -3557,10 +3563,14 @@ static int gdb_input_inner(struct connection *connection)
                                        retval = gdb_set_register_packet(connection, packet, packet_size);
                                        break;
                                case 'm':
+                                       gdb_con->output_flag = GDB_OUTPUT_NOTIF;
                                        retval = gdb_read_memory_packet(connection, packet, packet_size);
+                                       gdb_con->output_flag = GDB_OUTPUT_NO;
                                        break;
                                case 'M':
+                                       gdb_con->output_flag = GDB_OUTPUT_NOTIF;
                                        retval = gdb_write_memory_packet(connection, packet, packet_size);
+                                       gdb_con->output_flag = GDB_OUTPUT_NO;
                                        break;
                                case 'z':
                                case 'Z':
@@ -3651,9 +3661,9 @@ static int gdb_input_inner(struct connection *connection)
                                        retval = gdb_detach(connection);
                                        break;
                                case 'X':
+                                       gdb_con->output_flag = GDB_OUTPUT_NOTIF;
                                        retval = gdb_write_memory_binary_packet(connection, packet, packet_size);
-                                       if (retval != ERROR_OK)
-                                               return retval;
+                                       gdb_con->output_flag = GDB_OUTPUT_NO;
                                        break;
                                case 'k':
                                        if (gdb_con->extended_protocol) {
@@ -3749,19 +3759,51 @@ static int gdb_input(struct connection *connection)
        return ERROR_OK;
 }
 
+/*
+ * Send custom notification packet as keep-alive during memory read/write.
+ *
+ * From gdb 7.0 (released 2009-10-06) an unknown notification received during
+ * memory read/write would be silently dropped.
+ * Before gdb 7.0 any character, with exclusion of "+-$", would be considered
+ * as junk and ignored.
+ * In both cases the reception will reset the timeout counter in gdb, thus
+ * working as a keep-alive.
+ * Check putpkt_binary() and getpkt_sane() in gdb commit
+ * 74531fed1f2d662debc2c209b8b3faddceb55960
+ *
+ * Enable remote debug in gdb with 'set debug remote 1' to either dump the junk
+ * characters in gdb pre-7.0 and the notification from gdb 7.0.
+ */
+static void gdb_async_notif(struct connection *connection)
+{
+       static unsigned char count;
+       unsigned char checksum = 0;
+       char buf[22];
+
+       int len = sprintf(buf, "%%oocd_keepalive:%2.2x", count++);
+       for (int i = 1; i < len; i++)
+               checksum += buf[i];
+       len += sprintf(buf + len, "#%2.2x", checksum);
+
+#ifdef _DEBUG_GDB_IO_
+       LOG_DEBUG("sending packet '%s'", buf);
+#endif
+
+       gdb_write(connection, buf, len);
+}
+
 static void gdb_keep_client_alive(struct connection *connection)
 {
        struct gdb_connection *gdb_con = connection->priv;
 
-       if (gdb_con->busy) {
-               /* do not send packets, retry asap */
-               return;
-       }
-
        switch (gdb_con->output_flag) {
        case GDB_OUTPUT_NO:
                /* no need for keep-alive */
                break;
+       case GDB_OUTPUT_NOTIF:
+               /* send asynchronous notification */
+               gdb_async_notif(connection);
+               break;
        case GDB_OUTPUT_ALL:
                /* send an empty O packet */
                gdb_output_con(connection, "");

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)