This is the mail archive of the gdb-cvs@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]

[binutils-gdb] Ptrace support for Aarch64 SVE


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e9902bfc28b80190c76ffe5fad3bb73fd4a2ba28

commit e9902bfc28b80190c76ffe5fad3bb73fd4a2ba28
Author: Alan Hayward <alan.hayward@arm.com>
Date:   Fri Jun 15 12:21:31 2018 +0100

    Ptrace support for Aarch64 SVE
    
    Add support for reading and writing registers for Aarch64 SVE.
    
    We need to support the cases where the kernel only gives us a
    fpsimd structure. This occurs when there is no active SVE state
    in the kernel (for example, after starting a new process).
    
    Added checks to make sure the vector length has not changed whilst
    the process is running.
    
    gdb/
    	* aarch64-linux-nat.c (fetch_sveregs_from_thread): New function.
    	(store_sveregs_to_thread): Likewise.
    	(aarch64_linux_fetch_inferior_registers): Check for SVE.
    	(aarch64_linux_store_inferior_registers): Likewise.
    	* nat/aarch64-sve-linux-ptrace.c (aarch64_sve_get_sveregs): New
    	function.
    	(aarch64_sve_regs_copy_to_regcache): Likewise.
    	(aarch64_sve_regs_copy_from_regcache): Likewise.
    	* nat/aarch64-sve-linux-ptrace.h (aarch64_sve_get_sveregs): New
    	declaration.
    	(aarch64_sve_regs_copy_to_regcache): Likewise.
    	(aarch64_sve_regs_copy_from_regcache): Likewise.
    	(sve_context): Structure from Linux headers.
    	(SVE_SIG_ZREGS_SIZE): Define from Linux headers.
    	(SVE_SIG_ZREG_SIZE): Likewise.
    	(SVE_SIG_PREG_SIZE): Likewise.
    	(SVE_SIG_FFR_SIZE): Likewise.
    	(SVE_SIG_REGS_OFFSET): Likewise.
    	(SVE_SIG_ZREGS_OFFSET): Likewise.
    	(SVE_SIG_ZREG_OFFSET): Likewise.
    	(SVE_SIG_ZREGS_SIZE): Likewise.
    	(SVE_SIG_PREGS_OFFSET): Likewise.
    	(SVE_SIG_PREG_OFFSET): Likewise.
    	(SVE_SIG_PREGS_SIZE): Likewise.
    	(SVE_SIG_FFR_OFFSET): Likewise.
    	(SVE_SIG_REGS_SIZE): Likewise.
    	(SVE_SIG_CONTEXT_SIZE): Likewise.
    	(SVE_PT_REGS_MASK): Likewise.
    	(SVE_PT_REGS_FPSIMD): Likewise.
    	(SVE_PT_REGS_SVE): Likewise.
    	(SVE_PT_VL_INHERIT): Likewise.
    	(SVE_PT_VL_ONEXEC): Likewise.
    	(SVE_PT_REGS_OFFSET): Likewise.
    	(SVE_PT_FPSIMD_OFFSET): Likewise.
    	(SVE_PT_FPSIMD_SIZE): Likewise.
    	(SVE_PT_SVE_ZREG_SIZE): Likewise.
    	(SVE_PT_SVE_PREG_SIZE): Likewise.
    	(SVE_PT_SVE_FFR_SIZE): Likewise.
    	(SVE_PT_SVE_FPSR_SIZE): Likewise.
    	(SVE_PT_SVE_FPCR_SIZE): Likewise.
    	(__SVE_SIG_TO_PT): Likewise.
    	(SVE_PT_SVE_OFFSET): Likewise.
    	(SVE_PT_SVE_ZREGS_OFFSET): Likewise.
    	(SVE_PT_SVE_ZREG_OFFSET): Likewise.
    	(SVE_PT_SVE_ZREGS_SIZE): Likewise.
    	(SVE_PT_SVE_PREGS_OFFSET): Likewise.
    	(SVE_PT_SVE_PREG_OFFSET): Likewise.
    	(SVE_PT_SVE_PREGS_SIZE): Likewise.
    	(SVE_PT_SVE_FFR_OFFSET): Likewise.
    	(SVE_PT_SVE_FPSR_OFFSET): Likewise.
    	(SVE_PT_SVE_FPCR_OFFSET): Likewise.
    	(SVE_PT_SVE_SIZE): Likewise.
    	(SVE_PT_SIZE): Likewise.
    	(HAS_SVE_STATE): New define.
    
    gdbserver/
    	* Makefile.in: Add aarch64-sve-linux-ptrace.c.

Diff:
---
 gdb/ChangeLog                      |  57 ++++++++
 gdb/aarch64-linux-nat.c            |  54 +++++++-
 gdb/gdbserver/ChangeLog            |   4 +
 gdb/gdbserver/Makefile.in          |   1 +
 gdb/nat/aarch64-sve-linux-ptrace.c | 269 ++++++++++++++++++++++++++++++++++++-
 gdb/nat/aarch64-sve-linux-ptrace.h |  21 +++
 6 files changed, 403 insertions(+), 3 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b0ea280..4217b08 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,62 @@
 2018-06-18  Alan Hayward  <alan.hayward@arm.com>
 
+	* aarch64-linux-nat.c (fetch_sveregs_from_thread): New function.
+	(store_sveregs_to_thread): Likewise.
+	(aarch64_linux_fetch_inferior_registers): Check for SVE.
+	(aarch64_linux_store_inferior_registers): Likewise.
+	* nat/aarch64-sve-linux-ptrace.c (aarch64_sve_get_sveregs): New
+	function.
+	(aarch64_sve_regs_copy_to_regcache): Likewise.
+	(aarch64_sve_regs_copy_from_regcache): Likewise.
+	* nat/aarch64-sve-linux-ptrace.h (aarch64_sve_get_sveregs): New
+	declaration.
+	(aarch64_sve_regs_copy_to_regcache): Likewise.
+	(aarch64_sve_regs_copy_from_regcache): Likewise.
+	(sve_context): Structure from Linux headers.
+	(SVE_SIG_ZREGS_SIZE): Define from Linux headers.
+	(SVE_SIG_ZREG_SIZE): Likewise.
+	(SVE_SIG_PREG_SIZE): Likewise.
+	(SVE_SIG_FFR_SIZE): Likewise.
+	(SVE_SIG_REGS_OFFSET): Likewise.
+	(SVE_SIG_ZREGS_OFFSET): Likewise.
+	(SVE_SIG_ZREG_OFFSET): Likewise.
+	(SVE_SIG_ZREGS_SIZE): Likewise.
+	(SVE_SIG_PREGS_OFFSET): Likewise.
+	(SVE_SIG_PREG_OFFSET): Likewise.
+	(SVE_SIG_PREGS_SIZE): Likewise.
+	(SVE_SIG_FFR_OFFSET): Likewise.
+	(SVE_SIG_REGS_SIZE): Likewise.
+	(SVE_SIG_CONTEXT_SIZE): Likewise.
+	(SVE_PT_REGS_MASK): Likewise.
+	(SVE_PT_REGS_FPSIMD): Likewise.
+	(SVE_PT_REGS_SVE): Likewise.
+	(SVE_PT_VL_INHERIT): Likewise.
+	(SVE_PT_VL_ONEXEC): Likewise.
+	(SVE_PT_REGS_OFFSET): Likewise.
+	(SVE_PT_FPSIMD_OFFSET): Likewise.
+	(SVE_PT_FPSIMD_SIZE): Likewise.
+	(SVE_PT_SVE_ZREG_SIZE): Likewise.
+	(SVE_PT_SVE_PREG_SIZE): Likewise.
+	(SVE_PT_SVE_FFR_SIZE): Likewise.
+	(SVE_PT_SVE_FPSR_SIZE): Likewise.
+	(SVE_PT_SVE_FPCR_SIZE): Likewise.
+	(__SVE_SIG_TO_PT): Likewise.
+	(SVE_PT_SVE_OFFSET): Likewise.
+	(SVE_PT_SVE_ZREGS_OFFSET): Likewise.
+	(SVE_PT_SVE_ZREG_OFFSET): Likewise.
+	(SVE_PT_SVE_ZREGS_SIZE): Likewise.
+	(SVE_PT_SVE_PREGS_OFFSET): Likewise.
+	(SVE_PT_SVE_PREG_OFFSET): Likewise.
+	(SVE_PT_SVE_PREGS_SIZE): Likewise.
+	(SVE_PT_SVE_FFR_OFFSET): Likewise.
+	(SVE_PT_SVE_FPSR_OFFSET): Likewise.
+	(SVE_PT_SVE_FPCR_OFFSET): Likewise.
+	(SVE_PT_SVE_SIZE): Likewise.
+	(SVE_PT_SIZE): Likewise.
+	(HAS_SVE_STATE): New define.
+
+2018-06-18  Alan Hayward  <alan.hayward@arm.com>
+
 	* nat/aarch64-sve-linux-sigcontext.h: New file.
 	* nat/aarch64-sve-linux-ptrace.h (SVE_VQ_BYTES): Move to
 	new files.
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 1e4f937..1e7db29 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -384,19 +384,62 @@ store_fpregs_to_thread (const struct regcache *regcache)
     }
 }
 
+/* Fill GDB's register array with the sve register values
+   from the current thread.  */
+
+static void
+fetch_sveregs_from_thread (struct regcache *regcache)
+{
+  std::unique_ptr<gdb_byte[]> base
+    = aarch64_sve_get_sveregs (ptid_get_lwp (regcache->ptid ()));
+  aarch64_sve_regs_copy_to_reg_buf (regcache, base.get ());
+}
+
+/* Store to the current thread the valid sve register
+   values in the GDB's register array.  */
+
+static void
+store_sveregs_to_thread (struct regcache *regcache)
+{
+  int ret;
+  struct iovec iovec;
+  int tid = ptid_get_lwp (regcache->ptid ());
+
+  /* Obtain a dump of SVE registers from ptrace.  */
+  std::unique_ptr<gdb_byte[]> base = aarch64_sve_get_sveregs (tid);
+
+  /* Overwrite with regcache state.  */
+  aarch64_sve_regs_copy_from_reg_buf (regcache, base.get ());
+
+  /* Write back to the kernel.  */
+  iovec.iov_base = base.get ();
+  iovec.iov_len = ((struct user_sve_header *) base.get ())->size;
+  ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec);
+
+  if (ret < 0)
+    perror_with_name (_("Unable to store sve registers"));
+}
+
 /* Implement the "fetch_registers" target_ops method.  */
 
 void
 aarch64_linux_nat_target::fetch_registers (struct regcache *regcache,
 					   int regno)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+
   if (regno == -1)
     {
       fetch_gregs_from_thread (regcache);
-      fetch_fpregs_from_thread (regcache);
+      if (tdep->has_sve ())
+	fetch_sveregs_from_thread (regcache);
+      else
+	fetch_fpregs_from_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     fetch_gregs_from_thread (regcache);
+  else if (tdep->has_sve ())
+    fetch_sveregs_from_thread (regcache);
   else
     fetch_fpregs_from_thread (regcache);
 }
@@ -407,13 +450,20 @@ void
 aarch64_linux_nat_target::store_registers (struct regcache *regcache,
 					   int regno)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+
   if (regno == -1)
     {
       store_gregs_to_thread (regcache);
-      store_fpregs_to_thread (regcache);
+      if (tdep->has_sve ())
+	store_sveregs_to_thread (regcache);
+      else
+	store_fpregs_to_thread (regcache);
     }
   else if (regno < AARCH64_V0_REGNUM)
     store_gregs_to_thread (regcache);
+  else if (tdep->has_sve ())
+    store_sveregs_to_thread (regcache);
   else
     store_fpregs_to_thread (regcache);
 }
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index ac1eb1c..a1c72b2 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,7 @@
+2018-06-18  Alan Hayward  <alan.hayward@arm.com>
+
+	* Makefile.in: Add aarch64-sve-linux-ptrace.c.
+
 2018-06-11  Alan Hayward  <alan.hayward@arm.com>
 
 	* linux-aarch64-ipa.c (get_ipa_tdesc): Add null VQ param.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index cf04b7d..513f286 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -219,6 +219,7 @@ SFILES = \
 	$(srcdir)/common/tdesc.c \
 	$(srcdir)/common/vec.c \
 	$(srcdir)/common/xml-utils.c \
+	$(srcdir)/nat/aarch64-sve-linux-ptrace.c \
 	$(srcdir)/nat/linux-btrace.c \
 	$(srcdir)/nat/linux-namespaces.c \
 	$(srcdir)/nat/linux-osdata.c \
diff --git a/gdb/nat/aarch64-sve-linux-ptrace.c b/gdb/nat/aarch64-sve-linux-ptrace.c
index 119656b..a2f9261 100644
--- a/gdb/nat/aarch64-sve-linux-ptrace.c
+++ b/gdb/nat/aarch64-sve-linux-ptrace.c
@@ -24,6 +24,10 @@
 #include "elf/common.h"
 #include "aarch64-sve-linux-ptrace.h"
 #include "arch/aarch64.h"
+#include "common-regcache.h"
+#include "common/byte-vector.h"
+
+static bool vq_change_warned = false;
 
 /* See nat/aarch64-sve-linux-ptrace.h.  */
 
@@ -46,7 +50,7 @@ aarch64_sve_get_vq (int tid)
       return 0;
     }
 
-  long vq = sve_vq_from_vl (header.vl);
+  uint64_t vq = sve_vq_from_vl (header.vl);
 
   if (!sve_vl_valid (header.vl))
     {
@@ -56,3 +60,266 @@ aarch64_sve_get_vq (int tid)
 
   return vq;
 }
+
+/* See nat/aarch64-sve-linux-ptrace.h.  */
+
+std::unique_ptr<gdb_byte[]>
+aarch64_sve_get_sveregs (int tid)
+{
+  struct iovec iovec;
+  struct user_sve_header header;
+  uint64_t vq = aarch64_sve_get_vq (tid);
+
+  if (vq == 0)
+    perror_with_name (_("Unable to fetch SVE register header"));
+
+  /* A ptrace call with NT_ARM_SVE will return a header followed by either a
+     dump of all the SVE and FP registers, or an fpsimd structure (identical to
+     the one returned by NT_FPREGSET) if the kernel has not yet executed any
+     SVE code.  Make sure we allocate enough space for a full SVE dump.  */
+
+  iovec.iov_len = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
+  std::unique_ptr<gdb_byte[]> buf (new gdb_byte[iovec.iov_len]);
+  iovec.iov_base = buf.get ();
+
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
+    perror_with_name (_("Unable to fetch SVE registers"));
+
+  return buf;
+}
+
+/* See nat/aarch64-sve-linux-ptrace.h.  */
+
+void
+aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common *reg_buf,
+				  const void *buf)
+{
+  char *base = (char *) buf;
+  struct user_sve_header *header = (struct user_sve_header *) buf;
+  uint64_t vq, vg_reg_buf = 0;
+
+  vq = sve_vq_from_vl (header->vl);
+
+  /* Sanity check the data in the header.  */
+  if (!sve_vl_valid (header->vl)
+      || SVE_PT_SIZE (vq, header->flags) != header->size)
+    error (_("Invalid SVE header from kernel."));
+
+  if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM))
+    reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &vg_reg_buf);
+
+  if (vg_reg_buf == 0)
+    {
+      /* VG has not been set.  */
+      vg_reg_buf = sve_vg_from_vl (header->vl);
+      reg_buf->raw_supply (AARCH64_SVE_VG_REGNUM, &vg_reg_buf);
+    }
+  else if (vg_reg_buf != sve_vg_from_vl (header->vl) && !vq_change_warned)
+    {
+      /* Vector length on the running process has changed.  GDB currently does
+	 not support this and will result in GDB showing incorrect partially
+	 incorrect data for the vector registers.  Warn once and continue.  We
+	 do not expect many programs to exhibit this behaviour.  To fix this
+	 we need to spot the change earlier and generate a new target
+	 descriptor.  */
+      warning (_("SVE Vector length has changed (%ld to %d). "
+		 "Vector registers may show incorrect data."),
+	       vg_reg_buf, sve_vg_from_vl (header->vl));
+      vq_change_warned = true;
+    }
+
+  if (HAS_SVE_STATE (*header))
+    {
+      /* The register dump contains a set of SVE registers.  */
+
+      for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+	reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i,
+			     base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
+
+      for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
+	reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i,
+			     base + SVE_PT_SVE_PREG_OFFSET (vq, i));
+
+      reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM,
+			   base + SVE_PT_SVE_FFR_OFFSET (vq));
+      reg_buf->raw_supply (AARCH64_FPSR_REGNUM,
+			   base + SVE_PT_SVE_FPSR_OFFSET (vq));
+      reg_buf->raw_supply (AARCH64_FPCR_REGNUM,
+			   base + SVE_PT_SVE_FPCR_OFFSET (vq));
+    }
+  else
+    {
+      /* There is no SVE state yet - the register dump contains a fpsimd
+	 structure instead.  These registers still exist in the hardware, but
+	 the kernel has not yet initialised them, and so they will be null.  */
+
+      char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
+      struct user_fpsimd_state *fpsimd
+	= (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
+
+      /* Copy across the V registers from fpsimd structure to the Z registers,
+	 ensuring the non overlapping state is set to null.  */
+
+      memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
+
+      for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+	{
+	  memcpy (zero_reg, &fpsimd->vregs[i], sizeof (__int128_t));
+	  reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
+	}
+
+      reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
+      reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
+
+      /* Clear the SVE only registers.  */
+
+      for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
+	reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, zero_reg);
+
+      reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, zero_reg);
+    }
+}
+
+/* See nat/aarch64-sve-linux-ptrace.h.  */
+
+void
+aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
+				    void *buf)
+{
+  struct user_sve_header *header = (struct user_sve_header *) buf;
+  char *base = (char *) buf;
+  uint64_t vq, vg_reg_buf = 0;
+
+  vq = sve_vq_from_vl (header->vl);
+
+  /* Sanity check the data in the header.  */
+  if (!sve_vl_valid (header->vl)
+      || SVE_PT_SIZE (vq, header->flags) != header->size)
+    error (_("Invalid SVE header from kernel."));
+
+  if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM))
+    reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &vg_reg_buf);
+
+  if (vg_reg_buf != 0 && vg_reg_buf != sve_vg_from_vl (header->vl))
+    {
+      /* Vector length on the running process has changed.  GDB currently does
+	 not support this and will result in GDB writing invalid data back to
+	 the vector registers.  Error and exit.  We do not expect many programs
+	 to exhibit this behaviour.  To fix this we need to spot the change
+	 earlier and generate a new target descriptor.  */
+      error (_("SVE Vector length has changed (%ld to %d). "
+	       "Cannot write back registers."),
+	     vg_reg_buf, sve_vg_from_vl (header->vl));
+    }
+
+  if (!HAS_SVE_STATE (*header))
+    {
+      /* There is no SVE state yet - the register dump contains a fpsimd
+	 structure instead.  Where possible we want to write the reg_buf data
+	 back to the kernel using the fpsimd structure.  However, if we cannot
+	 then we'll need to reformat the fpsimd into a full SVE structure,
+	 resulting in the initialization of SVE state written back to the
+	 kernel, which is why we try to avoid it.  */
+
+      bool has_sve_state = false;
+      char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
+      struct user_fpsimd_state *fpsimd
+	= (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
+
+      memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
+
+      /* Check in the reg_buf if any of the Z registers are set after the
+	 first 128 bits, or if any of the other SVE registers are set.  */
+
+      for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+	{
+	  has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i,
+						 zero_reg, sizeof (__int128_t));
+	  if (has_sve_state)
+	    break;
+	}
+
+      if (!has_sve_state)
+	for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
+	  {
+	    has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i,
+						   zero_reg, 0);
+	    if (has_sve_state)
+	      break;
+	  }
+
+      if (!has_sve_state)
+	  has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM,
+						 zero_reg, 0);
+
+      /* If no SVE state exists, then use the existing fpsimd structure to
+	 write out state and return.  */
+      if (!has_sve_state)
+	{
+	  /* The collects of the Z registers will overflow the size of a vreg.
+	     There is enough space in the structure to allow for this, but we
+	     cannot overflow into the next register as we might not be
+	     collecting every register.  */
+
+	  for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+	    {
+	      if (REG_VALID
+		  == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
+		{
+		  reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
+		  memcpy (&fpsimd->vregs[i], zero_reg, sizeof (__int128_t));
+		}
+	    }
+
+	  if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
+	    reg_buf->raw_collect (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
+	  if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
+	    reg_buf->raw_collect (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
+
+	  return;
+	}
+
+      /* Otherwise, reformat the fpsimd structure into a full SVE set, by
+	 expanding the V registers (working backwards so we don't splat
+	 registers before they are copied) and using null for everything else.
+	 Note that enough space for a full SVE dump was originally allocated
+	 for base.  */
+
+      header->flags |= SVE_PT_REGS_SVE;
+      header->size = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
+
+      memcpy (base + SVE_PT_SVE_FPSR_OFFSET (vq), &fpsimd->fpsr,
+	      sizeof (uint32_t));
+      memcpy (base + SVE_PT_SVE_FPCR_OFFSET (vq), &fpsimd->fpcr,
+	      sizeof (uint32_t));
+
+      for (int i = AARCH64_SVE_Z_REGS_NUM; i >= 0 ; i--)
+	{
+	  memcpy (base + SVE_PT_SVE_ZREG_OFFSET (vq, i), &fpsimd->vregs[i],
+		  sizeof (__int128_t));
+	}
+    }
+
+  /* Replace the kernel values with those from reg_buf.  */
+
+  for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+    if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
+      reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i,
+			    base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
+
+  for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
+    if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_P0_REGNUM + i))
+      reg_buf->raw_collect (AARCH64_SVE_P0_REGNUM + i,
+			    base + SVE_PT_SVE_PREG_OFFSET (vq, i));
+
+  if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_FFR_REGNUM))
+    reg_buf->raw_collect (AARCH64_SVE_FFR_REGNUM,
+			  base + SVE_PT_SVE_FFR_OFFSET (vq));
+  if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
+    reg_buf->raw_collect (AARCH64_FPSR_REGNUM,
+			  base + SVE_PT_SVE_FPSR_OFFSET (vq));
+  if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
+    reg_buf->raw_collect (AARCH64_FPCR_REGNUM,
+			  base + SVE_PT_SVE_FPCR_OFFSET (vq));
+
+}
diff --git a/gdb/nat/aarch64-sve-linux-ptrace.h b/gdb/nat/aarch64-sve-linux-ptrace.h
index 7f5a81f..5a7186b 100644
--- a/gdb/nat/aarch64-sve-linux-ptrace.h
+++ b/gdb/nat/aarch64-sve-linux-ptrace.h
@@ -29,9 +29,30 @@
 #include "aarch64-sve-linux-sigcontext.h"
 #endif
 
+/* Indicates whether a SVE ptrace header is followed by SVE registers or a
+   fpsimd structure.  */
+
+#define HAS_SVE_STATE(header) ((header).flags && SVE_PT_REGS_SVE)
+
 /* Read VQ for the given tid using ptrace.  If SVE is not supported then zero
    is returned (on a system that supports SVE, then VQ cannot be zero).  */
 
 uint64_t aarch64_sve_get_vq (int tid);
 
+/* Read the current SVE register set using ptrace, allocating space as
+   required.  */
+
+extern std::unique_ptr<gdb_byte[]> aarch64_sve_get_sveregs (int tid);
+
+/* Put the registers from linux structure buf into register buffer.  */
+
+extern void aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common *reg_buf,
+					      const void *buf);
+
+/* Put the registers from register buffer into linux structure buf.  */
+
+extern void
+aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
+				    void *buf);
+
 #endif /* aarch64-sve-linux-ptrace.h */


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