This is the mail archive of the gdb-patches@sources.redhat.com 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]

Re: [csl-arm] VFP and iWMMXt support


On Tue, Mar 29, 2005 at 03:51:51AM +0100, Paul Brook wrote:
> I've applied the attached patch to the csl-arm-20050325-branch.
> 
> It adds support for the iWMMXt and VFP Arm coprocessors.
> This includes a new extension to the remote protocol to handle optional 
> register sets. The extension may need some more work before it's ready for 
> mainline.
> 
> Tested with cross to arm-none-eabi.

This patch, also applied to the branch, adds native support for iWMMXt
registers on arm-linux.  It requires a brand new kernel.  I didn't do
VFP, because no one's implemented the necessary kernel primitives yet.

The principle is the same as in the previous patch.  Before this moves
to mainline I intend to finish converting Linux to inf-ptrace, and then
NATIVE_XFER_AVAILABLE_REGISTERS will not be necessary.

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-03-30  Daniel Jacobowitz  <dan@codesourcery.com>

	* Makefile.in (arm-linux-nat.o): Update dependencies.
	* arm-linux-nat.c: Include "gdb_assert.h".
	(PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS): Define.
	(arm_linux_has_wmmx_registers): New flag.
	(GET_THREAD_ID): Remove stray punctuation.
	(IWMMXT_REGS_SIZE): Define.
	(fetch_wmmx_regs, store_wmmx_regs): New functions.
	(fetch_inferior_registers, store_inferior_registers): Call them.
	(arm_linux_available_registers): New function.
	* inftarg.c (child_xfer_partial): Handle
	TARGET_OBJECT_AVAILABLE_REGISTERS.
	* config/arm/nm-linux.h (arm_linux_available_registers): Add
	prototype.
	(NATIVE_XFER_AVAILABLE_REGISTERS): Define.

2005-03-30  Daniel Jacobowitz  <dan@codesourcery.com>

	* linux-arm-low.c (arm_fill_wmmxregset, arm_store_wmmxregset):
	Remove stray text.
	(arm_available_registers): Remove debugging output.  Use hex.
	* regcache.c (num_registers): Make global.
	* server.c (handle_p_packet, handle_P_packet): Check the value
	of regnum.

Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.707.2.4
diff -u -p -r1.707.2.4 Makefile.in
--- gdb/Makefile.in	29 Mar 2005 02:52:04 -0000	1.707.2.4
+++ gdb/Makefile.in	30 Mar 2005 14:53:20 -0000
@@ -1732,7 +1732,7 @@ 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)\
-	$(gdb_proc_service_h)
+	$(gdb_proc_service_h) $(gdb_assert_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) \
Index: gdb/arm-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/arm-linux-nat.c,v
retrieving revision 1.22.2.3
diff -u -p -r1.22.2.3 arm-linux-nat.c
--- gdb/arm-linux-nat.c	29 Mar 2005 02:52:04 -0000	1.22.2.3
+++ gdb/arm-linux-nat.c	30 Mar 2005 14:53:20 -0000
@@ -23,6 +23,7 @@
 #include "gdbcore.h"
 #include "gdb_string.h"
 #include "regcache.h"
+#include "gdb_assert.h"
 
 #include "arm-tdep.h"
 
@@ -41,6 +42,13 @@
 #define PTRACE_GET_THREAD_AREA 22
 #endif
 
+#ifndef PTRACE_GETWMMXREGS
+#define PTRACE_GETWMMXREGS 18
+#define PTRACE_SETWMMXREGS 19
+#endif
+
+static int arm_linux_has_wmmx_registers = 1;
+
 extern int arm_apcs_32;
 
 #define		typeNone		0x00
@@ -99,7 +107,7 @@ get_thread_id (ptid_t ptid)
     tid = PIDGET (ptid);
   return tid;
 }
-#define GET_THREAD_ID(PTID)	get_thread_id ((PTID));
+#define GET_THREAD_ID(PTID)	get_thread_id (PTID)
 
 static void
 fetch_nwfpe_single (unsigned int fn, FPA11 * fpa11)
@@ -550,6 +558,97 @@ store_regs (void)
     }
 }
 
+/* Fetch all WMMX registers of the process and store into
+   regcache.  */
+
+#define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4)
+
+static void
+fetch_wmmx_regs (void)
+{
+  char regbuf[IWMMXT_REGS_SIZE];
+  int ret, regno, tid, first;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+  
+  ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch WMMX registers."));
+      return;
+    }
+
+  first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+
+  for (regno = 0; regno < NUM_IWMMXT_COP0REGS; regno++)
+    regcache_raw_supply (current_regcache, first + regno,
+			 &regbuf[regno * 8]);
+
+  first += NUM_IWMMXT_COP0REGS;
+
+  for (regno = 0; regno < 2; regno++)
+    regcache_raw_supply (current_regcache, first + regno, NULL);
+
+  for (regno = 2; regno < 4; regno++)
+    regcache_raw_supply (current_regcache, first + regno,
+			 &regbuf[16 * 8 + (regno - 2) * 4]);
+
+  for (regno = 4; regno < 8; regno++)
+    regcache_raw_supply (current_regcache, first + regno, NULL);
+
+  for (regno = 8; regno < 12; regno++)
+    regcache_raw_supply (current_regcache, first + regno,
+			 &regbuf[16 * 8 + 2 * 4 + (regno - 8) * 4]);
+
+  for (regno = 12; regno < 16; regno++)
+    regcache_raw_supply (current_regcache, first + regno, NULL);
+}
+
+static void
+store_wmmx_regs (void)
+{
+  char regbuf[IWMMXT_REGS_SIZE];
+  int ret, regno, tid, first;
+
+  /* Get the thread id for the ptrace call.  */
+  tid = GET_THREAD_ID (inferior_ptid);
+  
+  ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
+  if (ret < 0)
+    {
+      warning (_("Unable to fetch WMMX registers."));
+      return;
+    }
+
+  first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+
+  for (regno = 0; regno < NUM_IWMMXT_COP0REGS; regno++)
+    if (register_cached (first + regno))
+      regcache_raw_collect (current_regcache, first + regno,
+			    &regbuf[regno * 8]);
+
+  first += 18;
+  for (regno = 0; regno < 2; regno++)
+    if (register_cached (first + regno))
+      regcache_raw_collect (current_regcache, first + regno,
+			    &regbuf[16 * 8 + regno * 4]);
+
+  first += 6;
+  for (regno = 0; regno < 4; regno++)
+    if (register_cached (first + regno))
+      regcache_raw_collect (current_regcache, first + regno,
+			    &regbuf[16 * 8 + 2 * 4 + regno * 4]);
+
+  ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
+
+  if (ret < 0)
+    {
+      warning (_("Unable to store WMMX registers."));
+      return;
+    }
+}
+
 /* Fetch registers from the child process.  Fetch all registers if
    regno == -1, otherwise fetch all general registers or all floating
    point registers depending upon the value of regno.  */
@@ -561,14 +660,21 @@ fetch_inferior_registers (int regno)
     {
       fetch_regs ();
       fetch_fpa_regs ();
+      if (arm_linux_has_wmmx_registers)
+	fetch_wmmx_regs ();
     }
   else 
     {
-      if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
+      if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
         fetch_register (regno);
-
-      if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
+      else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
         fetch_fpa_register (regno);
+      else if (arm_linux_has_wmmx_registers)
+	{
+	  int first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+	  if (regno >= first && regno < first + NUM_IWMMXT_REGS)
+	    fetch_wmmx_regs ();
+	}
     }
 }
 
@@ -583,14 +689,21 @@ store_inferior_registers (int regno)
     {
       store_regs ();
       store_fpa_regs ();
+      if (arm_linux_has_wmmx_registers)
+	store_wmmx_regs ();
     }
   else
     {
-      if ((regno < ARM_F0_REGNUM) || (regno > ARM_FPS_REGNUM))
+      if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
         store_register (regno);
-
-      if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
-        store_fpa_register (regno);
+      else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
+        store_fpa_register (regno); 
+      else if (arm_linux_has_wmmx_registers)
+	{
+	  int first = gdbarch_tdep (current_gdbarch)->first_iwmmxt_regnum;
+	  if (regno >= first && regno < first + NUM_IWMMXT_REGS)
+	    store_wmmx_regs ();
+	}
     }
 }
 
@@ -740,6 +853,50 @@ get_linux_version (unsigned int *vmajor,
   return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
 }
 
+LONGEST
+arm_linux_available_registers (struct target_ops *ops,
+			       int /* enum target_object */ object,
+			       const char *annex,
+			       void *readbuf,
+			       const void *writebuf,
+			       ULONGEST offset,
+			       LONGEST len)
+{
+  char *result = NULL;
+  int total_len;
+
+  gdb_assert (object == TARGET_OBJECT_AVAILABLE_REGISTERS);
+  gdb_assert (readbuf && !writebuf);
+
+  if (arm_linux_has_wmmx_registers)
+    {
+      int ret;
+      char regbuf[IWMMXT_REGS_SIZE];
+
+      ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid), 0,
+		    regbuf);
+      if (ret < 0)
+	/* Should we be checking the error code?  */
+	arm_linux_has_wmmx_registers = 0;
+    }
+
+  if (arm_linux_has_wmmx_registers)
+    result = "iwmmxt";
+
+  if (result == NULL)
+    return 0;
+
+  total_len = strlen (result);
+  if (total_len > offset)
+    {
+      int bytes_read = min (total_len - offset, len);
+      memcpy (readbuf, result + offset, bytes_read);
+      return bytes_read;
+    }
+
+  return 0;
+}
+
 void
 _initialize_arm_linux_nat (void)
 {
Index: gdb/inftarg.c
===================================================================
RCS file: /cvs/src/src/gdb/inftarg.c,v
retrieving revision 1.41
diff -u -p -r1.41 inftarg.c
--- gdb/inftarg.c	12 Feb 2005 00:39:19 -0000	1.41
+++ gdb/inftarg.c	30 Mar 2005 14:53:20 -0000
@@ -559,6 +559,13 @@ child_xfer_partial (struct target_ops *o
       return NATIVE_XFER_AUXV (ops, object, annex, readbuf, writebuf,
 			       offset, len);
 
+    case TARGET_OBJECT_AVAILABLE_REGISTERS:
+#ifndef NATIVE_XFER_AVAILABLE_REGISTERS
+#define NATIVE_XFER_AVAILABLE_REGISTERS(OPS,OBJECT,ANNEX,WRITEBUF,READBUF,OFFSET,LEN) (-1)
+#endif
+      return NATIVE_XFER_AVAILABLE_REGISTERS (ops, object, annex, readbuf,
+					      writebuf, offset, len);
+
     default:
       return -1;
     }
Index: gdb/config/arm/nm-linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/arm/nm-linux.h,v
retrieving revision 1.10
diff -u -p -r1.10 nm-linux.h
--- gdb/config/arm/nm-linux.h	29 Jul 2004 20:22:49 -0000	1.10
+++ gdb/config/arm/nm-linux.h	30 Mar 2005 14:53:20 -0000
@@ -38,4 +38,20 @@ extern int kernel_u_size (void);
 /* Override copies of {fetch,store}_inferior_registers in infptrace.c.  */
 #define FETCH_INFERIOR_REGISTERS
 
+/* This function is called like a to_xfer_partial hook,
+   but must be called with TARGET_OBJECT_AVAILABLE_REGISTERS.  */
+
+struct target_ops;
+
+extern LONGEST arm_linux_available_registers
+  (struct target_ops *ops,
+   int /* enum target_object */ object,
+   const char *annex,
+   void *readbuf,
+   const void *writebuf,
+   ULONGEST offset,
+   LONGEST len);
+
+#define NATIVE_XFER_AVAILABLE_REGISTERS arm_linux_available_registers
+
 #endif /* NM_ARMLINUX_H */
Index: gdb/gdbserver/linux-arm-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-arm-low.c,v
retrieving revision 1.7.14.2
diff -u -p -r1.7.14.2 linux-arm-low.c
--- gdb/gdbserver/linux-arm-low.c	29 Mar 2005 02:52:06 -0000	1.7.14.2
+++ gdb/gdbserver/linux-arm-low.c	30 Mar 2005 14:53:20 -0000
@@ -155,11 +155,6 @@ arm_fill_wmmxregset (void *buf)
  
   for (i = 0; i < 4; i++)
     collect_register (arm_num_regs + i + 16 + 8, ((char *) buf) + 16 * 8 + 8 + i * 4);
-
-        ((int*)buf)[0], 
-        ((int*)buf)[1], 
-        ((int*)buf)[2], 
-        ((int*)buf)[3]);
 }
  
 static void
@@ -167,10 +162,6 @@ arm_store_wmmxregset (const void *buf)
 {
   int i;
 
-        ((int*)buf)[0], 
-        ((int*)buf)[1], 
-        ((int*)buf)[2], 
-        ((int*)buf)[3]);
   for (i = 0; i < 16; i++)
     supply_register (arm_num_regs + i, ((char *) buf) + i * 8);
   
@@ -186,11 +177,10 @@ arm_available_registers (void)
 {
   char buf[64];
 
-  printf ("use_regsets %d target_regsets %d\n", use_regsets_p, target_regsets[1].size);
   if (use_regsets_p && target_regsets[1].size > 0)
     {
       int wr0 = find_regno ("wr0");
-      sprintf (buf, "iwmmxt:%d", wr0);
+      sprintf (buf, "iwmmxt:%x", wr0);
       return strdup (buf);
     }
 
Index: gdb/gdbserver/regcache.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/regcache.c,v
retrieving revision 1.7.18.1
diff -u -p -r1.7.18.1 regcache.c
--- gdb/gdbserver/regcache.c	29 Mar 2005 02:52:06 -0000	1.7.18.1
+++ gdb/gdbserver/regcache.c	30 Mar 2005 14:53:20 -0000
@@ -38,7 +38,7 @@ struct inferior_regcache_data
 static int register_bytes, g_register_bytes;
 
 static struct reg *reg_defs;
-static int num_registers;
+int num_registers;
 
 const char **gdbserver_expedite_regs;
 
Index: gdb/gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.23.2.1
diff -u -p -r1.23.2.1 server.c
--- gdb/gdbserver/server.c	29 Mar 2005 02:52:06 -0000	1.23.2.1
+++ gdb/gdbserver/server.c	30 Mar 2005 14:53:21 -0000
@@ -295,6 +295,8 @@ handle_v_requests (char *own_buf, char *
   return;
 }
 
+extern int num_registers;
+
 /* Handle a register fetch ('p') request.  */
 void
 handle_p_packet (char *own_buf)
@@ -302,7 +304,7 @@ handle_p_packet (char *own_buf)
   char *end = own_buf + 1;
   int regnum = strtol (own_buf + 1, &end, 16);
 
-  if (*end)
+  if (*end || regnum < 0 || regnum >= num_registers)
     {
       write_enn (own_buf);
       return;
@@ -318,7 +320,7 @@ handle_P_packet (char *own_buf)
   char *end = own_buf + 1;
   int regnum = strtol (own_buf + 1, &end, 16);
 
-  if (*end != '=')
+  if (*end != '=' || regnum < 0 || regnum >= num_registers)
     {
       write_enn (own_buf);
       return;


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