Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Bhushan Attarde <bhushan.attarde@imgtec.com>
To: <gdb-patches@sourceware.org>
Cc: <Maciej.Rozycki@imgtec.com>, <Matthew.Fortune@imgtec.com>,
	<James.Hogan@imgtec.com>, <Andrew.Bennett@imgtec.com>,
	<Jaydeep.Patil@imgtec.com>,
	Bhushan Attarde <bhushan.attarde@imgtec.com>
Subject: [PATCH 04/24]     Add MIPS Config5 register related support
Date: Mon, 27 Jun 2016 14:51:00 -0000	[thread overview]
Message-ID: <1467038991-6600-4-git-send-email-bhushan.attarde@imgtec.com> (raw)
In-Reply-To: <1467038991-6600-1-git-send-email-bhushan.attarde@imgtec.com>

    This patch has below changes:

    1. Add a Config5 register binding in order to get access to the FRE
    floating point mode bit. The internal register number is allocated
    dynamically only when provided by the target description, and is tracked in
    struct mips_regnum.

    2. MIPS native: Use FP regset to support Config5
    Use the NT_FPREGSET register set in preference to PTRACE_GETFPREGS for
    getting the floating point registers. This register set also provides the
    Config5 register which PTRACE_GETFPREGS doesn't.

    3. Define type for the MIPS CP0 Config5 register, allowing the important
    fields to be decoded.

    gdb/ChangeLog:

    	* mips-tdep.c (mips_config5_type): New function.
        (mips_linux_reg_names): Add config5.
    	(mips_gdbarch_init): Initialise config5 register number and bind
    	to named config5 register in target description.
        (mips_value_to_register): Return config5_type for config5 register.
    	* mips-tdep.h (struct mips_regnum): New config5 field.
        (gdbarch_tdep): New config5_type field.
    	* mips-linux-nat.c: Include "elf/common.h".
    	(PTRACE_GETREGSET, PTRACE_SETREGSET): New fallback definitions.
    	(have_ptrace_getregset_gp, have_ptrace_getregset_fp): New variables.
    	(mips64_linux_regsets_fetch_registers): Use PTRACE_GETREGSET with
    	NT_FPREGSET in preferance to PTRACE_GETFPREGS to get FP and
    	Config5 registers.
    	(mips64_linux_regsets_store_registers): Use PTRACE_SETREGSET with
    	NT_FPREGSET in preferance to PTRACE_SETFPREGS to get FP and
    	Config5 registers
---
 gdb/mips-linux-nat.c | 221 ++++++++++++++++++++++++++++++++++++++++++++++-----
 gdb/mips-tdep.c      |  35 ++++++++
 gdb/mips-tdep.h      |   4 +
 3 files changed, 239 insertions(+), 21 deletions(-)

diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index bfe9fcb..627c652 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -27,6 +27,7 @@
 #include "linux-nat.h"
 #include "mips-linux-tdep.h"
 #include "target-descriptions.h"
+#include "elf/common.h"
 
 #include "gdb_proc_service.h"
 #include "gregset.h"
@@ -46,10 +47,22 @@
 #define PTRACE_GET_THREAD_AREA 25
 #endif
 
+#ifndef PTRACE_GETREGSET
+#define PTRACE_GETREGSET	0x4204
+#endif
+
+#ifndef PTRACE_SETREGSET
+#define PTRACE_SETREGSET	0x4205
+#endif
+
 /* Assume that we have PTRACE_GETREGS et al. support.  If we do not,
    we'll clear this and use PTRACE_PEEKUSER instead.  */
 static int have_ptrace_regsets = 1;
 
+/* Does the current host support PTRACE_GETREGSET?  */
+static int have_ptrace_getregset_gp = 1;
+static int have_ptrace_getregset_fp = 1;
+
 /* Saved function pointers to fetch and store a single register using
    PTRACE_PEEKUSER and PTRACE_POKEUSER.  */
 
@@ -217,18 +230,25 @@ mips64_linux_regsets_fetch_registers (struct target_ops *ops,
 				      struct regcache *regcache, int regno)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG);
   int is_fp, is_dsp;
   int have_dsp;
   int regi;
   int tid;
 
-  if (regno >= mips_regnum (gdbarch)->fp0
-      && regno <= mips_regnum (gdbarch)->fp0 + 32)
+  /* FP registers can be obtained in several ways.
+     is_fp will be cleared once the registers have been obtained.  */
+  if (regno == -1)
+    is_fp = 1;
+  else if (regno >= mips_regnum (gdbarch)->fp0
+	   && regno <= mips_regnum (gdbarch)->fp0 + 32)
     is_fp = 1;
   else if (regno == mips_regnum (gdbarch)->fp_control_status)
     is_fp = 1;
   else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
     is_fp = 1;
+  else if (regno == mips_regnum (gdbarch)->config5)
+    is_fp = 1;
   else
     is_fp = 0;
 
@@ -266,23 +286,93 @@ mips64_linux_regsets_fetch_registers (struct target_ops *ops,
 			     (const mips64_elf_gregset_t *) &regs);
     }
 
-  if (regno == -1 || is_fp)
+  if (is_fp)
     {
-      mips64_elf_fpregset_t fp_regs;
+      const struct mips_regnum *rn = mips_regnum (gdbarch);
+      int float_regnum = rn->fp0;
 
-      if (ptrace (PTRACE_GETFPREGS, tid, 0L,
-		  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+      /* Try the FP regset next as it may contain Config5 */
+      if (have_ptrace_getregset_gp && have_ptrace_getregset_fp)
 	{
-	  if (errno == EIO)
+	  unsigned char fp_regs[34][8];
+	  struct iovec iovec;
+	  int ret;
+
+	  iovec.iov_base = &fp_regs;
+	  iovec.iov_len = sizeof (fp_regs);
+
+	  ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
+	  if (ret < 0)
 	    {
-	      have_ptrace_regsets = 0;
-	      return;
+	      if (errno == EIO)
+		have_ptrace_getregset_gp = 0;
+	      else if (errno == EINVAL)
+		have_ptrace_getregset_fp = 0;
+	      else
+		perror_with_name (_("Unable to fetch FP registers."));
+	    }
+	  else
+	    {
+	      for (regi = 0; regi < 32; regi++)
+		{
+		  if (register_size (gdbarch, float_regnum + regi) == 8)
+		    {
+		      /* FR = 1
+			 copy entire double */
+		      regcache_raw_supply (regcache, float_regnum + regi,
+					   (char *) fp_regs[regi]);
+		    }
+		  else if (regi & 1)
+		    {
+		      /* FR = 0
+			 odd single from top of even double */
+		      regcache_raw_supply (regcache, float_regnum + regi,
+					   (char *) fp_regs[regi - 1] +
+					   4 - 4*big_endian);
+		    }
+		  else
+		    {
+		      /* FR = 0
+			 even single from bottom of even double */
+		      regcache_raw_supply (regcache, float_regnum + regi,
+					   (char *) fp_regs[regi] + 4 * big_endian);
+		    }
+		}
+
+	      if (iovec.iov_len >= 32*8 + 4)
+		regcache_raw_supply (regcache, rn->fp_control_status,
+				     (char *) (fp_regs + 32) + 0);
+	      if (iovec.iov_len >= 32*8 + 8)
+		regcache_raw_supply (regcache, rn->fp_implementation_revision,
+				     (char *) (fp_regs + 32) + 4);
+	      if (iovec.iov_len >= 33*8 + 4 && rn->config5 >= 0)
+		regcache_raw_supply (regcache, rn->config5,
+				     (char *) (fp_regs + 33) + 0);
+
+	      /* we've got fp registers now */
+	      is_fp = 0;
 	    }
-	  perror_with_name (_("Couldn't get FP registers"));
 	}
 
-      mips64_supply_fpregset (regcache,
-			      (const mips64_elf_fpregset_t *) &fp_regs);
+      /* Fall back to GETFPREGS. */
+      if (is_fp)
+	{
+	  mips64_elf_fpregset_t fp_regs;
+
+	  if (ptrace (PTRACE_GETFPREGS, tid, 0L,
+		      (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+	    {
+	      if (errno == EIO)
+		{
+		  have_ptrace_regsets = 0;
+		  return;
+		}
+	      perror_with_name (_("Couldn't get FP registers"));
+	    }
+
+	  mips64_supply_fpregset (regcache,
+				  (const mips64_elf_fpregset_t *) &fp_regs);
+	}
     }
 
   if (is_dsp)
@@ -305,11 +395,16 @@ mips64_linux_regsets_store_registers (struct target_ops *ops,
 				      struct regcache *regcache, int regno)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG);
   int is_fp, is_dsp;
   int have_dsp;
   int regi;
   int tid;
 
+  /* FP registers can be written in several ways.
+     is_fp will be cleared once the registers have been written.  */
+  if (regno == -1)
+    is_fp = 1;
   if (regno >= mips_regnum (gdbarch)->fp0
       && regno <= mips_regnum (gdbarch)->fp0 + 32)
     is_fp = 1;
@@ -317,6 +412,8 @@ mips64_linux_regsets_store_registers (struct target_ops *ops,
     is_fp = 1;
   else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
     is_fp = 1;
+  else if (regno == mips_regnum (gdbarch)->config5)
+    is_fp = 1;
   else
     is_fp = 0;
 
@@ -349,19 +446,101 @@ mips64_linux_regsets_store_registers (struct target_ops *ops,
 	perror_with_name (_("Couldn't set registers"));
     }
 
-  if (regno == -1 || is_fp)
+  if (is_fp)
     {
-      mips64_elf_fpregset_t fp_regs;
+      const struct mips_regnum *rn = mips_regnum (gdbarch);
+      int float_regnum = rn->fp0;
+
+      /* Try the FP regset next as it may contain Config5 */
+      if (have_ptrace_getregset_gp && have_ptrace_getregset_fp)
+	{
+	  unsigned char fp_regs[34][8];
+	  struct iovec iovec;
+	  int ret;
+
+	  iovec.iov_base = &fp_regs;
+	  iovec.iov_len = sizeof (fp_regs);
 
-      if (ptrace (PTRACE_GETFPREGS, tid, 0L,
-		  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
-	perror_with_name (_("Couldn't get FP registers"));
+	  ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec);
+	  if (ret < 0)
+	    {
+	      if (errno == EIO)
+		have_ptrace_getregset_gp = 0;
+	      else if (errno == EINVAL)
+		have_ptrace_getregset_fp = 0;
+	      else
+		perror_with_name (_("Unable to fetch FP registers."));
+	    }
+	  else
+	    {
+	      for (regi = 0; regi < 32; regi++)
+		{
+		  if (register_size (gdbarch, float_regnum + regi) == 8)
+		    {
+		      /* FR = 1
+			 copy entire double */
+		      regcache_raw_collect (regcache, float_regnum + regi,
+					   (char *) fp_regs[regi]);
+		    }
+		  else if (regi & 1)
+		    {
+		      /* FR = 0
+			 odd single from top of even double */
+		      regcache_raw_collect (regcache, float_regnum + regi,
+					   (char *) fp_regs[regi - 1] +
+					   4 - 4*big_endian);
+		    }
+		  else
+		    {
+		      /* FR = 0
+			 even single from bottom of even double */
+		      regcache_raw_collect (regcache, float_regnum + regi,
+					   (char *) fp_regs[regi] + 4 * big_endian);
+		    }
+		}
+
+	      regcache_raw_collect (regcache, rn->fp_control_status,
+				   (char *) (fp_regs + 32) + 0);
+	      regcache_raw_collect (regcache, rn->fp_implementation_revision,
+				   (char *) (fp_regs + 32) + 4);
+	      if (rn->config5 >= 0)
+		regcache_raw_collect (regcache, rn->config5,
+				      (char *) (fp_regs + 33) + 0);
+
+	      /* don't modify iovec length from amount of data returned */
+	      ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iovec);
+	      if (ret < 0)
+		{
+		  if (errno == EIO)
+		    have_ptrace_getregset_gp = 0;
+		  else if (errno == EINVAL)
+		    have_ptrace_getregset_fp = 0;
+		  else
+		    perror_with_name (_("Unable to store FP/MSA registers."));
+		}
+	      else
+		{
+		  /* we've got fp registers now */
+		  is_fp = 0;
+		}
+	    }
+	}
 
-      mips64_fill_fpregset (regcache, &fp_regs, regno);
+      /* Fall back to SETFPREGS. */
+      if (is_fp)
+	{
+	  mips64_elf_fpregset_t fp_regs;
+
+	  if (ptrace (PTRACE_GETFPREGS, tid, 0L,
+		      (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+	    perror_with_name (_("Couldn't get FP registers"));
 
-      if (ptrace (PTRACE_SETFPREGS, tid, 0L,
-		  (PTRACE_TYPE_ARG3) &fp_regs) == -1)
-	perror_with_name (_("Couldn't set FP registers"));
+	  mips64_fill_fpregset (regcache, &fp_regs, regno);
+
+	  if (ptrace (PTRACE_SETFPREGS, tid, 0L,
+		      (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+	    perror_with_name (_("Couldn't set FP registers"));
+	}
     }
 
   if (is_dsp)
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index ae4dc2e..28cfb57 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -993,6 +993,25 @@ mips_register_to_value (struct frame_info *frame, int regnum,
     }
 }
 
+static struct type *
+mips_config5_type (struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (tdep->config5_type == NULL)
+    {
+      struct type *t;
+      /* top half has flags */
+      t = arch_flags_type (gdbarch, "__gdb_builtin_type_config5", 4);
+      append_flags_type_flag (t, 8, "FRE");
+
+      TYPE_NAME (t) = "config5";
+      tdep->config5_type = t;
+    }
+
+  return tdep->config5_type;
+}
+
 static void
 mips_value_to_register (struct frame_info *frame, int regnum,
 			struct type *type, const gdb_byte *from)
@@ -1080,6 +1099,8 @@ mips_register_type (struct gdbarch *gdbarch, int regnum)
       else if (rawnum == mips_regnum (gdbarch)->fp_control_status
 	  || rawnum == mips_regnum (gdbarch)->fp_implementation_revision)
 	return builtin_type (gdbarch)->builtin_int32;
+      else if (rawnum == mips_regnum (gdbarch)->config5)
+	return mips_config5_type (gdbarch);
       else if (gdbarch_osabi (gdbarch) != GDB_OSABI_IRIX
 	       && gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX
 	       && rawnum >= MIPS_FIRST_EMBED_REGNUM
@@ -1152,6 +1173,9 @@ mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
 	      && rawnum < mips_regnum (gdbarch)->dspacc + 6)))
     return builtin_type (gdbarch)->builtin_int32;
 
+  if (rawnum == mips_regnum (gdbarch)->config5)
+    return mips_config5_type (gdbarch);
+
   if (gdbarch_osabi (gdbarch) != GDB_OSABI_IRIX
       && gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX
       && rawnum >= MIPS_EMBED_FP0_REGNUM + 32
@@ -8236,6 +8260,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     info.tdep_info = &tdep_info;
 
   /* Fill in the OS dependent register numbers and names.  */
+  mips_regnum.config5 = -1;
   if (info.osabi == GDB_OSABI_IRIX)
     {
       mips_regnum.fp0 = 32;
@@ -8350,6 +8375,15 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       valid_p &= tdesc_numbered_register (feature, tdesc_data,
 					  mips_regnum.cause, "cause");
 
+      /* Optionally, Config5 contains FP mode bits */
+      if (tdesc_unnumbered_register (feature, "config5"))
+	{
+	  /* Allocate a new register.  */
+	  mips_regnum.config5 = num_regs++;
+	  tdesc_numbered_register (feature, tdesc_data,
+				   mips_regnum.config5, "config5");
+	}
+
       if (!valid_p)
 	{
 	  tdesc_data_cleanup (tdesc_data);
@@ -8666,6 +8700,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->register_size = 0;
   tdep->fp_register_size = info.tdep_info->fp_register_size;
   tdep->fp_register_size_fixed_p = 0;
+  tdep->config5_type = NULL;
 
   if (info.target_desc)
     {
diff --git a/gdb/mips-tdep.h b/gdb/mips-tdep.h
index 6c1d9ca..39af72b 100644
--- a/gdb/mips-tdep.h
+++ b/gdb/mips-tdep.h
@@ -63,6 +63,7 @@ struct mips_regnum
   int fp0;
   int fp_implementation_revision;
   int fp_control_status;
+  int config5;
   int badvaddr;		/* Bad vaddr for addressing exception.  */
   int cause;		/* Describes last exception.  */
   int hi;		/* Multiply/divide temp.  */
@@ -119,6 +120,9 @@ struct gdbarch_tdep
   int fp_register_size_fixed_p;
   int fp_register_size;
 
+  /* ISA-specific data types.  */
+  struct type *config5_type;
+
   /* Return the expected next PC if FRAME is stopped at a syscall
      instruction.  */
   CORE_ADDR (*syscall_next_pc) (struct frame_info *frame);
-- 
1.9-rc2


  parent reply	other threads:[~2016-06-27 14:50 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-27 14:50 [PATCH 01/24] MIPS: Handle run-time reconfigurable FPR size Bhushan Attarde
2016-06-27 14:50 ` [PATCH 06/24] mips-linux-nat: pick fp64 target description when appropriate Bhushan Attarde
2016-06-27 14:50 ` [PATCH 11/24] MIPS: Add support for hybrid fp32/fp64 mode Bhushan Attarde
2016-06-27 14:50 ` [PATCH 08/24] MIPS: Convert FP mode to enum and put fp registers into fp reggroup Bhushan Attarde
2016-06-27 14:50 ` [PATCH 10/24] MIPS: override fscr/fir types and print control registers specially Bhushan Attarde
2016-06-27 14:50 ` [PATCH 03/24] regcache: handle invalidated regcache Bhushan Attarde
2016-10-21 22:42   ` Maciej W. Rozycki
2016-06-27 14:51 ` [PATCH 12/24] o32 sigframe unwinding with FR1 Bhushan Attarde
2016-06-27 14:51 ` [PATCH 24/24] MIPS R6 forbidden slot support Bhushan Attarde
2016-06-27 14:51 ` [PATCH 05/24] MIPS: Add config5 to MIPS GDB target descriptions Bhushan Attarde
2016-06-27 14:51 ` [PATCH 19/24] Add MIPS MSA vector branch instruction support Bhushan Attarde
2016-06-27 14:51 ` [PATCH 22/24] Support all new ABIs when detecting if an FPU is present Bhushan Attarde
2016-06-27 14:51 ` [PATCH 09/24] MIPS: Enhance cooked FP format Bhushan Attarde
2016-06-27 14:51 ` [PATCH 14/24] Implement core MSA stuff Bhushan Attarde
2016-06-27 14:51 ` [PATCH 20/24] Drop FP and MSA control registers from default info registers Bhushan Attarde
2016-06-27 14:51 ` [PATCH 23/24] MIPS R6 opcode table shuffle for LDC2/SDC2 Bhushan Attarde
2016-06-27 14:51 ` [PATCH 13/24] Add MIPS MSA GDB target descriptions Bhushan Attarde
2016-06-27 14:51 ` [PATCH 07/24] MIPS: Make Linux restart register more dynamic Bhushan Attarde
2016-06-27 14:51 ` Bhushan Attarde [this message]
2016-06-27 14:51 ` [PATCH 02/24] Add MIPS32 FPU64 GDB target descriptions Bhushan Attarde
2016-10-12 12:42   ` Maciej W. Rozycki
2016-10-12 13:58     ` James Hogan
2016-10-12 16:30       ` Maciej W. Rozycki
2016-10-12 18:05         ` James Hogan
2016-10-12 22:04           ` Maciej W. Rozycki
2016-10-13 10:09             ` Matthew Fortune
2016-10-21 19:17               ` Maciej W. Rozycki
2016-10-21 19:24                 ` Maciej W. Rozycki
2016-06-27 14:51 ` [PATCH 18/24] mips-linux-nat: get msa registers Bhushan Attarde
2016-06-27 14:51 ` [PATCH 21/24] MIPSR6 support for GDB Bhushan Attarde
2016-07-29 21:10   ` Maciej W. Rozycki
2016-07-25 14:03 ` [PATCH 01/24] MIPS: Handle run-time reconfigurable FPR size Maciej W. Rozycki
2016-10-18 17:37   ` Maciej W. Rozycki
2016-11-08 19:46 ` Yao Qi
2016-11-10 12:43   ` Maciej W. Rozycki
2016-11-11 12:29     ` Yao Qi
2016-12-02  2:31       ` Maciej W. Rozycki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1467038991-6600-4-git-send-email-bhushan.attarde@imgtec.com \
    --to=bhushan.attarde@imgtec.com \
    --cc=Andrew.Bennett@imgtec.com \
    --cc=James.Hogan@imgtec.com \
    --cc=Jaydeep.Patil@imgtec.com \
    --cc=Maciej.Rozycki@imgtec.com \
    --cc=Matthew.Fortune@imgtec.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox