powerpc-linux biarch corefile support

Alan Modra amodra@bigpond.net.au
Sat Aug 25 01:23:00 GMT 2007


On Sat, Apr 28, 2007 at 06:19:36PM +0200, Ulrich Weigand wrote:
> Why don't we push the task of clearing individual registers down
> to ppc_supply_reg and ppc_collect_reg in rs6000-nat.c?  Have their
> callers always provide them with an "offset" value pointing to the
> start of the full field in REGS, and provide an extra "size" value
> denoting the length of the field in REGS.
> 
> The helper functions can compare that size with GDB's notion of
> the register_size, and if it is bigger (it cannot be smaller),
> supply only the right part of the field, and zero out the left
> part of the field when collecting.
> 
> The callers of ppc_supply_reg and ppc_collect_reg should be able
> to provide that new size value using offsets->gpr_size or fixed
> values.
> 
> Note that this should make ppc64_32_linux_reg_offsets unnecessary,
> you'll need to always use ppc64_linux_reg_offsets on a 64-bit host.

OK, that's what I've done in the following patch.

Looking first at the generic rs6000 changes, these are:
1) Add a "gpr_size" field to "struct ppc_reg_offsets" so that the
   collect_regset and supply_regset functions will work with both
   32-bit and 64-bit regsets.  We can't simply use tdep->wordsize to
   deduce the size of registers, because in some cases
   (eg. supply_gregset and fill_gregset in ppc-linux-nat.c) the size
   we want is "sizeof (long)" rather than the target wordsize.
2) The low level ppc_supply_reg and ppc_collect_reg functions are
   changed as per Ulrich's suggestion, to zero pad a larger register
   field as necessary.
3) I reorganized ppc_supply_gregset et al to be a little more
   efficient.  It seemed silly to run around a loop to find a gpr/fpr
   offset when transferring one register.  This particular change also
   fixes a bug in one of the register offsets, and removes uses of
   current_gdbarch where the gdbarch is available from the regcache.
4) ppc_supply_fpregset and ppc_collect_fpregset had an assert that
   the target had a fp unit, and callers generally tested the same.
   I changed the assert to instead return if !ppc_floating_point_unit_p
   and removed the caller tests.  It seems silly to duplicate the
   tests, and I believe it is correct for ppc_supply_fpregset and
   ppc_collect_fpregset to do nothing when the target has no fp unit.
   It is certainly consistent with other cases where one or more
   registers are not present in a target.

With these changes in place quite a lot of ppc-linux-nat.c and
ppc-linux-tdep.c can disappear, and we get biarch core file capability.
Note that without (4) above, we need a wrapper for ppc_supply_fpregset
and ppc_collect_fpregset so that these functions aren't called for
e500.

I removed the FIXMEs in ppcobsd-tdep.c because that seems appropriate
in line with removing the asserts in (4).  I left the other two
similar FIXMEs (in ppcobsd-nat.c and ppcnbsd-nat.c) as code there (and
in the callers of getfpregs_supplies) will need updating to handle
e500.

	* ppc-linux-nat.c (right_fill_reg): Delete.
	(supply_gregset): Use ppc_supply_gregset.
	(supply_fpregset): Use ppc_supply_fpregset.
	(fill_gregset): Use ppc_collect_gregset.
	(fill_fpregset): Use ppc_collect_fpregset.
	* ppc-linux-tdep.c (PPC_LINUX_PT_*): Don't define.
	(right_supply_register, ppc_linux_supply_gregset): Delete.
	(ppc32_linux_supply_gregset, ppc64_linux_supply_gregset): Delete.
	(ppc_linux_supply_fpregset): Delete.
	(ppc32_linux_reg_offsets, ppc64_linux_reg_offsets): New.
	(ppc32_linux_gregset, ppc64_linux_gregset): Update to use reg offsets,
	ppc_supply_gregset, and ppc_collect_gregset.
	(ppc_linux_fpregset): Rename to ppc32_linux_fpregset and update.
	(ppc_linux_gregset, ppc_linux_fpregset): New functions.
	(ppc_linux_regset_from_core_section): Update.
	* ppc-tdep.h (ppc_linux_gregset, ppc_linux_fpregset): Declare.
	(ppc_linux_supply_gregset, ppc_linux_supply_fpregset): Delete.
	(struct ppc_reg_offsets): Add "gpr_size" field.
	* ppcobsd-tdep.c (ppcobsd_supply_gregset): Delete FIXME and assert.
	(ppcobsd_collect_gregset): Likewise.
	(_initialize_ppcnbsd_tdep): Init gpr_size.
	* ppcnbsd-tdep.c (_initialize_ppcobsd_tdep): Likewise.
	* rs6000-aix-tdep.c (rs6000_aix_supply_regset): Call
	ppc_supply_fpregset without testing ppc_floating_point_unit_p.
	(rs6000_aix_collect_regset): Similarly.
	* rs6000-tdep.c (ppc_supply_reg): Add regsize param.  Adjust offset
	when regsize is larger than regcache register size.
	(ppc_collect_reg): Similarly zero pad when regsize is larger than
	regcache register size.
	(ppc_greg_offset): New function, split out from..
	(ppc_supply_gregset): ..here.  Separate code handling all regs from
	single reg case.  Correct xer offset.
	(ppc_fpreg_offset): New function, split out from..
	(ppc_supply_fpregset): ..here.  Separate code handling all regs from
	single reg case.
	(ppc_collect_gregset, ppc_collect_fpregset): Likewise.
	(ppc_supply_fpregset, ppc_collect_fpregset): Don't assert we have
	a fp unit, instead return if no fp.

Index: gdb/ppc-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-linux-nat.c,v
retrieving revision 1.69
diff -u -p -r1.69 ppc-linux-nat.c
--- gdb/ppc-linux-nat.c	23 Aug 2007 18:08:36 -0000	1.69
+++ gdb/ppc-linux-nat.c	24 Aug 2007 13:08:20 -0000
@@ -901,101 +901,46 @@ ppc_linux_store_inferior_registers (stru
     store_ppc_registers (regcache, tid);
 }
 
+/* Functions for transferring registers between a gregset_t or fpregset_t
+   (see sys/ucontext.h) and gdb's regcache.  The word size is that used
+   by the ptrace interface, not the current program's ABI.  eg. If a
+   powerpc64-linux gdb is being used to debug a powerpc32-linux app, we
+   read or write 64-bit gregsets.  This is to suit the host libthread_db.  */
+
 void
 supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
 {
-  /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace
-     interface, and not the wordsize of the program's ABI.  */
-  int wordsize = sizeof (long);
-  ppc_linux_supply_gregset (regcache, -1, gregsetp,
-			    sizeof (gdb_gregset_t), wordsize);
-}
+  const struct regset *regset = ppc_linux_gregset (sizeof (long));
 
-static void
-right_fill_reg (const struct regcache *regcache, int regnum, void *reg)
-{
-  /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace
-     interface, and not the wordsize of the program's ABI.  */
-  int wordsize = sizeof (long);
-  /* Right fill the register.  */
-  regcache_raw_collect (regcache, regnum,
-			((bfd_byte *) reg
-			 + wordsize
-			 - register_size (current_gdbarch, regnum)));
+  ppc_supply_gregset (regset, regcache, -1, gregsetp, sizeof (*gregsetp));
 }
 
 void
 fill_gregset (const struct regcache *regcache,
 	      gdb_gregset_t *gregsetp, int regno)
 {
-  int regi;
-  elf_greg_t *regp = (elf_greg_t *) gregsetp;
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); 
-  const int elf_ngreg = 48;
-
-
-  /* Start with zeros.  */
-  memset (regp, 0, elf_ngreg * sizeof (*regp));
-
-  for (regi = 0; regi < ppc_num_gprs; regi++)
-    {
-      if ((regno == -1) || regno == tdep->ppc_gp0_regnum + regi)
-	right_fill_reg (regcache, tdep->ppc_gp0_regnum + regi,
-			(regp + PT_R0 + regi));
-    }
-
-  if ((regno == -1) || regno == gdbarch_pc_regnum (current_gdbarch))
-    right_fill_reg (regcache, gdbarch_pc_regnum (current_gdbarch),
-		    regp + PT_NIP);
-  if ((regno == -1) || regno == tdep->ppc_lr_regnum)
-    right_fill_reg (regcache, tdep->ppc_lr_regnum, regp + PT_LNK);
-  if ((regno == -1) || regno == tdep->ppc_cr_regnum)
-    regcache_raw_collect (regcache, tdep->ppc_cr_regnum,
-			  regp + PT_CCR);
-  if ((regno == -1) || regno == tdep->ppc_xer_regnum)
-    regcache_raw_collect (regcache, tdep->ppc_xer_regnum,
-			  regp + PT_XER);
-  if ((regno == -1) || regno == tdep->ppc_ctr_regnum)
-    right_fill_reg (regcache, tdep->ppc_ctr_regnum, regp + PT_CTR);
-#ifdef PT_MQ
-  if (((regno == -1) || regno == tdep->ppc_mq_regnum)
-      && (tdep->ppc_mq_regnum != -1))
-    right_fill_reg (regcache, tdep->ppc_mq_regnum, regp + PT_MQ);
-#endif
-  if ((regno == -1) || regno == tdep->ppc_ps_regnum)
-    right_fill_reg (regcache, tdep->ppc_ps_regnum, regp + PT_MSR);
+  const struct regset *regset = ppc_linux_gregset (sizeof (long));
+
+  ppc_collect_gregset (regset, regcache, regno, gregsetp, sizeof (*gregsetp));
 }
 
 void
 supply_fpregset (struct regcache *regcache, const gdb_fpregset_t * fpregsetp)
 {
-  ppc_linux_supply_fpregset (NULL, regcache, -1, fpregsetp,
-			     sizeof (gdb_fpregset_t));
+  const struct regset *regset = ppc_linux_fpregset ();
+
+  ppc_supply_fpregset (regset, regcache, -1,
+		       fpregsetp, sizeof (*fpregsetp));
 }
 
-/* Given a pointer to a floating point register set in /proc format
-   (fpregset_t *), update the register specified by REGNO from gdb's
-   idea of the current floating point register set.  If REGNO is -1,
-   update them all.  */
 void
 fill_fpregset (const struct regcache *regcache,
 	       gdb_fpregset_t *fpregsetp, int regno)
 {
-  int regi;
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); 
-  bfd_byte *fpp = (void *) fpregsetp;
-  
-  if (ppc_floating_point_unit_p (current_gdbarch))
-    {
-      for (regi = 0; regi < ppc_num_fprs; regi++)
-        {
-          if ((regno == -1) || (regno == tdep->ppc_fp0_regnum + regi))
-            regcache_raw_collect (regcache, tdep->ppc_fp0_regnum + regi,
-				  fpp + 8 * regi);
-        }
-      if (regno == -1 || regno == tdep->ppc_fpscr_regnum)
-        right_fill_reg (regcache, tdep->ppc_fpscr_regnum, (fpp + 8 * 32));
-    }
+  const struct regset *regset = ppc_linux_fpregset ();
+
+  ppc_collect_fpregset (regset, regcache, regno,
+			fpregsetp, sizeof (*fpregsetp));
 }
 
 void _initialize_ppc_linux_nat (void);
Index: gdb/ppc-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppc-linux-tdep.c,v
retrieving revision 1.87
diff -u -p -r1.87 ppc-linux-tdep.c
--- gdb/ppc-linux-tdep.c	23 Aug 2007 18:08:36 -0000	1.87
+++ gdb/ppc-linux-tdep.c	24 Aug 2007 13:08:21 -0000
@@ -38,51 +38,6 @@
 #include "frame-unwind.h"
 #include "tramp-frame.h"
 
-/* From <asm/ptrace.h>, values for PT_NIP, PT_R1, and PT_LNK */
-#define PPC_LINUX_PT_R0		0
-#define PPC_LINUX_PT_R1		1
-#define PPC_LINUX_PT_R2		2
-#define PPC_LINUX_PT_R3		3
-#define PPC_LINUX_PT_R4		4
-#define PPC_LINUX_PT_R5		5
-#define PPC_LINUX_PT_R6		6
-#define PPC_LINUX_PT_R7		7
-#define PPC_LINUX_PT_R8		8
-#define PPC_LINUX_PT_R9		9
-#define PPC_LINUX_PT_R10	10
-#define PPC_LINUX_PT_R11	11
-#define PPC_LINUX_PT_R12	12
-#define PPC_LINUX_PT_R13	13
-#define PPC_LINUX_PT_R14	14
-#define PPC_LINUX_PT_R15	15
-#define PPC_LINUX_PT_R16	16
-#define PPC_LINUX_PT_R17	17
-#define PPC_LINUX_PT_R18	18
-#define PPC_LINUX_PT_R19	19
-#define PPC_LINUX_PT_R20	20
-#define PPC_LINUX_PT_R21	21
-#define PPC_LINUX_PT_R22	22
-#define PPC_LINUX_PT_R23	23
-#define PPC_LINUX_PT_R24	24
-#define PPC_LINUX_PT_R25	25
-#define PPC_LINUX_PT_R26	26
-#define PPC_LINUX_PT_R27	27
-#define PPC_LINUX_PT_R28	28
-#define PPC_LINUX_PT_R29	29
-#define PPC_LINUX_PT_R30	30
-#define PPC_LINUX_PT_R31	31
-#define PPC_LINUX_PT_NIP	32
-#define PPC_LINUX_PT_MSR	33
-#define PPC_LINUX_PT_CTR	35
-#define PPC_LINUX_PT_LNK	36
-#define PPC_LINUX_PT_XER	37
-#define PPC_LINUX_PT_CCR	38
-#define PPC_LINUX_PT_MQ		39
-#define PPC_LINUX_PT_FPR0	48	/* each FP reg occupies 2 slots in this space */
-#define PPC_LINUX_PT_FPR31 (PPC_LINUX_PT_FPR0 + 2*31)
-#define PPC_LINUX_PT_FPSCR (PPC_LINUX_PT_FPR0 + 2*32 + 1)
-
-
 static CORE_ADDR
 ppc_linux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
@@ -660,99 +615,85 @@ ppc_linux_convert_from_func_ptr_addr (st
   return addr;
 }
 
-static void
-right_supply_register (struct regcache *regcache, int wordsize, int regnum,
-		       const bfd_byte *buf)
-{
-  regcache_raw_supply (regcache, regnum,
-		       (buf + wordsize - register_size (current_gdbarch, regnum)));
-}
-
-/* Extract the register values found in the WORDSIZED ABI GREGSET,
-   storing their values in REGCACHE.  Note that some are left-aligned,
-   while others are right aligned.  */
-
-void
-ppc_linux_supply_gregset (struct regcache *regcache,
-			  int regnum, const void *gregs, size_t size,
-			  int wordsize)
-{
-  int regi;
-  struct gdbarch *regcache_arch = get_regcache_arch (regcache); 
-  struct gdbarch_tdep *regcache_tdep = gdbarch_tdep (regcache_arch);
-  const bfd_byte *buf = gregs;
-
-  for (regi = 0; regi < ppc_num_gprs; regi++)
-    right_supply_register (regcache, wordsize,
-                           regcache_tdep->ppc_gp0_regnum + regi,
-                           buf + wordsize * regi);
-
-  right_supply_register (regcache, wordsize, gdbarch_pc_regnum (regcache_arch),
-			 buf + wordsize * PPC_LINUX_PT_NIP);
-  right_supply_register (regcache, wordsize, regcache_tdep->ppc_lr_regnum,
-			 buf + wordsize * PPC_LINUX_PT_LNK);
-  regcache_raw_supply (regcache, regcache_tdep->ppc_cr_regnum,
-		       buf + wordsize * PPC_LINUX_PT_CCR);
-  regcache_raw_supply (regcache, regcache_tdep->ppc_xer_regnum,
-		       buf + wordsize * PPC_LINUX_PT_XER);
-  regcache_raw_supply (regcache, regcache_tdep->ppc_ctr_regnum,
-		       buf + wordsize * PPC_LINUX_PT_CTR);
-  if (regcache_tdep->ppc_mq_regnum != -1)
-    right_supply_register (regcache, wordsize, regcache_tdep->ppc_mq_regnum,
-			   buf + wordsize * PPC_LINUX_PT_MQ);
-  right_supply_register (regcache, wordsize, regcache_tdep->ppc_ps_regnum,
-			 buf + wordsize * PPC_LINUX_PT_MSR);
-}
+/* Regset descriptions.  */
+static const struct ppc_reg_offsets ppc32_linux_reg_offsets =
+  {
+    /* General-purpose registers.  */
+    /* .r0_offset = */ 0,
+    /* .gpr_size = */ 4,
+    /* .pc_offset = */ 128,
+    /* .ps_offset = */ 132,
+    /* .cr_offset = */ 152,
+    /* .lr_offset = */ 144,
+    /* .ctr_offset = */ 140,
+    /* .xer_offset = */ 148,
+    /* .mq_offset = */ 156,
+
+    /* Floating-point registers.  */
+    /* .f0_offset = */ 0,
+    /* .fpscr_offset = */ 256 + 4,
+
+    /* AltiVec registers.  */
+    /* .vr0_offset = */ 0,
+    /* .vrsave_offset = */ 512,
+    /* .vscr_offset = */ 512 + 12
+  };
 
-static void
-ppc32_linux_supply_gregset (const struct regset *regset,
-			    struct regcache *regcache,
-			    int regnum, const void *gregs, size_t size)
-{
-  ppc_linux_supply_gregset (regcache, regnum, gregs, size, 4);
-}
+static const struct ppc_reg_offsets ppc64_linux_reg_offsets =
+  {
+    /* General-purpose registers.  */
+    /* .r0_offset = */ 0,
+    /* .gpr_size = */ 8,
+    /* .pc_offset = */ 256,
+    /* .ps_offset = */ 264,
+    /* .cr_offset = */ 304,
+    /* .lr_offset = */ 288,
+    /* .ctr_offset = */ 280,
+    /* .xer_offset = */ 296,
+    /* .mq_offset = */ 312,
+
+    /* Floating-point registers.  */
+    /* .f0_offset = */ 0,
+    /* .fpscr_offset = */ 256,
+
+    /* AltiVec registers.  */
+    /* .vr0_offset = */ 0,
+    /* .vrsave_offset = */ 528,
+    /* .vscr_offset = */ 512 + 12
+  };
 
 static struct regset ppc32_linux_gregset = {
-  NULL, ppc32_linux_supply_gregset
+  &ppc32_linux_reg_offsets,
+  ppc_supply_gregset,
+  ppc_collect_gregset,
+  NULL
 };
 
-static void
-ppc64_linux_supply_gregset (const struct regset *regset,
-			    struct regcache * regcache,
-			    int regnum, const void *gregs, size_t size)
-{
-  ppc_linux_supply_gregset (regcache, regnum, gregs, size, 8);
-}
-
 static struct regset ppc64_linux_gregset = {
-  NULL, ppc64_linux_supply_gregset
+  &ppc64_linux_reg_offsets,
+  ppc_supply_gregset,
+  ppc_collect_gregset,
+  NULL
 };
 
-void
-ppc_linux_supply_fpregset (const struct regset *regset,
-			   struct regcache * regcache,
-			   int regnum, const void *fpset, size_t size)
-{
-  int regi;
-  struct gdbarch *regcache_arch = get_regcache_arch (regcache); 
-  struct gdbarch_tdep *regcache_tdep = gdbarch_tdep (regcache_arch);
-  const bfd_byte *buf = fpset;
-
-  if (! ppc_floating_point_unit_p (regcache_arch))
-    return;
-
-  for (regi = 0; regi < ppc_num_fprs; regi++)
-    regcache_raw_supply (regcache, 
-                         regcache_tdep->ppc_fp0_regnum + regi,
-                         buf + 8 * regi);
-
-  /* The FPSCR is stored in the low order word of the last
-     doubleword in the fpregset.  */
-  regcache_raw_supply (regcache, regcache_tdep->ppc_fpscr_regnum,
-                       buf + 8 * 32 + 4);
+static struct regset ppc32_linux_fpregset = {
+  &ppc32_linux_reg_offsets,
+  ppc_supply_fpregset,
+  ppc_collect_fpregset,
+  NULL
+};
+
+const struct regset *
+ppc_linux_gregset (int wordsize)
+{
+  return wordsize == 8 ? &ppc64_linux_gregset : &ppc32_linux_gregset;
 }
 
-static struct regset ppc_linux_fpregset = { NULL, ppc_linux_supply_fpregset };
+const struct regset *
+ppc_linux_fpregset (void)
+{
+  return &ppc32_linux_fpregset;
+}
 
 static const struct regset *
 ppc_linux_regset_from_core_section (struct gdbarch *core_arch,
@@ -767,7 +708,7 @@ ppc_linux_regset_from_core_section (stru
 	return &ppc64_linux_gregset;
     }
   if (strcmp (sect_name, ".reg2") == 0)
-    return &ppc_linux_fpregset;
+    return &ppc32_linux_fpregset;
   return NULL;
 }
 
Index: gdb/ppc-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/ppc-tdep.h,v
retrieving revision 1.55
diff -u -p -r1.55 ppc-tdep.h
--- gdb/ppc-tdep.h	23 Aug 2007 18:08:36 -0000	1.55
+++ gdb/ppc-tdep.h	24 Aug 2007 13:08:21 -0000
@@ -56,12 +56,8 @@ CORE_ADDR ppc64_sysv_abi_adjust_breakpoi
 						    CORE_ADDR bpaddr);
 int ppc_linux_memory_remove_breakpoint (struct bp_target_info *bp_tgt);
 struct link_map_offsets *ppc_linux_svr4_fetch_link_map_offsets (void);
-void ppc_linux_supply_gregset (struct regcache *regcache,
-			       int regnum, const void *gregs, size_t size,
-			       int wordsize);
-void ppc_linux_supply_fpregset (const struct regset *regset,
-				struct regcache *regcache,
-				int regnum, const void *gregs, size_t size);
+const struct regset *ppc_linux_gregset (int);
+const struct regset *ppc_linux_fpregset (void);
 
 enum return_value_convention ppc64_sysv_abi_return_value (struct gdbarch *gdbarch,
 							  struct type *valtype,
@@ -83,6 +79,7 @@ struct ppc_reg_offsets
 {
   /* General-purpose registers.  */
   int r0_offset;
+  int gpr_size;
   int pc_offset;
   int ps_offset;
   int cr_offset;
Index: gdb/ppcnbsd-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppcnbsd-tdep.c,v
retrieving revision 1.33
diff -u -p -r1.33 ppcnbsd-tdep.c
--- gdb/ppcnbsd-tdep.c	23 Aug 2007 18:08:36 -0000	1.33
+++ gdb/ppcnbsd-tdep.c	24 Aug 2007 13:08:21 -0000
@@ -213,6 +213,7 @@ _initialize_ppcnbsd_tdep (void)
     {
       /* General-purpose registers.  */
       ppcnbsd_reg_offsets.r0_offset = 0;
+      ppcnbsd_reg_offsets.gpr_size = 4;
       ppcnbsd_reg_offsets.lr_offset = 128;
       ppcnbsd_reg_offsets.cr_offset = 132;
       ppcnbsd_reg_offsets.xer_offset = 136;
Index: gdb/ppcobsd-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/ppcobsd-tdep.c,v
retrieving revision 1.17
diff -u -p -r1.17 ppcobsd-tdep.c
--- gdb/ppcobsd-tdep.c	23 Aug 2007 18:08:36 -0000	1.17
+++ gdb/ppcobsd-tdep.c	24 Aug 2007 13:08:21 -0000
@@ -51,18 +51,6 @@ ppcobsd_supply_gregset (const struct reg
 			struct regcache *regcache, int regnum,
 			const void *gregs, size_t len)
 {
-  /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
-     point registers.  Traditionally, GDB's register set has still
-     listed the floating point registers for such machines, so this
-     code is harmless.  However, the new E500 port actually omits the
-     floating point registers entirely from the register set --- they
-     don't even have register numbers assigned to them.
-
-     It's not clear to me how best to update this code, so this assert
-     will alert the first person to encounter the OpenBSD/E500
-     combination to the problem.  */
-  gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
-
   ppc_supply_gregset (regset, regcache, regnum, gregs, len);
   ppc_supply_fpregset (regset, regcache, regnum, gregs, len);
 }
@@ -77,18 +65,6 @@ ppcobsd_collect_gregset (const struct re
 			 const struct regcache *regcache, int regnum,
 			 void *gregs, size_t len)
 {
-  /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
-     point registers.  Traditionally, GDB's register set has still
-     listed the floating point registers for such machines, so this
-     code is harmless.  However, the new E500 port actually omits the
-     floating point registers entirely from the register set --- they
-     don't even have register numbers assigned to them.
-
-     It's not clear to me how best to update this code, so this assert
-     will alert the first person to encounter the OpenBSD/E500
-     combination to the problem.  */
-  gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
-
   ppc_collect_gregset (regset, regcache, regnum, gregs, len);
   ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
 }
@@ -331,6 +307,7 @@ _initialize_ppcobsd_tdep (void)
     {
       /* General-purpose registers.  */
       ppcobsd_reg_offsets.r0_offset = 0;
+      ppcobsd_reg_offsets.gpr_size = 4;
       ppcobsd_reg_offsets.pc_offset = 384;
       ppcobsd_reg_offsets.ps_offset = 388;
       ppcobsd_reg_offsets.cr_offset = 392;
Index: gdb/rs6000-aix-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-aix-tdep.c,v
retrieving revision 1.5
diff -u -p -r1.5 rs6000-aix-tdep.c
--- gdb/rs6000-aix-tdep.c	23 Aug 2007 18:08:37 -0000	1.5
+++ gdb/rs6000-aix-tdep.c	24 Aug 2007 13:08:21 -0000
@@ -85,9 +85,7 @@ rs6000_aix_supply_regset (const struct r
 			  const void *gregs, size_t len)
 {
   ppc_supply_gregset (regset, regcache, regnum, gregs, len);
-
-  if (ppc_floating_point_unit_p (get_regcache_arch (regcache)))
-    ppc_supply_fpregset (regset, regcache, regnum, gregs, len);
+  ppc_supply_fpregset (regset, regcache, regnum, gregs, len);
 }
 
 /* Collect register REGNUM in the general-purpose register set
@@ -101,9 +99,7 @@ rs6000_aix_collect_regset (const struct 
 			   void *gregs, size_t len)
 {
   ppc_collect_gregset (regset, regcache, regnum, gregs, len);
-
-  if (ppc_floating_point_unit_p (get_regcache_arch (regcache)))
-    ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
+  ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
 }
 
 /* AIX register set.  */
Index: gdb/rs6000-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.287
diff -u -p -r1.287 rs6000-tdep.c
--- gdb/rs6000-tdep.c	23 Aug 2007 18:08:37 -0000	1.287
+++ gdb/rs6000-tdep.c	24 Aug 2007 13:08:24 -0000
@@ -302,22 +302,106 @@ rs6000_register_sim_regno (int reg)
 
 /* Register set support functions.  */
 
+/* REGS + OFFSET contains register REGNUM in a field REGSIZE wide.
+   Write the register to REGCACHE.  */
+
 static void
 ppc_supply_reg (struct regcache *regcache, int regnum, 
-		const gdb_byte *regs, size_t offset)
+		const gdb_byte *regs, size_t offset, int regsize)
 {
   if (regnum != -1 && offset != -1)
-    regcache_raw_supply (regcache, regnum, regs + offset);
+    {
+      if (regsize > 4)
+	{
+	  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+	  int gdb_regsize = register_size (gdbarch, regnum);
+	  if (gdb_regsize < regsize
+	      && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    offset += regsize - gdb_regsize;
+	}
+      regcache_raw_supply (regcache, regnum, regs + offset);
+    }
 }
 
+/* Read register REGNUM from REGCACHE and store to REGS + OFFSET
+   in a field REGSIZE wide.  Zero pad as necessary.  */
+
 static void
 ppc_collect_reg (const struct regcache *regcache, int regnum,
-		 gdb_byte *regs, size_t offset)
+		 gdb_byte *regs, size_t offset, int regsize)
 {
   if (regnum != -1 && offset != -1)
-    regcache_raw_collect (regcache, regnum, regs + offset);
+    {
+      if (regsize > 4)
+	{
+	  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+	  int gdb_regsize = register_size (gdbarch, regnum);
+	  if (gdb_regsize < regsize)
+	    {
+	      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+		{
+		  memset (regs + offset, 0, regsize - gdb_regsize);
+		  offset += regsize - gdb_regsize;
+		}
+	      else
+		memset (regs + offset + regsize - gdb_regsize, 0,
+			regsize - gdb_regsize);
+	    }
+	}
+      regcache_raw_collect (regcache, regnum, regs + offset);
+    }
 }
     
+static int
+ppc_greg_offset (struct gdbarch *gdbarch,
+		 struct gdbarch_tdep *tdep,
+		 const struct ppc_reg_offsets *offsets,
+		 int regnum)
+{
+  if (regnum >= tdep->ppc_gp0_regnum
+      && regnum < tdep->ppc_gp0_regnum + ppc_num_gprs)
+    return (offsets->r0_offset
+	    + (regnum - tdep->ppc_gp0_regnum) * offsets->gpr_size);
+
+  if (regnum == gdbarch_pc_regnum (gdbarch))
+    return offsets->pc_offset;
+
+  if (regnum == tdep->ppc_ps_regnum)
+    return offsets->ps_offset;
+
+  if (regnum == tdep->ppc_cr_regnum)
+    return offsets->cr_offset;
+
+  if (regnum == tdep->ppc_lr_regnum)
+    return offsets->lr_offset;
+
+  if (regnum == tdep->ppc_ctr_regnum)
+    return offsets->ctr_offset;
+
+  if (regnum == tdep->ppc_xer_regnum)
+    return offsets->xer_offset;
+
+  if (regnum == tdep->ppc_mq_regnum)
+    return offsets->mq_offset;
+
+  return -1;
+}
+
+static int
+ppc_fpreg_offset (struct gdbarch_tdep *tdep,
+		  const struct ppc_reg_offsets *offsets,
+		  int regnum)
+{
+  if (regnum >= tdep->ppc_fp0_regnum
+      && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs)
+    return offsets->f0_offset + (regnum - tdep->ppc_fp0_regnum) * 8;
+
+  if (regnum == tdep->ppc_fpscr_regnum)
+    return offsets->fpscr_offset;
+
+  return -1;
+}
+
 /* Supply register REGNUM in the general-purpose register set REGSET
    from the buffer specified by GREGS and LEN to register cache
    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
@@ -330,36 +414,36 @@ ppc_supply_gregset (const struct regset 
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   const struct ppc_reg_offsets *offsets = regset->descr;
   size_t offset;
-  int i;
+  int gpr_size = offsets->gpr_size;
+
+  if (regnum == -1)
+    {
+      int i;
+
+      for (i = tdep->ppc_gp0_regnum, offset = offsets->r0_offset;
+	   i < tdep->ppc_gp0_regnum + ppc_num_gprs;
+	   i++, offset += gpr_size)
+	ppc_supply_reg (regcache, i, gregs, offset, gpr_size);
+
+      ppc_supply_reg (regcache, gdbarch_pc_regnum (gdbarch),
+		      gregs, offsets->pc_offset, gpr_size);
+      ppc_supply_reg (regcache, tdep->ppc_ps_regnum,
+		      gregs, offsets->ps_offset, gpr_size);
+      ppc_supply_reg (regcache, tdep->ppc_cr_regnum,
+		      gregs, offsets->cr_offset, gpr_size);
+      ppc_supply_reg (regcache, tdep->ppc_lr_regnum,
+		      gregs, offsets->lr_offset, gpr_size);
+      ppc_supply_reg (regcache, tdep->ppc_ctr_regnum,
+		      gregs, offsets->ctr_offset, gpr_size);
+      ppc_supply_reg (regcache, tdep->ppc_xer_regnum,
+		      gregs, offsets->xer_offset, gpr_size);
+      ppc_supply_reg (regcache, tdep->ppc_mq_regnum,
+		      gregs, offsets->mq_offset, gpr_size);
+      return;
+    }
 
-  for (i = tdep->ppc_gp0_regnum, offset = offsets->r0_offset;
-       i < tdep->ppc_gp0_regnum + ppc_num_gprs;
-       i++, offset += 4)
-    {
-      if (regnum == -1 || regnum == i)
-	ppc_supply_reg (regcache, i, gregs, offset);
-    }
-
-  if (regnum == -1 || regnum == gdbarch_pc_regnum (current_gdbarch))
-    ppc_supply_reg (regcache, gdbarch_pc_regnum (current_gdbarch),
-		    gregs, offsets->pc_offset);
-  if (regnum == -1 || regnum == tdep->ppc_ps_regnum)
-    ppc_supply_reg (regcache, tdep->ppc_ps_regnum,
-		    gregs, offsets->ps_offset);
-  if (regnum == -1 || regnum == tdep->ppc_cr_regnum)
-    ppc_supply_reg (regcache, tdep->ppc_cr_regnum,
-		    gregs, offsets->cr_offset);
-  if (regnum == -1 || regnum == tdep->ppc_lr_regnum)
-    ppc_supply_reg (regcache, tdep->ppc_lr_regnum,
-		    gregs, offsets->lr_offset);
-  if (regnum == -1 || regnum == tdep->ppc_ctr_regnum)
-    ppc_supply_reg (regcache, tdep->ppc_ctr_regnum,
-		    gregs, offsets->ctr_offset);
-  if (regnum == -1 || regnum == tdep->ppc_xer_regnum)
-    ppc_supply_reg (regcache, tdep->ppc_xer_regnum,
-		    gregs, offsets->cr_offset);
-  if (regnum == -1 || regnum == tdep->ppc_mq_regnum)
-    ppc_supply_reg (regcache, tdep->ppc_mq_regnum, gregs, offsets->mq_offset);
+  offset = ppc_greg_offset (gdbarch, tdep, offsets, regnum);
+  ppc_supply_reg (regcache, regnum, gregs, offset, gpr_size);
 }
 
 /* Supply register REGNUM in the floating-point register set REGSET
@@ -371,29 +455,36 @@ ppc_supply_fpregset (const struct regset
 		     int regnum, const void *fpregs, size_t len)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  const struct ppc_reg_offsets *offsets = regset->descr;
+  struct gdbarch_tdep *tdep;
+  const struct ppc_reg_offsets *offsets;
   size_t offset;
-  int i;
 
-  gdb_assert (ppc_floating_point_unit_p (gdbarch));
+  if (!ppc_floating_point_unit_p (gdbarch))
+    return;
 
-  offset = offsets->f0_offset;
-  for (i = tdep->ppc_fp0_regnum;
-       i < tdep->ppc_fp0_regnum + ppc_num_fprs;
-       i++, offset += 8)
+  tdep = gdbarch_tdep (gdbarch);
+  offsets = regset->descr;
+  if (regnum == -1)
     {
-      if (regnum == -1 || regnum == i)
-	ppc_supply_reg (regcache, i, fpregs, offset);
+      int i;
+
+      for (i = tdep->ppc_fp0_regnum, offset = offsets->f0_offset;
+	   i < tdep->ppc_fp0_regnum + ppc_num_fprs;
+	   i++, offset += 8)
+	ppc_supply_reg (regcache, i, fpregs, offset, 8);
+
+      ppc_supply_reg (regcache, tdep->ppc_fpscr_regnum,
+		      fpregs, offsets->fpscr_offset, offsets->gpr_size);
+      return;
     }
 
-  if (regnum == -1 || regnum == tdep->ppc_fpscr_regnum)
-    ppc_supply_reg (regcache, tdep->ppc_fpscr_regnum,
-		    fpregs, offsets->fpscr_offset);
+  offset = ppc_fpreg_offset (tdep, offsets, regnum);
+  ppc_supply_reg (regcache, regnum, fpregs, offset,
+		  regnum == tdep->ppc_fpscr_regnum ? offsets->gpr_size : 8);
 }
 
 /* Collect register REGNUM in the general-purpose register set
-   REGSET. from register cache REGCACHE into the buffer specified by
+   REGSET from register cache REGCACHE into the buffer specified by
    GREGS and LEN.  If REGNUM is -1, do this for all registers in
    REGSET.  */
 
@@ -406,42 +497,40 @@ ppc_collect_gregset (const struct regset
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   const struct ppc_reg_offsets *offsets = regset->descr;
   size_t offset;
-  int i;
+  int gpr_size = offsets->gpr_size;
+
+  if (regnum == -1)
+    {
+      int i;
+
+      for (i = tdep->ppc_gp0_regnum, offset = offsets->r0_offset;
+	   i < tdep->ppc_gp0_regnum + ppc_num_gprs;
+	   i++, offset += gpr_size)
+	ppc_collect_reg (regcache, i, gregs, offset, gpr_size);
+
+      ppc_collect_reg (regcache, gdbarch_pc_regnum (gdbarch),
+		       gregs, offsets->pc_offset, gpr_size);
+      ppc_collect_reg (regcache, tdep->ppc_ps_regnum,
+		       gregs, offsets->ps_offset, gpr_size);
+      ppc_collect_reg (regcache, tdep->ppc_cr_regnum,
+		       gregs, offsets->cr_offset, gpr_size);
+      ppc_collect_reg (regcache, tdep->ppc_lr_regnum,
+		       gregs, offsets->lr_offset, gpr_size);
+      ppc_collect_reg (regcache, tdep->ppc_ctr_regnum,
+		       gregs, offsets->ctr_offset, gpr_size);
+      ppc_collect_reg (regcache, tdep->ppc_xer_regnum,
+		       gregs, offsets->xer_offset, gpr_size);
+      ppc_collect_reg (regcache, tdep->ppc_mq_regnum,
+		       gregs, offsets->mq_offset, gpr_size);
+      return;
+    }
 
-  offset = offsets->r0_offset;
-  for (i = tdep->ppc_gp0_regnum;
-       i < tdep->ppc_gp0_regnum + ppc_num_gprs;
-       i++, offset += 4)
-    {
-      if (regnum == -1 || regnum == i)
-	ppc_collect_reg (regcache, i, gregs, offset);
-    }
-
-  if (regnum == -1 || regnum == gdbarch_pc_regnum (current_gdbarch))
-    ppc_collect_reg (regcache, gdbarch_pc_regnum (current_gdbarch),
-		     gregs, offsets->pc_offset);
-  if (regnum == -1 || regnum == tdep->ppc_ps_regnum)
-    ppc_collect_reg (regcache, tdep->ppc_ps_regnum,
-		     gregs, offsets->ps_offset);
-  if (regnum == -1 || regnum == tdep->ppc_cr_regnum)
-    ppc_collect_reg (regcache, tdep->ppc_cr_regnum,
-		     gregs, offsets->cr_offset);
-  if (regnum == -1 || regnum == tdep->ppc_lr_regnum)
-    ppc_collect_reg (regcache, tdep->ppc_lr_regnum,
-		     gregs, offsets->lr_offset);
-  if (regnum == -1 || regnum == tdep->ppc_ctr_regnum)
-    ppc_collect_reg (regcache, tdep->ppc_ctr_regnum,
-		     gregs, offsets->ctr_offset);
-  if (regnum == -1 || regnum == tdep->ppc_xer_regnum)
-    ppc_collect_reg (regcache, tdep->ppc_xer_regnum,
-		     gregs, offsets->xer_offset);
-  if (regnum == -1 || regnum == tdep->ppc_mq_regnum)
-    ppc_collect_reg (regcache, tdep->ppc_mq_regnum,
-		     gregs, offsets->mq_offset);
+  offset = ppc_greg_offset (gdbarch, tdep, offsets, regnum);
+  ppc_collect_reg (regcache, regnum, gregs, offset, gpr_size);
 }
 
 /* Collect register REGNUM in the floating-point register set
-   REGSET. from register cache REGCACHE into the buffer specified by
+   REGSET from register cache REGCACHE into the buffer specified by
    FPREGS and LEN.  If REGNUM is -1, do this for all registers in
    REGSET.  */
 
@@ -451,25 +540,32 @@ ppc_collect_fpregset (const struct regse
 		      int regnum, void *fpregs, size_t len)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  const struct ppc_reg_offsets *offsets = regset->descr;
+  struct gdbarch_tdep *tdep;
+  const struct ppc_reg_offsets *offsets;
   size_t offset;
-  int i;
 
-  gdb_assert (ppc_floating_point_unit_p (gdbarch));
+  if (!ppc_floating_point_unit_p (gdbarch))
+    return;
 
-  offset = offsets->f0_offset;
-  for (i = tdep->ppc_fp0_regnum;
-       i <= tdep->ppc_fp0_regnum + ppc_num_fprs;
-       i++, offset += 8)
+  tdep = gdbarch_tdep (gdbarch);
+  offsets = regset->descr;
+  if (regnum == -1)
     {
-      if (regnum == -1 || regnum == i)
-	ppc_collect_reg (regcache, i, fpregs, offset);
+      int i;
+
+      for (i = tdep->ppc_fp0_regnum, offset = offsets->f0_offset;
+	   i < tdep->ppc_fp0_regnum + ppc_num_fprs;
+	   i++, offset += 8)
+	ppc_collect_reg (regcache, i, fpregs, offset, 8);
+
+      ppc_collect_reg (regcache, tdep->ppc_fpscr_regnum,
+		       fpregs, offsets->fpscr_offset, offsets->gpr_size);
+      return;
     }
 
-  if (regnum == -1 || regnum == tdep->ppc_fpscr_regnum)
-    ppc_collect_reg (regcache, tdep->ppc_fpscr_regnum,
-		     fpregs, offsets->fpscr_offset);
+  offset = ppc_fpreg_offset (tdep, offsets, regnum);
+  ppc_collect_reg (regcache, regnum, fpregs, offset,
+		   regnum == tdep->ppc_fpscr_regnum ? offsets->gpr_size : 8);
 }
 
 

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Gdb-patches mailing list