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] Cross corefile support for ARM


I've reimplemented ARM Linux corefile support to use the new interfaces, and
work for cross-debuggers.  I needed this last week to track down a problem
in an EABI binary and I didn't have an EABI native GDB available.

I've tested it manually in both cross and native configurations; it actually
fixes FPA (NWFPE) support for core files, which had gotten broken at some
point in the past when ARM stopped providing FP0_REGNUM.

This whole story is a bit of an embarrassment.  I've implemented this at
least twice in the past but never cleaned it up enough to submit it.  And
Girish Shilamkar submitted something similar in February, although I didn't
notice at the time that (A) he didn't remove the existing core file support
in arm-linux-nat.c, which would probably break native ARM gdbs, and (B) the
FP support was bogus and didn't match any core dump layout I'm famliar with.
And I never heard back about TimeSys's copyright assignment, so that's been
sitting in limbo.

Look OK?

-- 
Daniel Jacobowitz
CodeSourcery

2006-06-08  Daniel Jacobowitz  <dan@codesourcery.com>

	* Makefile.in (arm_linux_tdep_h): New variable.
	(arm-linux-nat.o, arm-linux-tdep.o): Update.
	* arm-linux-nat.c: Include "arm-linux-tdep.h".
	(typeNone, typeSingle, typeDouble, typeExtended)
	(FPWORDS, ARM_CPSR_REGNUM, FPREG, FPA11)
	(fetch_nwfpe_single, fetch_nwfpe_double, fetch_nwfpe_none)
	(fetch_nwfpe_extended, fetch_nwfpe_register, store_nwfpe_single)
	(store_nwfpe_double, store_nwfpe_extended, store_nwfpe_register):
	Delete.
	(fetch_fpregister, fetch_fpregs, store_fpregister, store_fpregs):
	Use gdb_byte buffers, NWFPE_FPSR_OFFSET, supply_nwfpe_register,
	and collect_nwfpe_register.
	(fill_gregset, supply_gregset, fill_fpregset, supply_fpregset): Use
	new regset functions.
	* arm-linux-tdep.c: Include "regset.h" and "arm-linux-tdep.h".
	(arm_apcs_32): New declaration.
	(ARM_LINUX_SIZEOF_GREGSET, arm_linux_supply_gregset)
	(arm_linux_collect_gregset, typeNone, typeSingle, typeDouble)
	(typeExtended, supply_nwfpe_register, collect_nwfpe_register)
	(arm_linux_supply_nwfpe, arm_linux_collect_nwfpe)
	(arm_linux_regset_from_core_section): New.
	(arm_linux_init_abi): Register arm_linux_regset_from_core_section.
	* arm-linux-tdep.h: New file.
	* arm-tdep.h (struct regset): Declare.
	(struct gdbarch_tdep): Add gregset, fpregset members.
	* config/arm/linux.mh (NATDEPFILES): Remove corelow.o and
	core-regset.o.
	* config/arm/linux.mt (TDEPFILES): Add corelow.o.

Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2006-06-08 11:02:11.000000000 -0400
+++ src/gdb/Makefile.in	2006-06-08 11:12:48.000000000 -0400
@@ -641,6 +641,7 @@ amd64_nat_h = amd64-nat.h
 amd64_tdep_h = amd64-tdep.h $(i386_tdep_h)
 annotate_h = annotate.h $(symtab_h) $(gdbtypes_h)
 arch_utils_h = arch-utils.h
+arm_linux_tdep_h = arm-linux-tdep.h
 arm_tdep_h = arm-tdep.h
 auxv_h = auxv.h
 ax_gdb_h = ax-gdb.h
@@ -1769,10 +1770,11 @@ arch-utils.o: arch-utils.c $(defs_h) $(a
 	$(floatformat_h)
 arm-linux-nat.o: arm-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
 	$(gdb_string_h) $(regcache_h) $(arm_tdep_h) $(gregset_h) \
-	$(target_h) $(linux_nat_h) $(gdb_proc_service_h)
+	$(target_h) $(linux_nat_h) $(gdb_proc_service_h) $(arm_linux_tdep_h)
 arm-linux-tdep.o: arm-linux-tdep.c $(defs_h) $(target_h) $(value_h) \
 	$(gdbtypes_h) $(floatformat_h) $(gdbcore_h) $(frame_h) $(regcache_h) \
 	$(doublest_h) $(solib_svr4_h) $(osabi_h) $(arm_tdep_h) \
+	$(regset_h) $(arm_linux_tdep_h) \
 	$(glibc_tdep_h) $(trad_frame_h) $(tramp_frame_h) $(gdb_string_h)
 armnbsd-nat.o: armnbsd-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) \
 	$(regcache_h) $(target_h) $(gdb_string_h) $(arm_tdep_h) $(inf_ptrace_h)
Index: src/gdb/arm-linux-nat.c
===================================================================
--- src.orig/gdb/arm-linux-nat.c	2006-06-08 11:02:11.000000000 -0400
+++ src/gdb/arm-linux-nat.c	2006-06-08 11:08:17.000000000 -0400
@@ -28,6 +28,7 @@
 #include "linux-nat.h"
 
 #include "arm-tdep.h"
+#include "arm-linux-tdep.h"
 
 #include <sys/user.h>
 #include <sys/ptrace.h>
@@ -46,32 +47,6 @@
 
 extern int arm_apcs_32;
 
-#define		typeNone		0x00
-#define		typeSingle		0x01
-#define		typeDouble		0x02
-#define		typeExtended		0x03
-#define 	FPWORDS			28
-#define		ARM_CPSR_REGNUM		16
-
-typedef union tagFPREG
-  {
-    unsigned int fSingle;
-    unsigned int fDouble[2];
-    unsigned int fExtended[3];
-  }
-FPREG;
-
-typedef struct tagFPA11
-  {
-    FPREG fpreg[8];		/* 8 floating point registers */
-    unsigned int fpsr;		/* floating point status register */
-    unsigned int fpcr;		/* floating point control register */
-    unsigned char fType[8];	/* type of floating point value held in
-				   floating point registers.  */
-    int initflag;		/* NWFPE initialization flag.  */
-  }
-FPA11;
-
 /* The following variables are used to determine the version of the
    underlying GNU/Linux operating system.  Examples:
 
@@ -104,132 +79,6 @@ get_thread_id (ptid_t ptid)
 }
 #define GET_THREAD_ID(PTID)	get_thread_id ((PTID));
 
-static void
-fetch_nwfpe_single (unsigned int fn, FPA11 * fpa11)
-{
-  unsigned int mem[3];
-
-  mem[0] = fpa11->fpreg[fn].fSingle;
-  mem[1] = 0;
-  mem[2] = 0;
-  regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]);
-}
-
-static void
-fetch_nwfpe_double (unsigned int fn, FPA11 * fpa11)
-{
-  unsigned int mem[3];
-
-  mem[0] = fpa11->fpreg[fn].fDouble[1];
-  mem[1] = fpa11->fpreg[fn].fDouble[0];
-  mem[2] = 0;
-  regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]);
-}
-
-static void
-fetch_nwfpe_none (unsigned int fn)
-{
-  unsigned int mem[3] =
-  {0, 0, 0};
-
-  regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]);
-}
-
-static void
-fetch_nwfpe_extended (unsigned int fn, FPA11 * fpa11)
-{
-  unsigned int mem[3];
-
-  mem[0] = fpa11->fpreg[fn].fExtended[0];	/* sign & exponent */
-  mem[1] = fpa11->fpreg[fn].fExtended[2];	/* ls bits */
-  mem[2] = fpa11->fpreg[fn].fExtended[1];	/* ms bits */
-  regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]);
-}
-
-static void
-fetch_nwfpe_register (int regno, FPA11 * fpa11)
-{
-   int fn = regno - ARM_F0_REGNUM;
-
-   switch (fpa11->fType[fn])
-     {
-     case typeSingle:
-       fetch_nwfpe_single (fn, fpa11);
-       break;
-
-     case typeDouble:
-       fetch_nwfpe_double (fn, fpa11);
-       break;
-
-     case typeExtended:
-       fetch_nwfpe_extended (fn, fpa11);
-       break;
-
-     default:
-       fetch_nwfpe_none (fn);
-     }
-}
-
-static void
-store_nwfpe_single (unsigned int fn, FPA11 *fpa11)
-{
-  unsigned int mem[3];
-
-  regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn,
-			(char *) &mem[0]);
-  fpa11->fpreg[fn].fSingle = mem[0];
-  fpa11->fType[fn] = typeSingle;
-}
-
-static void
-store_nwfpe_double (unsigned int fn, FPA11 *fpa11)
-{
-  unsigned int mem[3];
-
-  regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn,
-			(char *) &mem[0]);
-  fpa11->fpreg[fn].fDouble[1] = mem[0];
-  fpa11->fpreg[fn].fDouble[0] = mem[1];
-  fpa11->fType[fn] = typeDouble;
-}
-
-void
-store_nwfpe_extended (unsigned int fn, FPA11 *fpa11)
-{
-  unsigned int mem[3];
-
-  regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn,
-			(char *) &mem[0]);
-  fpa11->fpreg[fn].fExtended[0] = mem[0];	/* sign & exponent */
-  fpa11->fpreg[fn].fExtended[2] = mem[1];	/* ls bits */
-  fpa11->fpreg[fn].fExtended[1] = mem[2];	/* ms bits */
-  fpa11->fType[fn] = typeDouble;
-}
-
-void
-store_nwfpe_register (int regno, FPA11 * fpa11)
-{
-  if (register_cached (regno))
-    {
-       unsigned int fn = regno - ARM_F0_REGNUM;
-       switch (fpa11->fType[fn])
-         {
-	 case typeSingle:
-	   store_nwfpe_single (fn, fpa11);
-	   break;
-
-	 case typeDouble:
-	   store_nwfpe_double (fn, fpa11);
-	   break;
-
-	 case typeExtended:
-	   store_nwfpe_extended (fn, fpa11);
-	   break;
-	 }
-    }
-}
-
-
 /* Get the value of a particular register from the floating point
    state of the process and store it into regcache.  */
 
@@ -237,13 +86,13 @@ static void
 fetch_fpregister (int regno)
 {
   int ret, tid;
-  FPA11 fp;
+  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
   
   /* Get the thread id for the ptrace call.  */
   tid = GET_THREAD_ID (inferior_ptid);
 
   /* Read the floating point state.  */
-  ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
+  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
   if (ret < 0)
     {
       warning (_("Unable to fetch floating point register."));
@@ -252,31 +101,12 @@ fetch_fpregister (int regno)
 
   /* Fetch fpsr.  */
   if (ARM_FPS_REGNUM == regno)
-    regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr);
+    regcache_raw_supply (current_regcache, ARM_FPS_REGNUM,
+			 fp + NWFPE_FPSR_OFFSET);
 
   /* Fetch the floating point register.  */
   if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
-    {
-      int fn = regno - ARM_F0_REGNUM;
-
-      switch (fp.fType[fn])
-	{
-	case typeSingle:
-	  fetch_nwfpe_single (fn, &fp);
-	  break;
-
-	case typeDouble:
-	    fetch_nwfpe_double (fn, &fp);
-	  break;
-
-	case typeExtended:
-	    fetch_nwfpe_extended (fn, &fp);
-	  break;
-
-	default:
-	    fetch_nwfpe_none (fn);
-	}
-    }
+    supply_nwfpe_register (current_regcache, regno, fp);
 }
 
 /* Get the whole floating point state of the process and store it
@@ -286,13 +116,13 @@ static void
 fetch_fpregs (void)
 {
   int ret, regno, tid;
-  FPA11 fp;
+  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
 
   /* Get the thread id for the ptrace call.  */
   tid = GET_THREAD_ID (inferior_ptid);
   
   /* Read the floating point state.  */
-  ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
+  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
   if (ret < 0)
     {
       warning (_("Unable to fetch the floating point registers."));
@@ -300,31 +130,12 @@ fetch_fpregs (void)
     }
 
   /* Fetch fpsr.  */
-  regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr);
+  regcache_raw_supply (current_regcache, ARM_FPS_REGNUM,
+		       fp + NWFPE_FPSR_OFFSET);
 
   /* Fetch the floating point registers.  */
   for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
-    {
-      int fn = regno - ARM_F0_REGNUM;
-
-      switch (fp.fType[fn])
-	{
-	case typeSingle:
-	  fetch_nwfpe_single (fn, &fp);
-	  break;
-
-	case typeDouble:
-	  fetch_nwfpe_double (fn, &fp);
-	  break;
-
-	case typeExtended:
-	  fetch_nwfpe_extended (fn, &fp);
-	  break;
-
-	default:
-	  fetch_nwfpe_none (fn);
-	}
-    }
+    supply_nwfpe_register (current_regcache, regno, fp);
 }
 
 /* Save a particular register into the floating point state of the
@@ -334,13 +145,13 @@ static void
 store_fpregister (int regno)
 {
   int ret, tid;
-  FPA11 fp;
+  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
 
   /* Get the thread id for the ptrace call.  */
   tid = GET_THREAD_ID (inferior_ptid);
   
   /* Read the floating point state.  */
-  ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
+  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
   if (ret < 0)
     {
       warning (_("Unable to fetch the floating point registers."));
@@ -349,15 +160,14 @@ store_fpregister (int regno)
 
   /* Store fpsr.  */
   if (ARM_FPS_REGNUM == regno && register_cached (ARM_FPS_REGNUM))
-    regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr);
+    regcache_raw_collect (current_regcache, ARM_FPS_REGNUM,
+			  fp + NWFPE_FPSR_OFFSET);
 
   /* Store the floating point register.  */
   if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
-    {
-      store_nwfpe_register (regno, &fp);
-    }
+    collect_nwfpe_register (current_regcache, regno, fp);
 
-  ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp);
+  ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
   if (ret < 0)
     {
       warning (_("Unable to store floating point register."));
@@ -372,13 +182,13 @@ static void
 store_fpregs (void)
 {
   int ret, regno, tid;
-  FPA11 fp;
+  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
 
   /* Get the thread id for the ptrace call.  */
   tid = GET_THREAD_ID (inferior_ptid);
   
   /* Read the floating point state.  */
-  ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
+  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
   if (ret < 0)
     {
       warning (_("Unable to fetch the floating point registers."));
@@ -387,15 +197,15 @@ store_fpregs (void)
 
   /* Store fpsr.  */
   if (register_cached (ARM_FPS_REGNUM))
-    regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr);
+    regcache_raw_collect (current_regcache, ARM_FPS_REGNUM,
+			  fp + NWFPE_FPSR_OFFSET);
 
   /* Store the floating point registers.  */
   for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
-    {
-      fetch_nwfpe_register (regno, &fp);
-    }
+    if (register_cached (regno))
+      collect_nwfpe_register (current_regcache, regno, fp);
 
-  ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp);
+  ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
   if (ret < 0)
     {
       warning (_("Unable to store floating point registers."));
@@ -597,83 +407,25 @@ arm_linux_store_inferior_registers (int 
     }
 }
 
-/* Fill register regno (if it is a general-purpose register) in
-   *gregsetp with the appropriate value from GDB's register array.
-   If regno is -1, do this for all registers.  */
+/* Wrapper functions for the standard regset handling, used by
+   thread debugging.  */
 
 void
 fill_gregset (gdb_gregset_t *gregsetp, int regno)
 {
-  if (-1 == regno)
-    {
-      int regnum;
-      for (regnum = ARM_A1_REGNUM; regnum <= ARM_PC_REGNUM; regnum++) 
-	regcache_raw_collect (current_regcache, regnum,
-			      (char *) &(*gregsetp)[regnum]);
-    }
-  else if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
-    regcache_raw_collect (current_regcache, regno,
-			  (char *) &(*gregsetp)[regno]);
-
-  if (ARM_PS_REGNUM == regno || -1 == regno)
-    {
-      if (arm_apcs_32)
-	regcache_raw_collect (current_regcache, ARM_PS_REGNUM,
-			      (char *) &(*gregsetp)[ARM_CPSR_REGNUM]);
-      else
-	regcache_raw_collect (current_regcache, ARM_PC_REGNUM,
-			      (char *) &(*gregsetp)[ARM_PC_REGNUM]);
-    }
+  arm_linux_collect_gregset (NULL, current_regcache, regno, gregsetp, 0);
 }
 
-/* Fill GDB's register array with the general-purpose register values
-   in *gregsetp.  */
-
 void
 supply_gregset (gdb_gregset_t *gregsetp)
 {
-  int regno, reg_pc;
-
-  for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
-    regcache_raw_supply (current_regcache, regno,
-			 (char *) &(*gregsetp)[regno]);
-
-  if (arm_apcs_32)
-    regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
-			 (char *) &(*gregsetp)[ARM_CPSR_REGNUM]);
-  else
-    regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
-			 (char *) &(*gregsetp)[ARM_PC_REGNUM]);
-
-  reg_pc = ADDR_BITS_REMOVE ((CORE_ADDR)(*gregsetp)[ARM_PC_REGNUM]);
-  regcache_raw_supply (current_regcache, ARM_PC_REGNUM, (char *) &reg_pc);
+  arm_linux_supply_gregset (NULL, current_regcache, -1, gregsetp, 0);
 }
 
-/* Fill register regno (if it is a floating-point register) in
-   *fpregsetp with the appropriate value from GDB's register array.
-   If regno is -1, do this for all registers.  */
-
 void
 fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
 {
-  FPA11 *fp = (FPA11 *) fpregsetp;
-  
-  if (-1 == regno)
-    {
-       int regnum;
-       for (regnum = ARM_F0_REGNUM; regnum <= ARM_F7_REGNUM; regnum++)
-         store_nwfpe_register (regnum, fp);
-    }
-  else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
-    {
-      store_nwfpe_register (regno, fp);
-      return;
-    }
-
-  /* Store fpsr.  */
-  if (ARM_FPS_REGNUM == regno || -1 == regno)
-    regcache_raw_collect (current_regcache, ARM_FPS_REGNUM,
-			  (char *) &fp->fpsr);
+  arm_linux_collect_nwfpe (NULL, current_regcache, regno, fpregsetp, 0);
 }
 
 /* Fill GDB's register array with the floating-point register values
@@ -682,17 +434,7 @@ fill_fpregset (gdb_fpregset_t *fpregsetp
 void
 supply_fpregset (gdb_fpregset_t *fpregsetp)
 {
-  int regno;
-  FPA11 *fp = (FPA11 *) fpregsetp;
-
-  /* Fetch fpsr.  */
-  regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp->fpsr);
-
-  /* Fetch the floating point registers.  */
-  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
-    {
-      fetch_nwfpe_register (regno, fp);
-    }
+  arm_linux_supply_nwfpe (NULL, current_regcache, -1, fpregsetp, 0);
 }
 
 int
Index: src/gdb/arm-linux-tdep.c
===================================================================
--- src.orig/gdb/arm-linux-tdep.c	2006-06-08 11:02:11.000000000 -0400
+++ src/gdb/arm-linux-tdep.c	2006-06-08 11:08:17.000000000 -0400
@@ -31,14 +31,18 @@
 #include "doublest.h"
 #include "solib-svr4.h"
 #include "osabi.h"
+#include "regset.h"
 #include "trad-frame.h"
 #include "tramp-frame.h"
 
 #include "arm-tdep.h"
+#include "arm-linux-tdep.h"
 #include "glibc-tdep.h"
 
 #include "gdb_string.h"
 
+extern int arm_apcs_32;
+
 /* Under ARM GNU/Linux the traditional way of performing a breakpoint
    is to execute a particular software interrupt, rather than use a
    particular undefined instruction to provoke a trap.  Upon exection
@@ -329,6 +333,217 @@ static struct tramp_frame arm_eabi_linux
   arm_linux_rt_sigreturn_init
 };
 
+/* Core file and register set support.  */
+
+#define ARM_LINUX_SIZEOF_GREGSET (18 * INT_REGISTER_SIZE)
+
+void
+arm_linux_supply_gregset (const struct regset *regset,
+			  struct regcache *regcache,
+			  int regnum, const void *gregs_buf, size_t len)
+{
+  const gdb_byte *gregs = gregs_buf;
+  int regno;
+  CORE_ADDR reg_pc;
+  gdb_byte pc_buf[INT_REGISTER_SIZE];
+
+  for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache_raw_supply (regcache, regno,
+			   gregs + INT_REGISTER_SIZE * regno);
+
+  if (regnum == ARM_PS_REGNUM || regnum == -1)
+    {
+      if (arm_apcs_32)
+	regcache_raw_supply (regcache, ARM_PS_REGNUM,
+			     gregs + INT_REGISTER_SIZE * ARM_CPSR_REGNUM);
+      else
+	regcache_raw_supply (regcache, ARM_PS_REGNUM,
+			     gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
+    }
+
+  if (regnum == ARM_PC_REGNUM || regnum == -1)
+    {
+      reg_pc = extract_unsigned_integer (gregs
+					 + INT_REGISTER_SIZE * ARM_PC_REGNUM,
+					 INT_REGISTER_SIZE);
+      reg_pc = ADDR_BITS_REMOVE (reg_pc);
+      store_unsigned_integer (pc_buf, INT_REGISTER_SIZE, reg_pc);
+      regcache_raw_supply (regcache, ARM_PC_REGNUM, pc_buf);
+    }
+}
+
+void
+arm_linux_collect_gregset (const struct regset *regset,
+			   const struct regcache *regcache,
+			   int regnum, void *gregs_buf, size_t len)
+{
+  gdb_byte *gregs = gregs_buf;
+  int regno;
+
+  for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      regcache_raw_collect (regcache, regno,
+			    gregs + INT_REGISTER_SIZE * regno);
+
+  if (regnum == ARM_PS_REGNUM || regnum == -1)
+    {
+      if (arm_apcs_32)
+	regcache_raw_collect (regcache, ARM_PS_REGNUM,
+			      gregs + INT_REGISTER_SIZE * ARM_CPSR_REGNUM);
+      else
+	regcache_raw_collect (regcache, ARM_PS_REGNUM,
+			      gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
+    }
+
+  if (regnum == ARM_PC_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, ARM_PC_REGNUM,
+			  gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
+}
+
+/* Support for register format used by the NWFPE FPA emulator.  */
+
+#define typeNone		0x00
+#define typeSingle		0x01
+#define typeDouble		0x02
+#define typeExtended		0x03
+
+void
+supply_nwfpe_register (struct regcache *regcache, int regno,
+		       const gdb_byte *regs)
+{
+  const gdb_byte *reg_data;
+  gdb_byte reg_tag;
+  gdb_byte buf[FP_REGISTER_SIZE];
+
+  reg_data = regs + (regno - ARM_F0_REGNUM) * FP_REGISTER_SIZE;
+  reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET];
+  memset (buf, 0, FP_REGISTER_SIZE);
+
+  switch (reg_tag)
+    {
+    case typeSingle:
+      memcpy (buf, reg_data, 4);
+      break;
+    case typeDouble:
+      memcpy (buf, reg_data + 4, 4);
+      memcpy (buf + 4, reg_data, 4);
+      break;
+    case typeExtended:
+      /* We want sign and exponent, then least significant bits,
+	 then most significant.  NWFPE does sign, most, least.  */
+      memcpy (buf, reg_data, 4);
+      memcpy (buf + 4, reg_data + 8, 4);
+      memcpy (buf + 8, reg_data + 4, 4);
+      break;
+    default:
+      break;
+    }
+
+  regcache_raw_supply (regcache, regno, buf);
+}
+
+void
+collect_nwfpe_register (const struct regcache *regcache, int regno,
+			gdb_byte *regs)
+{
+  gdb_byte *reg_data;
+  gdb_byte reg_tag;
+  gdb_byte buf[FP_REGISTER_SIZE];
+
+  regcache_raw_collect (regcache, regno, buf);
+
+  /* NOTE drow/2006-06-07: This code uses the tag already in the
+     register buffer.  I've preserved that when moving the code
+     from the native file to the target file.  But this doesn't
+     always make sense.  */
+
+  reg_data = regs + (regno - ARM_F0_REGNUM) * FP_REGISTER_SIZE;
+  reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET];
+
+  switch (reg_tag)
+    {
+    case typeSingle:
+      memcpy (reg_data, buf, 4);
+      break;
+    case typeDouble:
+      memcpy (reg_data, buf + 4, 4);
+      memcpy (reg_data + 4, buf, 4);
+      break;
+    case typeExtended:
+      memcpy (reg_data, buf, 4);
+      memcpy (reg_data + 4, buf + 8, 4);
+      memcpy (reg_data + 8, buf + 4, 4);
+      break;
+    default:
+      break;
+    }
+}
+
+void
+arm_linux_supply_nwfpe (const struct regset *regset,
+			struct regcache *regcache,
+			int regnum, const void *regs_buf, size_t len)
+{
+  const gdb_byte *regs = regs_buf;
+  int regno;
+
+  if (regnum == ARM_FPS_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, ARM_FPS_REGNUM,
+			 regs + NWFPE_FPSR_OFFSET);
+
+  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      supply_nwfpe_register (regcache, regno, regs);
+}
+
+void
+arm_linux_collect_nwfpe (const struct regset *regset,
+			 const struct regcache *regcache,
+			 int regnum, void *regs_buf, size_t len)
+{
+  gdb_byte *regs = regs_buf;
+  int regno;
+
+  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
+    if (regnum == -1 || regnum == regno)
+      collect_nwfpe_register (regcache, regno, regs);
+
+  if (regnum == ARM_FPS_REGNUM || regnum == -1)
+    regcache_raw_collect (regcache, ARM_FPS_REGNUM,
+			  regs + INT_REGISTER_SIZE * ARM_FPS_REGNUM);
+}
+
+/* Return the appropriate register set for the core section identified
+   by SECT_NAME and SECT_SIZE.  */
+
+static const struct regset *
+arm_linux_regset_from_core_section (struct gdbarch *gdbarch,
+				    const char *sect_name, size_t sect_size)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (strcmp (sect_name, ".reg") == 0
+      && sect_size == ARM_LINUX_SIZEOF_GREGSET)
+    {
+      if (tdep->gregset == NULL)
+        tdep->gregset = regset_alloc (gdbarch, arm_linux_supply_gregset,
+                                      arm_linux_collect_gregset);
+      return tdep->gregset;
+    }
+
+  if (strcmp (sect_name, ".reg2") == 0
+      && sect_size == ARM_LINUX_SIZEOF_NWFPE)
+    {
+      if (tdep->fpregset == NULL)
+        tdep->fpregset = regset_alloc (gdbarch, arm_linux_supply_nwfpe,
+                                       arm_linux_collect_nwfpe);
+      return tdep->fpregset;
+    }
+
+  return NULL;
+}
+
 static void
 arm_linux_init_abi (struct gdbarch_info info,
 		    struct gdbarch *gdbarch)
@@ -383,6 +598,10 @@ arm_linux_init_abi (struct gdbarch_info 
 				&arm_eabi_linux_sigreturn_tramp_frame);
   tramp_frame_prepend_unwinder (gdbarch,
 				&arm_eabi_linux_rt_sigreturn_tramp_frame);
+
+  /* Core file support.  */
+  set_gdbarch_regset_from_core_section (gdbarch,
+					arm_linux_regset_from_core_section);
 }
 
 void
Index: src/gdb/arm-linux-tdep.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/arm-linux-tdep.h	2006-06-08 11:08:17.000000000 -0400
@@ -0,0 +1,62 @@
+/* GNU/Linux on ARM target support, prototypes.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+struct regset;
+struct regcache;
+
+#define		ARM_CPSR_REGNUM		16
+
+#define ARM_LINUX_SIZEOF_NWFPE (8 * FP_REGISTER_SIZE \
+				+ 2 * INT_REGISTER_SIZE \
+				+ 8 + INT_REGISTER_SIZE)
+
+/* Support for register format used by the NWFPE FPA emulator.  Each
+   register takes three words, where either the first one, two, or
+   three hold a single, double, or extended precision value (depending
+   on the corresponding tag).  The register set is eight registers,
+   followed by the fpsr and fpcr, followed by eight tag bytes, and a
+   final word flag which indicates whether NWFPE has been
+   initialized.  */
+
+#define NWFPE_FPSR_OFFSET (8 * FP_REGISTER_SIZE)
+#define NWFPE_FPCR_OFFSET (NWFPE_FPSR_OFFSET + INT_REGISTER_SIZE)
+#define NWFPE_TAGS_OFFSET (NWFPE_FPCR_OFFSET + INT_REGISTER_SIZE)
+#define NWFPE_INITFLAG_OFFSET (NWFPE_TAGS_OFFSET + 8)
+
+void arm_linux_supply_gregset (const struct regset *regset,
+			       struct regcache *regcache,
+			       int regnum, const void *gregs_buf, size_t len);
+void arm_linux_collect_gregset (const struct regset *regset,
+				const struct regcache *regcache,
+				int regnum, void *gregs_buf, size_t len);
+
+void supply_nwfpe_register (struct regcache *regcache, int regno,
+			    const gdb_byte *regs);
+void collect_nwfpe_register (const struct regcache *regcache, int regno,
+			     gdb_byte *regs);
+
+void arm_linux_supply_nwfpe (const struct regset *regset,
+			     struct regcache *regcache,
+			     int regnum, const void *regs_buf, size_t len);
+void arm_linux_collect_nwfpe (const struct regset *regset,
+			      const struct regcache *regcache,
+			      int regnum, void *regs_buf, size_t len);
Index: src/gdb/arm-tdep.h
===================================================================
--- src.orig/gdb/arm-tdep.h	2006-06-08 11:02:11.000000000 -0400
+++ src/gdb/arm-tdep.h	2006-06-08 11:08:17.000000000 -0400
@@ -18,6 +18,9 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.  */
 
+/* Forward declarations.  */
+struct regset;
+
 /* Register numbers of various important registers.  Note that some of
    these values are "real" register numbers, and correspond to the
    general registers of the machine, and some are "phony" register
@@ -143,6 +146,9 @@ struct gdbarch_tdep
 				   If this is negative, longjmp support
 				   will be disabled.  */
   size_t jb_elt_size;		/* And the size of each entry in the buf.  */
+
+  /* Cached core file helpers.  */
+  struct regset *gregset, *fpregset;
 };
 
 #ifndef LOWEST_PC
Index: src/gdb/config/arm/linux.mh
===================================================================
--- src.orig/gdb/config/arm/linux.mh	2006-06-08 11:02:11.000000000 -0400
+++ src/gdb/config/arm/linux.mh	2006-06-08 11:08:17.000000000 -0400
@@ -1,8 +1,7 @@
 # Host: ARM based machine running GNU/Linux
 
 NAT_FILE= nm-linux.h
-NATDEPFILES= inf-ptrace.o fork-child.o corelow.o	\
-	core-regset.o arm-linux-nat.o gcore.o	\
+NATDEPFILES= inf-ptrace.o fork-child.o arm-linux-nat.o gcore.o \
 	proc-service.o linux-thread-db.o linux-nat.o linux-fork.o
 
 LOADLIBES= -ldl -rdynamic
Index: src/gdb/config/arm/linux.mt
===================================================================
--- src.orig/gdb/config/arm/linux.mt	2006-06-08 11:02:11.000000000 -0400
+++ src/gdb/config/arm/linux.mt	2006-06-08 11:08:17.000000000 -0400
@@ -1,3 +1,6 @@
 # Target: ARM based machine running GNU/Linux
 DEPRECATED_TM_FILE= tm-linux.h
-TDEPFILES= arm-tdep.o arm-linux-tdep.o glibc-tdep.o solib.o solib-svr4.o solib-legacy.o symfile-mem.o
+TDEPFILES= arm-tdep.o arm-linux-tdep.o glibc-tdep.o solib.o \
+  solib-svr4.o solib-legacy.o symfile-mem.o \
+  corelow.o
+


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