From 123dc839145c04e57435369a9f2551a505ce0b33 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Thu, 8 Feb 2007 21:00:36 +0000 Subject: [PATCH] * Makefile.in (arm-tdep.o, eval.o, target-descriptions.o) (xml-tdesc.o): Update. * xml-support.c: Add a comment. (gdb_xml_enums_boolean): New variable. (gdb_xml_parse_attr_enum): Use strcasecmp. * xml-support.h (gdb_xml_enums_boolean): Declare. * xml-tdesc.c (struct tdesc_parsing_data): Record current_feature, next_regnum, and current_union. (tdesc_start_feature, tdesc_start_reg, tdesc_start_union) (tdesc_end_union, tdesc_start_field, tdesc_start_vector) (field_attributes, union_children, reg_attributes, union_attributes) (vector_attributes, feature_attributes, feature_children): New. (target_children): Make static. Add . (tdesc_elements): Make static. * target-descriptions.c (struct tdesc_reg, tdesc_reg_p, type_p) (struct tdesc_feature, tdesc_feature_p): New types. (struct target_desc): Add features member. (struct tdesc_arch_data, tdesc_data): New. (target_find_description): Clarify error message. Warn about ignored register descriptions. (tdesc_has_registers, tdesc_find_feature, tdesc_feature_name) (tdesc_named_type, tdesc_data_init, tdesc_data_alloc) (tdesc_data_cleanup, tdesc_numbered_register) (tdesc_numbered_register_choices, tdesc_find_register) (tdesc_register_name, tdesc_register_type) (tdesc_remote_register_number, tdesc_register_reggroup_p) (set_tdesc_pseudo_register_name, set_tdesc_pseudo_register_type) (set_tdesc_pseudo_register_reggroup_p, tdesc_use_registers) (tdesc_free_reg, tdesc_create_reg, tdesc_free_feature) (tdesc_create_feature, tdesc_record_type): New. (free_target_description): Free features. (_initialize_target_descriptions): Initialize tdesc_data. * arch-utils.c (default_remote_register_number): New. * arch-utils.h (default_remote_register_number): New prototype. * target-descriptions.h (set_tdesc_pseudo_register_name) (set_tdesc_pseudo_register_type, set_tdesc_pseudo_register_reggroup_p) (tdesc_use_registers, tdesc_data_alloc, tdesc_data_cleanup) (tdesc_numbered_register, tdesc_numbered_register_choices) (tdesc_has_registers, tdesc_find_feature, tdesc_feature_name) (tdesc_named_type, tdesc_create_feature, tdesc_record_type) (tdesc_create_reg): Declare. * gdbarch.sh (remote_register_number): New entry. * gdbarch.c, gdbarch.h: Regenerate. * remote.c (init_remote_state): Use gdbarch_remote_register_number. * features/gdb-target.dtd: Add feature, reg, vector, union, and field. * arm-tdep.c (arm_register_aliases): New. (arm_register_name_strings): Rename to... (arm_register_names): ...this. Make const. Delete the old version. (current_option, arm_register_byte): Delete. (set_disassembly_style): Simplify. Do not adjust arm_register_names. (value_of_arm_user_reg): New. (arm_gdbarch_init): Verify any described registers. Call tdesc_use_registers. Don't use arm_register_byte. Create aliases for standard register names. (_initialize_arm_tdep): Do not adjust arm_register_names. * user-regs.c (struct user_reg): Add baton member. (append_user_reg, user_reg_add_builtin, user_regs_init) (user_reg_add, value_of_user_reg): Use a baton for user register functions. * std-regs.c: Update. * user-regs.h (user_reg_read_ftype, user_reg_add_builtin) (user_reg_add): Add baton argument. * NEWS: Mention target description register support. * features/arm-core.xml, features/arm-fpa.xml: New. * eval.c (evaluate_subexp_standard): Allow ptype $register when the program is not running. * gdb.texinfo (-target-disconnect): Use @smallexample. (Requirements): Add anchor for Expat. Update description. (Target Descriptions): Mention Expat. (Target Description Format): Document new elements. Use @smallexample. (Predefined Target Types, Standard Target Features): New sections. * doc/gdbint.texinfo (Target Descriptions): New section. * gdb.xml/single-reg.xml, gdb.xml/tdesc-regs.exp, gdb.xml/core-only.xml, gdb.xml/extra-regs.xml: New files. --- gdb/ChangeLog | 70 ++++ gdb/Makefile.in | 11 +- gdb/NEWS | 4 + gdb/arch-utils.c | 7 + gdb/arch-utils.h | 3 + gdb/arm-tdep.c | 199 +++++++---- gdb/doc/ChangeLog | 10 + gdb/doc/gdb.texinfo | 248 ++++++++++++-- gdb/doc/gdbint.texinfo | 130 +++++++ gdb/eval.c | 7 +- gdb/features/arm-core.xml | 31 ++ gdb/features/arm-fpa.xml | 23 ++ gdb/features/gdb-target.dtd | 31 +- gdb/gdbarch.c | 24 ++ gdb/gdbarch.h | 7 + gdb/gdbarch.sh | 4 + gdb/remote.c | 5 +- gdb/std-regs.c | 20 +- gdb/target-descriptions.c | 641 ++++++++++++++++++++++++++++++++++- gdb/target-descriptions.h | 93 ++++- gdb/testsuite/ChangeLog | 5 + gdb/testsuite/gdb.xml/core-only.xml | 3 + gdb/testsuite/gdb.xml/extra-regs.xml | 16 + gdb/testsuite/gdb.xml/single-reg.xml | 5 + gdb/testsuite/gdb.xml/tdesc-regs.exp | 95 ++++++ gdb/user-regs.c | 20 +- gdb/user-regs.h | 7 +- gdb/xml-support.c | 12 +- gdb/xml-support.h | 3 + gdb/xml-tdesc.c | 233 ++++++++++++- 30 files changed, 1855 insertions(+), 112 deletions(-) create mode 100644 gdb/features/arm-core.xml create mode 100644 gdb/features/arm-fpa.xml create mode 100644 gdb/testsuite/gdb.xml/core-only.xml create mode 100644 gdb/testsuite/gdb.xml/extra-regs.xml create mode 100644 gdb/testsuite/gdb.xml/single-reg.xml create mode 100644 gdb/testsuite/gdb.xml/tdesc-regs.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3c119c7..de6f607 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,73 @@ +2007-02-08 Daniel Jacobowitz + + * Makefile.in (arm-tdep.o, eval.o, target-descriptions.o) + (xml-tdesc.o): Update. + * xml-support.c: Add a comment. + (gdb_xml_enums_boolean): New variable. + (gdb_xml_parse_attr_enum): Use strcasecmp. + * xml-support.h (gdb_xml_enums_boolean): Declare. + * xml-tdesc.c (struct tdesc_parsing_data): Record current_feature, + next_regnum, and current_union. + (tdesc_start_feature, tdesc_start_reg, tdesc_start_union) + (tdesc_end_union, tdesc_start_field, tdesc_start_vector) + (field_attributes, union_children, reg_attributes, union_attributes) + (vector_attributes, feature_attributes, feature_children): New. + (target_children): Make static. Add . + (tdesc_elements): Make static. + * target-descriptions.c (struct tdesc_reg, tdesc_reg_p, type_p) + (struct tdesc_feature, tdesc_feature_p): New types. + (struct target_desc): Add features member. + (struct tdesc_arch_data, tdesc_data): New. + (target_find_description): Clarify error message. Warn about + ignored register descriptions. + (tdesc_has_registers, tdesc_find_feature, tdesc_feature_name) + (tdesc_named_type, tdesc_data_init, tdesc_data_alloc) + (tdesc_data_cleanup, tdesc_numbered_register) + (tdesc_numbered_register_choices, tdesc_find_register) + (tdesc_register_name, tdesc_register_type) + (tdesc_remote_register_number, tdesc_register_reggroup_p) + (set_tdesc_pseudo_register_name, set_tdesc_pseudo_register_type) + (set_tdesc_pseudo_register_reggroup_p, tdesc_use_registers) + (tdesc_free_reg, tdesc_create_reg, tdesc_free_feature) + (tdesc_create_feature, tdesc_record_type): New. + (free_target_description): Free features. + (_initialize_target_descriptions): Initialize tdesc_data. + * arch-utils.c (default_remote_register_number): New. + * arch-utils.h (default_remote_register_number): New prototype. + * target-descriptions.h (set_tdesc_pseudo_register_name) + (set_tdesc_pseudo_register_type, set_tdesc_pseudo_register_reggroup_p) + (tdesc_use_registers, tdesc_data_alloc, tdesc_data_cleanup) + (tdesc_numbered_register, tdesc_numbered_register_choices) + (tdesc_has_registers, tdesc_find_feature, tdesc_feature_name) + (tdesc_named_type, tdesc_create_feature, tdesc_record_type) + (tdesc_create_reg): Declare. + * gdbarch.sh (remote_register_number): New entry. + * gdbarch.c, gdbarch.h: Regenerate. + * remote.c (init_remote_state): Use gdbarch_remote_register_number. + * features/gdb-target.dtd: Add feature, reg, vector, union, and field. + + * arm-tdep.c (arm_register_aliases): New. + (arm_register_name_strings): Rename to... + (arm_register_names): ...this. Make const. Delete the old version. + (current_option, arm_register_byte): Delete. + (set_disassembly_style): Simplify. Do not adjust arm_register_names. + (value_of_arm_user_reg): New. + (arm_gdbarch_init): Verify any described registers. Call + tdesc_use_registers. Don't use arm_register_byte. Create aliases + for standard register names. + (_initialize_arm_tdep): Do not adjust arm_register_names. + * user-regs.c (struct user_reg): Add baton member. + (append_user_reg, user_reg_add_builtin, user_regs_init) + (user_reg_add, value_of_user_reg): Use a baton for user + register functions. + * std-regs.c: Update. + * user-regs.h (user_reg_read_ftype, user_reg_add_builtin) + (user_reg_add): Add baton argument. + * NEWS: Mention target description register support. + * features/arm-core.xml, features/arm-fpa.xml: New. + * eval.c (evaluate_subexp_standard): Allow ptype $register + when the program is not running. + 2007-02-09 Nick Roberts * mi/mi-cmd-var.c (mi_cmd_var_create): Add value field. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 0a0f477..0337207 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1823,7 +1823,8 @@ arm-tdep.o: arm-tdep.c $(defs_h) $(frame_h) $(inferior_h) $(gdbcmd_h) \ $(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(arm_tdep_h) \ $(gdb_sim_arm_h) $(elf_bfd_h) $(coff_internal_h) $(elf_arm_h) \ $(gdb_assert_h) $(bfd_in2_h) $(libcoff_h) $(objfiles_h) \ - $(dwarf2_frame_h) $(gdbtypes_h) $(prologue_value_h) + $(dwarf2_frame_h) $(gdbtypes_h) $(prologue_value_h) \ + $(target_descriptions_h) $(user_regs_h) auxv.o: auxv.c $(defs_h) $(target_h) $(gdbtypes_h) $(command_h) \ $(inferior_h) $(valprint_h) $(gdb_assert_h) $(auxv_h) \ $(elf_common_h) @@ -1986,7 +1987,7 @@ eval.o: eval.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(value_h) $(expression_h) $(target_h) $(frame_h) $(language_h) \ $(f_lang_h) $(cp_abi_h) $(infcall_h) $(objc_lang_h) $(block_h) \ $(parser_defs_h) $(cp_support_h) $(gdb_assert_h) $(exceptions_h) \ - $(uiout_h) + $(uiout_h) $(regcache_h) event-loop.o: event-loop.c $(defs_h) $(event_loop_h) $(event_top_h) \ $(gdb_string_h) $(exceptions_h) $(gdb_assert_h) $(gdb_select_h) event-top.o: event-top.c $(defs_h) $(top_h) $(inferior_h) $(target_h) \ @@ -2793,7 +2794,8 @@ target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \ $(exceptions_h) $(target_descriptions_h) target-descriptions.o: target-descriptions.c $(defs_h) $(arch_utils_h) \ $(target_h) $(target_descriptions_h) $(vec_h) $(xml_tdesc_h) \ - $(gdbcmd_h) $(gdb_assert_h) + $(gdbcmd_h) $(gdb_assert_h) $(gdbtypes_h) $(reggroups_h) \ + $(xml_support_h) $(gdb_obstack_h) $(hashtab_h) target-memory.o: target-memory.c $(defs_h) $(vec_h) $(target_h) \ $(memory_map_h) $(gdb_assert_h) thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \ @@ -2892,7 +2894,8 @@ xcoffread.o: xcoffread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(gdb_stat_h) \ xcoffsolib.o: xcoffsolib.c $(defs_h) $(bfd_h) $(xcoffsolib_h) $(inferior_h) \ $(gdbcmd_h) $(symfile_h) $(frame_h) $(gdb_regex_h) xml-tdesc.o: xml-tdesc.c $(defs_h) $(target_h) $(target_descriptions_h) \ - $(xml_tdesc_h) $(xml_support_h) $(filenames_h) $(gdb_assert_h) + $(xml_tdesc_h) $(xml_support_h) $(filenames_h) $(gdb_assert_h) \ + $(gdbtypes_h) xml-support.o: xml-support.c $(defs_h) $(xml_support_h) $(exceptions_h) \ $(gdbcmd_h) $(gdb_string_h) $(gdb_expat_h) $(safe_ctype_h) xstormy16-tdep.o: xstormy16-tdep.c $(defs_h) $(frame_h) $(frame_base_h) \ diff --git a/gdb/NEWS b/gdb/NEWS index d9d35f5..864f4d0 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -18,6 +18,10 @@ a local file or over the remote serial protocol. * Arrays of explicitly SIGNED or UNSIGNED CHARs are now printed as arrays of numbers. +* Target descriptions can now describe target-specific registers, +for architectures which have implemented the support (currently +only ARM). + * New commands set mem inaccessible-by-default diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index a5ca574..1a987f3 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -263,6 +263,13 @@ generic_instruction_nullified (struct gdbarch *gdbarch, return 0; } +int +default_remote_register_number (struct gdbarch *gdbarch, + int regno) +{ + return regno; +} + /* Functions to manipulate the endianness of the target. */ diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index cc00e58..d995fcb 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -109,6 +109,9 @@ extern int default_stabs_argument_has_addr (struct gdbarch *gdbarch, extern int generic_instruction_nullified (struct gdbarch *gdbarch, struct regcache *regcache); +int default_remote_register_number (struct gdbarch *gdbarch, + int regno); + /* For compatibility with older architectures, returns (LEGACY_SIM_REGNO_IGNORE) when the register doesn't have a valid name. */ diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 7b92cd7..ab7b2e9 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -41,6 +41,8 @@ #include "dwarf2-frame.h" #include "gdbtypes.h" #include "prologue-value.h" +#include "target-descriptions.h" +#include "user-regs.h" #include "arm-tdep.h" #include "gdb/sim-arm.h" @@ -103,13 +105,58 @@ static const char *arm_abi_string = "auto"; /* Number of different reg name sets (options). */ static int num_disassembly_options; -/* We have more registers than the disassembler as gdb can print the value - of special registers as well. - The general register names are overwritten by whatever is being used by - the disassembler at the moment. We also adjust the case of cpsr and fps. */ +/* The standard register names, and all the valid aliases for them. */ +static const struct +{ + const char *name; + int regnum; +} arm_register_aliases[] = { + /* Basic register numbers. */ + { "r0", 0 }, + { "r1", 1 }, + { "r2", 2 }, + { "r3", 3 }, + { "r4", 4 }, + { "r5", 5 }, + { "r6", 6 }, + { "r7", 7 }, + { "r8", 8 }, + { "r9", 9 }, + { "r10", 10 }, + { "r11", 11 }, + { "r12", 12 }, + { "r13", 13 }, + { "r14", 14 }, + { "r15", 15 }, + /* Synonyms (argument and variable registers). */ + { "a1", 0 }, + { "a2", 1 }, + { "a3", 2 }, + { "a4", 3 }, + { "v1", 4 }, + { "v2", 5 }, + { "v3", 6 }, + { "v4", 7 }, + { "v5", 8 }, + { "v6", 9 }, + { "v7", 10 }, + { "v8", 11 }, + /* Other platform-specific names for r9. */ + { "sb", 9 }, + { "tr", 9 }, + /* Special names. */ + { "ip", 12 }, + { "sp", 13 }, + { "lr", 14 }, + { "pc", 15 }, + /* Names used by GCC (not listed in the ARM EABI). */ + { "sl", 10 }, + { "fp", 11 }, + /* A special name from the older ATPCS. */ + { "wr", 7 }, +}; -/* Initial value: Register names used in ARM's ISA documentation. */ -static char * arm_register_name_strings[] = +static const char *const arm_register_names[] = {"r0", "r1", "r2", "r3", /* 0 1 2 3 */ "r4", "r5", "r6", "r7", /* 4 5 6 7 */ "r8", "r9", "r10", "r11", /* 8 9 10 11 */ @@ -117,15 +164,12 @@ static char * arm_register_name_strings[] = "f0", "f1", "f2", "f3", /* 16 17 18 19 */ "f4", "f5", "f6", "f7", /* 20 21 22 23 */ "fps", "cpsr" }; /* 24 25 */ -static char **arm_register_names = arm_register_name_strings; /* Valid register name styles. */ static const char **valid_disassembly_styles; /* Disassembly style to use. Default to "std" register names. */ static const char *disassembly_style; -/* Index to that option in the opcodes table. */ -static int current_option; /* This is used to keep the bfd arch_info in sync with the disassembly style. */ @@ -1343,23 +1387,6 @@ arm_register_type (struct gdbarch *gdbarch, int regnum) return builtin_type_uint32; } -/* Index within `registers' of the first byte of the space for - register N. */ - -static int -arm_register_byte (int regnum) -{ - if (regnum < ARM_F0_REGNUM) - return regnum * INT_REGISTER_SIZE; - else if (regnum < ARM_PS_REGNUM) - return (NUM_GREGS * INT_REGISTER_SIZE - + (regnum - ARM_F0_REGNUM) * FP_REGISTER_SIZE); - else - return (NUM_GREGS * INT_REGISTER_SIZE - + NUM_FREGS * FP_REGISTER_SIZE - + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE); -} - /* Map GDB internal REGNUM onto the Arm simulator register numbers. */ static int arm_register_sim_regno (int regnum) @@ -2461,32 +2488,13 @@ arm_register_name (int i) static void set_disassembly_style (void) { - const char *setname, *setdesc, *const *regnames; - int numregs, j; - - /* Find the style that the user wants in the opcodes table. */ - int current = 0; - numregs = get_arm_regnames (current, &setname, &setdesc, ®names); - while ((disassembly_style != setname) - && (current < num_disassembly_options)) - get_arm_regnames (++current, &setname, &setdesc, ®names); - current_option = current; + int current; - /* Fill our copy. */ - for (j = 0; j < numregs; j++) - arm_register_names[j] = (char *) regnames[j]; - - /* Adjust case. */ - if (isupper (*regnames[ARM_PC_REGNUM])) - { - arm_register_names[ARM_FPS_REGNUM] = "FPS"; - arm_register_names[ARM_PS_REGNUM] = "CPSR"; - } - else - { - arm_register_names[ARM_FPS_REGNUM] = "fps"; - arm_register_names[ARM_PS_REGNUM] = "cpsr"; - } + /* Find the style that the user wants. */ + for (current = 0; current < num_disassembly_options; current++) + if (disassembly_style == valid_disassembly_styles[current]) + break; + gdb_assert (current < num_disassembly_options); /* Synchronize the disassembler. */ set_arm_regname_option (current); @@ -2544,6 +2552,13 @@ arm_write_pc (CORE_ADDR pc, ptid_t ptid) write_register_pid (ARM_PS_REGNUM, val & ~(CORE_ADDR) 0x20, ptid); } } + +static struct value * +value_of_arm_user_reg (struct frame_info *frame, const void *baton) +{ + const int *reg_p = baton; + return value_of_register (*reg_p, frame); +} static enum gdb_osabi arm_elf_osabi_sniffer (bfd *abfd) @@ -2580,6 +2595,65 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) struct gdbarch_list *best_arch; enum arm_abi_kind arm_abi = arm_abi_global; enum arm_float_model fp_model = arm_fp_model; + struct tdesc_arch_data *tdesc_data = NULL; + int i; + + /* Check any target description for validity. */ + if (tdesc_has_registers (info.target_desc)) + { + /* For most registers we require GDB's default names; but also allow + the numeric names for sp / lr / pc, as a convenience. */ + static const char *const arm_sp_names[] = { "r13", "sp", NULL }; + static const char *const arm_lr_names[] = { "r14", "lr", NULL }; + static const char *const arm_pc_names[] = { "r15", "pc", NULL }; + + const struct tdesc_feature *feature; + int i, valid_p; + + feature = tdesc_find_feature (info.target_desc, + "org.gnu.gdb.arm.core"); + if (feature == NULL) + return NULL; + + tdesc_data = tdesc_data_alloc (); + + valid_p = 1; + for (i = 0; i < ARM_SP_REGNUM; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, i, + arm_register_names[i]); + valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, + ARM_SP_REGNUM, + arm_sp_names); + valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, + ARM_LR_REGNUM, + arm_lr_names); + valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, + ARM_PC_REGNUM, + arm_pc_names); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + ARM_PS_REGNUM, "cpsr"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + + feature = tdesc_find_feature (info.target_desc, + "org.gnu.gdb.arm.fpa"); + if (feature != NULL) + { + valid_p = 1; + for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, i, + arm_register_names[i]); + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + } + } /* If we have an object to base this architecture on, try to determine its ABI. */ @@ -2709,7 +2783,11 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } if (best_arch != NULL) - return best_arch->gdbarch; + { + if (tdesc_data != NULL) + tdesc_data_cleanup (tdesc_data); + return best_arch->gdbarch; + } tdep = xcalloc (1, sizeof (struct gdbarch_tdep)); gdbarch = gdbarch_alloc (&info, tdep); @@ -2784,7 +2862,6 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM); /* ??? */ set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM); set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM); - set_gdbarch_deprecated_register_byte (gdbarch, arm_register_byte); set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS); set_gdbarch_register_type (gdbarch, arm_register_type); @@ -2842,6 +2919,16 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double); } + if (tdesc_data) + tdesc_use_registers (gdbarch, tdesc_data); + + /* Add standard register aliases. We add aliases even for those + nanes which are used by the current architecture - it's simpler, + and does no harm, since nothing ever lists user registers. */ + for (i = 0; i < ARRAY_SIZE (arm_register_aliases); i++) + user_reg_add (gdbarch, arm_register_aliases[i].name, + value_of_arm_user_reg, &arm_register_aliases[i].regnum); + return gdbarch; } @@ -2906,13 +2993,11 @@ _initialize_arm_tdep (void) length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc); rdptr += length; rest -= length; - /* Copy the default names (if found) and synchronize disassembler. */ + /* When we find the default names, tell the disassembler to use + them. */ if (!strcmp (setname, "std")) { disassembly_style = setname; - current_option = i; - for (j = 0; j < numregs; j++) - arm_register_names[j] = (char *) regnames[j]; set_arm_regname_option (i); } } diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index b37890e..fd7efe0 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,13 @@ +2007-02-08 Daniel Jacobowitz + + * gdb.texinfo (-target-disconnect): Use @smallexample. + (Requirements): Add anchor for Expat. Update description. + (Target Descriptions): Mention Expat. + (Target Description Format): Document new elements. Use + @smallexample. + (Predefined Target Types, Standard Target Features): New sections. + * doc/gdbint.texinfo (Target Descriptions): New section. + 2007-02-07 Daniel Jacobowitz * gdb.texinfo (Target Description Format): Add section on XInclude. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 251ed9e..15c4d7e 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -21047,9 +21047,9 @@ The corresponding @value{GDBN} command is @samp{detach}. @subsubheading Synopsis -@example +@smallexample -target-disconnect -@end example +@end smallexample Disconnect from the remote target. There's no output and the target is generally not resumed. @@ -22222,6 +22222,7 @@ working C90 compiler, e.g.@: GCC. @heading Tools/packages optional for building @value{GDBN} @table @asis @item Expat +@anchor{Expat} @value{GDBN} can use the Expat XML parsing library. This library may be included with your operating system distribution; if it is not, you can get the latest version from @url{http://expat.sourceforge.net}. @@ -22229,8 +22230,8 @@ The @code{configure} script will search for this library in several standard locations; if it is installed in an unusual path, you can use the @option{--with-libexpat-prefix} option to specify its location. -Expat is used currently only used to implement some remote-specific -features. +Expat is used for remote protocol memory maps (@pxref{Memory map format}) +and for target descriptions (@pxref{Target Descriptions}). @end table @@ -25738,9 +25739,15 @@ actually describe its own features. This lets @value{GDBN} support processor variants it has never seen before --- to the extent that the descriptions are accurate, and that @value{GDBN} understands them. +@value{GDBN} must be compiled with Expat support to support XML target +descriptions. @xref{Expat}. + @menu * Retrieving Descriptions:: How descriptions are fetched from a target. * Target Description Format:: The contents of a target description. +* Predefined Target Types:: Standard types available for target + descriptions. +* Standard Target Features:: Features @value{GDBN} knows about. @end menu @node Retrieving Descriptions @@ -25787,32 +25794,35 @@ check that your feature descriptions are well-formed and valid. However, to help people unfamiliar with XML write descriptions for their targets, we also describe the grammar here. -At the moment, target descriptions can only provide minimal information -about the architecture of the remote target. @value{GDBN} can use this -information to autoconfigure, or to warn you if you connect to an -unsupported target. +Target descriptions can identify the architecture of the remote target +and (for some architectures) provide information about custom register +sets. @value{GDBN} can use this information to autoconfigure for your +target, or to warn you if you connect to an unsupported target. Here is a simple target description: -@example +@smallexample i386:x86-64 -@end example +@end smallexample @noindent This minimal description only says that the target uses the x86-64 architecture. -A target description has the overall form: +A target description has the following overall form, with [ ] marking +optional elements and @dots{} marking repeatable elements. The elements +are explained further below. -@example +@smallexample - @var{arch name} + @r{[}@var{architecture}@r{]} + @r{[}@var{feature}@dots{}@r{]} -@end example +@end smallexample @noindent The description is generally insensitive to whitespace and line @@ -25821,10 +25831,6 @@ declaration and document type declaration can generally be omitted (@value{GDBN} does not require them), but specifying them may be useful for XML validation tools. -The content of the @samp{} element is an architecture -name, from the same selection accepted by @code{set architecture} -(@pxref{Targets, ,Specifying a Debugging Target}). - @subsection Inclusion @cindex target descriptions, inclusion @cindex XInclude @@ -25838,9 +25844,9 @@ share files between different possible target descriptions. You can divide a description into multiple files by replacing any element of the target description with an inclusion directive of the form: -@example +@smallexample -@end example +@end smallexample @noindent When @value{GDBN} encounters an element of this form, it will retrieve @@ -25852,6 +25858,208 @@ current description was read from a file, @value{GDBN} will look for @var{document} as a file in the same directory where it found the original description. +@subsection Architecture +@cindex + +An @samp{} element has this form: + +@smallexample + @var{arch} +@end smallexample + +@var{arch} is an architecture name from the same selection +accepted by @code{set architecture} (@pxref{Targets, ,Specifying a +Debugging Target}). + +@subsection Features +@cindex + +Each @samp{} describes some logical portion of the target +system. Features are currently used to describe available CPU +registers and the types of their contents. A @samp{} element +has this form: + +@smallexample + + @r{[}@var{type}@dots{}@r{]} + @var{reg}@dots{} + +@end smallexample + +@noindent +Each feature's name should be unique within the description. The name +of a feature does not matter unless @value{GDBN} has some special +knowledge of the contents of that feature; if it does, the feature +should have its standard name. @xref{Standard Target Features}. + +@subsection Types + +Any register's value is a collection of bits which @value{GDBN} must +interpret. The default interpretation is a two's complement integer, +but other types can be requested by name in the register description. +Some predefined types are provided by @value{GDBN} (@pxref{Predefined +Target Types}), and the description can define additional composite types. + +Each type element must have an @samp{id} attribute, which gives +a unique (within the containing @samp{}) name to the type. +Types must be defined before they are used. + +@cindex +Some targets offer vector registers, which can be treated as arrays +of scalar elements. These types are written as @samp{} elements, +specifying the array element type, @var{type}, and the number of elements, +@var{count}: + +@smallexample + +@end smallexample + +@cindex +If a register's value is usefully viewed in multiple ways, define it +with a union type containing the useful representations. The +@samp{} element contains one or more @samp{} elements, +each of which has a @var{name} and a @var{type}: + +@smallexample + + + @dots{} + +@end smallexample + +@subsection Registers +@cindex + +Each register is represented as an element with this form: + +@smallexample + +@end smallexample + +@noindent +The components are as follows: + +@table @var + +@item name +The register's name; it must be unique within the target description. + +@item bitsize +The register's size, in bits. + +@item regnum +The register's number. If omitted, a register's number is one greater +than that of the previous register (either in the current feature or in +a preceeding feature); the first register in the target description +defaults to zero. This register number is used to read or write +the register; e.g.@: it is used in the remote @code{p} and @code{P} +packets, and registers appear in the @code{g} and @code{G} packets +in order of increasing register number. + +@item save-restore +Whether the register should be preserved across inferior function +calls; this must be either @code{yes} or @code{no}. The default is +@code{yes}, which is appropriate for most registers except for +some system control registers; this is not related to the target's +ABI. + +@item type +The type of the register. @var{type} may be a predefined type, a type +defined in the current feature, or one of the special types @code{int} +and @code{float}. @code{int} is an integer type of the correct size +for @var{bitsize}, and @code{float} is a floating point type (in the +architecture's normal floating point format) of the correct size for +@var{bitsize}. The default is @code{int}. + +@item group +The register group to which this register belongs. @var{group} must +be either @code{general}, @code{float}, or @code{vector}. If no +@var{group} is specified, @value{GDBN} will not display the register +in @code{info registers}. + +@end table + +@node Predefined Target Types +@section Predefined Target Types +@cindex target descriptions, predefined types + +Type definitions in the self-description can build up composite types +from basic building blocks, but can not define fundamental types. Instead, +standard identifiers are provided by @value{GDBN} for the fundamental +types. The currently supported types are: + +@table @code + +@item int8 +@itemx int16 +@itemx int32 +@itemx int64 +Signed integer types holding the specified number of bits. + +@item uint8 +@itemx uint16 +@itemx uint32 +@itemx uint64 +Unsigned integer types holding the specified number of bits. + +@item code_ptr +@itemx data_ptr +Pointers to unspecified code and data. The program counter and +any dedicated return address register may be marked as code +pointers; printing a code pointer converts it into a symbolic +address. The stack pointer and any dedicated address registers +may be marked as data pointers. + +@item arm_fpa_ext +The 12-byte extended precision format used by ARM FPA registers. + +@end table + +@node Standard Target Features +@section Standard Target Features +@cindex target descriptions, standard features + +A target description must contain either no registers or all the +target's registers. If the description contains no registers, then +@value{GDBN} will assume a default register layout, selected based on +the architecture. If the description contains any registers, the +default layout will not be used; the standard registers must be +described in the target description, in such a way that @value{GDBN} +can recognize them. + +This is accomplished by giving specific names to feature elements +which contain standard registers. @value{GDBN} will look for features +with those names and verify that they contain the expected registers; +if any known feature is missing required registers, or if any required +feature is missing, @value{GDBN} will reject the target +description. You can add additional registers to any of the +standard features --- @value{GDBN} will display them just as if +they were added to an unrecognized feature. + +This section lists the known features and their expected contents. +Sample XML documents for these features are included in the +@value{GDBN} source tree, in the directory @file{gdb/features}. + +Names recognized by @value{GDBN} should include the name of the +company or organization which selected the name, and the overall +architecture to which the feature applies; so e.g.@: the feature +containing ARM core registers is named @samp{org.gnu.gdb.arm.core}. + +@subsection ARM Features +@cindex target descriptions, ARM features + +The @samp{org.gnu.gdb.arm.core} feature is required for ARM targets. +It should contain registers @samp{r0} through @samp{r13}, @samp{sp}, +@samp{lr}, @samp{pc}, and @samp{cpsr}. + +The @samp{org.gnu.gdb.arm.fpa} feature is optional. If present, it +should contain registers @samp{f0} through @samp{f7} and @samp{fps}. + @include gpl.texi diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo index c71e1f9..e0017ad 100644 --- a/gdb/doc/gdbint.texinfo +++ b/gdb/doc/gdbint.texinfo @@ -80,6 +80,7 @@ as the mechanisms that adapt @value{GDBN} to specific hosts and targets. * Language Support:: * Host Definition:: * Target Architecture Definition:: +* Target Descriptions:: * Target Vector Definition:: * Native Debugging:: * Support Libraries:: @@ -4512,6 +4513,135 @@ The @file{tm-@var{arch}.h} can be deleted. @file{@var{arch}.mt} and @file{configure.in} updated. +@node Target Descriptions +@chapter Target Descriptions +@cindex target descriptions + +The target architecture definition (@pxref{Target Architecture Definition}) +contains @value{GDBN}'s hard-coded knowledge about an architecture. For +some platforms, it is handy to have more flexible knowledge about a specific +instance of the architecture---for instance, a processor or development board. +@dfn{Target descriptions} provide a mechanism for the user to tell @value{GDBN} +more about what their target supports, or for the target to tell @value{GDBN} +directly. + +For details on writing, automatically supplying, and manually selecting +target descriptions, see @ref{Target Descriptions, , , gdb, +Debugging with @value{GDBN}}. This section will cover some related +topics about the @value{GDBN} internals. + +@menu +* Target Descriptions Implementation:: +* Adding Target Described Register Support:: +@end menu + +@node Target Descriptions Implementation +@section Target Descriptions Implementation +@cindex target descriptions, implementation + +Before @value{GDBN} connects to a new target, or runs a new program on +an existing target, it discards any existing target description and +reverts to a default gdbarch. Then, after connecting, it looks for a +new target description by calling @code{target_find_description}. + +A description may come from a user specified file (XML), the remote +@samp{qXfer:features:read} packet (also XML), or from any custom +@code{to_read_description} routine in the target vector. For instance, +the remote target supports guessing whether a MIPS target is 32-bit or +64-bit based on the size of the @samp{g} packet. + +If any target description is found, @value{GDBN} creates a new gdbarch +incorporating the description by calling @code{gdbarch_update_p}. Any +@samp{} element is handled first, to determine which +architecture's gdbarch initialization routine is called to create the +new architecture. Then the initialization routine is called, and has +a chance to adjust the constructed architecture based on the contents +of the target description. For instance, it can recognize any +properties set by a @code{to_read_description} routine. Also +see @ref{Adding Target Described Register Support}. + +@node Adding Target Described Register Support +@section Adding Target Described Register Support +@cindex target descriptions, adding register support + +Target descriptions can report additional registers specific to an +instance of the target. But it takes a little work in the architecture +specific routines to support this. + +A target description must either have no registers or a complete +set---this avoids complexity in trying to merge standard registers +with the target defined registers. It is the architecture's +responsibility to validate that a description with registers has +everything it needs. To keep architecture code simple, the same +mechanism is used to assign fixed internal register numbers to +standard registers. + +If @code{tdesc_has_registers} returns 1, the description contains +registers. The architecture's @code{gdbarch_init} routine should: + +@itemize @bullet + +@item +Call @code{tdesc_data_alloc} to allocate storage, early, before +searching for a matching gdbarch or allocating a new one. + +@item +Use @code{tdesc_find_feature} to locate standard features by name. + +@item +Use @code{tdesc_numbered_register} and @code{tdesc_numbered_register_choices} +to locate the expected registers in the standard features. + +@item +Return @code{NULL} if a required feature is missing, or if any standard +feature is missing expected registers. This will produce a warning that +the description was incomplete. + +@item +Free the allocated data before returning, unless @code{tdesc_use_registers} +is called. + +@item +Call @code{set_gdbarch_num_regs} as usual, with a number higher than any +fixed number passed to @code{tdesc_numbered_register}. + +@item +Call @code{tdesc_use_registers} after creating a new gdbarch, before +returning it. + +@end itemize + +After @code{tdesc_use_registers} has been called, the architecture's +@code{register_name}, @code{register_type}, and @code{register_reggroup_p} +routines will not be called; that information will be taken from +the target description. @code{num_regs} may be increased to account +for any additional registers in the description. + +Pseudo-registers require some extra care: + +@itemize @bullet + +@item +Using @code{tdesc_numbered_register} allows the architecture to give +constant register numbers to standard architectural registers, e.g.@: +as an @code{enum} in @file{@var{arch}-tdep.h}. But because +pseudo-registers are always numbered above @code{num_regs}, +which may be increased by the description, constant numbers +can not be used for pseudos. They must be numbered relative to +@code{num_regs} instead. + +@item +The description will not describe pseudo-registers, so the +architecture must call @code{set_tdesc_pseudo_register_name}, +@code{set_tdesc_pseudo_register_type}, and +@code{set_tdesc_pseudo_register_reggroup_p} to supply routines +describing pseudo registers. These routines will be passed +internal register numbers, so the same routines used for the +gdbarch equivalents are usually suitable. + +@end itemize + + @node Target Vector Definition @chapter Target Vector Definition diff --git a/gdb/eval.c b/gdb/eval.c index 5d1dc73..c385539 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -39,6 +39,7 @@ #include "cp-support.h" #include "ui-out.h" #include "exceptions.h" +#include "regcache.h" #include "gdb_assert.h" @@ -500,8 +501,12 @@ evaluate_subexp_standard (struct type *expect_type, case OP_REGISTER: { int regno = longest_to_int (exp->elts[pc + 1].longconst); - struct value *val = value_of_register (regno, get_selected_frame (NULL)); + struct value *val; (*pos) += 2; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + val = value_zero (register_type (current_gdbarch, regno), not_lval); + else + val = value_of_register (regno, get_selected_frame (NULL)); if (val == NULL) error (_("Value of register %s not available."), frame_map_regnum_to_name (get_selected_frame (NULL), regno)); diff --git a/gdb/features/arm-core.xml b/gdb/features/arm-core.xml new file mode 100644 index 0000000..c2718f5 --- /dev/null +++ b/gdb/features/arm-core.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/arm-fpa.xml b/gdb/features/arm-fpa.xml new file mode 100644 index 0000000..87a5b89 --- /dev/null +++ b/gdb/features/arm-fpa.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + diff --git a/gdb/features/gdb-target.dtd b/gdb/features/gdb-target.dtd index 8bcb049..b05e063 100644 --- a/gdb/features/gdb-target.dtd +++ b/gdb/features/gdb-target.dtd @@ -6,9 +6,38 @@ - + + + + + + + + + + + + + + + + %xinclude; diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 8b6d60b..562897a 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -203,6 +203,7 @@ struct gdbarch CORE_ADDR decr_pc_after_break; CORE_ADDR deprecated_function_start_offset; gdbarch_remote_translate_xfer_address_ftype *remote_translate_xfer_address; + gdbarch_remote_register_number_ftype *remote_register_number; gdbarch_fetch_tls_load_module_address_ftype *fetch_tls_load_module_address; CORE_ADDR frame_args_skip; gdbarch_unwind_pc_ftype *unwind_pc; @@ -330,6 +331,7 @@ struct gdbarch startup_gdbarch = 0, /* decr_pc_after_break */ 0, /* deprecated_function_start_offset */ generic_remote_translate_xfer_address, /* remote_translate_xfer_address */ + default_remote_register_number, /* remote_register_number */ 0, /* fetch_tls_load_module_address */ 0, /* frame_args_skip */ 0, /* unwind_pc */ @@ -440,6 +442,7 @@ gdbarch_alloc (const struct gdbarch_info *info, current_gdbarch->memory_insert_breakpoint = default_memory_insert_breakpoint; current_gdbarch->memory_remove_breakpoint = default_memory_remove_breakpoint; current_gdbarch->remote_translate_xfer_address = generic_remote_translate_xfer_address; + current_gdbarch->remote_register_number = default_remote_register_number; current_gdbarch->stabs_argument_has_addr = default_stabs_argument_has_addr; current_gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity; current_gdbarch->addr_bits_remove = core_addr_identity; @@ -584,6 +587,7 @@ verify_gdbarch (struct gdbarch *current_gdbarch) /* Skip verify of decr_pc_after_break, invalid_p == 0 */ /* Skip verify of deprecated_function_start_offset, invalid_p == 0 */ /* Skip verify of remote_translate_xfer_address, invalid_p == 0 */ + /* Skip verify of remote_register_number, invalid_p == 0 */ /* Skip verify of fetch_tls_load_module_address, has predicate */ /* Skip verify of frame_args_skip, invalid_p == 0 */ /* Skip verify of unwind_pc, has predicate */ @@ -1442,6 +1446,9 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file) "gdbarch_dump: regset_from_core_section = <0x%lx>\n", (long) current_gdbarch->regset_from_core_section); fprintf_unfiltered (file, + "gdbarch_dump: remote_register_number = <0x%lx>\n", + (long) current_gdbarch->remote_register_number); + fprintf_unfiltered (file, "gdbarch_dump: remote_translate_xfer_address = <0x%lx>\n", (long) current_gdbarch->remote_translate_xfer_address); fprintf_unfiltered (file, @@ -2990,6 +2997,23 @@ set_gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, } int +gdbarch_remote_register_number (struct gdbarch *gdbarch, int regno) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->remote_register_number != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_remote_register_number called\n"); + return gdbarch->remote_register_number (gdbarch, regno); +} + +void +set_gdbarch_remote_register_number (struct gdbarch *gdbarch, + gdbarch_remote_register_number_ftype remote_register_number) +{ + gdbarch->remote_register_number = remote_register_number; +} + +int gdbarch_fetch_tls_load_module_address_p (struct gdbarch *gdbarch) { gdb_assert (gdbarch != NULL); diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 8cfd33b..2c9bc57 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -947,6 +947,13 @@ typedef void (gdbarch_remote_translate_xfer_address_ftype) (struct gdbarch *gdba extern void gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len); extern void set_gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch, gdbarch_remote_translate_xfer_address_ftype *remote_translate_xfer_address); +/* Return the remote protocol register number associated with this + register. Normally the identity mapping. */ + +typedef int (gdbarch_remote_register_number_ftype) (struct gdbarch *gdbarch, int regno); +extern int gdbarch_remote_register_number (struct gdbarch *gdbarch, int regno); +extern void set_gdbarch_remote_register_number (struct gdbarch *gdbarch, gdbarch_remote_register_number_ftype *remote_register_number); + /* Fetch the target specific address used to represent a load module. */ #if defined (FETCH_TLS_LOAD_MODULE_ADDRESS) diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index d054799..c776e28 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -574,6 +574,10 @@ v:=:CORE_ADDR:deprecated_function_start_offset:::0:::0 m::void:remote_translate_xfer_address:struct regcache *regcache, CORE_ADDR gdb_addr, int gdb_len, CORE_ADDR *rem_addr, int *rem_len:regcache, gdb_addr, gdb_len, rem_addr, rem_len::generic_remote_translate_xfer_address::0 +# Return the remote protocol register number associated with this +# register. Normally the identity mapping. +m::int:remote_register_number:int regno:regno::default_remote_register_number::0 + # Fetch the target specific address used to represent a load module. F:=:CORE_ADDR:fetch_tls_load_module_address:struct objfile *objfile:objfile # diff --git a/gdb/remote.c b/gdb/remote.c index 48be844..bb49aca 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -334,12 +334,13 @@ init_remote_state (struct gdbarch *gdbarch) rsa = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct remote_arch_state); - /* Assume a 1:1 regnum<->pnum table. */ + /* Use the architecture to build a regnum<->pnum table, which will be + 1:1 unless a feature set specifies otherwise. */ rsa->regs = GDBARCH_OBSTACK_CALLOC (gdbarch, NUM_REGS, struct packet_reg); for (regnum = 0; regnum < NUM_REGS; regnum++) { struct packet_reg *r = &rsa->regs[regnum]; - r->pnum = regnum; + r->pnum = gdbarch_remote_register_number (gdbarch, regnum); r->regnum = regnum; } diff --git a/gdb/std-regs.c b/gdb/std-regs.c index df50207..2edcba8 100644 --- a/gdb/std-regs.c +++ b/gdb/std-regs.c @@ -53,7 +53,7 @@ build_builtin_type_frame_reg (void) } static struct value * -value_of_builtin_frame_reg (struct frame_info *frame) +value_of_builtin_frame_reg (struct frame_info *frame, const void *baton) { struct value *val; gdb_byte *buf; @@ -72,7 +72,7 @@ value_of_builtin_frame_reg (struct frame_info *frame) } static struct value * -value_of_builtin_frame_fp_reg (struct frame_info *frame) +value_of_builtin_frame_fp_reg (struct frame_info *frame, const void *baton) { if (DEPRECATED_FP_REGNUM >= 0) /* NOTE: cagney/2003-04-24: Since the mere presence of "fp" in the @@ -96,7 +96,7 @@ value_of_builtin_frame_fp_reg (struct frame_info *frame) } static struct value * -value_of_builtin_frame_pc_reg (struct frame_info *frame) +value_of_builtin_frame_pc_reg (struct frame_info *frame, const void *baton) { if (PC_REGNUM >= 0) return value_of_register (PC_REGNUM, frame); @@ -114,7 +114,7 @@ value_of_builtin_frame_pc_reg (struct frame_info *frame) } static struct value * -value_of_builtin_frame_sp_reg (struct frame_info *frame) +value_of_builtin_frame_sp_reg (struct frame_info *frame, const void *baton) { #ifdef SP_REGNUM if (SP_REGNUM >= 0) @@ -124,7 +124,7 @@ value_of_builtin_frame_sp_reg (struct frame_info *frame) } static struct value * -value_of_builtin_frame_ps_reg (struct frame_info *frame) +value_of_builtin_frame_ps_reg (struct frame_info *frame, const void *baton) { #ifdef PS_REGNUM if (PS_REGNUM >= 0) @@ -147,14 +147,14 @@ _initialize_frame_reg (void) /* Frame based $fp, $pc, $sp and $ps. These only come into play when the target does not define its own version of these registers. */ - user_reg_add_builtin ("fp", value_of_builtin_frame_fp_reg); - user_reg_add_builtin ("pc", value_of_builtin_frame_pc_reg); - user_reg_add_builtin ("sp", value_of_builtin_frame_sp_reg); - user_reg_add_builtin ("ps", value_of_builtin_frame_ps_reg); + user_reg_add_builtin ("fp", value_of_builtin_frame_fp_reg, NULL); + user_reg_add_builtin ("pc", value_of_builtin_frame_pc_reg, NULL); + user_reg_add_builtin ("sp", value_of_builtin_frame_sp_reg, NULL); + user_reg_add_builtin ("ps", value_of_builtin_frame_ps_reg, NULL); /* NOTE: cagney/2002-04-05: For moment leave the $frame / $gdbframe / $gdb.frame disabled. It isn't yet clear which of the many options is the best. */ if (0) - user_reg_add_builtin ("frame", value_of_builtin_frame_reg); + user_reg_add_builtin ("frame", value_of_builtin_frame_reg, NULL); } diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index 1100f5e..1f8cf7e 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -24,12 +24,17 @@ #include "defs.h" #include "arch-utils.h" #include "gdbcmd.h" +#include "gdbtypes.h" +#include "reggroups.h" #include "target.h" #include "target-descriptions.h" #include "vec.h" +#include "xml-support.h" #include "xml-tdesc.h" #include "gdb_assert.h" +#include "gdb_obstack.h" +#include "hashtab.h" /* Types. */ @@ -40,6 +45,69 @@ typedef struct property } property_s; DEF_VEC_O(property_s); +/* An individual register from a target description. */ + +typedef struct tdesc_reg +{ + /* The name of this register. In standard features, it may be + recognized by the architecture support code, or it may be purely + for the user. */ + char *name; + + /* The register number used by this target to refer to this + register. This is used for remote p/P packets and to determine + the ordering of registers in the remote g/G packets. */ + long target_regnum; + + /* If this flag is set, GDB should save and restore this register + around calls to an inferior function. */ + int save_restore; + + /* The name of the register group containing this register, or NULL + if the group should be automatically determined from the + register's type. If this is "general", "float", or "vector", the + corresponding "info" command should display this register's + value. It can be an arbitrary string, but should be limited to + alphanumeric characters and internal hyphens. Currently other + strings are ignored (treated as NULL). */ + char *group; + + /* The size of the register, in bits. */ + int bitsize; + + /* The type of the register. This string corresponds to either + a named type from the target description or a predefined + type from GDB. */ + char *type; + + /* The target-described type corresponding to TYPE, if found. */ + struct type *gdb_type; +} *tdesc_reg_p; +DEF_VEC_P(tdesc_reg_p); + +/* A named type from a target description. */ +typedef struct type *type_p; +DEF_VEC_P(type_p); + +/* A feature from a target description. Each feature is a collection + of other elements, e.g. registers and types. */ + +typedef struct tdesc_feature +{ + /* The name of this feature. It may be recognized by the architecture + support code. */ + char *name; + + /* The registers associated with this feature. */ + VEC(tdesc_reg_p) *registers; + + /* The types associated with this feature. */ + VEC(type_p) *types; +} *tdesc_feature_p; +DEF_VEC_P(tdesc_feature_p); + +/* A target description. */ + struct target_desc { /* The architecture reported by the target, if any. */ @@ -47,6 +115,30 @@ struct target_desc /* Any architecture-specific properties specified by the target. */ VEC(property_s) *properties; + + /* The features associated with this target. */ + VEC(tdesc_feature_p) *features; +}; + +/* Per-architecture data associated with a target description. The + target description may be shared by multiple architectures, but + this data is private to one gdbarch. */ + +struct tdesc_arch_data +{ + /* A list of registers, indexed by GDB's internal register number. + During initialization of the gdbarch this list is used to store + registers which the architecture assigns a fixed register number. + Registers which are NULL in this array, or off the end, are + treated as zero-sized and nameless (i.e. placeholders in the + numbering). */ + VEC(tdesc_reg_p) *registers; + + /* Functions which report the register name, type, and reggroups for + pseudo-registers. */ + gdbarch_register_name_ftype *pseudo_register_name; + gdbarch_register_type_ftype *pseudo_register_type; + gdbarch_register_reggroup_p_ftype *pseudo_register_reggroup_p; }; /* Global state. These variables are associated with the current @@ -72,6 +164,11 @@ static const struct target_desc *current_target_desc; static char *target_description_filename; +/* A handle for architecture-specific data associated with the + target description (see struct tdesc_arch_data). */ + +static struct gdbarch_data *tdesc_data; + /* Fetch the current target's description, and switch the current architecture to one which incorporates that description. */ @@ -116,7 +213,17 @@ target_find_description (void) gdbarch_info_init (&info); info.target_desc = current_target_desc; if (!gdbarch_update_p (info)) - warning (_("Could not use target-supplied description")); + warning (_("Architecture rejected target-supplied description")); + else + { + struct tdesc_arch_data *data; + + data = gdbarch_data (current_gdbarch, tdesc_data); + if (tdesc_has_registers (current_target_desc) + && data->registers == NULL) + warning (_("Target-supplied registers are not supported " + "by the current architecture")); + } } /* Now that we know this description is usable, record that we @@ -158,7 +265,7 @@ target_current_description (void) } -/* Direct accessors for feature sets. */ +/* Direct accessors for target descriptions. */ /* Return the string value of a property named KEY, or NULL if the property was not specified. */ @@ -187,8 +294,529 @@ tdesc_architecture (const struct target_desc *target_desc) } +/* Return 1 if this target description includes any registers. */ + +int +tdesc_has_registers (const struct target_desc *target_desc) +{ + int ix; + struct tdesc_feature *feature; + + if (target_desc == NULL) + return 0; + + for (ix = 0; + VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature); + ix++) + if (! VEC_empty (tdesc_reg_p, feature->registers)) + return 1; + + return 0; +} + +/* Return the feature with the given name, if present, or NULL if + the named feature is not found. */ + +const struct tdesc_feature * +tdesc_find_feature (const struct target_desc *target_desc, + const char *name) +{ + int ix; + struct tdesc_feature *feature; + + for (ix = 0; + VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature); + ix++) + if (strcmp (feature->name, name) == 0) + return feature; + + return NULL; +} + +/* Return the name of FEATURE. */ + +const char * +tdesc_feature_name (const struct tdesc_feature *feature) +{ + return feature->name; +} + +/* Return the type associated with ID in the context of FEATURE, or + NULL if none. */ + +struct type * +tdesc_named_type (const struct tdesc_feature *feature, const char *id) +{ + int ix; + struct type *gdb_type; + + /* First try target-defined types. */ + for (ix = 0; VEC_iterate (type_p, feature->types, ix, gdb_type); ix++) + if (strcmp (TYPE_NAME (gdb_type), id) == 0) + return gdb_type; + + /* Next try some predefined types. Note that none of these types + depend on the current architecture; some of the builtin_type_foo + variables are swapped based on the architecture. */ + if (strcmp (id, "int8") == 0) + return builtin_type_int8; + + if (strcmp (id, "int16") == 0) + return builtin_type_int16; + + if (strcmp (id, "int32") == 0) + return builtin_type_int32; + + if (strcmp (id, "int64") == 0) + return builtin_type_int64; + + if (strcmp (id, "uint8") == 0) + return builtin_type_uint8; + + if (strcmp (id, "uint16") == 0) + return builtin_type_uint16; + + if (strcmp (id, "uint32") == 0) + return builtin_type_uint32; + + if (strcmp (id, "uint64") == 0) + return builtin_type_uint64; + + if (strcmp (id, "code_ptr") == 0) + return builtin_type_void_func_ptr; + + if (strcmp (id, "data_ptr") == 0) + return builtin_type_void_data_ptr; + + if (strcmp (id, "arm_fpa_ext") == 0) + return builtin_type_arm_ext; + + return NULL; +} + + +/* Support for registers from target descriptions. */ + +/* Construct the per-gdbarch data. */ + +static void * +tdesc_data_init (struct obstack *obstack) +{ + struct tdesc_arch_data *data; + + data = OBSTACK_ZALLOC (obstack, struct tdesc_arch_data); + return data; +} + +/* Similar, but for the temporary copy used during architecture + initialization. */ + +struct tdesc_arch_data * +tdesc_data_alloc (void) +{ + return XZALLOC (struct tdesc_arch_data); +} + +/* Free something allocated by tdesc_data_alloc, if it is not going + to be used (for instance if it was unsuitable for the + architecture). */ + +void +tdesc_data_cleanup (void *data_untyped) +{ + struct tdesc_arch_data *data = data_untyped; + + VEC_free (tdesc_reg_p, data->registers); + xfree (data); +} + +/* Search FEATURE for a register named NAME. */ + +int +tdesc_numbered_register (const struct tdesc_feature *feature, + struct tdesc_arch_data *data, + int regno, const char *name) +{ + int ixr; + struct tdesc_reg *reg; + + for (ixr = 0; + VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg); + ixr++) + if (strcasecmp (reg->name, name) == 0) + { + /* Make sure the vector includes a REGNO'th element. */ + while (regno >= VEC_length (tdesc_reg_p, data->registers)) + VEC_safe_push (tdesc_reg_p, data->registers, NULL); + VEC_replace (tdesc_reg_p, data->registers, regno, reg); + return 1; + } + + return 0; +} + +/* Search FEATURE for a register whose name is in NAMES. */ + +int +tdesc_numbered_register_choices (const struct tdesc_feature *feature, + struct tdesc_arch_data *data, + int regno, const char *const names[]) +{ + int i; + + for (i = 0; names[i] != NULL; i++) + if (tdesc_numbered_register (feature, data, regno, names[i])) + return 1; + + return 0; +} + +/* Look up a register by its GDB internal register number. */ + +static struct tdesc_reg * +tdesc_find_register (struct gdbarch *gdbarch, int regno) +{ + struct tdesc_reg *reg; + struct tdesc_arch_data *data; + + data = gdbarch_data (gdbarch, tdesc_data); + if (regno < VEC_length (tdesc_reg_p, data->registers)) + return VEC_index (tdesc_reg_p, data->registers, regno); + else + return NULL; +} + +static const char * +tdesc_register_name (int regno) +{ + struct tdesc_reg *reg = tdesc_find_register (current_gdbarch, regno); + int num_regs = gdbarch_num_regs (current_gdbarch); + int num_pseudo_regs = gdbarch_num_pseudo_regs (current_gdbarch); + + if (reg != NULL) + return reg->name; + + if (regno >= num_regs && regno < num_regs + num_pseudo_regs) + { + struct tdesc_arch_data *data = gdbarch_data (current_gdbarch, + tdesc_data); + gdb_assert (data->pseudo_register_name != NULL); + return data->pseudo_register_name (regno); + } + + return ""; +} + +static struct type * +tdesc_register_type (struct gdbarch *gdbarch, int regno) +{ + struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); + int num_regs = gdbarch_num_regs (gdbarch); + int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch); + + if (reg == NULL && regno >= num_regs && regno < num_regs + num_pseudo_regs) + { + struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + gdb_assert (data->pseudo_register_type != NULL); + return data->pseudo_register_type (gdbarch, regno); + } + + if (reg == NULL) + /* Return "int0_t", since "void" has a misleading size of one. */ + return builtin_type_int0; + + /* First check for a predefined or target defined type. */ + if (reg->gdb_type) + return reg->gdb_type; + + /* Next try size-sensitive type shortcuts. */ + if (strcmp (reg->type, "float") == 0) + { + if (reg->bitsize == gdbarch_float_bit (gdbarch)) + return builtin_type_float; + else if (reg->bitsize == gdbarch_double_bit (gdbarch)) + return builtin_type_double; + else if (reg->bitsize == gdbarch_long_double_bit (gdbarch)) + return builtin_type_long_double; + } + else if (strcmp (reg->type, "int") == 0) + { + if (reg->bitsize == gdbarch_long_bit (gdbarch)) + return builtin_type_long; + else if (reg->bitsize == TARGET_CHAR_BIT) + return builtin_type_char; + else if (reg->bitsize == gdbarch_short_bit (gdbarch)) + return builtin_type_short; + else if (reg->bitsize == gdbarch_int_bit (gdbarch)) + return builtin_type_int; + else if (reg->bitsize == gdbarch_long_long_bit (gdbarch)) + return builtin_type_long_long; + else if (reg->bitsize == gdbarch_ptr_bit (gdbarch)) + /* A bit desperate by this point... */ + return builtin_type_void_data_ptr; + } + else + internal_error (__FILE__, __LINE__, + "Register \"%s\" has an unknown type \"%s\"", + reg->name, reg->type); + + warning (_("Register \"%s\" has an unsupported size (%d bits)"), + reg->name, reg->bitsize); + return builtin_type_long; +} + +static int +tdesc_remote_register_number (struct gdbarch *gdbarch, int regno) +{ + struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); + + if (reg != NULL) + return reg->target_regnum; + else + return -1; +} + +/* Check whether REGNUM is a member of REGGROUP. Registers from the + target description may be classified as general, float, or vector. + Registers with no group specified go to the default reggroup + function and are handled by type. + + Arbitrary strings (other than "general", "float", and "vector") + from the description are not used; they cause the register to be + displayed in "info all-registers" but excluded from "info + registers" et al. The names of containing features are also not + used. This might be extended to display registers in some more + useful groupings. + + The save-restore flag is also implemented here. */ + +static int +tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno, + struct reggroup *reggroup) +{ + int num_regs = gdbarch_num_regs (gdbarch); + int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch); + struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno); + + if (reg == NULL && regno >= num_regs && regno < num_regs + num_pseudo_regs) + { + struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + gdb_assert (data->pseudo_register_reggroup_p != NULL); + return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup); + } + + if (reg != NULL && reg->group != NULL) + { + int general_p = 0, float_p = 0, vector_p = 0; + + if (strcmp (reg->group, "general") == 0) + general_p = 1; + else if (strcmp (reg->group, "float") == 0) + float_p = 1; + else if (strcmp (reg->group, "vector") == 0) + vector_p = 1; + + if (reggroup == float_reggroup) + return float_p; + + if (reggroup == vector_reggroup) + return vector_p; + + if (reggroup == general_reggroup) + return general_p; + } + + if (reg != NULL + && (reggroup == save_reggroup || reggroup == restore_reggroup)) + return reg->save_restore; + + return default_register_reggroup_p (gdbarch, regno, reggroup); +} + +/* Record architecture-specific functions to call for pseudo-register + support. */ + +void +set_tdesc_pseudo_register_name (struct gdbarch *gdbarch, + gdbarch_register_name_ftype *pseudo_name) +{ + struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + + data->pseudo_register_name = pseudo_name; +} + +void +set_tdesc_pseudo_register_type (struct gdbarch *gdbarch, + gdbarch_register_type_ftype *pseudo_type) +{ + struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + + data->pseudo_register_type = pseudo_type; +} + +void +set_tdesc_pseudo_register_reggroup_p + (struct gdbarch *gdbarch, + gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p) +{ + struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data); + + data->pseudo_register_reggroup_p = pseudo_reggroup_p; +} + +/* Update GDBARCH to use the target description for registers. */ + +void +tdesc_use_registers (struct gdbarch *gdbarch, + struct tdesc_arch_data *early_data) +{ + int num_regs = gdbarch_num_regs (gdbarch); + int i, ixf, ixr; + const struct target_desc *target_desc; + struct tdesc_feature *feature; + struct tdesc_reg *reg; + struct tdesc_arch_data *data; + htab_t reg_hash; + + target_desc = gdbarch_target_desc (gdbarch); + + /* We can't use the description for registers if it doesn't describe + any. This function should only be called after validating + registers, so the caller should know that registers are + included. */ + gdb_assert (tdesc_has_registers (target_desc)); + + data = gdbarch_data (gdbarch, tdesc_data); + data->registers = early_data->registers; + xfree (early_data); + + /* Build up a set of all registers, so that we can assign register + numbers where needed. The hash table expands as necessary, so + the initial size is arbitrary. */ + reg_hash = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL); + for (ixf = 0; + VEC_iterate (tdesc_feature_p, target_desc->features, ixf, feature); + ixf++) + for (ixr = 0; + VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg); + ixr++) + { + void **slot = htab_find_slot (reg_hash, reg, INSERT); + + *slot = reg; + } + + /* Remove any registers which were assigned numbers by the + architecture. */ + for (ixr = 0; VEC_iterate (tdesc_reg_p, data->registers, ixr, reg); ixr++) + if (reg) + htab_remove_elt (reg_hash, reg); + + /* Assign numbers to the remaining registers and add them to the + list of registers. The new numbers are always above NUM_REGS. + Iterate over the features, not the hash table, so that the order + matches that in the target description. */ + + gdb_assert (VEC_length (tdesc_reg_p, data->registers) <= num_regs); + while (VEC_length (tdesc_reg_p, data->registers) < num_regs) + VEC_safe_push (tdesc_reg_p, data->registers, NULL); + for (ixf = 0; + VEC_iterate (tdesc_feature_p, target_desc->features, ixf, feature); + ixf++) + for (ixr = 0; + VEC_iterate (tdesc_reg_p, feature->registers, ixr, reg); + ixr++) + if (htab_find (reg_hash, reg) != NULL) + { + VEC_safe_push (tdesc_reg_p, data->registers, reg); + num_regs++; + } + + htab_delete (reg_hash); + + /* Update the architecture. */ + set_gdbarch_num_regs (gdbarch, num_regs); + set_gdbarch_register_name (gdbarch, tdesc_register_name); + set_gdbarch_register_type (gdbarch, tdesc_register_type); + set_gdbarch_remote_register_number (gdbarch, + tdesc_remote_register_number); + set_gdbarch_register_reggroup_p (gdbarch, tdesc_register_reggroup_p); +} + + /* Methods for constructing a target description. */ +static void +tdesc_free_reg (struct tdesc_reg *reg) +{ + xfree (reg->name); + xfree (reg->type); + xfree (reg->group); + xfree (reg); +} + +void +tdesc_create_reg (struct tdesc_feature *feature, const char *name, + int regnum, int save_restore, const char *group, + int bitsize, const char *type) +{ + struct tdesc_reg *reg = XZALLOC (struct tdesc_reg); + + reg->name = xstrdup (name); + reg->target_regnum = regnum; + reg->save_restore = save_restore; + reg->group = group ? xstrdup (group) : NULL; + reg->bitsize = bitsize; + reg->type = type ? xstrdup (type) : NULL; + + /* If the register's type is target-defined, look it up now. We may not + have easy access to the containing feature when we want it later. */ + reg->gdb_type = tdesc_named_type (feature, reg->type); + + VEC_safe_push (tdesc_reg_p, feature->registers, reg); +} + +static void +tdesc_free_feature (struct tdesc_feature *feature) +{ + struct tdesc_reg *reg; + int ix; + + for (ix = 0; VEC_iterate (tdesc_reg_p, feature->registers, ix, reg); ix++) + tdesc_free_reg (reg); + VEC_free (tdesc_reg_p, feature->registers); + + /* There is no easy way to free xmalloc-allocated types, nor is + there a way to allocate types on an obstack not associated with + an objfile. Therefore we never free types. Since we only ever + parse an identical XML document once, this memory leak is mostly + contained. */ + VEC_free (type_p, feature->types); + + xfree (feature->name); + xfree (feature); +} + +struct tdesc_feature * +tdesc_create_feature (struct target_desc *tdesc, const char *name) +{ + struct tdesc_feature *new_feature = XZALLOC (struct tdesc_feature); + + new_feature->name = xstrdup (name); + + VEC_safe_push (tdesc_feature_p, tdesc->features, new_feature); + return new_feature; +} + +void +tdesc_record_type (struct tdesc_feature *feature, struct type *type) +{ + /* The type's ID should be used as its TYPE_NAME. */ + gdb_assert (TYPE_NAME (type) != NULL); + + VEC_safe_push (type_p, feature->types, type); +} + struct target_desc * allocate_target_description (void) { @@ -199,10 +827,17 @@ static void free_target_description (void *arg) { struct target_desc *target_desc = arg; + struct tdesc_feature *feature; struct property *prop; int ix; for (ix = 0; + VEC_iterate (tdesc_feature_p, target_desc->features, ix, feature); + ix++) + tdesc_free_feature (feature); + VEC_free (tdesc_feature_p, target_desc->features); + + for (ix = 0; VEC_iterate (property_s, target_desc->properties, ix, prop); ix++) { @@ -305,6 +940,8 @@ unset_tdesc_filename_cmd (char *args, int from_tty) void _initialize_target_descriptions (void) { + tdesc_data = gdbarch_data_register_pre_init (tdesc_data_init); + add_prefix_cmd ("tdesc", class_maintenance, set_tdesc_cmd, _("\ Set target description specific variables."), &tdesc_set_cmdlist, "set tdesc ", diff --git a/gdb/target-descriptions.h b/gdb/target-descriptions.h index f45e53b..9c64190 100644 --- a/gdb/target-descriptions.h +++ b/gdb/target-descriptions.h @@ -24,7 +24,12 @@ #ifndef TARGET_DESCRIPTIONS_H #define TARGET_DESCRIPTIONS_H 1 +struct tdesc_feature; +struct tdesc_arch_data; +struct tdesc_reg; struct target_desc; +struct target_ops; +struct type; /* Fetch the current target's description, and switch the current architecture to one which incorporates that description. */ @@ -42,6 +47,65 @@ void target_clear_description (void); const struct target_desc *target_current_description (void); +/* Record architecture-specific functions to call for pseudo-register + support. If tdesc_use_registers is called and NUM_PSEUDO_REGS + is greater than zero, then these should be called as well. + They are equivalent to the gdbarch methods with similar names, + except that they will only be called for pseudo registers. */ + +void set_tdesc_pseudo_register_name + (struct gdbarch *gdbarch, gdbarch_register_name_ftype *pseudo_name); + +void set_tdesc_pseudo_register_type + (struct gdbarch *gdbarch, gdbarch_register_type_ftype *pseudo_type); + +void set_tdesc_pseudo_register_reggroup_p + (struct gdbarch *gdbarch, + gdbarch_register_reggroup_p_ftype *pseudo_reggroup_p); + +/* Update GDBARCH to use the target description for registers. Fixed + register assignments are taken from EARLY_DATA, which is freed. + All registers which have not been assigned fixed numbers are given + numbers above the current value of NUM_REGS. NUM_REGS and various + register-related predicates are updated to refer to the target + description. This function should only be called from the + architecture's gdbarch initialization routine, and only after + successfully validating the required registers. */ + +void tdesc_use_registers (struct gdbarch *gdbarch, + struct tdesc_arch_data *early_data); + +/* Allocate initial data for validation of a target description during + gdbarch initialization. */ + +struct tdesc_arch_data *tdesc_data_alloc (void); + +/* Clean up data allocated by tdesc_data_alloc. This should only + be called to discard the data; tdesc_use_registers takes ownership + of its EARLY_DATA argument. */ + +void tdesc_data_cleanup (void *data_untyped); + +/* Search FEATURE for a register named NAME. Record REGNO and the + register in DATA; when tdesc_use_registers is called, REGNO will be + assigned to the register. 1 is returned if the register was found, + 0 if it was not. */ + +int tdesc_numbered_register (const struct tdesc_feature *feature, + struct tdesc_arch_data *data, + int regno, const char *name); + +/* Search FEATURE for a register with any of the names from NAMES + (NULL-terminated). Record REGNO and the register in DATA; when + tdesc_use_registers is called, REGNO will be assigned to the + register. 1 is returned if the register was found, 0 if it was + not. */ + +int tdesc_numbered_register_choices (const struct tdesc_feature *feature, + struct tdesc_arch_data *data, + int regno, const char *const names[]); + + /* Accessors for target descriptions. */ /* Return the BFD architecture associated with this target @@ -56,14 +120,41 @@ const struct bfd_arch_info *tdesc_architecture const char *tdesc_property (const struct target_desc *, const char *key); +/* Return 1 if this target description describes any registers. */ + +int tdesc_has_registers (const struct target_desc *); + +/* Return the feature with the given name, if present, or NULL if + the named feature is not found. */ + +const struct tdesc_feature *tdesc_find_feature (const struct target_desc *, + const char *name); + +/* Return the name of FEATURE. */ + +const char *tdesc_feature_name (const struct tdesc_feature *feature); + +/* Return the type associated with ID in the context of FEATURE, or + NULL if none. */ + +struct type *tdesc_named_type (const struct tdesc_feature *feature, + const char *id); + /* Methods for constructing a target description. */ struct target_desc *allocate_target_description (void); struct cleanup *make_cleanup_free_target_description (struct target_desc *); void set_tdesc_architecture (struct target_desc *, const struct bfd_arch_info *); - void set_tdesc_property (struct target_desc *, const char *key, const char *value); +struct tdesc_feature *tdesc_create_feature (struct target_desc *tdesc, + const char *name); +void tdesc_record_type (struct tdesc_feature *feature, struct type *type); + +void tdesc_create_reg (struct tdesc_feature *feature, const char *name, + int regnum, int save_restore, const char *group, + int bitsize, const char *type); + #endif /* TARGET_DESCRIPTIONS_H */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index e1a35a9..e7ac4b3 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-02-08 Daniel Jacobowitz + + * gdb.xml/single-reg.xml, gdb.xml/tdesc-regs.exp, + gdb.xml/core-only.xml, gdb.xml/extra-regs.xml: New files. + 2007-02-08 Nick Roberts * gdb.mi/mi-var-block.exp, gdb.mi/mi2-var-block.exp diff --git a/gdb/testsuite/gdb.xml/core-only.xml b/gdb/testsuite/gdb.xml/core-only.xml new file mode 100644 index 0000000..f2ddcd5 --- /dev/null +++ b/gdb/testsuite/gdb.xml/core-only.xml @@ -0,0 +1,3 @@ + + + diff --git a/gdb/testsuite/gdb.xml/extra-regs.xml b/gdb/testsuite/gdb.xml/extra-regs.xml new file mode 100644 index 0000000..5db426b --- /dev/null +++ b/gdb/testsuite/gdb.xml/extra-regs.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/gdb/testsuite/gdb.xml/single-reg.xml b/gdb/testsuite/gdb.xml/single-reg.xml new file mode 100644 index 0000000..f725bf9 --- /dev/null +++ b/gdb/testsuite/gdb.xml/single-reg.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/gdb/testsuite/gdb.xml/tdesc-regs.exp b/gdb/testsuite/gdb.xml/tdesc-regs.exp new file mode 100644 index 0000000..fde2111 --- /dev/null +++ b/gdb/testsuite/gdb.xml/tdesc-regs.exp @@ -0,0 +1,95 @@ +# Copyright 2007 Free Software Foundation, Inc. + +# 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 +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +if {[gdb_skip_xml_test]} { + unsupported "tdesc-regs.exp" + return -1 +} + +gdb_start + +# To test adding registers, we need a core set of registers for this +# architecture, or the description will be rejected. + +set core-regs "" +switch -glob -- [istarget] { + "*arm-*-*" { + set core-regs arm-core + } + "xscale-*-*" { + set core-regs arm-core + } +} + +# If no core registers were specified, assume this target does not +# support target-defined registers. Verify that we get a warning if +# we try to use them. This not only tests the warning, but also +# reminds maintainers to add test support when they add the feature. +if {[string equal ${core-regs} ""]} { + gdb_test "set tdesc file $srcdir/$subdir/single-reg.xml" \ + "warning: Target-supplied registers are not supported.*" \ + "set tdesc file single-reg.xml" + unsupported "register tests" + return 0 +} + +# Otherwise, we support both XML and target defined registers. + +# Make sure we reject a description missing standard registers, +# like the PC. +gdb_test "set tdesc file $srcdir/$subdir/single-reg.xml" \ + "warning: Architecture rejected target-supplied description" \ + "set tdesc file single-reg.xml" + +# Copy the core registers into the objdir if necessary, so that they +# will be found by . +file delete "core-regs.xml" +file copy "$srcdir/../features/${core-regs}.xml" "core-regs.xml" + +# Similarly, we need to copy files under test into the objdir. +proc load_description { file errmsg } { + global srcdir + global subdir + global gdb_prompt + + file delete "regs.xml" + file copy "$srcdir/$subdir/$file" "regs.xml" + + # Anchor the test output, so that error messages are detected. + set cmd "set tdesc filename regs.xml" + set msg "set tdesc filename $file" + set cmd_regex [string_to_regexp $cmd] + gdb_test_multiple $cmd $msg { + -re "^$cmd_regex\r\n$errmsg$gdb_prompt $" { + pass $msg + } + } +} + +load_description "extra-regs.xml" "" +gdb_test "ptype \$extrareg" "type = (int|long|long long)" +gdb_test "ptype \$uintreg" "type = uint32_t" +gdb_test "ptype \$vecreg" "type = int8_t \\\[4\\\]" +gdb_test "ptype \$unionreg" \ + "type = union {\r\n *v4int8 v4;\r\n *v2int16 v2;\r\n}" +gdb_test "ptype \$unionreg.v4" "type = int8_t \\\[4\\\]" + +load_description "core-only.xml" "" +# The extra register from the previous description should be gone. +gdb_test "ptype \$extrareg" "type = void" + +file delete "core-regs.xml" +file delete "regs.xml" diff --git a/gdb/user-regs.c b/gdb/user-regs.c index cde32ea..ef9d3b2 100644 --- a/gdb/user-regs.c +++ b/gdb/user-regs.c @@ -41,7 +41,8 @@ struct user_reg { const char *name; - struct value *(*read) (struct frame_info * frame); + struct value *(*read) (struct frame_info * frame, const void *baton); + const void *baton; struct user_reg *next; }; @@ -59,7 +60,8 @@ struct gdb_user_regs static void append_user_reg (struct gdb_user_regs *regs, const char *name, - user_reg_read_ftype *read, struct user_reg *reg) + user_reg_read_ftype *read, const void *baton, + struct user_reg *reg) { /* The caller is responsible for allocating memory needed to store the register. By doing this, the function can operate on a @@ -67,6 +69,7 @@ append_user_reg (struct gdb_user_regs *regs, const char *name, gdb_assert (reg != NULL); reg->name = name; reg->read = read; + reg->baton = baton; reg->next = NULL; (*regs->last) = reg; regs->last = &(*regs->last)->next; @@ -77,9 +80,10 @@ append_user_reg (struct gdb_user_regs *regs, const char *name, static struct gdb_user_regs builtin_user_regs = { NULL, &builtin_user_regs.first }; void -user_reg_add_builtin (const char *name, user_reg_read_ftype *read) +user_reg_add_builtin (const char *name, user_reg_read_ftype *read, + const void *baton) { - append_user_reg (&builtin_user_regs, name, read, + append_user_reg (&builtin_user_regs, name, read, baton, XMALLOC (struct user_reg)); } @@ -95,14 +99,14 @@ user_regs_init (struct gdbarch *gdbarch) struct gdb_user_regs *regs = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct gdb_user_regs); regs->last = ®s->first; for (reg = builtin_user_regs.first; reg != NULL; reg = reg->next) - append_user_reg (regs, reg->name, reg->read, + append_user_reg (regs, reg->name, reg->read, reg->baton, GDBARCH_OBSTACK_ZALLOC (gdbarch, struct user_reg)); return regs; } void user_reg_add (struct gdbarch *gdbarch, const char *name, - user_reg_read_ftype *read) + user_reg_read_ftype *read, const void *baton) { struct gdb_user_regs *regs = gdbarch_data (gdbarch, user_regs_data); if (regs == NULL) @@ -112,7 +116,7 @@ user_reg_add (struct gdbarch *gdbarch, const char *name, regs = user_regs_init (gdbarch); deprecated_set_gdbarch_data (gdbarch, user_regs_data, regs); } - append_user_reg (regs, name, read, + append_user_reg (regs, name, read, baton, GDBARCH_OBSTACK_ZALLOC (gdbarch, struct user_reg)); } @@ -199,7 +203,7 @@ value_of_user_reg (int regnum, struct frame_info *frame) + gdbarch_num_pseudo_regs (gdbarch)); struct user_reg *reg = usernum_to_user_reg (gdbarch, regnum - maxregs); gdb_assert (reg != NULL); - return reg->read (frame); + return reg->read (frame, reg->baton); } extern initialize_file_ftype _initialize_user_regs; /* -Wmissing-prototypes */ diff --git a/gdb/user-regs.h b/gdb/user-regs.h index 7af1cbf..5cc9d05 100644 --- a/gdb/user-regs.h +++ b/gdb/user-regs.h @@ -57,15 +57,16 @@ extern const char *user_reg_map_regnum_to_name (struct gdbarch *gdbarch, bytes as, at the time the register is being added, the type needed to describe the register has not bee initialized. */ -typedef struct value *(user_reg_read_ftype) (struct frame_info *frame); +typedef struct value *(user_reg_read_ftype) (struct frame_info *frame, + const void *baton); extern struct value *value_of_user_reg (int regnum, struct frame_info *frame); /* Add a builtin register (present in all architectures). */ extern void user_reg_add_builtin (const char *name, - user_reg_read_ftype *read); + user_reg_read_ftype *read, const void *baton); /* Add a per-architecture frame register. */ extern void user_reg_add (struct gdbarch *gdbarch, const char *name, - user_reg_read_ftype *read); + user_reg_read_ftype *read, const void *baton); #endif diff --git a/gdb/xml-support.c b/gdb/xml-support.c index 1a31db4..c9196ec 100644 --- a/gdb/xml-support.c +++ b/gdb/xml-support.c @@ -40,6 +40,8 @@ static int debug_xml; we just want to avoid running out of stack on loops. */ #define MAX_XINCLUDE_DEPTH 30 +/* Simplified XML parser infrastructure. */ + /* A parsing level -- used to keep track of the current element nesting. */ struct scope_level @@ -631,6 +633,14 @@ gdb_xml_parse_attr_ulongest (struct gdb_xml_parser *parser, return ret; } +/* A handler_data for yes/no boolean values. */ + +const struct gdb_xml_enum gdb_xml_enums_boolean[] = { + { "yes", 1 }, + { "no", 0 }, + { NULL, 0 } +}; + /* Map NAME to VALUE. A struct gdb_xml_enum * should be saved as the value of handler_data when using gdb_xml_parse_attr_enum to parse a fixed list of possible strings. The list is terminated by an entry @@ -645,7 +655,7 @@ gdb_xml_parse_attr_enum (struct gdb_xml_parser *parser, void *ret; for (enums = attribute->handler_data; enums->name != NULL; enums++) - if (strcmp (enums->name, value) == 0) + if (strcasecmp (enums->name, value) == 0) break; if (enums->name == NULL) diff --git a/gdb/xml-support.h b/gdb/xml-support.h index de8ae5b..b01ea19 100644 --- a/gdb/xml-support.h +++ b/gdb/xml-support.h @@ -209,6 +209,9 @@ struct gdb_xml_enum ULONGEST value; }; +/* A handler_data for yes/no boolean values. */ +extern const struct gdb_xml_enum gdb_xml_enums_boolean[]; + extern gdb_xml_attribute_handler gdb_xml_parse_attr_enum; /* Parse an integer string into a ULONGEST and return it, or call diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c index bc7c672..b45bb7e 100644 --- a/gdb/xml-tdesc.c +++ b/gdb/xml-tdesc.c @@ -23,6 +23,7 @@ Boston, MA 02110-1301, USA. */ #include "defs.h" +#include "gdbtypes.h" #include "target.h" #include "target-descriptions.h" #include "xml-support.h" @@ -79,6 +80,16 @@ struct tdesc_parsing_data { /* The target description we are building. */ struct target_desc *tdesc; + + /* The target feature we are currently parsing, or last parsed. */ + struct tdesc_feature *current_feature; + + /* The register number to use for the next register we see, if + it does not have its own. This starts at zero. */ + int next_regnum; + + /* The union we are currently parsing, or last parsed. */ + struct type *current_union; }; /* Handle the end of an element and its value. */ @@ -98,15 +109,233 @@ tdesc_end_arch (struct gdb_xml_parser *parser, set_tdesc_architecture (data->tdesc, arch); } +/* Handle the start of a element. */ + +static void +tdesc_start_feature (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC(gdb_xml_value_s) *attributes) +{ + struct tdesc_parsing_data *data = user_data; + char *name = VEC_index (gdb_xml_value_s, attributes, 0)->value; + + data->current_feature = tdesc_create_feature (data->tdesc, name); +} + +/* Handle the start of a element. Fill in the optional + attributes and attach it to the containing feature. */ + +static void +tdesc_start_reg (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC(gdb_xml_value_s) *attributes) +{ + struct tdesc_parsing_data *data = user_data; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + int ix = 0, length; + char *name, *group, *type; + int bitsize, regnum, save_restore; + + length = VEC_length (gdb_xml_value_s, attributes); + + name = attrs[ix++].value; + bitsize = * (ULONGEST *) attrs[ix++].value; + + if (ix < length && strcmp (attrs[ix].name, "regnum") == 0) + regnum = * (ULONGEST *) attrs[ix++].value; + else + regnum = data->next_regnum; + + if (ix < length && strcmp (attrs[ix].name, "type") == 0) + type = attrs[ix++].value; + else + type = "int"; + + if (ix < length && strcmp (attrs[ix].name, "group") == 0) + group = attrs[ix++].value; + else + group = NULL; + + if (ix < length && strcmp (attrs[ix].name, "save-restore") == 0) + save_restore = * (ULONGEST *) attrs[ix++].value; + else + save_restore = 1; + + if (strcmp (type, "int") != 0 + && strcmp (type, "float") != 0 + && tdesc_named_type (data->current_feature, type) == NULL) + gdb_xml_error (parser, _("Register \"%s\" has unknown type \"%s\""), + name, type); + + tdesc_create_reg (data->current_feature, name, regnum, save_restore, group, + bitsize, type); + + data->next_regnum = regnum + 1; +} + +/* Handle the start of a element. Initialize the type and + record it with the current feature. */ + +static void +tdesc_start_union (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC(gdb_xml_value_s) *attributes) +{ + struct tdesc_parsing_data *data = user_data; + char *id = VEC_index (gdb_xml_value_s, attributes, 0)->value; + struct type *type; + + type = init_composite_type (NULL, TYPE_CODE_UNION); + TYPE_NAME (type) = xstrdup (id); + tdesc_record_type (data->current_feature, type); + data->current_union = type; +} + +/* Handle the end of a element. */ + +static void +tdesc_end_union (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, const char *body_text) +{ + struct tdesc_parsing_data *data = user_data; + int i; + + /* If any of the children of this union are vectors, flag the union + as a vector also. This allows e.g. a union of two vector types + to show up automatically in "info vector". */ + for (i = 0; i < TYPE_NFIELDS (data->current_union); i++) + if (TYPE_VECTOR (TYPE_FIELD_TYPE (data->current_union, i))) + { + TYPE_FLAGS (data->current_union) |= TYPE_FLAG_VECTOR; + break; + } +} + +/* Handle the start of a element. Attach the field to the + current union. */ + +static void +tdesc_start_field (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC(gdb_xml_value_s) *attributes) +{ + struct tdesc_parsing_data *data = user_data; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + struct type *type, *field_type; + char *field_name, *field_type_id; + + field_name = attrs[0].value; + field_type_id = attrs[1].value; + + field_type = tdesc_named_type (data->current_feature, field_type_id); + if (field_type == NULL) + gdb_xml_error (parser, _("Union field \"%s\" references undefined " + "type \"%s\""), + field_name, field_type_id); + + append_composite_type_field (data->current_union, xstrdup (field_name), + field_type); +} + +/* Handle the start of a element. Initialize the type and + record it with the current feature. */ + +static void +tdesc_start_vector (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC(gdb_xml_value_s) *attributes) +{ + struct tdesc_parsing_data *data = user_data; + struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); + struct type *type, *field_type, *range_type; + char *id, *field_type_id; + int count; + + id = attrs[0].value; + field_type_id = attrs[1].value; + count = * (ULONGEST *) attrs[2].value; + + field_type = tdesc_named_type (data->current_feature, field_type_id); + if (field_type == NULL) + gdb_xml_error (parser, _("Vector \"%s\" references undefined type \"%s\""), + id, field_type_id); + + /* A vector is just an array plus a special flag. */ + range_type = create_range_type (NULL, builtin_type_int, 0, count - 1); + type = create_array_type (NULL, field_type, range_type); + TYPE_NAME (type) = xstrdup (id); + + TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR; + + tdesc_record_type (data->current_feature, type); +} + /* The elements and attributes of an XML target description. */ -const struct gdb_xml_element target_children[] = { +static const struct gdb_xml_attribute field_attributes[] = { + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { "type", GDB_XML_AF_NONE, NULL, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element union_children[] = { + { "field", field_attributes, NULL, GDB_XML_EF_REPEATABLE, + tdesc_start_field, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute reg_attributes[] = { + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { "bitsize", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "regnum", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, + { "type", GDB_XML_AF_OPTIONAL, NULL, NULL }, + { "group", GDB_XML_AF_OPTIONAL, NULL, NULL }, + { "save-restore", GDB_XML_AF_OPTIONAL, + gdb_xml_parse_attr_enum, gdb_xml_enums_boolean }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute union_attributes[] = { + { "id", GDB_XML_AF_NONE, NULL, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute vector_attributes[] = { + { "id", GDB_XML_AF_NONE, NULL, NULL }, + { "type", GDB_XML_AF_NONE, NULL, NULL }, + { "count", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute feature_attributes[] = { + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element feature_children[] = { + { "reg", reg_attributes, NULL, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + tdesc_start_reg, NULL }, + { "union", union_attributes, union_children, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + tdesc_start_union, tdesc_end_union }, + { "vector", vector_attributes, NULL, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + tdesc_start_vector, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element target_children[] = { { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL, NULL, tdesc_end_arch }, + { "feature", feature_attributes, feature_children, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + tdesc_start_feature, NULL }, { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } }; -const struct gdb_xml_element tdesc_elements[] = { +static const struct gdb_xml_element tdesc_elements[] = { { "target", NULL, target_children, GDB_XML_EF_NONE, NULL, NULL }, { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } -- 2.7.4