* Makefile.in (arm-tdep.o, eval.o, target-descriptions.o)
authorDaniel Jacobowitz <drow@false.org>
Thu, 8 Feb 2007 21:00:36 +0000 (21:00 +0000)
committerDaniel Jacobowitz <drow@false.org>
Thu, 8 Feb 2007 21:00:36 +0000 (21:00 +0000)
(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 <feature>.
(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.

30 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/NEWS
gdb/arch-utils.c
gdb/arch-utils.h
gdb/arm-tdep.c
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/doc/gdbint.texinfo
gdb/eval.c
gdb/features/arm-core.xml [new file with mode: 0644]
gdb/features/arm-fpa.xml [new file with mode: 0644]
gdb/features/gdb-target.dtd
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/remote.c
gdb/std-regs.c
gdb/target-descriptions.c
gdb/target-descriptions.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.xml/core-only.xml [new file with mode: 0644]
gdb/testsuite/gdb.xml/extra-regs.xml [new file with mode: 0644]
gdb/testsuite/gdb.xml/single-reg.xml [new file with mode: 0644]
gdb/testsuite/gdb.xml/tdesc-regs.exp [new file with mode: 0644]
gdb/user-regs.c
gdb/user-regs.h
gdb/xml-support.c
gdb/xml-support.h
gdb/xml-tdesc.c

index 3c119c7d156f5b70242aff7137ea30665a8be4b2..de6f607024ec5d6b987000775c6a0179ef5670f9 100644 (file)
@@ -1,3 +1,73 @@
+2007-02-08  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * 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 <feature>.
+       (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  <nickrob@snap.net.nz>
 
        * mi/mi-cmd-var.c (mi_cmd_var_create):  Add value field.
index 0a0f4779e71c4a733eea2c22e803450516130639..03372072d4bcc88dd12ecf78fdcb688fe7510ff5 100644 (file)
@@ -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) \
index d9d35f55d59377bf76c0f5287d46fef5c2b77462..864f4d0c607614ac87cc9fb9e4ad1f6b0a4b1c6c 100644 (file)
--- 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
index a5ca574ac097cba56a3a710f92f572d1c5eed5f0..1a987f34be911533bca5322822a68ec1f30a0cf3 100644 (file)
@@ -263,6 +263,13 @@ generic_instruction_nullified (struct gdbarch *gdbarch,
   return 0;
 }
 
+int
+default_remote_register_number (struct gdbarch *gdbarch,
+                               int regno)
+{
+  return regno;
+}
+
 \f
 /* Functions to manipulate the endianness of the target.  */
 
index cc00e58ecd7b1e149cadf5b741102f39906c3a91..d995fcbe2f27ddfbf88a7ce8898e69d1a41aff1a 100644 (file)
@@ -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.  */
index 7b92cd7975ce1d16b977183b49e6d325c2c163b9..ab7b2e99f3d2e3d74f35200e9d5835cca2767c21 100644 (file)
@@ -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, &regnames);
-  while ((disassembly_style != setname)
-        && (current < num_disassembly_options))
-    get_arm_regnames (++current, &setname, &setdesc, &regnames);
-  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);
+}
 \f
 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);
        }
     }
index b37890e6f597516cb35679a5ef2ee4206d1c033e..fd7efe0ef07e7ad7b1d883fa31fd88d9aba964fa 100644 (file)
@@ -1,3 +1,13 @@
+2007-02-08  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * 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  <dan@codesourcery.com>
 
        * gdb.texinfo (Target Description Format): Add section on XInclude.
index 251ed9ed617f78da9beb62821f65ac97e5698e49..15c4d7ead00bb16266692e6ac050f37d182a7f24 100644 (file)
@@ -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
 <target>
   <architecture>i386:x86-64</architecture>
 </target>
-@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
 <?xml version="1.0"?>
 <!DOCTYPE target SYSTEM "gdb-target.dtd">
 <target>
-  <architecture>@var{arch name}</architecture>
+  @r{[}@var{architecture}@r{]}
+  @r{[}@var{feature}@dots{}@r{]}
 </target>
-@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{<architecture>} 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
 <xi:include href="@var{document}"/>
-@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 <architecture>
+
+An @samp{<architecture>} element has this form:
+
+@smallexample
+  <architecture>@var{arch}</architecture>
+@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 <feature>
+
+Each @samp{<feature>} 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{<feature>} element
+has this form:
+
+@smallexample
+<feature name="@var{name}">
+  @r{[}@var{type}@dots{}@r{]}
+  @var{reg}@dots{}
+</feature>
+@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{<feature>}) name to the type.
+Types must be defined before they are used.
+
+@cindex <vector>
+Some targets offer vector registers, which can be treated as arrays
+of scalar elements.  These types are written as @samp{<vector>} elements,
+specifying the array element type, @var{type}, and the number of elements,
+@var{count}:
+
+@smallexample
+<vector id="@var{id}" type="@var{type}" count="@var{count}"/>
+@end smallexample
+
+@cindex <union>
+If a register's value is usefully viewed in multiple ways, define it
+with a union type containing the useful representations.  The
+@samp{<union>} element contains one or more @samp{<field>} elements,
+each of which has a @var{name} and a @var{type}:
+
+@smallexample
+<union id="@var{id}">
+  <field name="@var{name}" type="@var{type}"/>
+  @dots{}
+</union>
+@end smallexample
+
+@subsection Registers
+@cindex <reg>
+
+Each register is represented as an element with this form:
+
+@smallexample
+<reg name="@var{name}"
+     bitsize="@var{size}"
+     @r{[}regnum="@var{num}"@r{]}
+     @r{[}save-restore="@var{save-restore}"@r{]}
+     @r{[}type="@var{type}"@r{]}
+     @r{[}group="@var{group}"@r{]}/>
+@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
 
index c71e1f90fb5a40f50d21c1f6e59713c28cc65c75..e0017ad3d93e44fcc656303b02a73fa6dc5b415e 100644 (file)
@@ -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{<architecture>} 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
index 5d1dc735d4eb7c296b1a5e7f2b6a79fddb233500..c385539c1a78deedc70df3459f5966030d9b8343 100644 (file)
@@ -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 (file)
index 0000000..c2718f5
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.core">
+  <reg name="r0" bitsize="32"/>
+  <reg name="r1" bitsize="32"/>
+  <reg name="r2" bitsize="32"/>
+  <reg name="r3" bitsize="32"/>
+  <reg name="r4" bitsize="32"/>
+  <reg name="r5" bitsize="32"/>
+  <reg name="r6" bitsize="32"/>
+  <reg name="r7" bitsize="32"/>
+  <reg name="r8" bitsize="32"/>
+  <reg name="r9" bitsize="32"/>
+  <reg name="r10" bitsize="32"/>
+  <reg name="r11" bitsize="32"/>
+  <reg name="r12" bitsize="32"/>
+  <reg name="sp" bitsize="32"/>
+  <reg name="lr" bitsize="32"/>
+  <reg name="pc" bitsize="32"/>
+
+  <!-- The CPSR is register 25, rather than register 16, because
+       the FPA registers historically were placed between the PC
+       and the CPSR in the "g" packet.  -->
+  <reg name="cpsr" bitsize="32" regnum="25"/>
+</feature>
diff --git a/gdb/features/arm-fpa.xml b/gdb/features/arm-fpa.xml
new file mode 100644 (file)
index 0000000..87a5b89
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.fpa">
+  <!-- f0's regnum is set explicitly, because the FPA registers
+       historically were placed between the PC and the CPSR in the "g"
+       packet - in the middle of org.gnu.gdb.arm.core.  -->
+  <reg name="f0" bitsize="96" type="arm_fpa_ext" regnum="16"/>
+  <reg name="f1" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f2" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f3" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f4" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f5" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f6" bitsize="96" type="arm_fpa_ext"/>
+  <reg name="f7" bitsize="96" type="arm_fpa_ext"/>
+
+  <reg name="fps" bitsize="32"/>
+</feature>
index 8bcb049dabe45889e09e8776f0b72925463d644a..b05e063d9db7ab537a4441a3cd4e880d1dacb737 100644 (file)
@@ -6,9 +6,38 @@
 
 <!-- The root element of a GDB target description is <target>.  -->
 
-<!ELEMENT target       (architecture?)>
+<!ELEMENT target       (architecture?, feature*)>
 
 <!ELEMENT architecture (#PCDATA)>
 
+<!ELEMENT feature      ((vector | union)*, reg*)>
+<!ATTLIST feature
+       name            ID      #REQUIRED>
+
+<!ELEMENT reg          (description*)>
+<!ATTLIST reg
+       name            CDATA   #REQUIRED
+       bitsize         CDATA   #REQUIRED
+       regnum          CDATA   #IMPLIED
+       save-restore    (yes | no) 'yes'
+       type            CDATA   'int'
+       group           CDATA   #IMPLIED
+       >
+
+<!ELEMENT vector       EMPTY>
+<!ATTLIST vector
+       id              CDATA   #REQUIRED
+       type            CDATA   #REQUIRED
+       count           CDATA   #REQUIRED>
+
+<!ELEMENT union                (field+)>
+<!ATTLIST union
+       id              CDATA   #REQUIRED>
+
+<!ELEMENT field                EMPTY>
+<!ATTLIST field
+       name            CDATA   #REQUIRED
+       type            CDATA   #REQUIRED>
+
 <!ENTITY % xinclude SYSTEM "xinclude.dtd">
 %xinclude;
index 8b6d60b4a01d734196e880529756d1c24df03d3a..562897a72cf85c3a8c0424ff3d2208086c1dba3f 100644 (file)
@@ -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 */
@@ -1441,6 +1445,9 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (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);
@@ -2989,6 +2996,23 @@ set_gdbarch_remote_translate_xfer_address (struct gdbarch *gdbarch,
   gdbarch->remote_translate_xfer_address = remote_translate_xfer_address;
 }
 
+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)
 {
index 8cfd33b18d7bf27931562d279268ccf3117737ab..2c9bc579c52573420c92c53ad8d8873d4957bd12 100644 (file)
@@ -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)
index d0547991bc4fb7ca527004d18813f0e780460c4b..c776e28ad99c58852595c32b9c6d0fd486f43091 100755 (executable)
@@ -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
 #
index 48be84479ec338e13a85d326418cc4365a07bb08..bb49aca9b9c85334afc6fce30962e8bd6e40eff6 100644 (file)
@@ -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;
     }
 
index df5020709ef1a8d08fb37c3939290216db4e7d13..2edcba8ac38545934071cb8058ac16a69e712c22 100644 (file)
@@ -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);
 }
index 1100f5ebaf3d5cea8abee588704f011695c31e97..1f8cf7e17e5b672584cf42941f04d86eb6f53d8b 100644 (file)
 #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)
 }
 \f
 
-/* 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)
 }
 \f
 
+/* 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;
+}
+\f
+
+/* 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);
+}
+\f
+
 /* 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,9 +827,16 @@ 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 ",
index f45e53be23cef5d6909d3059c977434aa1853489..9c641903e57ca68b2ba477c8ff52e802658ee207 100644 (file)
 #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 */
index e1a35a9145d00f8a7ab6ae7faeaf0f9df34490b4..e7ac4b3f09451f6ab97f15aac23cc2e2a179b08d 100644 (file)
@@ -1,3 +1,8 @@
+2007-02-08  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * 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  <nickrob@snap.net.nz>
 
        * 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 (file)
index 0000000..f2ddcd5
--- /dev/null
@@ -0,0 +1,3 @@
+<target>
+  <xi:include href="core-regs.xml"/>
+</target>
diff --git a/gdb/testsuite/gdb.xml/extra-regs.xml b/gdb/testsuite/gdb.xml/extra-regs.xml
new file mode 100644 (file)
index 0000000..5db426b
--- /dev/null
@@ -0,0 +1,16 @@
+<target>
+  <xi:include href="core-regs.xml"/>
+  <feature name="extra">
+    <vector id="v4int8" type="int8" count="4"/>
+    <vector id="v2int16" type="int16" count="2"/>
+    <union id="vecint">
+      <field name="v4" type="v4int8"/>
+      <field name="v2" type="v2int16"/>
+    </union>
+
+    <reg name="extrareg" bitsize="32"/>
+    <reg name="uintreg" bitsize="32" type="uint32"/>
+    <reg name="vecreg" bitsize="32" type="v4int8"/>
+    <reg name="unionreg" bitsize="32" type="vecint"/>
+  </feature>
+</target>
diff --git a/gdb/testsuite/gdb.xml/single-reg.xml b/gdb/testsuite/gdb.xml/single-reg.xml
new file mode 100644 (file)
index 0000000..f725bf9
--- /dev/null
@@ -0,0 +1,5 @@
+<target>
+  <feature name="single">
+    <reg name="one" bitsize="32"/>
+  </feature>
+</target>
diff --git a/gdb/testsuite/gdb.xml/tdesc-regs.exp b/gdb/testsuite/gdb.xml/tdesc-regs.exp
new file mode 100644 (file)
index 0000000..fde2111
--- /dev/null
@@ -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 <xi:include>.
+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"
index cde32ea3b72a81a17f4398a3a320caadc0869e1a..ef9d3b2f84b1c635089c3c924814b84126c5453d 100644 (file)
@@ -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 = &regs->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 */
index 7af1cbf38f08784d08b42b727e6473cd0c512789..5cc9d0586ad5a807dec986df52f688183268ff94 100644 (file)
@@ -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
index 1a31db4805b4e2532af446cb45749a98d51ca556..c9196ecfe16ca92cb8df6c21f49797675fbefad4 100644 (file)
@@ -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)
index de8ae5bef400ab6d7903e6710ab733abcaf22ba7..b01ea1903d968b7017443b2611bf7a4ead0c4722 100644 (file)
@@ -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
index bc7c6721f407cebf9b1c6182e44faf69d384fed2..b45bb7ea5f41214764916bd113e37cc666419d8d 100644 (file)
@@ -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 <architecture> 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 <feature> 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 <reg> 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 <union> 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 <union> 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 <field> 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 <vector> 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 }