fix flash bank auto_probe() fail with multiple targets
[fw/openocd] / src / server / gdb_server.c
index b9c8e5e83ece6c24917d07dd1588bf4abdcdffb2..28cb3ab71baaa42f2a31f9bb7cfd34a877543e79 100644 (file)
  * found in most modern embedded processors.
  */
 
+struct target_desc_format {
+       char *tdesc;
+       uint32_t tdesc_length;
+};
+
 /* private connection data for GDB */
 struct gdb_connection {
        char buffer[GDB_BUFFER_SIZE];
@@ -85,6 +90,8 @@ struct gdb_connection {
         * normally we reply with a S reply via gdb_last_signal_packet.
         * as a side note this behaviour only effects gdb > 6.8 */
        bool attached;
+       /* temporarily used for target description support */
+       struct target_desc_format target_desc;
 };
 
 #if 0
@@ -97,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);
@@ -122,8 +129,8 @@ static int gdb_report_data_abort;
 
 /* set if we are sending target descriptions to gdb
  * via qXfer:features:read packet */
-/* disabled by default */
-static int gdb_use_target_description;
+/* enabled by default */
+static int gdb_use_target_description = 1;
 
 /* current processing free-run type, used by file-I/O */
 static char gdb_running_type;
@@ -909,6 +916,8 @@ static int gdb_new_connection(struct connection *connection)
        gdb_connection->sync = false;
        gdb_connection->mem_write_error = false;
        gdb_connection->attached = true;
+       gdb_connection->target_desc.tdesc = NULL;
+       gdb_connection->target_desc.tdesc_length = 0;
 
        /* send ACK to GDB for debug request */
        gdb_write(connection, "+", 1);
@@ -948,6 +957,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 " \
@@ -1723,14 +1735,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 *),
@@ -1828,6 +1842,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_INT:
+                       return "int";
                case REG_TYPE_INT8:
                        return "int8";
                case REG_TYPE_INT16:
@@ -1852,6 +1868,8 @@ static const char *gdb_get_reg_type_name(enum reg_type type)
                        return "code_ptr";
                case REG_TYPE_DATA_PTR:
                        return "data_ptr";
+               case REG_TYPE_FLOAT:
+                       return "float";
                case REG_TYPE_IEEE_SINGLE:
                        return "ieee_single";
                case REG_TYPE_IEEE_DOUBLE:
@@ -1963,7 +1981,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.
  */
-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 **feature_list[], int *feature_list_size,
                struct reg **reg_list, int reg_list_size)
 {
        int tbl_sz = 0;
@@ -1975,7 +1993,8 @@ int get_reg_features_list(struct target *target, char **feature_list[], int *fea
                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
@@ -2001,19 +2020,15 @@ int get_reg_features_list(struct target *target, char **feature_list[], int *fea
        return ERROR_OK;
 }
 
-static int gdb_generate_target_description(struct target *target, char **tdesc)
+static int gdb_generate_target_description(struct target *target, char **tdesc_out)
 {
        int retval = ERROR_OK;
        struct reg **reg_list;
        int reg_list_size;
+       char *tdesc = NULL;
        int pos = 0;
        int size = 0;
 
-       xml_printf(&retval, tdesc, &pos, &size,
-                       "<?xml version=\"1.0\"?>\n"
-                       "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n"
-                       "<target version=\"1.0\">\n");
-
        retval = target_get_gdb_reg_list(target, &reg_list,
                        &reg_list_size, REG_CLASS_ALL);
 
@@ -2022,25 +2037,33 @@ static int gdb_generate_target_description(struct target *target, char **tdesc)
                return ERROR_FAIL;
        }
 
-       if (reg_list_size <= 0)
+       if (reg_list_size <= 0) {
+               free(reg_list);
                return ERROR_FAIL;
+       }
 
        char **features = NULL;
        /* Get a list of available target registers features */
        retval = get_reg_features_list(target, &features, NULL, reg_list, reg_list_size);
        if (retval != ERROR_OK) {
                LOG_ERROR("Can't get the registers feature list");
+               free(reg_list);
                return ERROR_FAIL;
        }
 
        /* 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,
+                       xml_printf(&retval, &tdesc, &pos, &size,
                                        "<feature name=\"%s\">\n",
                                        features[current_feature]);
 
@@ -2057,7 +2080,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc)
                                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,
+                                               gdb_generate_reg_type_description(target, &tdesc, &pos, &size,
                                                                reg_list[i]->reg_data_type);
 
                                                type_str = reg_list[i]->reg_data_type->id;
@@ -2071,57 +2094,69 @@ static int gdb_generate_target_description(struct target *target, char **tdesc)
                                        type_str = "int";
                                }
 
-                               xml_printf(&retval, tdesc, &pos, &size,
+                               xml_printf(&retval, &tdesc, &pos, &size,
                                                "<reg name=\"%s\"", reg_list[i]->name);
-                               xml_printf(&retval, tdesc, &pos, &size,
+                               xml_printf(&retval, &tdesc, &pos, &size,
                                                " bitsize=\"%d\"", reg_list[i]->size);
-                               xml_printf(&retval, tdesc, &pos, &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,
+                                       xml_printf(&retval, &tdesc, &pos, &size,
                                                        " save-restore=\"yes\"");
                                else
-                                       xml_printf(&retval, tdesc, &pos, &size,
+                                       xml_printf(&retval, &tdesc, &pos, &size,
                                                        " save-restore=\"no\"");
 
-                               xml_printf(&retval, tdesc, &pos, &size,
+                               xml_printf(&retval, &tdesc, &pos, &size,
                                                " type=\"%s\"", type_str);
 
                                if (reg_list[i]->group != NULL)
-                                       xml_printf(&retval, tdesc, &pos, &size,
+                                       xml_printf(&retval, &tdesc, &pos, &size,
                                                        " group=\"%s\"", reg_list[i]->group);
 
-                               xml_printf(&retval, tdesc, &pos, &size,
+                               xml_printf(&retval, &tdesc, &pos, &size,
                                                "/>\n");
                        }
 
-                       xml_printf(&retval, tdesc, &pos, &size,
+                       xml_printf(&retval, &tdesc, &pos, &size,
                                        "</feature>\n");
 
                        current_feature++;
                }
        }
 
-       xml_printf(&retval, tdesc, &pos, &size,
+       xml_printf(&retval, &tdesc, &pos, &size,
                        "</target>\n");
 
-       if (reg_list != NULL)
-               free(reg_list);
+       free(reg_list);
+       free(features);
 
-       if (features != NULL)
-               free(features);
+       if (retval == ERROR_OK)
+               *tdesc_out = tdesc;
+       else
+               free(tdesc);
 
-       return ERROR_OK;
+       return retval;
 }
 
-static int gdb_get_target_description_chunk(struct target *target, char **chunk,
-               int32_t offset, uint32_t length)
+static int gdb_get_target_description_chunk(struct target *target, struct target_desc_format *target_desc,
+               char **chunk, int32_t offset, uint32_t length)
 {
-       static char *tdesc;
-       static uint32_t tdesc_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) {
-               gdb_generate_target_description(target, &tdesc);
+               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);
        }
 
@@ -2133,6 +2168,11 @@ static int gdb_get_target_description_chunk(struct target *target, char **chunk,
                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);
@@ -2147,9 +2187,56 @@ static int gdb_get_target_description_chunk(struct target *target, char **chunk,
                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;
+       int feature_list_size = 0;
+
+       retval = target_get_gdb_reg_list(target, &reg_list,
+                       &reg_list_size, REG_CLASS_ALL);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("get register list failed");
+               goto error;
+       }
+
+       if (reg_list_size <= 0) {
+               retval = ERROR_FAIL;
+               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) {
+               LOG_ERROR("Can't get the registers feature list");
+               goto error;
+       }
+
+       if (supported) {
+               if (feature_list_size)
+                       *supported = 1;
+               else
+                       *supported = 0;
+       }
+
+error:
+       if (reg_list != NULL)
+               free(reg_list);
+
+       if (features != NULL)
+               free(features);
+
+       return retval;
+}
+
 static int gdb_query_packet(struct connection *connection,
                char *packet, int packet_size)
 {
@@ -2214,11 +2301,26 @@ static int gdb_query_packet(struct connection *connection,
                }
        } else if (strncmp(packet, "qSupported", 10) == 0) {
                /* we currently support packet size and qXfer:memory-map:read (if enabled)
-                * disable qXfer:features:read for the moment */
+                * qXfer:features:read is supported for some targets */
                int retval = ERROR_OK;
                char *buffer = NULL;
                int pos = 0;
                int size = 0;
+               int gdb_target_desc_supported = 0;
+
+               /* we need to test that the target supports target descriptions */
+               retval = gdb_target_description_supported(target, &gdb_target_desc_supported);
+               if (retval != ERROR_OK) {
+                       LOG_INFO("Failed detecting Target Description Support, disabling");
+                       gdb_target_desc_supported = 0;
+               }
+
+               /* support may be disabled globally */
+               if (gdb_use_target_description == 0) {
+                       if (gdb_target_desc_supported)
+                               LOG_WARNING("Target Descriptions Supported, but disabled");
+                       gdb_target_desc_supported = 0;
+               }
 
                xml_printf(&retval,
                        &buffer,
@@ -2227,7 +2329,7 @@ static int gdb_query_packet(struct connection *connection,
                        "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;QStartNoAckMode+",
                        (GDB_BUFFER_SIZE - 1),
                        ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-',
-                       (gdb_use_target_description == 1) ? '+' : '-');
+                       (gdb_target_desc_supported == 1) ? '+' : '-');
 
                if (retval != ERROR_OK) {
                        gdb_send_error(connection, 01);
@@ -2262,7 +2364,8 @@ static int gdb_query_packet(struct connection *connection,
                 * there are *more* chunks to transfer. 'l' for it is the *last*
                 * chunk of target description.
                 */
-               retval = gdb_get_target_description_chunk(target, &xml, offset, length);
+               retval = gdb_get_target_description_chunk(target, &gdb_connection->target_desc,
+                               &xml, offset, length);
                if (retval != ERROR_OK) {
                        gdb_error(connection, retval);
                        return retval;
@@ -2803,7 +2906,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);
                        }
                }
@@ -2850,7 +2953,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;
@@ -2918,41 +3021,46 @@ COMMAND_HANDLER(handle_gdb_target_description_command)
 
 COMMAND_HANDLER(handle_gdb_save_tdesc_command)
 {
-       static char *tdesc;
-       static uint32_t tdesc_length;
+       char *tdesc;
+       uint32_t tdesc_length;
        struct target *target = get_current_target(CMD_CTX);
-       char *tdesc_filename;
 
-       if (tdesc == NULL) {
-               gdb_generate_target_description(target, &tdesc);
-               tdesc_length = strlen(tdesc);
+       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);
+
        struct fileio fileio;
        size_t size_written;
 
-       tdesc_filename = malloc(strlen(target_type_name(target)) + 5);
-       sprintf(tdesc_filename, "%s.xml", target_type_name(target));
+       char *tdesc_filename = alloc_printf("%s.xml", target_type_name(target));
+       if (tdesc_filename == NULL) {
+               retval = ERROR_FAIL;
+               goto out;
+       }
 
-       int retval = fileio_open(&fileio, tdesc_filename, FILEIO_WRITE, FILEIO_TEXT);
+       retval = fileio_open(&fileio, tdesc_filename, FILEIO_WRITE, FILEIO_TEXT);
 
        if (retval != ERROR_OK) {
-               LOG_WARNING("Can't open %s for writing", tdesc_filename);
-               free(tdesc_filename);
-               return ERROR_FAIL;
+               LOG_ERROR("Can't open %s for writing", tdesc_filename);
+               goto out;
        }
 
        retval = fileio_write(&fileio, tdesc_length, tdesc, &size_written);
 
        fileio_close(&fileio);
-       free(tdesc_filename);
 
-       if (retval != ERROR_OK) {
-               LOG_WARNING("Error while writing the tdesc file");
-               return ERROR_FAIL;
-       }
+       if (retval != ERROR_OK)
+               LOG_ERROR("Error while writing the tdesc file");
 
-       return ERROR_OK;
+out:
+       free(tdesc_filename);
+       free(tdesc);
+
+       return retval;
 }
 
 static const struct command_registration gdb_command_handlers[] = {