+ switch (type) {
+ case REG_TYPE_BOOL:
+ return "bool";
+ case REG_TYPE_INT:
+ return "int";
+ case REG_TYPE_INT8:
+ return "int8";
+ case REG_TYPE_INT16:
+ return "int16";
+ case REG_TYPE_INT32:
+ return "int32";
+ case REG_TYPE_INT64:
+ return "int64";
+ case REG_TYPE_INT128:
+ return "int128";
+ case REG_TYPE_UINT:
+ return "uint";
+ case REG_TYPE_UINT8:
+ return "uint8";
+ case REG_TYPE_UINT16:
+ return "uint16";
+ case REG_TYPE_UINT32:
+ return "uint32";
+ case REG_TYPE_UINT64:
+ return "uint64";
+ case REG_TYPE_UINT128:
+ return "uint128";
+ case REG_TYPE_CODE_PTR:
+ 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:
+ return "ieee_double";
+ case REG_TYPE_ARCH_DEFINED:
+ return "int"; /* return arbitrary string to avoid compile warning. */
+ }
+
+ return "int"; /* "int" as default value */
+}
+
+static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], const char *type_id,
+ int *num_arch_defined_types)
+{
+ int tbl_sz = *num_arch_defined_types;
+
+ if (type_id != NULL && (strcmp(type_id, ""))) {
+ for (int j = 0; j < (tbl_sz + 1); j++) {
+ if (!((*arch_defined_types_list)[j])) {
+ (*arch_defined_types_list)[tbl_sz++] = type_id;
+ *arch_defined_types_list = realloc(*arch_defined_types_list,
+ sizeof(char *) * (tbl_sz + 1));
+ (*arch_defined_types_list)[tbl_sz] = NULL;
+ *num_arch_defined_types = tbl_sz;
+ return 1;
+ } else {
+ if (!strcmp((*arch_defined_types_list)[j], type_id))
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static int gdb_generate_reg_type_description(struct target *target,
+ char **tdesc, int *pos, int *size, struct reg_data_type *type,
+ char const **arch_defined_types_list[], int * num_arch_defined_types)
+{
+ int retval = ERROR_OK;
+
+ if (type->type_class == REG_TYPE_CLASS_VECTOR) {
+ struct reg_data_type *data_type = type->reg_type_vector->type;
+ if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+ if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+ num_arch_defined_types))
+ gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+ arch_defined_types_list,
+ num_arch_defined_types);
+ }
+ /* <vector id="id" type="type" count="count"/> */
+ xml_printf(&retval, tdesc, pos, size,
+ "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
+ type->id, type->reg_type_vector->type->id,
+ type->reg_type_vector->count);
+
+ } else if (type->type_class == REG_TYPE_CLASS_UNION) {
+ struct reg_data_type_union_field *field;
+ field = type->reg_type_union->fields;
+ while (field != NULL) {
+ struct reg_data_type *data_type = field->type;
+ if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+ if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+ num_arch_defined_types))
+ gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+ arch_defined_types_list,
+ num_arch_defined_types);
+ }
+
+ field = field->next;
+ }
+ /* <union id="id">
+ * <field name="name" type="type"/> ...
+ * </union> */
+ xml_printf(&retval, tdesc, pos, size,
+ "<union id=\"%s\">\n",
+ type->id);
+
+ field = type->reg_type_union->fields;
+ while (field != NULL) {
+ xml_printf(&retval, tdesc, pos, size,
+ "<field name=\"%s\" type=\"%s\"/>\n",
+ field->name, field->type->id);
+
+ field = field->next;
+ }
+
+ xml_printf(&retval, tdesc, pos, size,
+ "</union>\n");
+
+ } else if (type->type_class == REG_TYPE_CLASS_STRUCT) {
+ struct reg_data_type_struct_field *field;
+ field = type->reg_type_struct->fields;
+
+ if (field->use_bitfields) {
+ /* <struct id="id" size="size">
+ * <field name="name" start="start" end="end"/> ...
+ * </struct> */
+ xml_printf(&retval, tdesc, pos, size,
+ "<struct id=\"%s\" size=\"%d\">\n",
+ type->id, type->reg_type_struct->size);
+ while (field != NULL) {
+ xml_printf(&retval, tdesc, pos, size,
+ "<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+ field->name, field->bitfield->start, field->bitfield->end,
+ gdb_get_reg_type_name(field->bitfield->type));
+
+ field = field->next;
+ }
+ } else {
+ while (field != NULL) {
+ struct reg_data_type *data_type = field->type;
+ if (data_type->type == REG_TYPE_ARCH_DEFINED) {
+ if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id,
+ num_arch_defined_types))
+ gdb_generate_reg_type_description(target, tdesc, pos, size, data_type,
+ arch_defined_types_list,
+ num_arch_defined_types);
+ }
+ }
+
+ /* <struct id="id">
+ * <field name="name" type="type"/> ...
+ * </struct> */
+ xml_printf(&retval, tdesc, pos, size,
+ "<struct id=\"%s\">\n",
+ type->id);
+ while (field != NULL) {
+ xml_printf(&retval, tdesc, pos, size,
+ "<field name=\"%s\" type=\"%s\"/>\n",
+ field->name, field->type->id);
+
+ field = field->next;
+ }
+ }
+
+ xml_printf(&retval, tdesc, pos, size,
+ "</struct>\n");
+
+ } else if (type->type_class == REG_TYPE_CLASS_FLAGS) {
+ /* <flags id="id" size="size">
+ * <field name="name" start="start" end="end"/> ...
+ * </flags> */
+ xml_printf(&retval, tdesc, pos, size,
+ "<flags id=\"%s\" size=\"%d\">\n",
+ type->id, type->reg_type_flags->size);
+
+ struct reg_data_type_flags_field *field;
+ field = type->reg_type_flags->fields;
+ while (field != NULL) {
+ xml_printf(&retval, tdesc, pos, size,
+ "<field name=\"%s\" start=\"%d\" end=\"%d\" type=\"%s\" />\n",
+ field->name, field->bitfield->start, field->bitfield->end,
+ gdb_get_reg_type_name(field->bitfield->type));
+
+ field = field->next;
+ }
+
+ xml_printf(&retval, tdesc, pos, size,
+ "</flags>\n");
+
+ }
+
+ return ERROR_OK;
+}
+
+/* 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 const **feature_list[], int *feature_list_size,
+ struct reg **reg_list, int reg_list_size)
+{
+ int tbl_sz = 0;
+
+ /* Start with only one element */
+ *feature_list = calloc(1, sizeof(char *));
+
+ for (int i = 0; i < reg_list_size; i++) {
+ if (reg_list[i]->exist == false)
+ continue;
+
+ 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
+ * put the new feature in it.
+ */
+ for (int j = 0; j < (tbl_sz + 1); j++) {
+ if (!((*feature_list)[j])) {
+ (*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;
+ } else {
+ if (!strcmp((*feature_list)[j], reg_list[i]->feature->name))
+ break;
+ }
+ }
+ }
+ }
+
+ if (feature_list_size)
+ *feature_list_size = tbl_sz;
+
+ return ERROR_OK;
+}
+
+static int gdb_generate_target_description(struct target *target, char **tdesc_out)
+{
+ int retval = ERROR_OK;
+ struct reg **reg_list = NULL;
+ int reg_list_size;
+ char const **features = NULL;
+ char const **arch_defined_types = NULL;
+ int feature_list_size = 0;
+ int num_arch_defined_types = 0;
+ char *tdesc = NULL;
+ int pos = 0;
+ int size = 0;
+
+ arch_defined_types = calloc(1, sizeof(char *));
+
+ retval = target_get_gdb_reg_list(target, ®_list,
+ ®_list_size, REG_CLASS_ALL);
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("get register list failed");
+ retval = ERROR_FAIL;
+ 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");
+ 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]);
+