+
+ if (reg_list_size <= 0) {
+ LOG_ERROR("get register list failed");
+ retval = ERROR_FAIL;
+ goto error;
+ }
+
+ /* 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) {
+ LOG_ERROR("Can't get the registers feature list");
+ retval = ERROR_FAIL;
+ goto error;
+ }
+
+ /* If we found some features associated with registers, create sections */
+ int current_feature = 0;
+
+ xml_printf(&retval, &tdesc, &pos, &size,
+ "<?xml version=\"1.0\"?>\n"
+ "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n"
+ "<target version=\"1.0\">\n");
+
+ /* generate target description according to register list */
+ if (features != NULL) {
+ while (features[current_feature]) {
+
+ xml_printf(&retval, &tdesc, &pos, &size,
+ "<feature name=\"%s\">\n",
+ features[current_feature]);
+
+ int i;
+ for (i = 0; i < reg_list_size; i++) {
+
+ if (reg_list[i]->exist == false)
+ continue;
+
+ if (strcmp(reg_list[i]->feature->name, features[current_feature]))
+ continue;
+
+ const char *type_str;
+ 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. */
+ 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 {
+ /* predefined type */
+ type_str = gdb_get_reg_type_name(
+ reg_list[i]->reg_data_type->type);
+ }
+ } else {
+ /* Default type is "int" */
+ type_str = "int";
+ }
+
+ xml_printf(&retval, &tdesc, &pos, &size,
+ "<reg name=\"%s\"", reg_list[i]->name);
+ xml_printf(&retval, &tdesc, &pos, &size,
+ " bitsize=\"%d\"", reg_list[i]->size);
+ xml_printf(&retval, &tdesc, &pos, &size,
+ " regnum=\"%d\"", reg_list[i]->number);
+ if (reg_list[i]->caller_save)
+ xml_printf(&retval, &tdesc, &pos, &size,
+ " save-restore=\"yes\"");
+ else
+ xml_printf(&retval, &tdesc, &pos, &size,
+ " save-restore=\"no\"");
+
+ xml_printf(&retval, &tdesc, &pos, &size,
+ " type=\"%s\"", type_str);
+
+ if (reg_list[i]->group != NULL)
+ xml_printf(&retval, &tdesc, &pos, &size,
+ " group=\"%s\"", reg_list[i]->group);
+
+ xml_printf(&retval, &tdesc, &pos, &size,
+ "/>\n");
+ }
+
+ xml_printf(&retval, &tdesc, &pos, &size,
+ "</feature>\n");
+
+ current_feature++;
+ }
+ }
+
+ xml_printf(&retval, &tdesc, &pos, &size,
+ "</target>\n");
+
+error:
+ free(features);
+ free(reg_list);
+ free(arch_defined_types);
+
+ if (retval == ERROR_OK)
+ *tdesc_out = tdesc;
+ else
+ free(tdesc);
+
+ return retval;
+}
+
+static int gdb_get_target_description_chunk(struct target *target, struct target_desc_format *target_desc,
+ char **chunk, int32_t offset, uint32_t length)
+{
+ if (target_desc == NULL) {
+ LOG_ERROR("Unable to Generate Target Description");
+ return ERROR_FAIL;
+ }
+
+ char *tdesc = target_desc->tdesc;
+ uint32_t tdesc_length = target_desc->tdesc_length;
+
+ if (tdesc == NULL) {
+ int retval = gdb_generate_target_description(target, &tdesc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Unable to Generate Target Description");
+ return ERROR_FAIL;
+ }
+
+ tdesc_length = strlen(tdesc);
+ }
+
+ char transfer_type;
+
+ if (length < (tdesc_length - offset))
+ transfer_type = 'm';
+ else
+ transfer_type = 'l';
+
+ *chunk = malloc(length + 2);
+ if (*chunk == NULL) {
+ LOG_ERROR("Unable to allocate memory");
+ return ERROR_FAIL;
+ }
+
+ (*chunk)[0] = transfer_type;
+ if (transfer_type == 'm') {
+ strncpy((*chunk) + 1, tdesc + offset, length);
+ (*chunk)[1 + length] = '\0';
+ } else {
+ strncpy((*chunk) + 1, tdesc + offset, tdesc_length - offset);
+ (*chunk)[1 + (tdesc_length - offset)] = '\0';
+
+ /* After gdb-server sends out last chunk, invalidate tdesc. */
+ free(tdesc);
+ tdesc = NULL;
+ tdesc_length = 0;
+ }
+
+ target_desc->tdesc = tdesc;
+ target_desc->tdesc_length = tdesc_length;
+
+ return ERROR_OK;
+}
+
+static int gdb_target_description_supported(struct target *target, int *supported)
+{
+ int retval = ERROR_OK;
+ struct reg **reg_list = NULL;
+ int reg_list_size = 0;
+ char const **features = NULL;
+ int feature_list_size = 0;
+
+ retval = target_get_gdb_reg_list(target, ®_list,
+ ®_list_size, REG_CLASS_ALL);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("get register list failed");
+ goto error;
+ }
+
+ if (reg_list_size <= 0) {
+ LOG_ERROR("get register list failed");
+ retval = ERROR_FAIL;
+ goto error;
+ }
+
+ /* 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) {
+ LOG_ERROR("Can't get the registers feature list");
+ goto error;
+ }
+
+ if (supported) {
+ if (feature_list_size)
+ *supported = 1;
+ else
+ *supported = 0;
+ }
+
+error:
+ free(features);
+
+ free(reg_list);
+
+ return retval;
+}
+
+static int gdb_generate_thread_list(struct target *target, char **thread_list_out)
+{
+ struct rtos *rtos = target->rtos;
+ int retval = ERROR_OK;
+ char *thread_list = NULL;
+ int pos = 0;
+ int size = 0;
+
+ xml_printf(&retval, &thread_list, &pos, &size,
+ "<?xml version=\"1.0\"?>\n"
+ "<threads>\n");
+
+ if (rtos != NULL) {
+ for (int i = 0; i < rtos->thread_count; i++) {
+ struct thread_detail *thread_detail = &rtos->thread_details[i];
+
+ if (!thread_detail->exists)
+ continue;
+
+ xml_printf(&retval, &thread_list, &pos, &size,
+ "<thread id=\"%" PRIx64 "\">", thread_detail->threadid);
+
+ if (thread_detail->thread_name_str != NULL)
+ xml_printf(&retval, &thread_list, &pos, &size,
+ "Name: %s", thread_detail->thread_name_str);
+
+ if (thread_detail->extra_info_str != NULL) {
+ if (thread_detail->thread_name_str != NULL)
+ xml_printf(&retval, &thread_list, &pos, &size,
+ ", ");
+ xml_printf(&retval, &thread_list, &pos, &size,
+ thread_detail->extra_info_str);
+ }
+
+ xml_printf(&retval, &thread_list, &pos, &size,
+ "</thread>\n");
+ }
+ }
+
+ xml_printf(&retval, &thread_list, &pos, &size,
+ "</threads>\n");
+
+ if (retval == ERROR_OK)
+ *thread_list_out = thread_list;
+ else
+ free(thread_list);
+
+ return retval;
+}
+
+static int gdb_get_thread_list_chunk(struct target *target, char **thread_list,
+ char **chunk, int32_t offset, uint32_t length)
+{
+ if (*thread_list == NULL) {
+ int retval = gdb_generate_thread_list(target, thread_list);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Unable to Generate Thread List");
+ return ERROR_FAIL;
+ }
+ }
+
+ size_t thread_list_length = strlen(*thread_list);
+ char transfer_type;
+
+ length = MIN(length, thread_list_length - offset);
+ if (length < (thread_list_length - offset))
+ transfer_type = 'm';
+ else
+ transfer_type = 'l';
+
+ *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;
+ }
+
+ (*chunk)[0] = transfer_type;
+ strncpy((*chunk) + 1, (*thread_list) + offset, length);
+ (*chunk)[1 + length] = '\0';
+
+ /* After gdb-server sends out last chunk, invalidate thread list. */
+ if (transfer_type == 'l') {
+ free(*thread_list);
+ *thread_list = NULL;
+ }
+
+ return ERROR_OK;
+}
+
+static int gdb_query_packet(struct connection *connection,
+ char const *packet, int packet_size)
+{
+ struct command_context *cmd_ctx = connection->cmd_ctx;
+ struct gdb_connection *gdb_connection = connection->priv;
+ struct target *target = get_target_from_connection(connection);
+
+ if (strncmp(packet, "qRcmd,", 6) == 0) {
+ if (packet_size > 6) {
+ char *cmd;
+ cmd = malloc((packet_size - 6) / 2 + 1);
+ 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 */
+ log_add_callback(gdb_log_callback, connection);
+ target_call_timer_callbacks_now();
+ /* some commands need to know the GDB connection, make note of current
+ * GDB connection. */
+ current_gdb_connection = gdb_connection;
+ command_run_line(cmd_ctx, cmd);
+ current_gdb_connection = NULL;
+ target_call_timer_callbacks_now();
+ log_remove_callback(gdb_log_callback, connection);
+ free(cmd);
+ }
+ gdb_put_packet(connection, "OK", 2);
+ return ERROR_OK;
+ } else if (strncmp(packet, "qCRC:", 5) == 0) {
+ if (packet_size > 5) {
+ int retval;
+ char gdb_reply[10];
+ char *separator;
+ uint32_t checksum;
+ target_addr_t addr = 0;
+ uint32_t len = 0;
+
+ /* skip command character */
+ packet += 5;
+
+ addr = strtoull(packet, &separator, 16);
+
+ if (*separator != ',') {
+ LOG_ERROR("incomplete read memory packet received, dropping connection");
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+
+ len = strtoul(separator + 1, NULL, 16);
+
+ retval = target_checksum_memory(target, addr, len, &checksum);
+
+ if (retval == ERROR_OK) {
+ snprintf(gdb_reply, 10, "C%8.8" PRIx32 "", checksum);
+ gdb_put_packet(connection, gdb_reply, 9);
+ } else {
+ retval = gdb_error(connection, retval);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ return ERROR_OK;
+ }
+ } else if (strncmp(packet, "qSupported", 10) == 0) {
+ /* we currently support packet size and qXfer:memory-map:read (if enabled)
+ * qXfer:features:read is supported for some targets */
+ int retval = ERROR_OK;
+ char *buffer = NULL;