diff options
author | Hsiangkai Wang <hsiangkai@gmail.com> | 2013-05-07 21:43:35 +0800 |
---|---|---|
committer | Spencer Oliver <spen@spen-soft.co.uk> | 2013-08-07 21:00:40 +0000 |
commit | d979d78e97786667d168ba183c9fc60c622d29c1 (patch) | |
tree | 19e03565245a64cb7f3138433f78abce8c6acc9a /src/target | |
parent | 9f2922aa7abb385d1fb24def91fac7eb4e2304c5 (diff) |
gdb_server: support gdb target description
* Add a parameter in .get_gdb_reg_list() to return different
register lists as generating target description.
* Modify STRUCT REG to let gdb generate target description
according to register information.
The modified structure of register is
struct reg {
const char *name;
uint32_t number; /* for regnum="num" */
struct reg_feature *feature; /* for register group feature name */
bool caller_save; /* for save-restore="yes|no" */
void *value;
bool dirty;
bool valid;
bool exist;
uint32_t size;
struct reg_data_type *reg_data_type; /* for type="type" */
const char *group; /* for group="general|float|vector" */
void *arch_info;
const struct reg_arch_type *type;
};
Change-Id: I2096b67adf94518ba0b8b23d8c6a9f64ad7932b8
Signed-off-by: Hsiangkai Wang <hsiangkai@gmail.com>
Reviewed-on: http://openocd.zylin.com/1382
Tested-by: jenkins
Reviewed-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Diffstat (limited to 'src/target')
-rw-r--r-- | src/target/arm.h | 3 | ||||
-rw-r--r-- | src/target/armv4_5.c | 3 | ||||
-rw-r--r-- | src/target/armv7m.c | 3 | ||||
-rw-r--r-- | src/target/armv7m.h | 3 | ||||
-rw-r--r-- | src/target/avr32_ap7k.c | 3 | ||||
-rw-r--r-- | src/target/dsp563xx.c | 3 | ||||
-rw-r--r-- | src/target/mips32.c | 3 | ||||
-rw-r--r-- | src/target/mips32.h | 3 | ||||
-rw-r--r-- | src/target/nds32.c | 134 | ||||
-rw-r--r-- | src/target/nds32.h | 5 | ||||
-rw-r--r-- | src/target/register.h | 93 | ||||
-rw-r--r-- | src/target/target.c | 5 | ||||
-rw-r--r-- | src/target/target.h | 9 | ||||
-rw-r--r-- | src/target/target_type.h | 3 |
14 files changed, 239 insertions, 34 deletions
diff --git a/src/target/arm.h b/src/target/arm.h index 4a4d928c..e2d26461 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -211,7 +211,8 @@ extern const struct command_registration arm_command_handlers[]; int arm_arch_state(struct target *target); int arm_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size); + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); int arm_init_arch_info(struct target *target, struct arm *arm); diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 91830f57..a2f05575 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -1051,7 +1051,8 @@ const struct command_registration arm_command_handlers[] = { }; int arm_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size) + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class) { struct arm *arm = target_to_arm(target); int i; diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 622de490..d32352a7 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -259,7 +259,8 @@ static int armv7m_write_core_reg(struct target *target, struct reg *r, * hardware, so this also fakes a set of long-obsolete FPA registers that * are not used in EABI based software stacks. */ -int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) +int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) { struct armv7m_common *armv7m = target_to_armv7m(target); int i; diff --git a/src/target/armv7m.h b/src/target/armv7m.h index bc245fb7..d028f4ef 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -195,7 +195,8 @@ int armv7m_mode_to_number(enum armv7m_mode mode); int armv7m_arch_state(struct target *target); int armv7m_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size); + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m); diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index cc9ab5af..7c97234d 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -576,7 +576,8 @@ int avr32_ap7k_arch_state(struct target *target) return ERROR_OK; } -int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) +int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) { #if 0 /* get pointers to arch-specific information */ diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 1211ac56..8c470168 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -354,7 +354,8 @@ static uint8_t gdb_reg_list_idx[] = { static int dsp563xx_get_gdb_reg_list(struct target *target, struct reg **reg_list[], - int *reg_list_size) + int *reg_list_size, + enum target_register_class reg_class) { int i; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); diff --git a/src/target/mips32.c b/src/target/mips32.c index 1067f7b6..c9cbf86e 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -173,7 +173,8 @@ static int mips32_write_core_reg(struct target *target, int num) return ERROR_OK; } -int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) +int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); diff --git a/src/target/mips32.h b/src/target/mips32.h index 97fb5d03..951b2ed7 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -243,7 +243,8 @@ int mips32_examine(struct target *target); int mips32_register_commands(struct command_context *cmd_ctx); int mips32_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size); + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); int mips32_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum); int mips32_blank_check_memory(struct target *target, diff --git a/src/target/nds32.c b/src/target/nds32.c index 2d477097..95a249d0 100644 --- a/src/target/nds32.c +++ b/src/target/nds32.c @@ -91,21 +91,23 @@ static int nds32_get_core_reg(struct reg *reg) 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, @@ -301,44 +303,46 @@ static int nds32_set_core_reg(struct reg *reg, uint8_t *buf) 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); } @@ -415,17 +419,62 @@ static struct reg_cache *nds32_build_reg_cache(struct target *target, 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++; } @@ -451,9 +500,7 @@ static struct reg *nds32_reg_current(struct nds32 *nds32, unsigned regnum) { 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; } @@ -512,12 +559,36 @@ int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value) 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; @@ -525,12 +596,35 @@ int nds32_get_gdb_reg_list(struct target *target, /** 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) { diff --git a/src/target/nds32.h b/src/target/nds32.h index f585c2d3..b7e787cf 100644 --- a/src/target/nds32.h +++ b/src/target/nds32.h @@ -341,7 +341,7 @@ struct nds32 { }; struct nds32_reg { - uint32_t num; + int32_t num; uint32_t value; uint64_t value_64; struct target *target; @@ -364,7 +364,8 @@ extern int nds32_remove_software_breakpoint(struct target *target, struct breakpoint *breakpoint); extern int nds32_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size); + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); extern int nds32_write_buffer(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer); diff --git a/src/target/register.h b/src/target/register.h index 3810d145..9e0f1ce8 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -26,12 +26,105 @@ struct target; +enum reg_type { + REG_TYPE_INT8, + REG_TYPE_INT16, + REG_TYPE_INT32, + REG_TYPE_INT64, + REG_TYPE_INT128, + REG_TYPE_UINT8, + REG_TYPE_UINT16, + REG_TYPE_UINT32, + REG_TYPE_UINT64, + REG_TYPE_UINT128, + REG_TYPE_CODE_PTR, + REG_TYPE_DATA_PTR, + REG_TYPE_IEEE_SINGLE, + REG_TYPE_IEEE_DOUBLE, + REG_TYPE_ARCH_DEFINED, +}; + +struct reg_feature { + const char *name; +}; + +struct reg_data_type_vector { + struct reg_data_type *type; + uint32_t count; +}; + +struct reg_data_type_union_field { + const char *name; + struct reg_data_type *type; + struct reg_data_type_union_field *next; +}; + +struct reg_data_type_union { + struct reg_data_type_union_field *fields; +}; + +struct reg_data_type_bitfield { + uint32_t start; + uint32_t end; +}; + +struct reg_data_type_struct_field { + const char *name; + bool use_bitfields; + union { + struct reg_data_type_bitfield *bitfield; + struct reg_data_type *type; + }; + struct reg_data_type_struct_field *next; +}; + +struct reg_data_type_struct { + uint32_t size; + struct reg_data_type_struct_field *fields; +}; + +struct reg_data_type_flags_field { + const char *name; + struct reg_data_type_bitfield *bitfield; + struct reg_data_type_flags_field *next; +}; + +struct reg_data_type_flags { + uint32_t size; + struct reg_data_type_flags_field *fields; +}; + +enum reg_data_type_class { + REG_TYPE_CLASS_VECTOR, + REG_TYPE_CLASS_UNION, + REG_TYPE_CLASS_STRUCT, + REG_TYPE_CLASS_FLAGS, +}; + +struct reg_data_type { + enum reg_type type; + const char *id; + enum reg_data_type_class type_class; + union { + struct reg_data_type_vector *reg_type_vector; + struct reg_data_type_union *reg_type_union; + struct reg_data_type_struct *reg_type_struct; + struct reg_data_type_flags *reg_type_flags; + }; +}; + struct reg { const char *name; + uint32_t number; + struct reg_feature *feature; + bool caller_save; void *value; bool dirty; bool valid; + bool exist; uint32_t size; + struct reg_data_type *reg_data_type; + const char *group; void *arch_info; const struct reg_arch_type *type; }; diff --git a/src/target/target.c b/src/target/target.c index 1f517ac0..c5b80d64 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1037,9 +1037,10 @@ int target_remove_watchpoint(struct target *target, } int target_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size) + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class) { - return target->type->get_gdb_reg_list(target, reg_list, reg_list_size); + return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); } int target_step(struct target *target, int current, uint32_t address, int handle_breakpoints) diff --git a/src/target/target.h b/src/target/target.h index 38bb8753..42414c69 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -114,6 +114,12 @@ struct backoff_timer { int count; }; +/* split target registers into multiple class */ +enum target_register_class { + REG_CLASS_ALL, + REG_CLASS_GENERAL, +}; + /* target_type.h contains the full definition of struct target_type */ struct target { struct target_type *type; /* target type definition (name, access functions) */ @@ -399,7 +405,8 @@ int target_remove_watchpoint(struct target *target, * This routine is a wrapper for target->type->get_gdb_reg_list. */ int target_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size); + struct reg **reg_list[], int *reg_list_size, + enum target_register_class reg_class); /** * Step the target. diff --git a/src/target/target_type.h b/src/target/target_type.h index 3a3de7a2..4d9a33f9 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -101,7 +101,8 @@ struct target_type { * list, however it is after GDB is connected that monitor commands can * be run to properly initialize the target */ - int (*get_gdb_reg_list)(struct target *target, struct reg **reg_list[], int *reg_list_size); + int (*get_gdb_reg_list)(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class); /* target memory access * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) |