* Copyright (C) ST-Ericsson SA 2011 *
* michel.jaouen@stericsson.com : smp minimum support *
* *
+ * Copyright (C) 2013 Andes Technology *
+ * Hsiangkai Wang <hkwang@andestech.com> *
+ * *
+ * Copyright (C) 2013 Franck Jullien *
+ * elec4fun@gmail.com *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
*/
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;
+
static int gdb_last_signal(struct target *target)
{
switch (target->debug_reason) {
if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg_list(connection)))
return ERROR_OK;
- retval = target_get_gdb_reg_list(target, ®_list, ®_list_size);
+ retval = target_get_gdb_reg_list(target, ®_list, ®_list_size,
+ REG_CLASS_GENERAL);
if (retval != ERROR_OK)
return gdb_error(connection, retval);
return ERROR_SERVER_REMOTE_CLOSED;
}
- retval = target_get_gdb_reg_list(target, ®_list, ®_list_size);
+ retval = target_get_gdb_reg_list(target, ®_list, ®_list_size,
+ REG_CLASS_GENERAL);
if (retval != ERROR_OK)
return gdb_error(connection, retval);
LOG_DEBUG("-");
#endif
- retval = target_get_gdb_reg_list(target, ®_list, ®_list_size);
+ retval = target_get_gdb_reg_list(target, ®_list, ®_list_size,
+ REG_CLASS_ALL);
if (retval != ERROR_OK)
return gdb_error(connection, retval);
LOG_DEBUG("-");
- retval = target_get_gdb_reg_list(target, ®_list, ®_list_size);
+ retval = target_get_gdb_reg_list(target, ®_list, ®_list_size,
+ REG_CLASS_ALL);
if (retval != ERROR_OK)
return gdb_error(connection, retval);
return ERROR_OK;
}
+static const char *gdb_get_reg_type_name(enum reg_type type)
+{
+ switch (type) {
+ 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_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_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 gdb_generate_reg_type_description(struct target *target,
+ char **tdesc, int *pos, int *size, struct reg_data_type *type)
+{
+ int retval = ERROR_OK;
+
+ if (type->type_class == REG_TYPE_CLASS_VECTOR) {
+ /* <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) {
+ /* <union id="id">
+ * <field name="name" type="type"/> ...
+ * </union> */
+ xml_printf(&retval, tdesc, pos, size,
+ "<union id=\"%s\">\n",
+ type->id);
+
+ struct reg_data_type_union_field *field;
+ 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\"/>\n",
+ field->name, field->bitfield->start,
+ field->bitfield->end);
+
+ field = field->next;
+ }
+ } else {
+ /* <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\"/>\n",
+ field->name, field->bitfield->start, field->bitfield->end);
+
+ 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.
+ */
+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;
+
+ /* 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->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++] = strdup(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)
+{
+ int retval = ERROR_OK;
+ struct reg **reg_list;
+ int reg_list_size;
+ 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, ®_list,
+ ®_list_size, REG_CLASS_ALL);
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("get register list failed");
+ return ERROR_FAIL;
+ }
+
+ if (reg_list_size <= 0)
+ 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");
+ return ERROR_FAIL;
+ }
+
+ /* If we found some features associated with registers, create sections */
+ int current_feature = 0;
+
+ /* 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. */
+ gdb_generate_reg_type_description(target, tdesc, &pos, &size,
+ reg_list[i]->reg_data_type);
+
+ 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");
+
+ if (reg_list != NULL)
+ free(reg_list);
+
+ if (features != NULL)
+ free(features);
+
+ return ERROR_OK;
+}
+
+static int gdb_get_target_description_chunk(struct target *target, char **chunk,
+ int32_t offset, uint32_t length)
+{
+ static char *tdesc;
+ static uint32_t tdesc_length;
+
+ if (tdesc == NULL) {
+ gdb_generate_target_description(target, &tdesc);
+ tdesc_length = strlen(tdesc);
+ }
+
+ char transfer_type;
+
+ if (length < (tdesc_length - offset))
+ transfer_type = 'm';
+ else
+ transfer_type = 'l';
+
+ *chunk = malloc(length + 2);
+ (*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;
+ }
+
+ return ERROR_OK;
+}
+
static int gdb_query_packet(struct connection *connection,
char *packet, int packet_size)
{
&buffer,
&pos,
&size,
- "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-;QStartNoAckMode+",
+ "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_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-',
+ (gdb_use_target_description == 1) ? '+' : '-');
if (retval != ERROR_OK) {
gdb_send_error(connection, 01);
return gdb_memory_map(connection, packet, packet_size);
else if (strncmp(packet, "qXfer:features:read:", 20) == 0) {
char *xml = NULL;
- int size = 0;
- int pos = 0;
int retval = ERROR_OK;
int offset;
return ERROR_OK;
}
- if (strcmp(annex, "target.xml") != 0) {
- gdb_send_error(connection, 01);
- return ERROR_OK;
- }
-
- xml_printf(&retval,
- &xml,
- &pos,
- &size, \
- "l < target version=\"1.0\">\n < architecture > arm</architecture>\n</target>\n");
-
+ /* Target should prepare correct target description for annex.
+ * The first character of returned xml is 'm' or 'l'. 'm' for
+ * 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);
if (retval != ERROR_OK) {
gdb_error(connection, retval);
return retval;
return ERROR_OK;
}
+COMMAND_HANDLER(handle_gdb_target_description_command)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_target_description);
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_gdb_save_tdesc_command)
+{
+ static char *tdesc;
+ static 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);
+ }
+
+ 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));
+
+ int retval = fileio_open(&fileio, tdesc_filename, FILEIO_WRITE, FILEIO_TEXT);
+
+ free(tdesc_filename);
+
+ if (retval != ERROR_OK) {
+ LOG_WARNING("Can't open %s for writing", tdesc_filename);
+ return ERROR_FAIL;
+ }
+
+ retval = fileio_write(&fileio, tdesc_length, tdesc, &size_written);
+
+ fileio_close(&fileio);
+
+ if (retval != ERROR_OK) {
+ LOG_WARNING("Error while writing the tdesc file");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
static const struct command_registration gdb_command_handlers[] = {
{
.name = "gdb_sync",
"to be used by gdb 'break' commands.",
.usage = "('hard'|'soft'|'disable')"
},
+ {
+ .name = "gdb_target_description",
+ .handler = handle_gdb_target_description_command,
+ .mode = COMMAND_CONFIG,
+ .help = "enable or disable target description",
+ .usage = "('enable'|'disable')"
+ },
+ {
+ .name = "gdb_save_tdesc",
+ .handler = handle_gdb_save_tdesc_command,
+ .mode = COMMAND_EXEC,
+ .help = "Save the target description file",
+ },
COMMAND_REGISTRATION_DONE
};
return ERROR_OK;
}
+ int mapped_regnum = nds32->register_map(nds32, reg_arch_info->num);
+
if (reg_arch_info->enable == false) {
reg_arch_info->value = NDS32_REGISTER_DISABLE;
retval = ERROR_FAIL;
} else {
if ((nds32->fpu_enable == false) &&
- (NDS32_REG_TYPE_FPU == nds32_reg_type(reg_arch_info->num))) {
+ (NDS32_REG_TYPE_FPU == nds32_reg_type(mapped_regnum))) {
reg_arch_info->value = 0;
retval = ERROR_OK;
} else if ((nds32->audio_enable == false) &&
- (NDS32_REG_TYPE_AUMR == nds32_reg_type(reg_arch_info->num))) {
+ (NDS32_REG_TYPE_AUMR == nds32_reg_type(mapped_regnum))) {
reg_arch_info->value = 0;
retval = ERROR_OK;
} else {
retval = aice_read_register(aice,
- reg_arch_info->num, &(reg_arch_info->value));
+ mapped_regnum, &(reg_arch_info->value));
}
LOG_DEBUG("reading register %i(%s), value: 0x%8.8" PRIx32,
return ERROR_TARGET_NOT_HALTED;
}
+ int mapped_regnum = nds32->register_map(nds32, reg_arch_info->num);
+
/* ignore values that will generate exception */
- if (nds32_reg_exception(reg_arch_info->num, value))
+ if (nds32_reg_exception(mapped_regnum, value))
return ERROR_OK;
LOG_DEBUG("writing register %i(%s) with value 0x%8.8" PRIx32,
reg_arch_info->num, reg->name, value);
if ((nds32->fpu_enable == false) &&
- (NDS32_REG_TYPE_FPU == nds32_reg_type(reg_arch_info->num))) {
+ (NDS32_REG_TYPE_FPU == nds32_reg_type(mapped_regnum))) {
buf_set_u32(reg->value, 0, 32, 0);
} else if ((nds32->audio_enable == false) &&
- (NDS32_REG_TYPE_AUMR == nds32_reg_type(reg_arch_info->num))) {
+ (NDS32_REG_TYPE_AUMR == nds32_reg_type(mapped_regnum))) {
buf_set_u32(reg->value, 0, 32, 0);
} else {
buf_set_u32(reg->value, 0, 32, value);
- aice_write_register(aice, reg_arch_info->num, reg_arch_info->value);
+ aice_write_register(aice, mapped_regnum, reg_arch_info->value);
/* After set value to registers, read the value from target
* to avoid W1C inconsistency. */
- aice_read_register(aice, reg_arch_info->num, &(reg_arch_info->value));
+ aice_read_register(aice, mapped_regnum, &(reg_arch_info->value));
}
reg->valid = true;
reg->dirty = false;
/* update registers to take effect right now */
- if (IR0 == reg_arch_info->num) {
+ if (IR0 == mapped_regnum) {
nds32_update_psw(nds32);
- } else if (MR0 == reg_arch_info->num) {
+ } else if (MR0 == mapped_regnum) {
nds32_update_mmu_info(nds32);
- } else if ((MR6 == reg_arch_info->num) || (MR7 == reg_arch_info->num)) {
+ } else if ((MR6 == mapped_regnum) || (MR7 == mapped_regnum)) {
/* update lm information */
nds32_update_lm_info(nds32);
- } else if (MR8 == reg_arch_info->num) {
+ } else if (MR8 == mapped_regnum) {
nds32_update_cache_info(nds32);
- } else if (FUCPR == reg_arch_info->num) {
+ } else if (FUCPR == mapped_regnum) {
/* update audio/fpu setting */
nds32_check_extension(nds32);
}
reg_arch_info[i].enable = false;
reg_list[i].name = nds32_reg_simple_name(i);
+ reg_list[i].number = reg_arch_info[i].num;
reg_list[i].size = nds32_reg_size(i);
reg_list[i].arch_info = ®_arch_info[i];
+ reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type));
+
if (FD0 <= reg_arch_info[i].num && reg_arch_info[i].num <= FD31) {
reg_list[i].value = &(reg_arch_info[i].value_64);
reg_list[i].type = &nds32_reg_access_type_64;
+
+ reg_list[i].reg_data_type->type = REG_TYPE_IEEE_DOUBLE;
+ reg_list[i].reg_data_type->id = "ieee_double";
+ reg_list[i].group = "float";
} else {
reg_list[i].value = &(reg_arch_info[i].value);
reg_list[i].type = &nds32_reg_access_type;
+ reg_list[i].group = "general";
+
+ if ((FS0 <= reg_arch_info[i].num) && (reg_arch_info[i].num <= FS31)) {
+ reg_list[i].reg_data_type->type = REG_TYPE_IEEE_SINGLE;
+ reg_list[i].reg_data_type->id = "ieee_single";
+ reg_list[i].group = "float";
+ } else if ((reg_arch_info[i].num == FPCSR) ||
+ (reg_arch_info[i].num == FPCFG)) {
+ reg_list[i].group = "float";
+ } else if ((reg_arch_info[i].num == R28) ||
+ (reg_arch_info[i].num == R29) ||
+ (reg_arch_info[i].num == R31)) {
+ reg_list[i].reg_data_type->type = REG_TYPE_DATA_PTR;
+ reg_list[i].reg_data_type->id = "data_ptr";
+ } else if ((reg_arch_info[i].num == R30) ||
+ (reg_arch_info[i].num == PC)) {
+ reg_list[i].reg_data_type->type = REG_TYPE_CODE_PTR;
+ reg_list[i].reg_data_type->id = "code_ptr";
+ } else {
+ reg_list[i].reg_data_type->type = REG_TYPE_UINT32;
+ reg_list[i].reg_data_type->id = "uint32";
+ }
}
+ if (R16 <= reg_arch_info[i].num && reg_arch_info[i].num <= R25)
+ reg_list[i].caller_save = true;
+ else
+ reg_list[i].caller_save = false;
+
+ reg_list[i].feature = malloc(sizeof(struct reg_feature));
+
+ if (R0 <= reg_arch_info[i].num && reg_arch_info[i].num <= IFC_LP)
+ reg_list[i].feature->name = "org.gnu.gdb.nds32.core";
+ else if (CR0 <= reg_arch_info[i].num && reg_arch_info[i].num <= SECUR0)
+ reg_list[i].feature->name = "org.gnu.gdb.nds32.system";
+ else if (D0L24 <= reg_arch_info[i].num && reg_arch_info[i].num <= CBE3)
+ reg_list[i].feature->name = "org.gnu.gdb.nds32.audio";
+ else if (FPCSR <= reg_arch_info[i].num && reg_arch_info[i].num <= FD31)
+ reg_list[i].feature->name = "org.gnu.gdb.nds32.fpu";
+
cache->num_regs++;
}
{
struct reg *r;
- /* Register mapping, pass user-view registers to gdb */
- int mapped_regnum = nds32->register_map(nds32, regnum);
- r = nds32->core_cache->reg_list + mapped_regnum;
+ r = nds32->core_cache->reg_list + regnum;
return r;
}
return r->type->set(r, set_value);
}
+/** get general register list */
+static int nds32_get_general_reg_list(struct nds32 *nds32,
+ struct reg **reg_list[], int *reg_list_size)
+{
+ struct reg *reg_current;
+ int i;
+ int current_idx;
+
+ /** freed in gdb_server.c */
+ *reg_list = malloc(sizeof(struct reg *) * (IFC_LP - R0 + 1));
+ current_idx = 0;
+
+ for (i = R0; i < IFC_LP + 1; i++) {
+ reg_current = nds32_reg_current(nds32, i);
+ if (((struct nds32_reg *)reg_current->arch_info)->enable) {
+ (*reg_list)[current_idx] = reg_current;
+ current_idx++;
+ }
+ }
+ *reg_list_size = current_idx;
+
+ return ERROR_OK;
+}
+
/** get all register list */
-int nds32_get_gdb_reg_list(struct target *target,
+static int nds32_get_all_reg_list(struct nds32 *nds32,
struct reg **reg_list[], int *reg_list_size)
{
- struct nds32 *nds32 = target_to_nds32(target);
struct reg_cache *reg_cache = nds32->core_cache;
+ struct reg *reg_current;
unsigned int i;
*reg_list_size = reg_cache->num_regs;
/** freed in gdb_server.c */
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
- for (i = 0; i < reg_cache->num_regs; i++)
- (*reg_list)[i] = nds32_reg_current(nds32, i);
+ for (i = 0; i < reg_cache->num_regs; i++) {
+ reg_current = nds32_reg_current(nds32, i);
+ reg_current->exist = ((struct nds32_reg *)
+ reg_current->arch_info)->enable;
+ (*reg_list)[i] = reg_current;
+ }
return ERROR_OK;
}
+/** get all register list */
+int nds32_get_gdb_reg_list(struct target *target,
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class)
+{
+ struct nds32 *nds32 = target_to_nds32(target);
+
+ switch (reg_class) {
+ case REG_CLASS_ALL:
+ return nds32_get_all_reg_list(nds32, reg_list, reg_list_size);
+ case REG_CLASS_GENERAL:
+ return nds32_get_general_reg_list(nds32, reg_list, reg_list_size);
+ default:
+ return ERROR_FAIL;
+ }
+
+ return ERROR_FAIL;
+}
+
static int nds32_select_memory_mode(struct target *target, uint32_t address,
uint32_t length, uint32_t *end_address)
{