[rfc] Target-described register support for MIPS

Daniel Jacobowitz
2007-05-21T13:40:01Z

This patch adds target-described register support to the MIPS port, in
basically the same way I did for ARM. The target must supply some CPU
registers, a tiny subset of CP0, and an FPU - obviously the FPU should
be optional, but the MIPS port isn't prepared to cope with missing FP
registers yet, and I did not want to do that at the same time.

I had to make a few target-descriptions.c functions global that I'd
been hoping not to, because of MIPS's unique use of pseudo registers.
We need to report the empty string for the name of every real
register, but use the target-provided name for the corresponding
pseudo register. Only the well-known registers that GDB already
supported are converted from 64-bit to 32-bit depending on the ABI;
other processor registers will be displayed as-is.

Maciej, I copied you in case you see anything obviously wrong with my
choices of required registers, et cetera. You may not be familiar
with the protocol extensions and so forth I've added for target
descriptions - it's been my pet project for the last year or two - but
this is something that I hope would be very useful for MIPS. Could
you look it over? Additional information about the feature is already
in the manual; this is just the MIPS-specific support.

Eli, docs OK?

Tested mips64-linux, all three ABIs. The next followup will add a
target-specific "register" for MIPS GNU/Linux to fix interrupt.exp.

--
Daniel Jacobowitz
CodeSourcery

2007-05-18 Daniel Jacobowitz <dan@codesourcery.com>

* Makefile.in (mips-tdep.o): Update.
* mips-tdep.c (struct register_alias, mips_o32_aliases)
(mips_n32_n64_aliases, mips_register_aliases): New.
(mips_register_name): Call tdesc_register_name.
(mips_tdesc_register_reggroup_p): New.
(mips_pseudo_register_type, value_of_mips_user_reg): New.
(mips_gdbarch_init): Add target-described register support.
Register aliases for register names.
* target-descriptions.c (tdesc_register_name): Make global.
(tdesc_register_in_reggroup_p): New function, broken out from
tdesc_register_reggroup_p.
(tdesc_register_reggroup_p): Use it.
* target-descriptions.h (tdesc_register_name)
(tdesc_register_in_reggroup_p): New prototypes.
* NEWS: Correct formatting. Mention MIPS register support.

* gdb.xml/tdesc-regs.exp: Add MIPS support. Allow multiple
required features to be included.

* features/mips-cp0.xml, features/mips-fpu.xml,
features/mips64-cp0.xml, gdb/features/mips64-fpu.xml, mips-cpu.xml,
features/mips64-cpu.xml: New files.

* gdb.texinfo (MIPS Features): New subsection.

---
Makefile.in | 2
NEWS | 4
doc/gdb.texinfo | 17 ++
features/mips-cp0.xml | 13 +
features/mips-cpu.xml | 46 ++++++
features/mips-fpu.xml | 45 +++++
features/mips64-cp0.xml | 13 +
features/mips64-cpu.xml | 46 ++++++
features/mips64-fpu.xml | 45 +++++
mips-tdep.c | 297 ++++++++++++++++++++++++++++++++++++++-
target-descriptions.c | 51 ++++--
target-descriptions.h | 12 +
testsuite/gdb.xml/tdesc-regs.exp | 32 +++-
13 files changed, 596 insertions(+), 27 deletions(-)

Index: gdb/Makefile.in
===================================================================
--- gdb.orig/Makefile.in 2007-05-18 12:01:06.000000000 -0400
+++ gdb/Makefile.in 2007-05-18 12:16:59.000000000 -0400
@@ -2361,7 +2361,7 @@ mips-tdep.o: mips-tdep.c $(defs_h) $(gdb
$(elf_bfd_h) $(symcat_h) $(sim_regno_h) $(dis_asm_h) \
$(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(infcall_h) \
$(floatformat_h) $(remote_h) $(target_descriptions_h) \
- $(dwarf2_frame_h)
+ $(dwarf2_frame_h) $(user_regs_h)
memory-map.o: memory-map.c $(defs_h) $(memory_map_h) $(xml_support_h) \
$(gdb_assert_h) $(exceptions_h) $(gdb_string_h)
mn10300-linux-tdep.o: mn10300-linux-tdep.c $(defs_h) $(gdbcore_h) \
Index: gdb/mips-tdep.c
===================================================================
--- gdb.orig/mips-tdep.c 2007-05-18 12:01:06.000000000 -0400
+++ gdb/mips-tdep.c 2007-05-18 12:18:26.000000000 -0400
@@ -58,6 +58,7 @@
#include "remote.h"
#include "target-descriptions.h"
#include "dwarf2-frame.h"
+#include "user-regs.h"

static const struct objfile_data *mips_pdr_data;

@@ -94,6 +95,55 @@ static const char *mips_abi_strings[] =
NULL
};

+/* The standard register names, and all the valid aliases for them. */
+struct register_alias
+{
+ const char *name;
+ int regnum;
+};
+
+/* Aliases for o32 and most other ABIs. */
+const struct register_alias mips_o32_aliases[] = {
+ { "ta0", 12 },
+ { "ta1", 13 },
+ { "ta2", 14 },
+ { "ta3", 15 }
+};
+
+/* Aliases for n32 and n64. */
+const struct register_alias mips_n32_n64_aliases[] = {
+ { "ta0", 8 },
+ { "ta1", 9 },
+ { "ta2", 10 },
+ { "ta3", 11 }
+};
+
+/* Aliases for ABI-independent registers. */
+const struct register_alias mips_register_aliases[] = {
+ /* The architecture manuals specify these ABI-independent names for
+ the GPRs. */
+#define R(n) { "r" #n, n }
+ R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7),
+ R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15),
+ R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
+ R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
+#undef R
+
+ /* k0 and k1 are sometimes called these instead (for "kernel
+ temp"). */
+ { "kt0", 26 },
+ { "kt1", 27 },
+
+ /* This is the traditional GDB name for the CP0 status register. */
+ { "sr", MIPS_PS_REGNUM },
+
+ /* This is the traditional GDB name for the CP0 BadVAddr register. */
+ { "bad", MIPS_EMBED_BADVADDR_REGNUM },
+
+ /* This is the traditional GDB name for the FCSR. */
+ { "fsr", MIPS_EMBED_FP0_REGNUM + 32 }
+};
+
/* Some MIPS boards don't support floating point while others only
support single-precision floating-point operations. */

@@ -509,6 +559,8 @@ mips_register_name (int regno)
else
return mips_gpr_names[rawnum];
}
+ else if (tdesc_has_registers (gdbarch_target_desc (current_gdbarch)))
+ return tdesc_register_name (rawnum);
else if (32 <= rawnum && rawnum < NUM_REGS)
{
gdb_assert (rawnum - 32 < NUM_MIPS_PROCESSOR_REGS);
@@ -556,6 +608,35 @@ mips_register_reggroup_p (struct gdbarch
return 0;
}

+/* Return the groups that a MIPS register can be categorised into.
+ This version is only used if we have a target description which
+ describes real registers (and their groups). */
+
+static int
+mips_tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *reggroup)
+{
+ int rawnum = regnum % NUM_REGS;
+ int pseudo = regnum / NUM_REGS;
+ int ret;
+
+ /* Only save, restore, and display the pseudo registers. Need to
+ make certain that any code extracting register values from a
+ saved register cache also uses pseudo registers.
+
+ Note: saving and restoring the pseudo registers is slightly
+ strange; if we have 64 bits, we should save and restore all
+ 64 bits. But this is hard and has little benefit. */
+ if (!pseudo)
+ return 0;
+
+ ret = tdesc_register_in_reggroup_p (gdbarch, rawnum, reggroup);
+ if (ret != -1)
+ return ret;
+
+ return mips_register_reggroup_p (gdbarch, regnum, reggroup);
+}
+
/* Map the symbol table registers which live in the range [1 *
NUM_REGS .. 2 * NUM_REGS) back onto the corresponding raw
registers. Take care of alignment and size problems. */
@@ -713,6 +794,58 @@ mips_register_type (struct gdbarch *gdba
}
}

+/* Return the GDB type for the pseudo register REGNUM, which is the
+ ABI-level view. This function is only called if there is a target
+ description which includes registers, so we know precisely the
+ types of hardware registers. */
+
+static struct type *
+mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int rawnum = regnum % NUM_REGS;
+ struct type *rawtype;
+
+ gdb_assert (regnum >= NUM_REGS && regnum < 2 * NUM_REGS);
+
+ /* Absent registers are still absent. */
+ rawtype = gdbarch_register_type (gdbarch, rawnum);
+ if (TYPE_LENGTH (rawtype) == 0)
+ return rawtype;
+
+ if (rawnum >= MIPS_EMBED_FP0_REGNUM && rawnum < MIPS_EMBED_FP0_REGNUM + 32)
+ /* Present the floating point registers however the hardware did;
+ do not try to convert between FPU layouts. */
+ return rawtype;
+
+ if (rawnum >= MIPS_EMBED_FP0_REGNUM + 32 && rawnum <= MIPS_LAST_EMBED_REGNUM)
+ {
+ /* The pseudo/cooked view of embedded registers is always
+ 32-bit, even if the target transfers 64-bit values for them.
+ New targets relying on XML descriptions should only transfer
+ the necessary 32 bits, but older versions of GDB expected 64,
+ so allow the target to provide 64 bits without interfering
+ with the displayed type. */
+ return builtin_type_int32;
+ }
+
+ /* Use pointer types for registers if we can. For n32 we can not,
+ since we do not have a 64-bit pointer type. */
+ if (mips_abi_regsize (gdbarch) == TYPE_LENGTH (builtin_type_void_data_ptr))
+ {
+ if (rawnum == MIPS_SP_REGNUM || rawnum == MIPS_EMBED_BADVADDR_REGNUM)
+ return builtin_type_void_data_ptr;
+ else if (rawnum == MIPS_EMBED_PC_REGNUM)
+ return builtin_type_void_func_ptr;
+ }
+
+ if (mips_abi_regsize (gdbarch) == 4 && TYPE_LENGTH (rawtype) == 8
+ && rawnum >= MIPS_ZERO_REGNUM && rawnum <= MIPS_EMBED_PC_REGNUM)
+ return builtin_type_int32;
+
+ /* For all other registers, pass through the hardware type. */
+ return rawtype;
+}

/* Should the upper word of 64-bit addresses be zeroed? */
enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
@@ -4624,6 +4757,13 @@ mips_register_g_packet_guesses (struct g
/* Otherwise we don't have a useful guess. */
}

+static struct value *
+value_of_mips_user_reg (struct frame_info *frame, const void *baton)
+{
+ const int *reg_p = baton;
+ return value_of_register (*reg_p, frame);
+}
+
static struct gdbarch *
mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
@@ -4631,8 +4771,108 @@ mips_gdbarch_init (struct gdbarch_info i
struct gdbarch_tdep *tdep;
int elf_flags;
enum mips_abi mips_abi, found_abi, wanted_abi;
- int num_regs;
+ int i, num_regs;
enum mips_fpu_type fpu_type;
+ struct tdesc_arch_data *tdesc_data = NULL;
+
+ /* Check any target description for validity. */
+ if (tdesc_has_registers (info.target_desc))
+ {
+ static const char *const mips_gprs[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+ };
+ static const char *const mips_fprs[] = {
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ };
+
+ const struct tdesc_feature *feature;
+ int valid_p;
+
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.mips.cpu");
+ if (feature == NULL)
+ return NULL;
+
+ tdesc_data = tdesc_data_alloc ();
+
+ valid_p = 1;
+ for (i = MIPS_ZERO_REGNUM; i <= MIPS_RA_REGNUM; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+ mips_gprs[i]);
+
+
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ MIPS_EMBED_LO_REGNUM, "lo");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ MIPS_EMBED_HI_REGNUM, "hi");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ MIPS_EMBED_PC_REGNUM, "pc");
+
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.mips.cp0");
+ if (feature == NULL)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ valid_p = 1;
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ MIPS_EMBED_BADVADDR_REGNUM,
+ "badvaddr");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ MIPS_PS_REGNUM, "status");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ MIPS_EMBED_CAUSE_REGNUM, "cause");
+
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ /* FIXME drow/2007-05-17: The FPU should be optional. The MIPS
+ backend is not prepared for that, though. */
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.mips.fpu");
+ if (feature == NULL)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ valid_p = 1;
+ for (i = 0; i < 32; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ i + MIPS_EMBED_FP0_REGNUM,
+ mips_fprs[i]);
+
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ MIPS_EMBED_FP0_REGNUM + 32, "fcsr");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ MIPS_EMBED_FP0_REGNUM + 33, "fir");
+
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ /* It would be nice to detect an attempt to use a 64-bit ABI
+ when only 32-bit registers are provided. */
+ }

/* First of all, extract the elf_flags, if available. */
if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
@@ -4776,7 +5016,11 @@ mips_gdbarch_init (struct gdbarch_info i
&& tdesc_property (info.target_desc, PROPERTY_GP32) != NULL
&& mips_abi != MIPS_ABI_EABI32
&& mips_abi != MIPS_ABI_O32)
- return NULL;
+ {
+ if (tdesc_data != NULL)
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }

/* try to find a pre-existing architecture */
for (arches = gdbarch_list_lookup_by_info (arches, &info);
@@ -4797,6 +5041,9 @@ mips_gdbarch_init (struct gdbarch_info i
/* Be pedantic about which FPU is selected. */
if (gdbarch_tdep (arches->gdbarch)->mips_fpu_type != fpu_type)
continue;
+
+ if (tdesc_data != NULL)
+ tdesc_data_cleanup (tdesc_data);
return arches->gdbarch;
}

@@ -4844,7 +5091,20 @@ mips_gdbarch_init (struct gdbarch_info i
const char **reg_names;
struct mips_regnum *regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch,
struct mips_regnum);
- if (info.osabi == GDB_OSABI_IRIX)
+ if (tdesc_has_registers (info.target_desc))
+ {
+ regnum->lo = MIPS_EMBED_LO_REGNUM;
+ regnum->hi = MIPS_EMBED_HI_REGNUM;
+ regnum->badvaddr = MIPS_EMBED_BADVADDR_REGNUM;
+ regnum->cause = MIPS_EMBED_CAUSE_REGNUM;
+ regnum->pc = MIPS_EMBED_PC_REGNUM;
+ regnum->fp0 = MIPS_EMBED_FP0_REGNUM;
+ regnum->fp_control_status = 70;
+ regnum->fp_implementation_revision = 71;
+ num_regs = MIPS_LAST_EMBED_REGNUM + 1;
+ reg_names = NULL;
+ }
+ else if (info.osabi == GDB_OSABI_IRIX)
{
regnum->fp0 = 32;
regnum->pc = 64;
@@ -5108,6 +5368,37 @@ mips_gdbarch_init (struct gdbarch_info i
frame_base_append_sniffer (gdbarch, mips_insn16_frame_base_sniffer);
frame_base_append_sniffer (gdbarch, mips_insn32_frame_base_sniffer);

+ if (tdesc_data)
+ {
+ set_tdesc_pseudo_register_type (gdbarch, mips_pseudo_register_type);
+ tdesc_use_registers (gdbarch, tdesc_data);
+
+ /* Override the normal target description methods to handle our
+ dual real and pseudo registers. */
+ set_gdbarch_register_name (gdbarch, mips_register_name);
+ set_gdbarch_register_reggroup_p (gdbarch, mips_tdesc_register_reggroup_p);
+
+ num_regs = gdbarch_num_regs (gdbarch);
+ set_gdbarch_num_pseudo_regs (gdbarch, num_regs);
+ set_gdbarch_pc_regnum (gdbarch, tdep->regnum->pc + num_regs);
+ set_gdbarch_sp_regnum (gdbarch, MIPS_SP_REGNUM + num_regs);
+ }
+
+ /* Add ABI-specific aliases for the registers. */
+ if (mips_abi == MIPS_ABI_N32 || mips_abi == MIPS_ABI_N64)
+ for (i = 0; i < ARRAY_SIZE (mips_n32_n64_aliases); i++)
+ user_reg_add (gdbarch, mips_n32_n64_aliases[i].name,
+ value_of_mips_user_reg, &mips_n32_n64_aliases[i].regnum);
+ else
+ for (i = 0; i < ARRAY_SIZE (mips_o32_aliases); i++)
+ user_reg_add (gdbarch, mips_o32_aliases[i].name,
+ value_of_mips_user_reg, &mips_o32_aliases[i].regnum);
+
+ /* Add some other standard aliases. */
+ for (i = 0; i < ARRAY_SIZE (mips_register_aliases); i++)
+ user_reg_add (gdbarch, mips_register_aliases[i].name,
+ value_of_mips_user_reg, &mips_register_aliases[i].regnum);
+
return gdbarch;
}

Index: gdb/target-descriptions.c
===================================================================
--- gdb.orig/target-descriptions.c 2007-05-18 12:01:06.000000000 -0400
+++ gdb/target-descriptions.c 2007-05-18 12:01:07.000000000 -0400
@@ -486,7 +486,10 @@ tdesc_find_register (struct gdbarch *gdb
return NULL;
}

-static const char *
+/* Return the name of register REGNO, from the target description or
+ from an architecture-provided pseudo_register_name method. */
+
+const char *
tdesc_register_name (int regno)
{
struct tdesc_reg *reg = tdesc_find_register (current_gdbarch, regno);
@@ -582,8 +585,9 @@ tdesc_remote_register_number (struct gdb

/* 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.
+ Unlike a gdbarch register_reggroup_p method, this function will
+ return -1 if it does not know; the caller should handle registers
+ with no specified group.

Arbitrary strings (other than "general", "float", and "vector")
from the description are not used; they cause the register to be
@@ -594,21 +598,12 @@ tdesc_remote_register_number (struct gdb

The save-restore flag is also implemented here. */

-static int
-tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regno,
- struct reggroup *reggroup)
+int
+tdesc_register_in_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;
@@ -634,6 +629,32 @@ tdesc_register_reggroup_p (struct gdbarc
&& (reggroup == save_reggroup || reggroup == restore_reggroup))
return reg->save_restore;

+ return -1;
+}
+
+/* Check whether REGNUM is a member of REGGROUP. Registers with no
+ group specified go to the default reggroup function and are handled
+ by type. */
+
+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);
+ int ret;
+
+ if (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);
+ }
+
+ ret = tdesc_register_in_reggroup_p (gdbarch, regno, reggroup);
+ if (ret != -1)
+ return ret;
+
return default_register_reggroup_p (gdbarch, regno, reggroup);
}

Index: gdb/target-descriptions.h
===================================================================
--- gdb.orig/target-descriptions.h 2007-05-18 12:01:06.000000000 -0400
+++ gdb/target-descriptions.h 2007-05-18 12:01:07.000000000 -0400
@@ -140,6 +140,18 @@ const char *tdesc_feature_name (const st
struct type *tdesc_named_type (const struct tdesc_feature *feature,
const char *id);

+/* Return the name of register REGNO, from the target description or
+ from an architecture-provided pseudo_register_name method. */
+
+const char *tdesc_register_name (int regno);
+
+/* Check whether REGNUM is a member of REGGROUP using the target
+ description. Return -1 if the target description does not
+ specify a group. */
+
+int tdesc_register_in_reggroup_p (struct gdbarch *gdbarch, int regno,
+ struct reggroup *reggroup);
+
/* Methods for constructing a target description. */

struct target_desc *allocate_target_description (void);
Index: gdb/testsuite/gdb.xml/tdesc-regs.exp
===================================================================
--- gdb.orig/testsuite/gdb.xml/tdesc-regs.exp 2007-05-18 12:01:06.000000000 -0400
+++ gdb/testsuite/gdb.xml/tdesc-regs.exp 2007-05-18 12:01:07.000000000 -0400
@@ -27,10 +27,13 @@ gdb_start
set core-regs ""
switch -glob -- [istarget] {
"*arm-*-*" {
- set core-regs arm-core
+ set core-regs {arm-core.xml}
}
"xscale-*-*" {
- set core-regs arm-core
+ set core-regs {arm-core.xml}
+ }
+ "mips*-*-*" {
+ set core-regs {mips-cpu.xml mips-cp0.xml mips-fpu.xml}
}
}

@@ -56,17 +59,32 @@ gdb_test "set tdesc file $srcdir/$subdir

# 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"
+foreach src ${core-regs} {
+ file delete "$src"
+ file copy "$srcdir/../features/$src" "$src"
+}

# Similarly, we need to copy files under test into the objdir.
proc load_description { file errmsg } {
global srcdir
global subdir
global gdb_prompt
+ global core-regs

file delete "regs.xml"
- file copy "$srcdir/$subdir/$file" "regs.xml"
+ set ifd [open "$srcdir/$subdir/$file" r]
+ set ofd [open "regs.xml" w]
+ while {[gets $ifd line] >= 0} {
+ if {[regexp {<xi:include href="core-regs.xml"/>} $line]} {
+ foreach src ${core-regs} {
+ puts $ofd " <xi:include href=\"$src\"/>"
+ }
+ } else {
+ puts $ofd $line
+ }
+ }
+ close $ifd
+ close $ofd

# Anchor the test output, so that error messages are detected.
set cmd "set tdesc filename regs.xml"
@@ -91,5 +109,7 @@ 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"
+foreach src ${core-regs} {
+ file delete "$src"
+}
file delete "regs.xml"
Index: gdb/features/mips-cp0.xml
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/features/mips-cp0.xml 2007-05-18 12:01:07.000000000 -0400
@@ -0,0 +1,13 @@
+<?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. -->
+
+
+<feature name="org.gnu.gdb.mips.cp0">
+ <reg name="status" bitsize="32" regnum="32"/>
+ <reg name="badvaddr" bitsize="32" regnum="35"/>
+ <reg name="cause" bitsize="32" regnum="36"/>
+</feature>
Index: gdb/features/mips-fpu.xml
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/features/mips-fpu.xml 2007-05-18 12:01:07.000000000 -0400
@@ -0,0 +1,45 @@
+<?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. -->
+
+
+<feature name="org.gnu.gdb.mips.fpu">
+ <reg name="f0" bitsize="32" type="ieee_single"/>
+ <reg name="f1" bitsize="32" type="ieee_single"/>
+ <reg name="f2" bitsize="32" type="ieee_single"/>
+ <reg name="f3" bitsize="32" type="ieee_single"/>
+ <reg name="f4" bitsize="32" type="ieee_single"/>
+ <reg name="f5" bitsize="32" type="ieee_single"/>
+ <reg name="f6" bitsize="32" type="ieee_single"/>
+ <reg name="f7" bitsize="32" type="ieee_single"/>
+ <reg name="f8" bitsize="32" type="ieee_single"/>
+ <reg name="f9" bitsize="32" type="ieee_single"/>
+ <reg name="f10" bitsize="32" type="ieee_single"/>
+ <reg name="f11" bitsize="32" type="ieee_single"/>
+ <reg name="f12" bitsize="32" type="ieee_single"/>
+ <reg name="f13" bitsize="32" type="ieee_single"/>
+ <reg name="f14" bitsize="32" type="ieee_single"/>
+ <reg name="f15" bitsize="32" type="ieee_single"/>
+ <reg name="f16" bitsize="32" type="ieee_single"/>
+ <reg name="f17" bitsize="32" type="ieee_single"/>
+ <reg name="f18" bitsize="32" type="ieee_single"/>
+ <reg name="f19" bitsize="32" type="ieee_single"/>
+ <reg name="f20" bitsize="32" type="ieee_single"/>
+ <reg name="f21" bitsize="32" type="ieee_single"/>
+ <reg name="f22" bitsize="32" type="ieee_single"/>
+ <reg name="f23" bitsize="32" type="ieee_single"/>
+ <reg name="f24" bitsize="32" type="ieee_single"/>
+ <reg name="f25" bitsize="32" type="ieee_single"/>
+ <reg name="f26" bitsize="32" type="ieee_single"/>
+ <reg name="f27" bitsize="32" type="ieee_single"/>
+ <reg name="f28" bitsize="32" type="ieee_single"/>
+ <reg name="f29" bitsize="32" type="ieee_single"/>
+ <reg name="f30" bitsize="32" type="ieee_single"/>
+ <reg name="f31" bitsize="32" type="ieee_single"/>
+
+ <reg name="fcsr" bitsize="32" group="float"/>
+ <reg name="fir" bitsize="32" group="float"/>
+</feature>
Index: gdb/features/mips64-cp0.xml
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/features/mips64-cp0.xml 2007-05-18 12:01:07.000000000 -0400
@@ -0,0 +1,13 @@
+<?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. -->
+
+
+<feature name="org.gnu.gdb.mips.cp0">
+ <reg name="status" bitsize="64" regnum="32"/>
+ <reg name="badvaddr" bitsize="64" regnum="35"/>
+ <reg name="cause" bitsize="64" regnum="36"/>
+</feature>
Index: gdb/features/mips64-fpu.xml
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/features/mips64-fpu.xml 2007-05-18 12:01:07.000000000 -0400
@@ -0,0 +1,45 @@
+<?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. -->
+
+
+<feature name="org.gnu.gdb.mips.fpu">
+ <reg name="f0" bitsize="64" type="ieee_double"/>
+ <reg name="f1" bitsize="64" type="ieee_double"/>
+ <reg name="f2" bitsize="64" type="ieee_double"/>
+ <reg name="f3" bitsize="64" type="ieee_double"/>
+ <reg name="f4" bitsize="64" type="ieee_double"/>
+ <reg name="f5" bitsize="64" type="ieee_double"/>
+ <reg name="f6" bitsize="64" type="ieee_double"/>
+ <reg name="f7" bitsize="64" type="ieee_double"/>
+ <reg name="f8" bitsize="64" type="ieee_double"/>
+ <reg name="f9" bitsize="64" type="ieee_double"/>
+ <reg name="f10" bitsize="64" type="ieee_double"/>
+ <reg name="f11" bitsize="64" type="ieee_double"/>
+ <reg name="f12" bitsize="64" type="ieee_double"/>
+ <reg name="f13" bitsize="64" type="ieee_double"/>
+ <reg name="f14" bitsize="64" type="ieee_double"/>
+ <reg name="f15" bitsize="64" type="ieee_double"/>
+ <reg name="f16" bitsize="64" type="ieee_double"/>
+ <reg name="f17" bitsize="64" type="ieee_double"/>
+ <reg name="f18" bitsize="64" type="ieee_double"/>
+ <reg name="f19" bitsize="64" type="ieee_double"/>
+ <reg name="f20" bitsize="64" type="ieee_double"/>
+ <reg name="f21" bitsize="64" type="ieee_double"/>
+ <reg name="f22" bitsize="64" type="ieee_double"/>
+ <reg name="f23" bitsize="64" type="ieee_double"/>
+ <reg name="f24" bitsize="64" type="ieee_double"/>
+ <reg name="f25" bitsize="64" type="ieee_double"/>
+ <reg name="f26" bitsize="64" type="ieee_double"/>
+ <reg name="f27" bitsize="64" type="ieee_double"/>
+ <reg name="f28" bitsize="64" type="ieee_double"/>
+ <reg name="f29" bitsize="64" type="ieee_double"/>
+ <reg name="f30" bitsize="64" type="ieee_double"/>
+ <reg name="f31" bitsize="64" type="ieee_double"/>
+
+ <reg name="fcsr" bitsize="64" group="float"/>
+ <reg name="fir" bitsize="64" group="float"/>
+</feature>
Index: gdb/doc/gdb.texinfo
===================================================================
--- gdb.orig/doc/gdb.texinfo 2007-05-18 12:01:06.000000000 -0400
+++ gdb/doc/gdb.texinfo 2007-05-18 12:01:08.000000000 -0400
@@ -25671,6 +25671,23 @@ it should contain at least registers @sa
@samp{wCGR0} through @samp{wCGR3}. The @samp{wCID}, @samp{wCon},
@samp{wCSSF}, and @samp{wCASF} registers are optional.

+@subsection MIPS Features
+@cindex target descriptions, MIPS features
+
+The @samp{org.gnu.gdb.mips.cpu} feature is required for MIPS targets.
+It should contain registers @samp{r0} through @samp{r31}, @samp{lo},
+@samp{hi}, and @samp{pc}. They may be 32-bit or 64-bit depending
+on the target.
+
+The @samp{org.gnu.gdb.mips.cp0} feature is also required. It should
+contain at least the @samp{status}, @samp{badvaddr}, and @samp{cause}
+registers. They may be 32-bit or 64-bit depending on the target.
+
+The @samp{org.gnu.gdb.mips.fpu} feature is currently required, though
+it may be optional in a future version of @value{GDBN}. It should
+contain registers @samp{f0} through @samp{f31}, @samp{fcsr}, and
+@samp{fir}. They may be 32-bit or 64-bit depending on the target.
+
@include gpl.texi

@raisesections
Index: gdb/features/mips-cpu.xml
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/features/mips-cpu.xml 2007-05-18 12:01:08.000000000 -0400
@@ -0,0 +1,46 @@
+<?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. -->
+
+
+<feature name="org.gnu.gdb.mips.cpu">
+ <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="r13" bitsize="32"/>
+ <reg name="r14" bitsize="32"/>
+ <reg name="r15" bitsize="32"/>
+ <reg name="r16" bitsize="32"/>
+ <reg name="r17" bitsize="32"/>
+ <reg name="r18" bitsize="32"/>
+ <reg name="r19" bitsize="32"/>
+ <reg name="r20" bitsize="32"/>
+ <reg name="r21" bitsize="32"/>
+ <reg name="r22" bitsize="32"/>
+ <reg name="r23" bitsize="32"/>
+ <reg name="r24" bitsize="32"/>
+ <reg name="r25" bitsize="32"/>
+ <reg name="r26" bitsize="32"/>
+ <reg name="r27" bitsize="32"/>
+ <reg name="r28" bitsize="32"/>
+ <reg name="r29" bitsize="32"/>
+ <reg name="r30" bitsize="32"/>
+ <reg name="r31" bitsize="32"/>
+
+ <reg name="lo" bitsize="32" regnum="33"/>
+ <reg name="hi" bitsize="32" regnum="34"/>
+ <reg name="pc" bitsize="32" regnum="37"/>
+</feature>
Index: gdb/features/mips64-cpu.xml
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/features/mips64-cpu.xml 2007-05-18 12:01:08.000000000 -0400
@@ -0,0 +1,46 @@
+<?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. -->
+
+
+<feature name="org.gnu.gdb.mips.cpu">
+ <reg name="r0" bitsize="64"/>
+ <reg name="r1" bitsize="64"/>
+ <reg name="r2" bitsize="64"/>
+ <reg name="r3" bitsize="64"/>
+ <reg name="r4" bitsize="64"/>
+ <reg name="r5" bitsize="64"/>
+ <reg name="r6" bitsize="64"/>
+ <reg name="r7" bitsize="64"/>
+ <reg name="r8" bitsize="64"/>
+ <reg name="r9" bitsize="64"/>
+ <reg name="r10" bitsize="64"/>
+ <reg name="r11" bitsize="64"/>
+ <reg name="r12" bitsize="64"/>
+ <reg name="r13" bitsize="64"/>
+ <reg name="r14" bitsize="64"/>
+ <reg name="r15" bitsize="64"/>
+ <reg name="r16" bitsize="64"/>
+ <reg name="r17" bitsize="64"/>
+ <reg name="r18" bitsize="64"/>
+ <reg name="r19" bitsize="64"/>
+ <reg name="r20" bitsize="64"/>
+ <reg name="r21" bitsize="64"/>
+ <reg name="r22" bitsize="64"/>
+ <reg name="r23" bitsize="64"/>
+ <reg name="r24" bitsize="64"/>
+ <reg name="r25" bitsize="64"/>
+ <reg name="r26" bitsize="64"/>
+ <reg name="r27" bitsize="64"/>
+ <reg name="r28" bitsize="64"/>
+ <reg name="r29" bitsize="64"/>
+ <reg name="r30" bitsize="64"/>
+ <reg name="r31" bitsize="64"/>
+
+ <reg name="lo" bitsize="64" regnum="33"/>
+ <reg name="hi" bitsize="64" regnum="34"/>
+ <reg name="pc" bitsize="64" regnum="37"/>
+</feature>
Index: gdb/NEWS
===================================================================
--- gdb.orig/NEWS 2007-05-18 12:01:06.000000000 -0400
+++ gdb/NEWS 2007-05-18 12:01:08.000000000 -0400
@@ -20,11 +20,11 @@ target's overall architecture. GDB can
a local file or over the remote serial protocol.

* Arrays of explicitly SIGNED or UNSIGNED CHARs are now printed as arrays
- of numbers.
+of numbers.

* Target descriptions can now describe target-specific registers,
for architectures which have implemented the support (currently
-only ARM).
+only ARM and MIPS).

* GDB and the GDB remote stub, gdbserver, now support the XScale
iWMMXt coprocessor.