Ptrace support for Aarch64 SVE
authorAlan Hayward <alan.hayward@arm.com>
Fri, 15 Jun 2018 11:21:31 +0000 (12:21 +0100)
committerAlan Hayward <alan.hayward@arm.com>
Mon, 18 Jun 2018 09:06:53 +0000 (10:06 +0100)
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.

gdb/ChangeLog
gdb/aarch64-linux-nat.c
gdb/gdbserver/ChangeLog
gdb/gdbserver/Makefile.in
gdb/nat/aarch64-sve-linux-ptrace.c
gdb/nat/aarch64-sve-linux-ptrace.h

index b0ea28010537241d30eaef50f52e63ce2b933150..4217b08d9c18d952e1f67d07f85c9caa1e4fc15b 100644 (file)
@@ -1,3 +1,60 @@
+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.
index 1e4f937dc9162bcb5528f570a441c6663899b8b9..1e7db2920b9119dc925bc5fcf4642def85748446 100644 (file)
@@ -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);
 }
index ac1eb1c909978f582c9a5a6419a906da53bc922d..a1c72b2b0331e051113f7536dd160778f61d8b42 100644 (file)
@@ -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.
index cf04b7d7b5adba6d93c9c65be35cd7402701b03b..513f286289964bb972f566f0fc1fea358d01e9eb 100644 (file)
@@ -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 \
index 119656b8864fe76f59ec4b934c01c9c1686d7711..a2f9261ba6f8ad9aaaacd165d28dce6cb5e3e544 100644 (file)
 #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));
+
+}
index 7f5a81f3252df76c517a10cdbad20be255107975..5a7186b7aa7687d74f65486225dc97a0a2a9017a 100644 (file)
 #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 */