This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 01/24] MIPS: Handle run-time reconfigurable FPR size


    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.
---
 gdb/gdbarch.c         |  32 +++++++++
 gdb/gdbarch.h         |  11 +++
 gdb/gdbarch.sh        |   5 ++
 gdb/mips-linux-tdep.c |   7 +-
 gdb/mips-tdep.c       | 194 +++++++++++++++++++++++++++++++++++---------------
 gdb/mips-tdep.h       |  16 +++++
 gdb/regcache.c        |  25 ++++++-
 7 files changed, 227 insertions(+), 63 deletions(-)

diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 4143744..0673fc1 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -199,6 +199,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;
@@ -543,6 +544,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.  */
@@ -1225,6 +1227,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "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,
@@ -2171,6 +2179,30 @@ set_gdbarch_register_type (struct gdbarch *gdbarch,
 }
 
 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);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 3fadcd1..22b02a3 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -356,6 +356,17 @@ typedef struct type * (gdbarch_register_type_ftype) (struct gdbarch *gdbarch, in
 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);
+
 extern int gdbarch_dummy_id_p (struct gdbarch *gdbarch);
 
 typedef struct frame_id (gdbarch_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *this_frame);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 4ac6b90..2c09371 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -469,6 +469,11 @@ m:const char *:register_name:int regnr:regnr::0
 # 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
 
 M:struct frame_id:dummy_id:struct frame_info *this_frame:this_frame
 # Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete
diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index 8dc0566..6b9743b 100644
--- a/gdb/mips-linux-tdep.c
+++ b/gdb/mips-linux-tdep.c
@@ -1737,8 +1737,9 @@ mips_linux_init_abi (struct gdbarch_info info,
 				    mips_gdb_signal_to_target);
 
   tdep->syscall_next_pc = mips_linux_syscall_next_pc;
+  tdep->fp_register_size_fixed_p = 1;
 
-  if (tdesc_data)
+  if (((struct gdbarch_tdep_info*)(info.tdep_info))->tdesc_data)
     {
       const struct tdesc_feature *feature;
 
@@ -1753,8 +1754,8 @@ mips_linux_init_abi (struct gdbarch_info 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, (((struct gdbarch_tdep_info*)(info.tdep_info))->tdesc_data),
+				 MIPS_RESTART_REGNUM, "restart");
     }
 }
 
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 63c1560..ae4dc2e 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -58,8 +58,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 *gdbarch,
 					      ULONGEST inst);
 static int micromips_instruction_has_delay_slot (ULONGEST insn, int mustbe32);
@@ -274,6 +272,77 @@ mips_abi_regsize (struct gdbarch *gdbarch)
     }
 }
 
+/* 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
@@ -504,32 +573,6 @@ mips_xfer_register (struct gdbarch *gdbarch, struct regcache *regcache,
     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);
@@ -1005,31 +1048,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
@@ -1074,8 +1122,10 @@ mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
     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,
@@ -6187,13 +6237,13 @@ mips_read_fp_register_single (struct frame_info *frame, int regno,
 			      gdb_byte *rare_buffer)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
-  int raw_size = register_size (gdbarch, regno);
-  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
+  int fpsize = register_size (gdbarch, regno);
+  gdb_byte *raw_buffer = alloca (fpsize);
 
   if (!deprecated_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.  */
@@ -6221,9 +6271,9 @@ mips_read_fp_register_double (struct frame_info *frame, int regno,
 			      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.  */
@@ -6260,20 +6310,19 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
 			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
-    = ((gdb_byte *)
-       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;
 
@@ -8167,6 +8216,7 @@ value_of_mips_user_reg (struct frame_info *frame, const void *baton)
 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;
@@ -8181,6 +8231,10 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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)
     {
@@ -8252,6 +8306,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
       const struct tdesc_feature *feature;
       int valid_p;
+      int fpsize;
 
       feature = tdesc_find_feature (info.target_desc,
 				    "org.gnu.gdb.mips.cpu");
@@ -8311,7 +8366,15 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	  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]);
@@ -8366,6 +8429,9 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	    }
 	}
 
+      /* 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;
@@ -8576,6 +8642,11 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       /* 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);
@@ -8593,6 +8664,8 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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;
 
   if (info.target_desc)
     {
@@ -8609,6 +8682,12 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	}
     }
 
+  /* 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);
@@ -8830,6 +8909,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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);
 
@@ -8869,7 +8949,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   mips_register_g_packet_guesses (gdbarch);
 
   /* Hook in OS ABI-specific overrides, if they have been registered.  */
-  info.tdep_info = tdesc_data;
+  ((struct gdbarch_tdep_info*)(info.tdep_info))->tdesc_data = tdesc_data;
   gdbarch_init_osabi (info, gdbarch);
 
   /* The hook may have adjusted num_regs, fetch the final value and
diff --git a/gdb/mips-tdep.h b/gdb/mips-tdep.h
index 2e4d194..6c1d9ca 100644
--- a/gdb/mips-tdep.h
+++ b/gdb/mips-tdep.h
@@ -113,11 +113,27 @@ 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;
+
   /* Return the expected next PC if FRAME is stopped at a syscall
      instruction.  */
   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
diff --git a/gdb/regcache.c b/gdb/regcache.c
index f0ba0cf..c3405b6 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -534,16 +534,35 @@ get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
 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);
     }
+}
+
+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 get_thread_arch_regcache (ptid, current_thread_arch);
+  return new_regcache;
 }
 
 struct regcache *
-- 
1.9-rc2


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]