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]

[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 *


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