]> git.sur5r.net Git - openocd/blobdiff - src/server/gdb_server.c
Perform small writes before sending OK.
[openocd] / src / server / gdb_server.c
index 7bf7319c54cc60b338951f953890d1a457bb357f..7fd579b4651170052c78dd53e0a6119e11167ab3 100644 (file)
@@ -31,9 +31,7 @@
  *   GNU General Public License for more details.                          *
  *                                                                         *
  *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -628,7 +626,7 @@ static int gdb_get_packet_inner(struct connection *connection,
                                         * warning only about subsequent ACK's. */
                                        if (gdb_con->noack_mode > 1) {
                                                LOG_WARNING("acknowledgment received, but no packet pending");
-                                       } else {
+                                       } else if (gdb_con->noack_mode) {
                                                LOG_DEBUG("Received first acknowledgment after entering noack mode. Ignoring it.");
                                                gdb_con->noack_mode = 2;
                                        }
@@ -714,11 +712,14 @@ static int gdb_output(struct command_context *context, const char *line)
 static void gdb_signal_reply(struct target *target, struct connection *connection)
 {
        struct gdb_connection *gdb_connection = connection->priv;
-       char sig_reply[20];
+       char sig_reply[45];
        char stop_reason[20];
+       char current_thread[25];
        int sig_reply_len;
        int signal_var;
 
+       rtos_update_threads(target);
+
        if (target->debug_reason == DBG_REASON_EXIT) {
                sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "W00");
        } else {
@@ -754,13 +755,18 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
                        }
                }
 
-               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s",
-                               signal_var, stop_reason);
+               current_thread[0] = '\0';
+               if (target->rtos != NULL) {
+                       snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", target->rtos->current_thread);
+                       target->rtos->current_threadid = target->rtos->current_thread;
+               }
+
+               sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s",
+                               signal_var, stop_reason, current_thread);
        }
 
        gdb_put_packet(connection, sig_reply, sig_reply_len);
        gdb_connection->frontend_state = TARGET_HALTED;
-       rtos_update_threads(target);
 }
 
 static void gdb_fileio_reply(struct target *target, struct connection *connection)
@@ -1044,7 +1050,7 @@ static void gdb_send_error(struct connection *connection, uint8_t the_error)
 }
 
 static int gdb_last_signal_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        struct gdb_connection *gdb_con = connection->priv;
@@ -1101,7 +1107,7 @@ static void gdb_str_to_target(struct target *target,
 
 /* copy over in register buffer */
 static void gdb_target_to_reg(struct target *target,
-               char *tstr, int str_len, uint8_t *bin)
+               char const *tstr, int str_len, uint8_t *bin)
 {
        if (str_len % 2) {
                LOG_ERROR("BUG: gdb value with uneven number of characters encountered");
@@ -1122,7 +1128,7 @@ static void gdb_target_to_reg(struct target *target,
 }
 
 static int gdb_get_registers_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        struct reg **reg_list;
@@ -1151,6 +1157,9 @@ static int gdb_get_registers_packet(struct connection *connection,
        assert(reg_packet_size > 0);
 
        reg_packet = malloc(reg_packet_size + 1); /* plus one for string termination null */
+       if (reg_packet == NULL)
+               return ERROR_FAIL;
+
        reg_packet_p = reg_packet;
 
        for (i = 0; i < reg_list_size; i++) {
@@ -1178,14 +1187,14 @@ static int gdb_get_registers_packet(struct connection *connection,
 }
 
 static int gdb_set_registers_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        int i;
        struct reg **reg_list;
        int reg_list_size;
        int retval;
-       char *packet_p;
+       char const *packet_p;
 
 #ifdef _DEBUG_GDB_IO_
        LOG_DEBUG("-");
@@ -1233,7 +1242,7 @@ static int gdb_set_registers_packet(struct connection *connection,
 }
 
 static int gdb_get_register_packet(struct connection *connection,
-       char *packet, int packet_size)
+       char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *reg_packet;
@@ -1272,7 +1281,7 @@ static int gdb_get_register_packet(struct connection *connection,
 }
 
 static int gdb_set_register_packet(struct connection *connection,
-       char *packet, int packet_size)
+       char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
@@ -1338,7 +1347,7 @@ static int gdb_error(struct connection *connection, int retval)
  * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192?????
  */
 static int gdb_read_memory_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
@@ -1409,7 +1418,7 @@ static int gdb_read_memory_packet(struct connection *connection,
 }
 
 static int gdb_write_memory_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
@@ -1440,7 +1449,7 @@ static int gdb_write_memory_packet(struct connection *connection,
 
        LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len);
 
-       if (unhexify((char *)buffer, separator, len) != (int)len)
+       if (unhexify(buffer, separator, len) != len)
                LOG_ERROR("unable to decode memory packet");
 
        retval = target_write_buffer(target, addr, len, buffer);
@@ -1456,7 +1465,7 @@ static int gdb_write_memory_packet(struct connection *connection,
 }
 
 static int gdb_write_memory_binary_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
@@ -1464,6 +1473,10 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
        uint32_t len = 0;
 
        int retval = ERROR_OK;
+       /* Packets larger than fast_limit bytes will be acknowledged instantly on
+        * the assumption that we're in a download and it's important to go as fast
+        * as possible. */
+       uint32_t fast_limit = 8;
 
        /* skip command character */
        packet++;
@@ -1484,19 +1497,23 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
 
        struct gdb_connection *gdb_connection = connection->priv;
 
-       if (gdb_connection->mem_write_error) {
+       if (gdb_connection->mem_write_error)
                retval = ERROR_FAIL;
-               /* now that we have reported the memory write error, we can clear the condition */
-               gdb_connection->mem_write_error = false;
-       }
 
-       /* By replying the packet *immediately* GDB will send us a new packet
-        * while we write the last one to the target.
-        */
-       if (retval == ERROR_OK)
-               gdb_put_packet(connection, "OK", 2);
-       else {
+       if (retval == ERROR_OK) {
+               if (len >= fast_limit) {
+                       /* By replying the packet *immediately* GDB will send us a new packet
+                        * while we write the last one to the target.
+                        * We only do this for larger writes, so that users who do something like:
+                        * p *((int*)0xdeadbeef)=8675309
+                        * will get immediate feedback that that write failed.
+                        */
+                       gdb_put_packet(connection, "OK", 2);
+               }
+       } else {
                retval = gdb_error(connection, retval);
+               /* now that we have reported the memory write error, we can clear the condition */
+               gdb_connection->mem_write_error = false;
                if (retval != ERROR_OK)
                        return retval;
        }
@@ -1509,11 +1526,20 @@ static int gdb_write_memory_binary_packet(struct connection *connection,
                        gdb_connection->mem_write_error = true;
        }
 
+       if (len < fast_limit) {
+               if (retval != ERROR_OK) {
+                       gdb_error(connection, retval);
+                       gdb_connection->mem_write_error = false;
+               } else {
+                       gdb_put_packet(connection, "OK", 2);
+               }
+       }
+
        return ERROR_OK;
 }
 
 static int gdb_step_continue_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        int current = 0;
@@ -1522,10 +1548,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];
@@ -1542,7 +1567,7 @@ static int gdb_step_continue_packet(struct connection *connection,
 }
 
 static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        int type;
@@ -1670,29 +1695,31 @@ 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 const *buf, char **annex, int *ofs, unsigned int *len)
 {
-       char *separator;
-
-       /* Extract and NUL-terminate the annex. */
-       *annex = buf;
-       while (*buf && *buf != ':')
-               buf++;
-       if (*buf == '\0')
-               return -1;
-       *buf++ = 0;
+       /* Locate the annex. */
+       const char *annex_end = strchr(buf, ':');
+       if (annex_end == NULL)
+               return ERROR_FAIL;
 
        /* After the read marker and annex, qXfer looks like a
         * traditional 'm' packet. */
-
-       *ofs = strtoul(buf, &separator, 16);
+       char *separator;
+       *ofs = strtoul(annex_end + 1, &separator, 16);
 
        if (*separator != ',')
-               return -1;
+               return ERROR_FAIL;
 
        *len = strtoul(separator + 1, NULL, 16);
 
-       return 0;
+       /* Extract the annex if needed */
+       if (annex != NULL) {
+               *annex = strndup(buf, annex_end - buf);
+               if (*annex == NULL)
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
 }
 
 static int compare_bank(const void *a, const void *b)
@@ -1710,7 +1737,7 @@ static int compare_bank(const void *a, const void *b)
 }
 
 static int gdb_memory_map(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        /* We get away with only specifying flash here. Regions that are not
         * specified are treated as if we provided no memory map(if not we
@@ -1997,7 +2024,7 @@ static int gdb_generate_reg_type_description(struct target *target,
 /* Get a list of available target registers features. feature_list must
  * be freed by caller.
  */
-static int get_reg_features_list(struct target *target, char **feature_list[], int *feature_list_size,
+static int get_reg_features_list(struct target *target, char const **feature_list[], int *feature_list_size,
                struct reg **reg_list, int reg_list_size)
 {
        int tbl_sz = 0;
@@ -2018,7 +2045,7 @@ static int get_reg_features_list(struct target *target, char **feature_list[], i
                         */
                        for (int j = 0; j < (tbl_sz + 1); j++) {
                                if (!((*feature_list)[j])) {
-                                       (*feature_list)[tbl_sz++] = strdup(reg_list[i]->feature->name);
+                                       (*feature_list)[tbl_sz++] = reg_list[i]->feature->name;
                                        *feature_list = realloc(*feature_list, sizeof(char *) * (tbl_sz + 1));
                                        (*feature_list)[tbl_sz] = NULL;
                                        break;
@@ -2039,8 +2066,10 @@ static int get_reg_features_list(struct target *target, char **feature_list[], i
 static int gdb_generate_target_description(struct target *target, char **tdesc_out)
 {
        int retval = ERROR_OK;
-       struct reg **reg_list;
+       struct reg **reg_list = NULL;
        int reg_list_size;
+       char const **features = NULL;
+       int feature_list_size = 0;
        char *tdesc = NULL;
        int pos = 0;
        int size = 0;
@@ -2050,21 +2079,22 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
 
        if (retval != ERROR_OK) {
                LOG_ERROR("get register list failed");
-               return ERROR_FAIL;
+               retval = ERROR_FAIL;
+               goto error;
        }
 
        if (reg_list_size <= 0) {
-               free(reg_list);
-               return ERROR_FAIL;
+               LOG_ERROR("get register list failed");
+               retval = ERROR_FAIL;
+               goto error;
        }
 
-       char **features = NULL;
        /* Get a list of available target registers features */
-       retval = get_reg_features_list(target, &features, NULL, reg_list, reg_list_size);
+       retval = get_reg_features_list(target, &features, &feature_list_size, reg_list, reg_list_size);
        if (retval != ERROR_OK) {
                LOG_ERROR("Can't get the registers feature list");
-               free(reg_list);
-               return ERROR_FAIL;
+               retval = ERROR_FAIL;
+               goto error;
        }
 
        /* If we found some features associated with registers, create sections */
@@ -2144,8 +2174,9 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
        xml_printf(&retval, &tdesc, &pos, &size,
                        "</target>\n");
 
-       free(reg_list);
+error:
        free(features);
+       free(reg_list);
 
        if (retval == ERROR_OK)
                *tdesc_out = tdesc;
@@ -2214,8 +2245,8 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        int retval = ERROR_OK;
        struct reg **reg_list = NULL;
        int reg_list_size = 0;
+       char const **features = NULL;
        int feature_list_size = 0;
-       char **features = NULL;
 
        retval = target_get_gdb_reg_list(target, &reg_list,
                        &reg_list_size, REG_CLASS_ALL);
@@ -2225,6 +2256,7 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        }
 
        if (reg_list_size <= 0) {
+               LOG_ERROR("get register list failed");
                retval = ERROR_FAIL;
                goto error;
        }
@@ -2244,17 +2276,15 @@ static int gdb_target_description_supported(struct target *target, int *supporte
        }
 
 error:
-       if (reg_list != NULL)
-               free(reg_list);
+       free(features);
 
-       if (features != NULL)
-               free(features);
+       free(reg_list);
 
        return retval;
 }
 
 static int gdb_query_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct command_context *cmd_ctx = connection->cmd_ctx;
        struct gdb_connection *gdb_connection = connection->priv;
@@ -2264,7 +2294,7 @@ static int gdb_query_packet(struct connection *connection,
                if (packet_size > 6) {
                        char *cmd;
                        cmd = malloc((packet_size - 6) / 2 + 1);
-                       int len = unhexify(cmd, packet + 6, (packet_size - 6) / 2);
+                       size_t len = unhexify((uint8_t *)cmd, packet + 6, (packet_size - 6) / 2);
                        cmd[len] = 0;
 
                        /* We want to print all debug output to GDB connection */
@@ -2365,12 +2395,11 @@ static int gdb_query_packet(struct connection *connection,
 
                int offset;
                unsigned int length;
-               char *annex;
 
                /* skip command character */
                packet += 20;
 
-               if (decode_xfer_read(packet, &annex, &offset, &length) < 0) {
+               if (decode_xfer_read(packet, NULL, &offset, &length) < 0) {
                        gdb_send_error(connection, 01);
                        return ERROR_OK;
                }
@@ -2402,7 +2431,7 @@ static int gdb_query_packet(struct connection *connection,
 }
 
 static int gdb_v_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct gdb_connection *gdb_connection = connection->priv;
        struct gdb_service *gdb_service = connection->service->priv;
@@ -2419,20 +2448,20 @@ static int gdb_v_packet(struct connection *connection,
                unsigned long addr;
                unsigned long length;
 
-               char *parse = packet + 12;
+               char const *parse = packet + 12;
                if (*parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
 
-               addr = strtoul(parse, &parse, 16);
+               addr = strtoul(parse, (char **)&parse, 16);
 
                if (*(parse++) != ',' || *parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
 
-               length = strtoul(parse, &parse, 16);
+               length = strtoul(parse, (char **)&parse, 16);
 
                if (*parse != '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
@@ -2475,13 +2504,13 @@ static int gdb_v_packet(struct connection *connection,
                int retval;
                unsigned long addr;
                unsigned long length;
-               char *parse = packet + 12;
+               char const *parse = packet + 12;
 
                if (*parse == '\0') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
                }
-               addr = strtoul(parse, &parse, 16);
+               addr = strtoul(parse, (char **)&parse, 16);
                if (*(parse++) != ':') {
                        LOG_ERROR("incomplete vFlashErase packet received, dropping connection");
                        return ERROR_SERVER_REMOTE_CLOSED;
@@ -2496,7 +2525,7 @@ static int gdb_v_packet(struct connection *connection,
 
                /* create new section with content from packet buffer */
                retval = image_add_section(gdb_connection->vflash_image,
-                               addr, length, 0x0, (uint8_t *)parse);
+                               addr, length, 0x0, (uint8_t const *)parse);
                if (retval != ERROR_OK)
                        return retval;
 
@@ -2548,7 +2577,7 @@ static int gdb_detach(struct connection *connection)
  * Fretcode,errno,Ctrl-C flag;call-specific attachment
  */
 static int gdb_fileio_response_packet(struct connection *connection,
-               char *packet, int packet_size)
+               char const *packet, int packet_size)
 {
        struct target *target = get_target_from_connection(connection);
        char *separator;
@@ -2620,7 +2649,7 @@ static int gdb_input_inner(struct connection *connection)
 
        struct gdb_service *gdb_service = connection->service->priv;
        struct target *target = gdb_service->target;
-       char *packet = gdb_packet_buffer;
+       char const *packet = gdb_packet_buffer;
        int packet_size;
        int retval;
        struct gdb_connection *gdb_con = connection->priv;
@@ -2639,12 +2668,12 @@ static int gdb_input_inner(struct connection *connection)
         */
        do {
                packet_size = GDB_BUFFER_SIZE-1;
-               retval = gdb_get_packet(connection, packet, &packet_size);
+               retval = gdb_get_packet(connection, gdb_packet_buffer, &packet_size);
                if (retval != ERROR_OK)
                        return retval;
 
                /* terminate with zero */
-               packet[packet_size] = 0;
+               gdb_packet_buffer[packet_size] = '\0';
 
                if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) {
                        if (packet[0] == 'X') {
@@ -2909,6 +2938,11 @@ static int gdb_target_start(struct target *target, const char *port)
 
 static int gdb_target_add_one(struct target *target)
 {
+       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;
@@ -2932,6 +2966,11 @@ 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;
@@ -3049,7 +3088,7 @@ COMMAND_HANDLER(handle_gdb_save_tdesc_command)
 
        tdesc_length = strlen(tdesc);
 
-       struct fileio fileio;
+       struct fileio *fileio;
        size_t size_written;
 
        char *tdesc_filename = alloc_printf("%s.xml", target_type_name(target));
@@ -3065,9 +3104,9 @@ COMMAND_HANDLER(handle_gdb_save_tdesc_command)
                goto out;
        }
 
-       retval = fileio_write(&fileio, tdesc_length, tdesc, &size_written);
+       retval = fileio_write(fileio, tdesc_length, tdesc, &size_written);
 
-       fileio_close(&fileio);
+       fileio_close(fileio);
 
        if (retval != ERROR_OK)
                LOG_ERROR("Error while writing the tdesc file");
@@ -3097,7 +3136,7 @@ static const struct command_registration gdb_command_handlers[] = {
                        "server listens for the next port number after the "
                        "base port number specified. "
                        "No arguments reports GDB port. \"pipe\" means listen to stdin "
-                       "output to stdout, an integer is base port number, \"disable\" disables "
+                       "output to stdout, an integer is base port number, \"disabled\" disables "
                        "port. Any other string is are interpreted as named pipe to listen to. "
                        "Output pipe is the same name as input pipe, but with 'o' appended.",
                .usage = "[port_num]",