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