This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[RFA][PR gdb/7518] MIPS: Handle run-time reconfigurable FPR size
- From: "Maciej W. Rozycki" <macro at codesourcery dot com>
- To: <gdb-patches at sourceware dot org>
- Cc: Daniel Jacobowitz <drow at false dot org>, Rich Fuhler <rich at mips dot com>
- Date: Wed, 6 Jun 2012 21:39:03 +0100
- Subject: [RFA][PR gdb/7518] MIPS: Handle run-time reconfigurable FPR size
Hello,
Many MIPS architecture processors can reconfigure the size of their
floating-point registers at the run time. The file comprising 32
registers can be either 32-bit or 64-bit wide depending on whether CP0
Status register's bit FR is zero or one, respectively. Fortunately access
to Status is available on all targets.
Here's a change to handle this property. It requires the generic
register access code to raise the target backend's attention whenever a
new register set has been retrieved so that it can examine the state of
CP0.Status.FR and act accordingly. I have added this hook to
get_thread_regcache, the backend has then an opportunity to switch gdbarch
as necessary and let the caller know if it did so. If that indeed
happened, then the register cache originally retrieved is then discarded
and another one obtained using the newly-selected gdbarch. This new
register cache is not revalidated.
This has been regression-tested successfully, using o32 and n64 multilibs
on mips-sde-elf and mips-linux-gnu targets. The ability to flip
CP0.Status.FR is not however covered by any test suite, and was therefore
tested manually. An example session with a bare-iron MIPS64 target looks
like this (I've stripped out some noise):
(gdb) info all-registers
zero at v0 v1
R0 0000000000000000 0000000000000000 0000000000000000 0000000020000000
a0 a1 a2 a3
R4 0000000000000000 0000000000000000 0000000000000000 0000000000000000
a4 a5 a6 a7
R8 0000000000000000 0000000000000000 0000000000000000 0000000000000000
t0 t1 t2 t3
R12 0000000000000000 0000000000000000 0000000000000000 0000000000000000
s0 s1 s2 s3
R16 0000000000000000 0000000000000000 0000000000000000 0000000000000000
s4 s5 s6 s7
R20 0000000000000000 0000000000000000 0000000000000000 0000000000000000
t8 t9 k0 k1
R24 0000000000000000 0000000000000000 0000000000000000 0000000000000000
gp sp s8 ra
R28 0000000000000000 0000000000000000 0000000000000000 0000000000000000
sr lo hi bad
0000000024000000 0000000000000000 0000000000000000 0000000000000000
cause pc
0000000000000000 ffffffff80000000
f0: 0x0000000000000000 flt: 0 dbl: 0
f1: 0x000000003f800000 flt: 1 dbl: 5.2635442471208903e-315
f2: 0x0000000000000000 flt: 0 dbl: 0
f3: 0x0000000040000000 flt: 2 dbl: 5.3049894774131808e-315
f4: 0x0000000000000000 flt: 0 dbl: 0
f5: 0x0000000040400000 flt: 3 dbl: 5.325712092559326e-315
f6: 0x0000000000000000 flt: 0 dbl: 0
f7: 0x0000000040800000 flt: 4 dbl: 5.3464347077054713e-315
f8: 0x0000000000000000 flt: 0 dbl: 0
f9: 0x0000000040a00000 flt: 5 dbl: 5.3567960152785439e-315
f10: 0x0000000000000000 flt: 0 dbl: 0
f11: 0x0000000040c00000 flt: 6 dbl: 5.3671573228516165e-315
f12: 0x0000000000000000 flt: 0 dbl: 0
f13: 0x0000000040e00000 flt: 7 dbl: 5.3775186304246891e-315
f14: 0x0000000000000000 flt: 0 dbl: 0
f15: 0x0000000041000000 flt: 8 dbl: 5.3878799379977617e-315
f16: 0x0000000000000000 flt: 0 dbl: 0
f17: 0x0000000041100000 flt: 9 dbl: 5.393060591784298e-315
f18: 0x0000000000000000 flt: 0 dbl: 0
f19: 0x0000000041200000 flt: 10 dbl: 5.3982412455708344e-315
f20: 0x0000000000000000 flt: 0 dbl: 0
f21: 0x0000000041300000 flt: 11 dbl: 5.4034218993573707e-315
f22: 0x0000000000000000 flt: 0 dbl: 0
f23: 0x0000000041400000 flt: 12 dbl: 5.408602553143907e-315
f24: 0x0000000000000000 flt: 0 dbl: 0
f25: 0x0000000041500000 flt: 13 dbl: 5.4137832069304433e-315
f26: 0x0000000000000000 flt: 0 dbl: 0
f27: 0x0000000041600000 flt: 14 dbl: 5.4189638607169796e-315
f28: 0x0000000000000000 flt: 0 dbl: 0
f29: 0x0000000041700000 flt: 15 dbl: 5.4241445145035159e-315
f30: 0x0000000000000000 flt: 0 dbl: 0
f31: 0x0000000041800000 flt: 16 dbl: 5.4293251682900522e-315
fsr fir
00000000 00738900
(gdb) x /i $pc
=> 0xffffffff80000000: mtc0 v1,c0_status
(gdb) stepi
0xffffffff80000004 in ?? ()
(gdb) info all-registers
zero at v0 v1
R0 0000000000000000 0000000000000000 0000000000000000 0000000020000000
a0 a1 a2 a3
R4 0000000000000000 0000000000000000 0000000000000000 0000000000000000
a4 a5 a6 a7
R8 0000000000000000 0000000000000000 0000000000000000 0000000000000000
t0 t1 t2 t3
R12 0000000000000000 0000000000000000 0000000000000000 0000000000000000
s0 s1 s2 s3
R16 0000000000000000 0000000000000000 0000000000000000 0000000000000000
s4 s5 s6 s7
R20 0000000000000000 0000000000000000 0000000000000000 0000000000000000
t8 t9 k0 k1
R24 0000000000000000 0000000000000000 0000000000000000 0000000000000000
gp sp s8 ra
R28 0000000000000000 0000000000000000 0000000000000000 0000000000000000
sr lo hi bad
0000000020000000 0000000000000000 0000000000000000 0000000000000000
cause pc
0000000000000000 ffffffff80000004
f0: 0x00000000 flt: 0 dbl: 0.0078125
f1: 0x3f800000 flt: 1
f2: 0x00000000 flt: 0 dbl: 2
f3: 0x40000000 flt: 2
f4: 0x00000000 flt: 0 dbl: 32
f5: 0x40400000 flt: 3
f6: 0x00000000 flt: 0 dbl: 512
f7: 0x40800000 flt: 4
f8: 0x00000000 flt: 0 dbl: 2048
f9: 0x40a00000 flt: 5
f10: 0x00000000 flt: 0 dbl: 8192
f11: 0x40c00000 flt: 6
f12: 0x00000000 flt: 0 dbl: 32768
f13: 0x40e00000 flt: 7
f14: 0x00000000 flt: 0 dbl: 131072
f15: 0x41000000 flt: 8
f16: 0x00000000 flt: 0 dbl: 262144
f17: 0x41100000 flt: 9
f18: 0x00000000 flt: 0 dbl: 524288
f19: 0x41200000 flt: 10
f20: 0x00000000 flt: 0 dbl: 1048576
f21: 0x41300000 flt: 11
f22: 0x00000000 flt: 0 dbl: 2097152
f23: 0x41400000 flt: 12
f24: 0x00000000 flt: 0 dbl: 4194304
f25: 0x41500000 flt: 13
f26: 0x00000000 flt: 0 dbl: 8388608
f27: 0x41600000 flt: 14
f28: 0x00000000 flt: 0 dbl: 16777216
f29: 0x41700000 flt: 15
f30: 0x00000000 flt: 0 dbl: 33554432
f31: 0x41800000 flt: 16
fsr fir
00000000 00738900
(gdb) set $sr ^= 1 << 26
(gdb) info all-registers
zero at v0 v1
R0 0000000000000000 0000000000000000 0000000000000000 0000000020000000
a0 a1 a2 a3
R4 0000000000000000 0000000000000000 0000000000000000 0000000000000000
a4 a5 a6 a7
R8 0000000000000000 0000000000000000 0000000000000000 0000000000000000
t0 t1 t2 t3
R12 0000000000000000 0000000000000000 0000000000000000 0000000000000000
s0 s1 s2 s3
R16 0000000000000000 0000000000000000 0000000000000000 0000000000000000
s4 s5 s6 s7
R20 0000000000000000 0000000000000000 0000000000000000 0000000000000000
t8 t9 k0 k1
R24 0000000000000000 0000000000000000 0000000000000000 0000000000000000
gp sp s8 ra
R28 0000000000000000 0000000000000000 0000000000000000 0000000000000000
sr lo hi bad
0000000024000000 0000000000000000 0000000000000000 0000000000000000
cause pc
0000000000000000 ffffffff80000004
f0: 0x0000000000000000 flt: 0 dbl: 0
f1: 0x000000003f800000 flt: 1 dbl: 5.2635442471208903e-315
f2: 0x0000000000000000 flt: 0 dbl: 0
f3: 0x0000000040000000 flt: 2 dbl: 5.3049894774131808e-315
f4: 0x0000000000000000 flt: 0 dbl: 0
f5: 0x0000000040400000 flt: 3 dbl: 5.325712092559326e-315
f6: 0x0000000000000000 flt: 0 dbl: 0
f7: 0x0000000040800000 flt: 4 dbl: 5.3464347077054713e-315
f8: 0x0000000000000000 flt: 0 dbl: 0
f9: 0x0000000040a00000 flt: 5 dbl: 5.3567960152785439e-315
f10: 0x0000000000000000 flt: 0 dbl: 0
f11: 0x0000000040c00000 flt: 6 dbl: 5.3671573228516165e-315
f12: 0x0000000000000000 flt: 0 dbl: 0
f13: 0x0000000040e00000 flt: 7 dbl: 5.3775186304246891e-315
f14: 0x0000000000000000 flt: 0 dbl: 0
f15: 0x0000000041000000 flt: 8 dbl: 5.3878799379977617e-315
f16: 0x0000000000000000 flt: 0 dbl: 0
f17: 0x0000000041100000 flt: 9 dbl: 5.393060591784298e-315
f18: 0x0000000000000000 flt: 0 dbl: 0
f19: 0x0000000041200000 flt: 10 dbl: 5.3982412455708344e-315
f20: 0x0000000000000000 flt: 0 dbl: 0
f21: 0x0000000041300000 flt: 11 dbl: 5.4034218993573707e-315
f22: 0x0000000000000000 flt: 0 dbl: 0
f23: 0x0000000041400000 flt: 12 dbl: 5.408602553143907e-315
f24: 0x0000000000000000 flt: 0 dbl: 0
f25: 0x0000000041500000 flt: 13 dbl: 5.4137832069304433e-315
f26: 0x0000000000000000 flt: 0 dbl: 0
f27: 0x0000000041600000 flt: 14 dbl: 5.4189638607169796e-315
f28: 0x0000000000000000 flt: 0 dbl: 0
f29: 0x0000000041700000 flt: 15 dbl: 5.4241445145035159e-315
f30: 0x0000000000000000 flt: 0 dbl: 0
f31: 0x0000000041800000 flt: 16 dbl: 5.4293251682900522e-315
fsr fir
00000000 00738900
(gdb)
This is implemented by retaining the raw register size for the FPRs at its
native size (64-bits; this is required for remote packet offsets to work
out correctly) and then truncating the cooked register size or not as
required. I have skipped `maintenance print registers' dumps here for
brevity, the types flip between "double" and "float" as expected.
This change supports bare-iron, Linux and IRIX targets. For Linux and
IRIX the width of the floating-point registers is set by the ABI of the
program being run by the OS kernel and the kernel is responsible for
setting CP0.Status.FR correctly; the image of Status accessible via
ptrace(2) is read-only. Therefore the respective backends mark the width
as fixed and cause the run-time check to be skipped for efficiency. I
have verified that the Linux target does that correctly; the change for
IRIX is the same and is expected to be all right, but I have no access to
such a system (I will appreciate anyone verifying that).
The change currently supports 64-bit processors only as GDB has no way to
access upper halves of floating-point registers on 32-bit processors that
have a 64-bit FPU (i.e. MIPS32r2 and newer processors); this is mentioned
in the explanatory notes included with the change itself.
The change also supports both XML and non-XML targets, but currently
bare-iron targets for which this update has any significant meaning do not
really support XML. Any XML target is supposed to always provide an FPU
description that matches the current setting of CP0.Status.FR, the new
code verifies this is always the case and rejects the description as
invalid otherwise.
Generic parts require a general maintainer's approval, would whoever
finds themselves most familiar with regcache internals please have a look
at these bits? Thanks.
This addresses the CP0.Status.FR part of PR gdb/7518 (former GNATS PR
gdb/413) and is based on work started by Nigel and David (neither at MIPS
Technologies anymore).
2012-06-06 Maciej W. Rozycki <macro@codesourcery.com>
Nigel Stephens <nigel@mips.com>
David Ung <davidu@mips.com>
PR gdb/7518
gdb/
* gdbarch.sh (regcache_changed): New function.
* regcache.c (set_current_thread_ptid_arch): New function,
factored out from...
(get_thread_regcache): ... here. Call gdbarch_regcache_changed
as necessary.
* mips-tdep.h (gdbarch_tdep): Add fp_register_size_fixed_p and
fp_register_size members.
(gdbarch_tdep_info): New structure.
* mips-tdep.c (mips_register_type): Remove forward declaration.
(mips_set_float_regsize, mips_float_regsize): New functions.
(mips2_fp_compat): Remove function.
(mips_register_type): Use mips_float_regsize to handle cooked
floating-point registers. Fold floating-point cases into common
code.
(mips_pseudo_register_type): Update comment on floating-point
registers.
(mips_read_fp_register_single): Rename raw_size local variable
to fpsize.
(mips_read_fp_register_double): Likewise. Remove call to
mips2_fp_compat.
(mips_print_fp_register): Check the size of the register
requested rather than $f0 and use fpsize local variable to hold
it. Remove call to mips2_fp_compat.
(mips_print_float_info): Use mips_float_regsize.
(mips_gdbarch_init): Use a proper tdep_info structure. Match
gdbarch against fp_register_size requested if any. Initialize
fp_register_size and fp_register_size_fixed_p in gdbarch target
data. Install mips_set_float_regsize as gdbarch regcache_changed
routine.
* mips-irix-tdep.c (mips_irix_init_abi): Set
fp_register_size_fixed_p in gdbarch target data.
* mips-linux-tdep.c (mips_linux_init_abi): Likewise. Adjust for
tdep_info update.
* gdbarch.h: Regenerate.
* gdbarch.c: Regenerate.
Maciej
gdb-mips-fpr-size.diff
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.c 2012-06-06 20:10:41.905563887 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.c 2012-06-06 20:20:30.025578610 +0100
@@ -179,6 +179,7 @@ struct gdbarch
gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum;
gdbarch_register_name_ftype *register_name;
gdbarch_register_type_ftype *register_type;
+ gdbarch_regcache_changed_ftype *regcache_changed;
gdbarch_dummy_id_ftype *dummy_id;
int deprecated_fp_regnum;
gdbarch_push_dummy_call_ftype *push_dummy_call;
@@ -350,6 +351,7 @@ struct gdbarch startup_gdbarch =
no_op_reg_to_regnum, /* dwarf2_reg_to_regnum */
0, /* register_name */
0, /* register_type */
+ 0, /* regcache_changed */
0, /* dummy_id */
-1, /* deprecated_fp_regnum */
0, /* push_dummy_call */
@@ -656,6 +658,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
if (gdbarch->register_name == 0)
fprintf_unfiltered (log, "\n\tregister_name");
/* Skip verify of register_type, has predicate. */
+ /* Skip verify of regcache_changed, has predicate. */
/* Skip verify of dummy_id, has predicate. */
/* Skip verify of deprecated_fp_regnum, invalid_p == 0 */
/* Skip verify of push_dummy_call, has predicate. */
@@ -1228,6 +1231,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
"gdbarch_dump: record_special_symbol = <%s>\n",
host_address_to_string (gdbarch->record_special_symbol));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_regcache_changed_p() = %d\n",
+ gdbarch_regcache_changed_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: regcache_changed = <%s>\n",
+ host_address_to_string (gdbarch->regcache_changed));
+ fprintf_unfiltered (file,
"gdbarch_dump: register_name = <%s>\n",
host_address_to_string (gdbarch->register_name));
fprintf_unfiltered (file,
@@ -2165,6 +2174,30 @@ set_gdbarch_register_type (struct gdbarc
}
int
+gdbarch_regcache_changed_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->regcache_changed != NULL;
+}
+
+int
+gdbarch_regcache_changed (struct gdbarch *gdbarch, struct regcache *regcache)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->regcache_changed != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_regcache_changed called\n");
+ return gdbarch->regcache_changed (gdbarch, regcache);
+}
+
+void
+set_gdbarch_regcache_changed (struct gdbarch *gdbarch,
+ gdbarch_regcache_changed_ftype regcache_changed)
+{
+ gdbarch->regcache_changed = regcache_changed;
+}
+
+int
gdbarch_dummy_id_p (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.h 2012-06-06 20:10:41.905563887 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.h 2012-06-06 20:20:30.025578610 +0100
@@ -334,6 +334,17 @@ typedef struct type * (gdbarch_register_
extern struct type * gdbarch_register_type (struct gdbarch *gdbarch, int reg_nr);
extern void set_gdbarch_register_type (struct gdbarch *gdbarch, gdbarch_register_type_ftype *register_type);
+/* Notify the architecture that the registers have changed and we now have
+ a new regcache to examine. Return one if a new architecture has been
+ selected that changed the layout of the regcache and it has to be
+ discarded and a new one initialised, zero otherwise. */
+
+extern int gdbarch_regcache_changed_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_regcache_changed_ftype) (struct gdbarch *gdbarch, struct regcache *regcache);
+extern int gdbarch_regcache_changed (struct gdbarch *gdbarch, struct regcache *regcache);
+extern void set_gdbarch_regcache_changed (struct gdbarch *gdbarch, gdbarch_regcache_changed_ftype *regcache_changed);
+
/* See gdbint.texinfo, and PUSH_DUMMY_CALL. */
extern int gdbarch_dummy_id_p (struct gdbarch *gdbarch);
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.sh
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.sh 2012-06-06 20:10:41.905563887 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.sh 2012-06-06 20:20:30.025578610 +0100
@@ -465,6 +465,11 @@ m:const char *:register_name:int regnr:r
# the register cache should call this function directly; others should
# use "register_type".
M:struct type *:register_type:int reg_nr:reg_nr
+# Notify the architecture that the registers have changed and we now have
+# a new regcache to examine. Return one if a new architecture has been
+# selected that changed the layout of the regcache and it has to be
+# discarded and a new one initialised, zero otherwise.
+M:int:regcache_changed:struct regcache *regcache:regcache
# See gdbint.texinfo, and PUSH_DUMMY_CALL.
M:struct frame_id:dummy_id:struct frame_info *this_frame:this_frame
Index: gdb-fsf-trunk-quilt/gdb/mips-irix-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-irix-tdep.c 2012-06-06 18:41:27.995511096 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-irix-tdep.c 2012-06-06 20:20:30.035445388 +0100
@@ -273,6 +273,7 @@ mips_irix_init_abi (struct gdbarch_info
set_solib_ops (gdbarch, &irix_so_ops);
tramp_frame_prepend_unwinder (gdbarch, &mips_irix_n32_stack_tramp_frame);
tramp_frame_prepend_unwinder (gdbarch, &mips_irix_n32_tramp_frame);
+ gdbarch_tdep (gdbarch)->fp_register_size_fixed_p = 1;
}
/* Provide a prototype to silence -Wmissing-prototypes. */
Index: gdb-fsf-trunk-quilt/gdb/mips-linux-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-linux-tdep.c 2012-06-06 20:11:43.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-linux-tdep.c 2012-06-06 20:20:30.035445388 +0100
@@ -1433,7 +1433,6 @@ mips_linux_init_abi (struct gdbarch_info
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum mips_abi abi = mips_abi (gdbarch);
- struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
linux_init_abi (info, gdbarch);
@@ -1517,8 +1516,9 @@ mips_linux_init_abi (struct gdbarch_info
mips_linux_regset_from_core_section);
tdep->syscall_next_pc = mips_linux_syscall_next_pc;
+ tdep->fp_register_size_fixed_p = 1;
- if (tdesc_data)
+ if (info.tdep_info->tdesc_data)
{
const struct tdesc_feature *feature;
@@ -1533,8 +1533,8 @@ mips_linux_init_abi (struct gdbarch_info
feature = tdesc_find_feature (info.target_desc,
"org.gnu.gdb.mips.linux");
if (feature != NULL)
- tdesc_numbered_register (feature, tdesc_data, MIPS_RESTART_REGNUM,
- "restart");
+ tdesc_numbered_register (feature, info.tdep_info->tdesc_data,
+ MIPS_RESTART_REGNUM, "restart");
}
}
Index: gdb-fsf-trunk-quilt/gdb/mips-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-tdep.c 2012-06-06 20:13:52.065560164 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-tdep.c 2012-06-06 20:20:30.035445388 +0100
@@ -60,8 +60,6 @@
static const struct objfile_data *mips_pdr_data;
-static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum);
-
static int mips32_instruction_has_delay_slot (struct gdbarch *, CORE_ADDR);
static int micromips_instruction_has_delay_slot (struct gdbarch *, CORE_ADDR,
int);
@@ -266,6 +264,77 @@ mips_abi_regsize (struct gdbarch *gdbarc
}
}
+/* Determine the current floating-point register size and update our
+ architecture data accordingly. Return one if the size has changed
+ and a new architecture has been selected, zero otherwise.
+
+ For MIPS1, MIPS2 and MIPS32 rev. 1 processors the size is hardwired
+ to 32 bits. For MIPS3 and other 64-bit processors up to the MIPS64
+ rev. 1 ISA the size is determined by the CP0 Status register's bit
+ FR. If this bit is 1, then the size is 64 bits. If it is 0, then
+ the FPU operates in the compatibility mode and the size is 32 bits.
+
+ From MIPS32 and MIPS64 rev. 2 ISAs up the size is implementation
+ specific and reported by the CP1 FIR register's bit F64. If this
+ bit is 0, then the size is hardwired to 32 bits. If this bit is 1,
+ then the size is determined by the CP0 Status register's bit FR as
+ described above. Unfortunately we may not have access to the CP0
+ registers needed to determine whether the ISA implemented is MIPS32
+ or MIPS64 rev. 2 or higher.
+
+ We currently cannot handle the 64-bit floating-point register size
+ on MIPS32 rev. 2 and higher ISA processors though as no target
+ provides access to upper halves of such registers. Therefore we
+ hardcode the size to 32 bits for any 32-bit processors.
+
+ As the CP0 Status register's bit FR cannot be modified on processors
+ that do not implement an FPU, backends for operating systems that
+ can emulate the FPU in software should set the size according to the
+ ABI in use and then set fp_register_size_fixed_p to 1 to prevent
+ further updates. */
+
+static int
+mips_set_float_regsize (struct gdbarch *gdbarch, struct regcache *regcache)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ struct gdbarch_tdep_info tdep_info = { NULL };
+ struct gdbarch_info info;
+ int fpsize;
+
+ if (tdep->fp_register_size_fixed_p)
+ return 0;
+
+ fpsize = mips_isa_regsize (gdbarch);
+ if (fpsize == 8)
+ {
+ enum register_status status;
+ ULONGEST sr;
+
+ status = regcache_raw_read_unsigned (regcache, MIPS_PS_REGNUM, &sr);
+ if (status == REG_VALID)
+ fpsize = (sr & ST0_FR) ? 8 : 4;
+ }
+
+ if (fpsize == tdep->fp_register_size)
+ return 0;
+
+ /* Need a new gdbarch, go get one. */
+ gdbarch_info_init (&info);
+ info.tdep_info = &tdep_info;
+ info.tdep_info->fp_register_size = fpsize;
+ gdbarch_update_p (info);
+
+ return 1;
+}
+
+/* Return the currently configured floating-point register size. */
+
+static int
+mips_float_regsize (struct gdbarch *gdbarch)
+{
+ return gdbarch_tdep (gdbarch)->fp_register_size;
+}
+
/* MIPS16/microMIPS function addresses are odd (bit 0 is set). Here
are some functions to handle addresses associated with compressed
code including but not limited to testing, setting, or clearing
@@ -475,32 +544,6 @@ mips_xfer_register (struct gdbarch *gdba
fprintf_unfiltered (gdb_stdlog, "\n");
}
-/* Determine if a MIPS3 or later cpu is operating in MIPS{1,2} FPU
- compatiblity mode. A return value of 1 means that we have
- physical 64-bit registers, but should treat them as 32-bit registers. */
-
-static int
-mips2_fp_compat (struct frame_info *frame)
-{
- struct gdbarch *gdbarch = get_frame_arch (frame);
- /* MIPS1 and MIPS2 have only 32 bit FPRs, and the FR bit is not
- meaningful. */
- if (register_size (gdbarch, mips_regnum (gdbarch)->fp0) == 4)
- return 0;
-
-#if 0
- /* FIXME drow 2002-03-10: This is disabled until we can do it consistently,
- in all the places we deal with FP registers. PR gdb/413. */
- /* Otherwise check the FR bit in the status register - it controls
- the FP compatiblity mode. If it is clear we are in compatibility
- mode. */
- if ((get_frame_register_unsigned (frame, MIPS_PS_REGNUM) & ST0_FR) == 0)
- return 1;
-#endif
-
- return 0;
-}
-
#define VM_MIN_ADDRESS (CORE_ADDR)0x400000
static CORE_ADDR heuristic_proc_start (struct gdbarch *, CORE_ADDR);
@@ -976,31 +1019,36 @@ static struct type *
mips_register_type (struct gdbarch *gdbarch, int regnum)
{
gdb_assert (regnum >= 0 && regnum < 2 * gdbarch_num_regs (gdbarch));
- if (mips_float_register_p (gdbarch, regnum))
- {
- /* The floating-point registers raw, or cooked, always match
- mips_isa_regsize(), and also map 1:1, byte for byte. */
- if (mips_isa_regsize (gdbarch) == 4)
- return builtin_type (gdbarch)->builtin_float;
- else
- return builtin_type (gdbarch)->builtin_double;
- }
- else if (regnum < gdbarch_num_regs (gdbarch))
+ if (regnum < gdbarch_num_regs (gdbarch))
{
/* The raw or ISA registers. These are all sized according to
the ISA regsize. */
- if (mips_isa_regsize (gdbarch) == 4)
- return builtin_type (gdbarch)->builtin_int32;
+ int regsize = mips_isa_regsize (gdbarch);
+
+ if (mips_float_register_p (gdbarch, regnum))
+ return (regsize == 4
+ ? builtin_type (gdbarch)->builtin_float
+ : builtin_type (gdbarch)->builtin_double);
else
- return builtin_type (gdbarch)->builtin_int64;
+ return (regsize == 4
+ ? builtin_type (gdbarch)->builtin_int32
+ : builtin_type (gdbarch)->builtin_int64);
}
else
{
- int rawnum = regnum - gdbarch_num_regs (gdbarch);
-
/* The cooked or ABI registers. These are sized according to
the ABI (with a few complications). */
- if (rawnum == mips_regnum (gdbarch)->fp_control_status
+ int rawnum = regnum - gdbarch_num_regs (gdbarch);
+
+ /* Floating-point registers of most 64-bit and some 32-bit MIPS
+ processors can be reconfigured dynamically at the run time as
+ either 64-bit or 32-bit via the CP0 Status register's FR bit.
+ Use the current setting for cooked registers. */
+ if (mips_float_register_p (gdbarch, regnum))
+ return (mips_float_regsize (gdbarch) == 4
+ ? builtin_type (gdbarch)->builtin_float
+ : builtin_type (gdbarch)->builtin_double);
+ else if (rawnum == mips_regnum (gdbarch)->fp_control_status
|| rawnum == mips_regnum (gdbarch)->fp_implementation_revision)
return builtin_type (gdbarch)->builtin_int32;
else if (gdbarch_osabi (gdbarch) != GDB_OSABI_IRIX
@@ -1046,8 +1094,10 @@ mips_pseudo_register_type (struct gdbarc
return rawtype;
if (mips_float_register_p (gdbarch, rawnum))
- /* Present the floating point registers however the hardware did;
- do not try to convert between FPU layouts. */
+ /* Present the floating point registers however the hardware did; do
+ not try to convert between FPU layouts. A target description is
+ expected to have taken the CP0 Status register's FR bit into account
+ as necessary, this has been already verified in mips_gdbarch_init. */
return rawtype;
/* Use pointer types for registers if we can. For n32 we can not,
@@ -5987,13 +6037,13 @@ mips_read_fp_register_single (struct fra
gdb_byte *rare_buffer)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
- int raw_size = register_size (gdbarch, regno);
- gdb_byte *raw_buffer = alloca (raw_size);
+ int fpsize = register_size (gdbarch, regno);
+ gdb_byte *raw_buffer = alloca (fpsize);
if (!frame_register_read (frame, regno, raw_buffer))
error (_("can't read register %d (%s)"),
regno, gdbarch_register_name (gdbarch, regno));
- if (raw_size == 8)
+ if (fpsize == 8)
{
/* We have a 64-bit value for this register. Find the low-order
32 bits. */
@@ -6021,9 +6071,9 @@ mips_read_fp_register_double (struct fra
gdb_byte *rare_buffer)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
- int raw_size = register_size (gdbarch, regno);
+ int fpsize = register_size (gdbarch, regno);
- if (raw_size == 8 && !mips2_fp_compat (frame))
+ if (fpsize == 8)
{
/* We have a 64-bit value for this register, and we should use
all 64 bits. */
@@ -6060,19 +6110,19 @@ mips_print_fp_register (struct ui_file *
int regnum)
{ /* Do values for FP (float) regs. */
struct gdbarch *gdbarch = get_frame_arch (frame);
+ int fpsize = register_size (gdbarch, regnum);
gdb_byte *raw_buffer;
double doub, flt1; /* Doubles extracted from raw hex data. */
int inv1, inv2;
- raw_buffer = alloca (2 * register_size (gdbarch,
- mips_regnum (gdbarch)->fp0));
+ raw_buffer = alloca (2 * fpsize);
fprintf_filtered (file, "%s:", gdbarch_register_name (gdbarch, regnum));
fprintf_filtered (file, "%*s",
4 - (int) strlen (gdbarch_register_name (gdbarch, regnum)),
"");
- if (register_size (gdbarch, regnum) == 4 || mips2_fp_compat (frame))
+ if (fpsize == 4)
{
struct value_print_options opts;
@@ -6223,7 +6273,7 @@ mips_print_float_info (struct gdbarch *g
return;
fprintf_filtered (file, "reg size: %d bits\n",
- register_size (gdbarch, mips_regnum (gdbarch)->fp0) * 8);
+ mips_float_regsize (gdbarch) * 8);
fcs = get_frame_register_unsigned (frame, fcsr);
@@ -7939,6 +7989,7 @@ value_of_mips_user_reg (struct frame_inf
static struct gdbarch *
mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
+ struct gdbarch_tdep_info tdep_info = { NULL };
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
int elf_flags;
@@ -7953,6 +8004,10 @@ mips_gdbarch_init (struct gdbarch_info i
int dspacc;
int dspctl;
+ /* Wire in an empty template tdep_info if one hasn't been supplied. */
+ if (info.tdep_info == NULL)
+ info.tdep_info = &tdep_info;
+
/* Fill in the OS dependent register numbers and names. */
if (info.osabi == GDB_OSABI_IRIX)
{
@@ -8024,6 +8079,7 @@ mips_gdbarch_init (struct gdbarch_info i
const struct tdesc_feature *feature;
int valid_p;
+ int fpsize;
feature = tdesc_find_feature (info.target_desc,
"org.gnu.gdb.mips.cpu");
@@ -8083,7 +8139,15 @@ mips_gdbarch_init (struct gdbarch_info i
return NULL;
}
- valid_p = 1;
+ /* Set the floating-point register size, assuming that whoever
+ supplied the description got the current setting right wrt
+ CP0 Status register's bit FR if applicable. */
+ fpsize = tdesc_register_size (feature, mips_fprs[0]) / 8;
+
+ /* Only accept a description whose floating-point register size
+ matches the requested size or if none was specified. */
+ valid_p = (info.tdep_info->fp_register_size == 0
+ || info.tdep_info->fp_register_size == fpsize);
for (i = 0; i < 32; i++)
valid_p &= tdesc_numbered_register (feature, tdesc_data,
i + mips_regnum.fp0, mips_fprs[i]);
@@ -8138,6 +8202,9 @@ mips_gdbarch_init (struct gdbarch_info i
}
}
+ /* Fix the floating-point register size found. */
+ info.tdep_info->fp_register_size = fpsize;
+
/* It would be nice to detect an attempt to use a 64-bit ABI
when only 32-bit registers are provided. */
reg_names = NULL;
@@ -8346,6 +8413,11 @@ 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;
+ /* Ditto the requested floating-point register size if any. */
+ if (info.tdep_info->fp_register_size != 0
+ && (gdbarch_tdep (arches->gdbarch)->fp_register_size)
+ != info.tdep_info->fp_register_size)
+ continue;
if (tdesc_data != NULL)
tdesc_data_cleanup (tdesc_data);
@@ -8363,6 +8435,8 @@ mips_gdbarch_init (struct gdbarch_info i
tdep->mips_fpu_type = fpu_type;
tdep->register_size_valid_p = 0;
tdep->register_size = 0;
+ tdep->fp_register_size = info.tdep_info->fp_register_size;
+ tdep->fp_register_size_fixed_p = 0;
tdep->gregset = NULL;
tdep->gregset64 = NULL;
tdep->fpregset = NULL;
@@ -8383,6 +8457,12 @@ mips_gdbarch_init (struct gdbarch_info i
}
}
+ /* If we haven't figured out the size of floating-point registers
+ by now yet, then assume it is the same as for general-purpose
+ registers. */
+ if (tdep->fp_register_size == 0)
+ tdep->fp_register_size = mips_isa_regsize (gdbarch);
+
/* Initially set everything according to the default ABI/ISA. */
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_int_bit (gdbarch, 32);
@@ -8604,6 +8684,7 @@ mips_gdbarch_init (struct gdbarch_info i
set_gdbarch_integer_to_address (gdbarch, mips_integer_to_address);
set_gdbarch_register_type (gdbarch, mips_register_type);
+ set_gdbarch_regcache_changed (gdbarch, mips_set_float_regsize);
set_gdbarch_print_registers_info (gdbarch, mips_print_registers_info);
@@ -8643,7 +8724,7 @@ mips_gdbarch_init (struct gdbarch_info i
mips_register_g_packet_guesses (gdbarch);
/* Hook in OS ABI-specific overrides, if they have been registered. */
- info.tdep_info = (void *) tdesc_data;
+ info.tdep_info->tdesc_data = tdesc_data;
gdbarch_init_osabi (info, gdbarch);
/* The hook may have adjusted num_regs, fetch the final value and
Index: gdb-fsf-trunk-quilt/gdb/mips-tdep.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-tdep.h 2012-06-06 20:11:43.435423000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-tdep.h 2012-06-06 20:20:30.035445388 +0100
@@ -107,6 +107,12 @@ struct gdbarch_tdep
int register_size_valid_p;
int register_size;
+ /* The size of floating-point registers determined at the run time.
+ This corresponds to CP0 Status register's bit FR setting if
+ implemented unless fixed_p is set. */
+ int fp_register_size_fixed_p;
+ int fp_register_size;
+
/* General-purpose registers. */
struct regset *gregset;
struct regset *gregset64;
@@ -120,6 +126,16 @@ struct gdbarch_tdep
CORE_ADDR (*syscall_next_pc) (struct frame_info *frame);
};
+/* MIPS specific per-architecture initialization information. */
+struct gdbarch_tdep_info
+{
+ /* Target description data. */
+ struct tdesc_arch_data *tdesc_data;
+
+ /* The size of floating-point registers determined at the run time. */
+ int fp_register_size;
+};
+
/* Register numbers of various important registers. */
enum
Index: gdb-fsf-trunk-quilt/gdb/regcache.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/regcache.c 2012-06-06 18:41:27.975638466 +0100
+++ gdb-fsf-trunk-quilt/gdb/regcache.c 2012-06-06 20:20:30.035445388 +0100
@@ -494,16 +494,35 @@ get_thread_arch_regcache (ptid_t ptid, s
static ptid_t current_thread_ptid;
static struct gdbarch *current_thread_arch;
-struct regcache *
-get_thread_regcache (ptid_t ptid)
+static void
+set_current_thread_ptid_arch (ptid_t ptid)
{
if (!current_thread_arch || !ptid_equal (current_thread_ptid, ptid))
{
current_thread_ptid = ptid;
current_thread_arch = target_thread_architecture (ptid);
}
+}
- return get_thread_arch_regcache (ptid, current_thread_arch);
+struct regcache *
+get_thread_regcache (ptid_t ptid)
+{
+ int registers_changed_p = current_regcache == NULL;
+ struct regcache *new_regcache;
+
+ set_current_thread_ptid_arch (ptid);
+ new_regcache = get_thread_arch_regcache (ptid, current_thread_arch);
+
+ if (registers_changed_p
+ && gdbarch_regcache_changed_p (current_thread_arch)
+ && gdbarch_regcache_changed (current_thread_arch, new_regcache))
+ {
+ registers_changed ();
+ set_current_thread_ptid_arch (ptid);
+ new_regcache = get_thread_arch_regcache (ptid, current_thread_arch);
+ }
+
+ return new_regcache;
}
struct regcache *