refactor: Rename SVE-specific files
authorLuis Machado <luis.machado@arm.com>
Mon, 6 Feb 2023 17:24:32 +0000 (17:24 +0000)
committerLuis Machado <luis.machado@arm.com>
Wed, 4 Oct 2023 15:23:39 +0000 (16:23 +0100)
In preparation to the SME support patches, rename the SVE-specific files to
something a bit more meaningful that can be shared with the SME code.

In this case, I've renamed the "sve" in the names to "scalable".

No functional changes.

Regression-tested on aarch64-linux Ubuntu 22.04/20.04.

Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
12 files changed:
gdb/Makefile.in
gdb/aarch64-linux-nat.c
gdb/configure.nat
gdb/nat/aarch64-scalable-linux-ptrace.c [new file with mode: 0644]
gdb/nat/aarch64-scalable-linux-ptrace.h [new file with mode: 0644]
gdb/nat/aarch64-scalable-linux-sigcontext.h [new file with mode: 0644]
gdb/nat/aarch64-sve-linux-ptrace.c [deleted file]
gdb/nat/aarch64-sve-linux-ptrace.h [deleted file]
gdb/nat/aarch64-sve-linux-sigcontext.h [deleted file]
gdbserver/Makefile.in
gdbserver/configure.srv
gdbserver/linux-aarch64-low.cc

index 9b992a3d8c0e5c995f9cfded938ddd254e821b77..cdfbad4deed63473a16f6df853097141fae56647 100644 (file)
@@ -1561,7 +1561,7 @@ HFILES_NO_SRCDIR = \
        nat/aarch64-linux.h \
        nat/aarch64-linux-hw-point.h \
        nat/aarch64-mte-linux-ptrace.h \
-       nat/aarch64-sve-linux-ptrace.h \
+       nat/aarch64-scalable-linux-ptrace.h \
        nat/amd64-linux-siginfo.h \
        nat/gdb_ptrace.h \
        nat/gdb_thread_db.h \
index 8844fc722cf3adfbe0ea83338babf225b748d16d..9f32279c0acdf7e72f4bfea4ef20a346cc1110ce 100644 (file)
@@ -35,7 +35,7 @@
 #include "arch/arm.h"
 #include "nat/aarch64-linux.h"
 #include "nat/aarch64-linux-hw-point.h"
-#include "nat/aarch64-sve-linux-ptrace.h"
+#include "nat/aarch64-scalable-linux-ptrace.h"
 
 #include "elf/external.h"
 #include "elf/common.h"
index 2739d14a1c4e79fe68d593a1e4d4adf25316ac73..1dc4206b69c00e9fa00819d05303bfb17fe56858 100644 (file)
@@ -239,7 +239,7 @@ case ${gdb_host} in
                aarch32-linux-nat.o nat/aarch64-hw-point.o \
                nat/aarch64-linux-hw-point.o \
                nat/aarch64-linux.o \
-               nat/aarch64-sve-linux-ptrace.o \
+               nat/aarch64-scalable-linux-ptrace.o \
                nat/aarch64-mte-linux-ptrace.o"
                ;;
            arc)
diff --git a/gdb/nat/aarch64-scalable-linux-ptrace.c b/gdb/nat/aarch64-scalable-linux-ptrace.c
new file mode 100644 (file)
index 0000000..cc43f51
--- /dev/null
@@ -0,0 +1,393 @@
+/* Common target dependent routines for AArch64 Scalable Extensions
+   (SVE/SME).
+
+   Copyright (C) 2018-2023 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <sys/utsname.h>
+#include <sys/uio.h>
+#include "gdbsupport/common-defs.h"
+#include "elf/external.h"
+#include "elf/common.h"
+#include "aarch64-scalable-linux-ptrace.h"
+#include "arch/aarch64.h"
+#include "gdbsupport/common-regcache.h"
+#include "gdbsupport/byte-vector.h"
+#include <endian.h>
+
+/* See nat/aarch64-scalable-linux-ptrace.h.  */
+
+uint64_t
+aarch64_sve_get_vq (int tid)
+{
+  struct iovec iovec;
+  struct user_sve_header header;
+
+  iovec.iov_len = sizeof (header);
+  iovec.iov_base = &header;
+
+  /* Ptrace gives the vector length in bytes.  Convert it to VQ, the number of
+     128bit chunks in a Z register.  We use VQ because 128bits is the minimum
+     a Z register can increase in size.  */
+
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
+    {
+      /* SVE is not supported.  */
+      return 0;
+    }
+
+  uint64_t vq = sve_vq_from_vl (header.vl);
+
+  if (!sve_vl_valid (header.vl))
+    {
+      warning (_("Invalid SVE state from kernel; SVE disabled."));
+      return 0;
+    }
+
+  return vq;
+}
+
+/* See nat/aarch64-scalable-linux-ptrace.h.  */
+
+bool
+aarch64_sve_set_vq (int tid, uint64_t vq)
+{
+  struct iovec iovec;
+  struct user_sve_header header;
+
+  iovec.iov_len = sizeof (header);
+  iovec.iov_base = &header;
+
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
+    {
+      /* SVE is not supported.  */
+      return false;
+    }
+
+  header.vl = sve_vl_from_vq (vq);
+
+  if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
+    {
+      /* Vector length change failed.  */
+      return false;
+    }
+
+  return true;
+}
+
+/* See nat/aarch64-scalable-linux-ptrace.h.  */
+
+bool
+aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf)
+{
+  uint64_t reg_vg = 0;
+
+  /* The VG register may not be valid if we've not collected any value yet.
+     This can happen, for example,  if we're restoring the regcache after an
+     inferior function call, and the VG register comes after the Z
+     registers.  */
+  if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
+    {
+      /* If vg is not available yet, fetch it from ptrace.  The VG value from
+        ptrace is likely the correct one.  */
+      uint64_t vq = aarch64_sve_get_vq (tid);
+
+      /* If something went wrong, just bail out.  */
+      if (vq == 0)
+       return false;
+
+      reg_vg = sve_vg_from_vq (vq);
+    }
+  else
+    reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &reg_vg);
+
+  return aarch64_sve_set_vq (tid, sve_vq_from_vg (reg_vg));
+}
+
+/* See nat/aarch64-scalable-linux-ptrace.h.  */
+
+std::unique_ptr<gdb_byte[]>
+aarch64_sve_get_sveregs (int tid)
+{
+  struct iovec iovec;
+  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;
+}
+
+/* If we are running in BE mode, byteswap the contents
+   of SRC to DST for SIZE bytes.  Other, just copy the contents
+   from SRC to DST.  */
+
+static void
+aarch64_maybe_swab128 (gdb_byte *dst, const gdb_byte *src, size_t size)
+{
+  gdb_assert (src != nullptr && dst != nullptr);
+  gdb_assert (size > 1);
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+  for (int i = 0; i < size - 1; i++)
+    dst[i] = src[size - i];
+#else
+  memcpy (dst, src, size);
+#endif
+}
+
+/* See nat/aarch64-scalable-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 = sve_vq_from_vl (header->vl);
+  uint64_t vg = sve_vg_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."));
+
+  /* Update VG.  Note, the registers in the regcache will already be of the
+     correct length.  */
+  reg_buf->raw_supply (AARCH64_SVE_VG_REGNUM, &vg);
+
+  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
+    {
+      /* WARNING: SIMD state is laid out in memory in target-endian format,
+        while SVE state is laid out in an endianness-independent format (LE).
+
+        So we have a couple cases to consider:
+
+        1 - If the target is big endian, then SIMD state is big endian,
+        requiring a byteswap.
+
+        2 - If the target is little endian, then SIMD state is little endian,
+        which matches the SVE format, so no byteswap is needed. */
+
+      /* 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.  */
+
+      gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
+      struct user_fpsimd_state *fpsimd
+       = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
+
+      /* Make sure we have a zeroed register buffer.  We will need the zero
+        padding below.  */
+      memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
+
+      /* Copy across the V registers from fpsimd structure to the Z registers,
+        ensuring the non overlapping state is set to null.  */
+
+      for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
+       {
+         /* Handle big endian/little endian SIMD/SVE conversion.  */
+         aarch64_maybe_swab128 (reg, (const gdb_byte *) &fpsimd->vregs[i],
+                                V_REGISTER_SIZE);
+         reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, reg);
+       }
+
+      reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
+      reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
+
+      /* Clear the SVE only registers.  */
+      memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
+
+      for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
+       reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, reg);
+
+      reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, reg);
+    }
+}
+
+/* See nat/aarch64-scalable-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 = 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 (!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;
+      gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
+      struct user_fpsimd_state *fpsimd
+       = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
+
+      memset (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,
+                                                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,
+                                                  reg, 0);
+           if (has_sve_state)
+             break;
+         }
+
+      if (!has_sve_state)
+         has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM,
+                                                reg, 0);
+
+      /* If no SVE state exists, then use the existing fpsimd structure to
+        write out state and return.  */
+      if (!has_sve_state)
+       {
+         /* WARNING: SIMD state is laid out in memory in target-endian format,
+            while SVE state is laid out in an endianness-independent format
+            (LE).
+
+            So we have a couple cases to consider:
+
+            1 - If the target is big endian, then SIMD state is big endian,
+            requiring a byteswap.
+
+            2 - If the target is little endian, then SIMD state is little
+            endian, which matches the SVE format, so no byteswap is needed. */
+
+         /* 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, reg);
+                 /* Handle big endian/little endian SIMD/SVE conversion.  */
+                 aarch64_maybe_swab128 ((gdb_byte *) &fpsimd->vregs[i], reg,
+                                        V_REGISTER_SIZE);
+               }
+           }
+
+         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-scalable-linux-ptrace.h b/gdb/nat/aarch64-scalable-linux-ptrace.h
new file mode 100644 (file)
index 0000000..2847c4e
--- /dev/null
@@ -0,0 +1,73 @@
+/* Common target dependent definitions for AArch64 Scalable Extensions
+   (SVE/SME).
+
+   Copyright (C) 2018-2023 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NAT_AARCH64_SCALABLE_LINUX_PTRACE_H
+#define NAT_AARCH64_SCALABLE_LINUX_PTRACE_H
+
+#include <signal.h>
+#include <sys/utsname.h>
+
+/* The order in which <sys/ptrace.h> and <asm/ptrace.h> are included
+   can be important.  <sys/ptrace.h> often declares various PTRACE_*
+   enums.  <asm/ptrace.h> often defines preprocessor constants for
+   these very same symbols.  When that's the case, build errors will
+   result when <asm/ptrace.h> is included before <sys/ptrace.h>.  */
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#ifndef SVE_SIG_ZREGS_SIZE
+#include "aarch64-scalable-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);
+
+/* Set VQ in the kernel for the given tid, using either the value VQ or
+   reading from the register VG in the register buffer.  */
+
+bool aarch64_sve_set_vq (int tid, uint64_t vq);
+bool aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf);
+
+/* 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.  Assumes the
+   vector lengths in the register buffer match the size in the kernel.  */
+
+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.  Assumes the
+   vector lengths in the register buffer match the size in the kernel.  */
+
+extern void
+aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
+                                   void *buf);
+
+#endif /* NAT_AARCH64_SCALABLE_LINUX_PTRACE_H */
diff --git a/gdb/nat/aarch64-scalable-linux-sigcontext.h b/gdb/nat/aarch64-scalable-linux-sigcontext.h
new file mode 100644 (file)
index 0000000..e0120e0
--- /dev/null
@@ -0,0 +1,270 @@
+/* Linux Kernel sigcontext definitions for AArch64 Scalable Extensions
+   (SVE/SME).
+
+   Copyright (C) 2018-2023 Free Software Foundation, Inc.
+   Contributed by Arm Ltd.
+
+   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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NAT_AARCH64_SCALABLE_LINUX_SIGCONTEXT_H
+#define NAT_AARCH64_SCALABLE_LINUX_SIGCONTEXT_H
+
+#define SVE_MAGIC      0x53564501
+
+struct sve_context {
+       struct _aarch64_ctx head;
+       __u16 vl;
+       __u16 __reserved[3];
+};
+
+/*
+ * The SVE architecture leaves space for future expansion of the
+ * vector length beyond its initial architectural limit of 2048 bits
+ * (16 quadwords).
+ *
+ * See linux/Documentation/arm64/sve.txt for a description of the VL/VQ
+ * terminology.
+ */
+#define SVE_VQ_BYTES           16      /* number of bytes per quadword */
+
+#define SVE_VQ_MIN             1
+#define SVE_VQ_MAX             512
+
+#define SVE_VL_MIN             (SVE_VQ_MIN * SVE_VQ_BYTES)
+#define SVE_VL_MAX             (SVE_VQ_MAX * SVE_VQ_BYTES)
+
+#define SVE_NUM_ZREGS          32
+#define SVE_NUM_PREGS          16
+
+#define sve_vl_valid(vl) \
+       ((vl) % SVE_VQ_BYTES == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX)
+
+/*
+ * If the SVE registers are currently live for the thread at signal delivery,
+ * sve_context.head.size >=
+ *     SVE_SIG_CONTEXT_SIZE(sve_vq_from_vl(sve_context.vl))
+ * and the register data may be accessed using the SVE_SIG_*() macros.
+ *
+ * If sve_context.head.size <
+ *     SVE_SIG_CONTEXT_SIZE(sve_vq_from_vl(sve_context.vl)),
+ * the SVE registers were not live for the thread and no register data
+ * is included: in this case, the SVE_SIG_*() macros should not be
+ * used except for this check.
+ *
+ * The same convention applies when returning from a signal: a caller
+ * will need to remove or resize the sve_context block if it wants to
+ * make the SVE registers live when they were previously non-live or
+ * vice-versa.  This may require the caller to allocate fresh
+ * memory and/or move other context blocks in the signal frame.
+ *
+ * Changing the vector length during signal return is not permitted:
+ * sve_context.vl must equal the thread's current vector length when
+ * doing a sigreturn.
+ *
+ *
+ * Note: for all these macros, the "vq" argument denotes the SVE
+ * vector length in quadwords (i.e., units of 128 bits).
+ *
+ * The correct way to obtain vq is to use sve_vq_from_vl(vl).  The
+ * result is valid if and only if sve_vl_valid(vl) is true.  This is
+ * guaranteed for a struct sve_context written by the kernel.
+ *
+ *
+ * Additional macros describe the contents and layout of the payload.
+ * For each, SVE_SIG_x_OFFSET(args) is the start offset relative to
+ * the start of struct sve_context, and SVE_SIG_x_SIZE(args) is the
+ * size in bytes:
+ *
+ *     x       type                            description
+ *     -       ----                            -----------
+ *     REGS                                    the entire SVE context
+ *
+ *     ZREGS   __uint128_t[SVE_NUM_ZREGS][vq]  all Z-registers
+ *     ZREG    __uint128_t[vq]                 individual Z-register Zn
+ *
+ *     PREGS   uint16_t[SVE_NUM_PREGS][vq]     all P-registers
+ *     PREG    uint16_t[vq]                    individual P-register Pn
+ *
+ *     FFR     uint16_t[vq]                    first-fault status register
+ *
+ * Additional data might be appended in the future.
+ */
+
+#define SVE_SIG_ZREG_SIZE(vq)  ((__u32)(vq) * SVE_VQ_BYTES)
+#define SVE_SIG_PREG_SIZE(vq)  ((__u32)(vq) * (SVE_VQ_BYTES / 8))
+#define SVE_SIG_FFR_SIZE(vq)   SVE_SIG_PREG_SIZE(vq)
+
+#define SVE_SIG_REGS_OFFSET                                    \
+       ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1))      \
+               / SVE_VQ_BYTES * SVE_VQ_BYTES)
+
+#define SVE_SIG_ZREGS_OFFSET   SVE_SIG_REGS_OFFSET
+#define SVE_SIG_ZREG_OFFSET(vq, n) \
+       (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n))
+#define SVE_SIG_ZREGS_SIZE(vq) \
+       (SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET)
+
+#define SVE_SIG_PREGS_OFFSET(vq) \
+       (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq))
+#define SVE_SIG_PREG_OFFSET(vq, n) \
+       (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n))
+#define SVE_SIG_PREGS_SIZE(vq) \
+       (SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq))
+
+#define SVE_SIG_FFR_OFFSET(vq) \
+       (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq))
+
+#define SVE_SIG_REGS_SIZE(vq) \
+       (SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET)
+
+#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq))
+
+/* SVE/FP/SIMD state (NT_ARM_SVE) */
+
+struct user_sve_header {
+       __u32 size; /* total meaningful regset content in bytes */
+       __u32 max_size; /* maximum possible size for this thread */
+       __u16 vl; /* current vector length */
+       __u16 max_vl; /* maximum possible vector length */
+       __u16 flags;
+       __u16 __reserved;
+};
+
+/* Definitions for user_sve_header.flags: */
+#define SVE_PT_REGS_MASK               (1 << 0)
+
+#define SVE_PT_REGS_FPSIMD             0
+#define SVE_PT_REGS_SVE                        SVE_PT_REGS_MASK
+
+/*
+ * Common SVE_PT_* flags:
+ * These must be kept in sync with prctl interface in <linux/ptrace.h>
+ */
+#define SVE_PT_VL_INHERIT              (PR_SVE_VL_INHERIT >> 16)
+#define SVE_PT_VL_ONEXEC               (PR_SVE_SET_VL_ONEXEC >> 16)
+
+
+/*
+ * The remainder of the SVE state follows struct user_sve_header.  The
+ * total size of the SVE state (including header) depends on the
+ * metadata in the header:  SVE_PT_SIZE(vq, flags) gives the total size
+ * of the state in bytes, including the header.
+ *
+ * Refer to <asm/sigcontext.h> for details of how to pass the correct
+ * "vq" argument to these macros.
+ */
+
+/* Offset from the start of struct user_sve_header to the register data */
+#define SVE_PT_REGS_OFFSET                                     \
+       ((sizeof(struct user_sve_header) + (SVE_VQ_BYTES - 1))  \
+               / SVE_VQ_BYTES * SVE_VQ_BYTES)
+
+/*
+ * The register data content and layout depends on the value of the
+ * flags field.
+ */
+
+/*
+ * (flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD case:
+ *
+ * The payload starts at offset SVE_PT_FPSIMD_OFFSET, and is of type
+ * struct user_fpsimd_state.  Additional data might be appended in the
+ * future: use SVE_PT_FPSIMD_SIZE(vq, flags) to compute the total size.
+ * SVE_PT_FPSIMD_SIZE(vq, flags) will never be less than
+ * sizeof(struct user_fpsimd_state).
+ */
+
+#define SVE_PT_FPSIMD_OFFSET           SVE_PT_REGS_OFFSET
+
+#define SVE_PT_FPSIMD_SIZE(vq, flags)  (sizeof(struct user_fpsimd_state))
+
+/*
+ * (flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE case:
+ *
+ * The payload starts at offset SVE_PT_SVE_OFFSET, and is of size
+ * SVE_PT_SVE_SIZE(vq, flags).
+ *
+ * Additional macros describe the contents and layout of the payload.
+ * For each, SVE_PT_SVE_x_OFFSET(args) is the start offset relative to
+ * the start of struct user_sve_header, and SVE_PT_SVE_x_SIZE(args) is
+ * the size in bytes:
+ *
+ *     x       type                            description
+ *     -       ----                            -----------
+ *     ZREGS           \
+ *     ZREG            |
+ *     PREGS           | refer to <asm/sigcontext.h>
+ *     PREG            |
+ *     FFR             /
+ *
+ *     FPSR    uint32_t                        FPSR
+ *     FPCR    uint32_t                        FPCR
+ *
+ * Additional data might be appended in the future.
+ */
+
+#define SVE_PT_SVE_ZREG_SIZE(vq)       SVE_SIG_ZREG_SIZE(vq)
+#define SVE_PT_SVE_PREG_SIZE(vq)       SVE_SIG_PREG_SIZE(vq)
+#define SVE_PT_SVE_FFR_SIZE(vq)                SVE_SIG_FFR_SIZE(vq)
+#define SVE_PT_SVE_FPSR_SIZE           sizeof(__u32)
+#define SVE_PT_SVE_FPCR_SIZE           sizeof(__u32)
+
+#define __SVE_SIG_TO_PT(offset) \
+       ((offset) - SVE_SIG_REGS_OFFSET + SVE_PT_REGS_OFFSET)
+
+#define SVE_PT_SVE_OFFSET              SVE_PT_REGS_OFFSET
+
+#define SVE_PT_SVE_ZREGS_OFFSET \
+       __SVE_SIG_TO_PT(SVE_SIG_ZREGS_OFFSET)
+#define SVE_PT_SVE_ZREG_OFFSET(vq, n) \
+       __SVE_SIG_TO_PT(SVE_SIG_ZREG_OFFSET(vq, n))
+#define SVE_PT_SVE_ZREGS_SIZE(vq) \
+       (SVE_PT_SVE_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_PT_SVE_ZREGS_OFFSET)
+
+#define SVE_PT_SVE_PREGS_OFFSET(vq) \
+       __SVE_SIG_TO_PT(SVE_SIG_PREGS_OFFSET(vq))
+#define SVE_PT_SVE_PREG_OFFSET(vq, n) \
+       __SVE_SIG_TO_PT(SVE_SIG_PREG_OFFSET(vq, n))
+#define SVE_PT_SVE_PREGS_SIZE(vq) \
+       (SVE_PT_SVE_PREG_OFFSET(vq, SVE_NUM_PREGS) - \
+               SVE_PT_SVE_PREGS_OFFSET(vq))
+
+#define SVE_PT_SVE_FFR_OFFSET(vq) \
+       __SVE_SIG_TO_PT(SVE_SIG_FFR_OFFSET(vq))
+
+#define SVE_PT_SVE_FPSR_OFFSET(vq)                             \
+       ((SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq) + \
+                       (SVE_VQ_BYTES - 1))                     \
+               / SVE_VQ_BYTES * SVE_VQ_BYTES)
+#define SVE_PT_SVE_FPCR_OFFSET(vq) \
+       (SVE_PT_SVE_FPSR_OFFSET(vq) + SVE_PT_SVE_FPSR_SIZE)
+
+/*
+ * Any future extension appended after FPCR must be aligned to the next
+ * 128-bit boundary.
+ */
+
+#define SVE_PT_SVE_SIZE(vq, flags)                                     \
+       ((SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE             \
+                       - SVE_PT_SVE_OFFSET + (SVE_VQ_BYTES - 1))       \
+               / SVE_VQ_BYTES * SVE_VQ_BYTES)
+
+#define SVE_PT_SIZE(vq, flags)                                         \
+        (((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ?             \
+                 SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags)        \
+               : SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags))
+
+#endif /* NAT_AARCH64_SCALABLE_LINUX_SIGCONTEXT_H */
diff --git a/gdb/nat/aarch64-sve-linux-ptrace.c b/gdb/nat/aarch64-sve-linux-ptrace.c
deleted file mode 100644 (file)
index 5114653..0000000
+++ /dev/null
@@ -1,392 +0,0 @@
-/* Common target dependent for AArch64 systems.
-
-   Copyright (C) 2018-2023 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 3 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, see <http://www.gnu.org/licenses/>.  */
-
-#include <sys/utsname.h>
-#include <sys/uio.h>
-#include "gdbsupport/common-defs.h"
-#include "elf/external.h"
-#include "elf/common.h"
-#include "aarch64-sve-linux-ptrace.h"
-#include "arch/aarch64.h"
-#include "gdbsupport/common-regcache.h"
-#include "gdbsupport/byte-vector.h"
-#include <endian.h>
-
-/* See nat/aarch64-sve-linux-ptrace.h.  */
-
-uint64_t
-aarch64_sve_get_vq (int tid)
-{
-  struct iovec iovec;
-  struct user_sve_header header;
-
-  iovec.iov_len = sizeof (header);
-  iovec.iov_base = &header;
-
-  /* Ptrace gives the vector length in bytes.  Convert it to VQ, the number of
-     128bit chunks in a Z register.  We use VQ because 128bits is the minimum
-     a Z register can increase in size.  */
-
-  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
-    {
-      /* SVE is not supported.  */
-      return 0;
-    }
-
-  uint64_t vq = sve_vq_from_vl (header.vl);
-
-  if (!sve_vl_valid (header.vl))
-    {
-      warning (_("Invalid SVE state from kernel; SVE disabled."));
-      return 0;
-    }
-
-  return vq;
-}
-
-/* See nat/aarch64-sve-linux-ptrace.h.  */
-
-bool
-aarch64_sve_set_vq (int tid, uint64_t vq)
-{
-  struct iovec iovec;
-  struct user_sve_header header;
-
-  iovec.iov_len = sizeof (header);
-  iovec.iov_base = &header;
-
-  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
-    {
-      /* SVE is not supported.  */
-      return false;
-    }
-
-  header.vl = sve_vl_from_vq (vq);
-
-  if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
-    {
-      /* Vector length change failed.  */
-      return false;
-    }
-
-  return true;
-}
-
-/* See nat/aarch64-sve-linux-ptrace.h.  */
-
-bool
-aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf)
-{
-  uint64_t reg_vg = 0;
-
-  /* The VG register may not be valid if we've not collected any value yet.
-     This can happen, for example,  if we're restoring the regcache after an
-     inferior function call, and the VG register comes after the Z
-     registers.  */
-  if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
-    {
-      /* If vg is not available yet, fetch it from ptrace.  The VG value from
-        ptrace is likely the correct one.  */
-      uint64_t vq = aarch64_sve_get_vq (tid);
-
-      /* If something went wrong, just bail out.  */
-      if (vq == 0)
-       return false;
-
-      reg_vg = sve_vg_from_vq (vq);
-    }
-  else
-    reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &reg_vg);
-
-  return aarch64_sve_set_vq (tid, sve_vq_from_vg (reg_vg));
-}
-
-/* See nat/aarch64-sve-linux-ptrace.h.  */
-
-std::unique_ptr<gdb_byte[]>
-aarch64_sve_get_sveregs (int tid)
-{
-  struct iovec iovec;
-  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;
-}
-
-/* If we are running in BE mode, byteswap the contents
-   of SRC to DST for SIZE bytes.  Other, just copy the contents
-   from SRC to DST.  */
-
-static void
-aarch64_maybe_swab128 (gdb_byte *dst, const gdb_byte *src, size_t size)
-{
-  gdb_assert (src != nullptr && dst != nullptr);
-  gdb_assert (size > 1);
-
-#if (__BYTE_ORDER == __BIG_ENDIAN)
-  for (int i = 0; i < size - 1; i++)
-    dst[i] = src[size - i];
-#else
-  memcpy (dst, src, size);
-#endif
-}
-
-/* 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 = sve_vq_from_vl (header->vl);
-  uint64_t vg = sve_vg_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."));
-
-  /* Update VG.  Note, the registers in the regcache will already be of the
-     correct length.  */
-  reg_buf->raw_supply (AARCH64_SVE_VG_REGNUM, &vg);
-
-  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
-    {
-      /* WARNING: SIMD state is laid out in memory in target-endian format,
-        while SVE state is laid out in an endianness-independent format (LE).
-
-        So we have a couple cases to consider:
-
-        1 - If the target is big endian, then SIMD state is big endian,
-        requiring a byteswap.
-
-        2 - If the target is little endian, then SIMD state is little endian,
-        which matches the SVE format, so no byteswap is needed. */
-
-      /* 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.  */
-
-      gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
-      struct user_fpsimd_state *fpsimd
-       = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
-
-      /* Make sure we have a zeroed register buffer.  We will need the zero
-        padding below.  */
-      memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
-
-      /* Copy across the V registers from fpsimd structure to the Z registers,
-        ensuring the non overlapping state is set to null.  */
-
-      for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
-       {
-         /* Handle big endian/little endian SIMD/SVE conversion.  */
-         aarch64_maybe_swab128 (reg, (const gdb_byte *) &fpsimd->vregs[i],
-                                V_REGISTER_SIZE);
-         reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, reg);
-       }
-
-      reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
-      reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
-
-      /* Clear the SVE only registers.  */
-      memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
-
-      for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
-       reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, reg);
-
-      reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, 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 = 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 (!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;
-      gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
-      struct user_fpsimd_state *fpsimd
-       = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
-
-      memset (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,
-                                                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,
-                                                  reg, 0);
-           if (has_sve_state)
-             break;
-         }
-
-      if (!has_sve_state)
-         has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM,
-                                                reg, 0);
-
-      /* If no SVE state exists, then use the existing fpsimd structure to
-        write out state and return.  */
-      if (!has_sve_state)
-       {
-         /* WARNING: SIMD state is laid out in memory in target-endian format,
-            while SVE state is laid out in an endianness-independent format
-            (LE).
-
-            So we have a couple cases to consider:
-
-            1 - If the target is big endian, then SIMD state is big endian,
-            requiring a byteswap.
-
-            2 - If the target is little endian, then SIMD state is little
-            endian, which matches the SVE format, so no byteswap is needed. */
-
-         /* 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, reg);
-                 /* Handle big endian/little endian SIMD/SVE conversion.  */
-                 aarch64_maybe_swab128 ((gdb_byte *) &fpsimd->vregs[i], reg,
-                                        V_REGISTER_SIZE);
-               }
-           }
-
-         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
deleted file mode 100644 (file)
index 9539e19..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Common target dependent for AArch64 systems.
-
-   Copyright (C) 2018-2023 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 3 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, see <http://www.gnu.org/licenses/>.  */
-
-#ifndef NAT_AARCH64_SVE_LINUX_PTRACE_H
-#define NAT_AARCH64_SVE_LINUX_PTRACE_H
-
-#include <signal.h>
-#include <sys/utsname.h>
-
-/* The order in which <sys/ptrace.h> and <asm/ptrace.h> are included
-   can be important.  <sys/ptrace.h> often declares various PTRACE_*
-   enums.  <asm/ptrace.h> often defines preprocessor constants for
-   these very same symbols.  When that's the case, build errors will
-   result when <asm/ptrace.h> is included before <sys/ptrace.h>.  */
-#include <sys/ptrace.h>
-#include <asm/ptrace.h>
-
-#ifndef SVE_SIG_ZREGS_SIZE
-#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);
-
-/* Set VQ in the kernel for the given tid, using either the value VQ or
-   reading from the register VG in the register buffer.  */
-
-bool aarch64_sve_set_vq (int tid, uint64_t vq);
-bool aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf);
-
-/* 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.  Assumes the
-   vector lengths in the register buffer match the size in the kernel.  */
-
-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.  Assumes the
-   vector lengths in the register buffer match the size in the kernel.  */
-
-extern void
-aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
-                                   void *buf);
-
-#endif /* NAT_AARCH64_SVE_LINUX_PTRACE_H */
diff --git a/gdb/nat/aarch64-sve-linux-sigcontext.h b/gdb/nat/aarch64-sve-linux-sigcontext.h
deleted file mode 100644 (file)
index aba3c15..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-/* Copyright (C) 2018-2023 Free Software Foundation, Inc.
-   Contributed by Arm Ltd.
-
-   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 3 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, see <http://www.gnu.org/licenses/>.  */
-
-#ifndef NAT_AARCH64_SVE_LINUX_SIGCONTEXT_H
-#define NAT_AARCH64_SVE_LINUX_SIGCONTEXT_H
-
-#define SVE_MAGIC      0x53564501
-
-struct sve_context {
-       struct _aarch64_ctx head;
-       __u16 vl;
-       __u16 __reserved[3];
-};
-
-/*
- * The SVE architecture leaves space for future expansion of the
- * vector length beyond its initial architectural limit of 2048 bits
- * (16 quadwords).
- *
- * See linux/Documentation/arm64/sve.txt for a description of the VL/VQ
- * terminology.
- */
-#define SVE_VQ_BYTES           16      /* number of bytes per quadword */
-
-#define SVE_VQ_MIN             1
-#define SVE_VQ_MAX             512
-
-#define SVE_VL_MIN             (SVE_VQ_MIN * SVE_VQ_BYTES)
-#define SVE_VL_MAX             (SVE_VQ_MAX * SVE_VQ_BYTES)
-
-#define SVE_NUM_ZREGS          32
-#define SVE_NUM_PREGS          16
-
-#define sve_vl_valid(vl) \
-       ((vl) % SVE_VQ_BYTES == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX)
-
-/*
- * If the SVE registers are currently live for the thread at signal delivery,
- * sve_context.head.size >=
- *     SVE_SIG_CONTEXT_SIZE(sve_vq_from_vl(sve_context.vl))
- * and the register data may be accessed using the SVE_SIG_*() macros.
- *
- * If sve_context.head.size <
- *     SVE_SIG_CONTEXT_SIZE(sve_vq_from_vl(sve_context.vl)),
- * the SVE registers were not live for the thread and no register data
- * is included: in this case, the SVE_SIG_*() macros should not be
- * used except for this check.
- *
- * The same convention applies when returning from a signal: a caller
- * will need to remove or resize the sve_context block if it wants to
- * make the SVE registers live when they were previously non-live or
- * vice-versa.  This may require the caller to allocate fresh
- * memory and/or move other context blocks in the signal frame.
- *
- * Changing the vector length during signal return is not permitted:
- * sve_context.vl must equal the thread's current vector length when
- * doing a sigreturn.
- *
- *
- * Note: for all these macros, the "vq" argument denotes the SVE
- * vector length in quadwords (i.e., units of 128 bits).
- *
- * The correct way to obtain vq is to use sve_vq_from_vl(vl).  The
- * result is valid if and only if sve_vl_valid(vl) is true.  This is
- * guaranteed for a struct sve_context written by the kernel.
- *
- *
- * Additional macros describe the contents and layout of the payload.
- * For each, SVE_SIG_x_OFFSET(args) is the start offset relative to
- * the start of struct sve_context, and SVE_SIG_x_SIZE(args) is the
- * size in bytes:
- *
- *     x       type                            description
- *     -       ----                            -----------
- *     REGS                                    the entire SVE context
- *
- *     ZREGS   __uint128_t[SVE_NUM_ZREGS][vq]  all Z-registers
- *     ZREG    __uint128_t[vq]                 individual Z-register Zn
- *
- *     PREGS   uint16_t[SVE_NUM_PREGS][vq]     all P-registers
- *     PREG    uint16_t[vq]                    individual P-register Pn
- *
- *     FFR     uint16_t[vq]                    first-fault status register
- *
- * Additional data might be appended in the future.
- */
-
-#define SVE_SIG_ZREG_SIZE(vq)  ((__u32)(vq) * SVE_VQ_BYTES)
-#define SVE_SIG_PREG_SIZE(vq)  ((__u32)(vq) * (SVE_VQ_BYTES / 8))
-#define SVE_SIG_FFR_SIZE(vq)   SVE_SIG_PREG_SIZE(vq)
-
-#define SVE_SIG_REGS_OFFSET                                    \
-       ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1))      \
-               / SVE_VQ_BYTES * SVE_VQ_BYTES)
-
-#define SVE_SIG_ZREGS_OFFSET   SVE_SIG_REGS_OFFSET
-#define SVE_SIG_ZREG_OFFSET(vq, n) \
-       (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n))
-#define SVE_SIG_ZREGS_SIZE(vq) \
-       (SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET)
-
-#define SVE_SIG_PREGS_OFFSET(vq) \
-       (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq))
-#define SVE_SIG_PREG_OFFSET(vq, n) \
-       (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n))
-#define SVE_SIG_PREGS_SIZE(vq) \
-       (SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq))
-
-#define SVE_SIG_FFR_OFFSET(vq) \
-       (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq))
-
-#define SVE_SIG_REGS_SIZE(vq) \
-       (SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET)
-
-#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq))
-
-/* SVE/FP/SIMD state (NT_ARM_SVE) */
-
-struct user_sve_header {
-       __u32 size; /* total meaningful regset content in bytes */
-       __u32 max_size; /* maximum possible size for this thread */
-       __u16 vl; /* current vector length */
-       __u16 max_vl; /* maximum possible vector length */
-       __u16 flags;
-       __u16 __reserved;
-};
-
-/* Definitions for user_sve_header.flags: */
-#define SVE_PT_REGS_MASK               (1 << 0)
-
-#define SVE_PT_REGS_FPSIMD             0
-#define SVE_PT_REGS_SVE                        SVE_PT_REGS_MASK
-
-/*
- * Common SVE_PT_* flags:
- * These must be kept in sync with prctl interface in <linux/ptrace.h>
- */
-#define SVE_PT_VL_INHERIT              (PR_SVE_VL_INHERIT >> 16)
-#define SVE_PT_VL_ONEXEC               (PR_SVE_SET_VL_ONEXEC >> 16)
-
-
-/*
- * The remainder of the SVE state follows struct user_sve_header.  The
- * total size of the SVE state (including header) depends on the
- * metadata in the header:  SVE_PT_SIZE(vq, flags) gives the total size
- * of the state in bytes, including the header.
- *
- * Refer to <asm/sigcontext.h> for details of how to pass the correct
- * "vq" argument to these macros.
- */
-
-/* Offset from the start of struct user_sve_header to the register data */
-#define SVE_PT_REGS_OFFSET                                     \
-       ((sizeof(struct user_sve_header) + (SVE_VQ_BYTES - 1))  \
-               / SVE_VQ_BYTES * SVE_VQ_BYTES)
-
-/*
- * The register data content and layout depends on the value of the
- * flags field.
- */
-
-/*
- * (flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD case:
- *
- * The payload starts at offset SVE_PT_FPSIMD_OFFSET, and is of type
- * struct user_fpsimd_state.  Additional data might be appended in the
- * future: use SVE_PT_FPSIMD_SIZE(vq, flags) to compute the total size.
- * SVE_PT_FPSIMD_SIZE(vq, flags) will never be less than
- * sizeof(struct user_fpsimd_state).
- */
-
-#define SVE_PT_FPSIMD_OFFSET           SVE_PT_REGS_OFFSET
-
-#define SVE_PT_FPSIMD_SIZE(vq, flags)  (sizeof(struct user_fpsimd_state))
-
-/*
- * (flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE case:
- *
- * The payload starts at offset SVE_PT_SVE_OFFSET, and is of size
- * SVE_PT_SVE_SIZE(vq, flags).
- *
- * Additional macros describe the contents and layout of the payload.
- * For each, SVE_PT_SVE_x_OFFSET(args) is the start offset relative to
- * the start of struct user_sve_header, and SVE_PT_SVE_x_SIZE(args) is
- * the size in bytes:
- *
- *     x       type                            description
- *     -       ----                            -----------
- *     ZREGS           \
- *     ZREG            |
- *     PREGS           | refer to <asm/sigcontext.h>
- *     PREG            |
- *     FFR             /
- *
- *     FPSR    uint32_t                        FPSR
- *     FPCR    uint32_t                        FPCR
- *
- * Additional data might be appended in the future.
- */
-
-#define SVE_PT_SVE_ZREG_SIZE(vq)       SVE_SIG_ZREG_SIZE(vq)
-#define SVE_PT_SVE_PREG_SIZE(vq)       SVE_SIG_PREG_SIZE(vq)
-#define SVE_PT_SVE_FFR_SIZE(vq)                SVE_SIG_FFR_SIZE(vq)
-#define SVE_PT_SVE_FPSR_SIZE           sizeof(__u32)
-#define SVE_PT_SVE_FPCR_SIZE           sizeof(__u32)
-
-#define __SVE_SIG_TO_PT(offset) \
-       ((offset) - SVE_SIG_REGS_OFFSET + SVE_PT_REGS_OFFSET)
-
-#define SVE_PT_SVE_OFFSET              SVE_PT_REGS_OFFSET
-
-#define SVE_PT_SVE_ZREGS_OFFSET \
-       __SVE_SIG_TO_PT(SVE_SIG_ZREGS_OFFSET)
-#define SVE_PT_SVE_ZREG_OFFSET(vq, n) \
-       __SVE_SIG_TO_PT(SVE_SIG_ZREG_OFFSET(vq, n))
-#define SVE_PT_SVE_ZREGS_SIZE(vq) \
-       (SVE_PT_SVE_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_PT_SVE_ZREGS_OFFSET)
-
-#define SVE_PT_SVE_PREGS_OFFSET(vq) \
-       __SVE_SIG_TO_PT(SVE_SIG_PREGS_OFFSET(vq))
-#define SVE_PT_SVE_PREG_OFFSET(vq, n) \
-       __SVE_SIG_TO_PT(SVE_SIG_PREG_OFFSET(vq, n))
-#define SVE_PT_SVE_PREGS_SIZE(vq) \
-       (SVE_PT_SVE_PREG_OFFSET(vq, SVE_NUM_PREGS) - \
-               SVE_PT_SVE_PREGS_OFFSET(vq))
-
-#define SVE_PT_SVE_FFR_OFFSET(vq) \
-       __SVE_SIG_TO_PT(SVE_SIG_FFR_OFFSET(vq))
-
-#define SVE_PT_SVE_FPSR_OFFSET(vq)                             \
-       ((SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq) + \
-                       (SVE_VQ_BYTES - 1))                     \
-               / SVE_VQ_BYTES * SVE_VQ_BYTES)
-#define SVE_PT_SVE_FPCR_OFFSET(vq) \
-       (SVE_PT_SVE_FPSR_OFFSET(vq) + SVE_PT_SVE_FPSR_SIZE)
-
-/*
- * Any future extension appended after FPCR must be aligned to the next
- * 128-bit boundary.
- */
-
-#define SVE_PT_SVE_SIZE(vq, flags)                                     \
-       ((SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE             \
-                       - SVE_PT_SVE_OFFSET + (SVE_VQ_BYTES - 1))       \
-               / SVE_VQ_BYTES * SVE_VQ_BYTES)
-
-#define SVE_PT_SIZE(vq, flags)                                         \
-        (((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ?             \
-                 SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags)        \
-               : SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags))
-
-#endif /* NAT_AARCH64_SVE_LINUX_SIGCONTEXT_H */
index 39cb9e7a1512379510736a86e1ac96107f658ceb..b597515d428d7ff94dbcabe1afc062be00eaa61c 100644 (file)
@@ -218,7 +218,7 @@ SFILES = \
        $(srcdir)/../gdb/arch/ppc-linux-common.c \
        $(srcdir)/../gdb/arch/riscv.c \
        $(srcdir)/../gdb/nat/aarch64-mte-linux-ptrace.c \
-       $(srcdir)/../gdb/nat/aarch64-sve-linux-ptrace.c \
+       $(srcdir)/../gdb/nat/aarch64-scalable-linux-ptrace.c \
        $(srcdir)/../gdb/nat/linux-btrace.c \
        $(srcdir)/../gdb/nat/linux-namespaces.c \
        $(srcdir)/../gdb/nat/linux-osdata.c \
index 72256f828716dcfe4acc9c9689607f55325f7b26..7a7575ac43b793024234a08ea84d85b301bdf199 100644 (file)
@@ -51,7 +51,7 @@ case "${gdbserver_host}" in
                        srv_tgtobj="$srv_tgtobj arch/aarch64-mte-linux.o"
                        srv_tgtobj="$srv_tgtobj linux-aarch64-tdesc.o"
                        srv_tgtobj="$srv_tgtobj nat/aarch64-mte-linux-ptrace.o"
-                       srv_tgtobj="$srv_tgtobj nat/aarch64-sve-linux-ptrace.o"
+                       srv_tgtobj="$srv_tgtobj nat/aarch64-scalable-linux-ptrace.o"
                        srv_tgtobj="${srv_tgtobj} $srv_linux_obj"
                        srv_linux_regsets=yes
                        srv_linux_thread_db=yes
index 2474a000ea301c459e03a50100622ed0ecd4f5f2..8b22f1979d61e5bf0cc52c6c875a9e88fd38c07f 100644 (file)
@@ -44,7 +44,7 @@
 #include "linux-aarch32-tdesc.h"
 #include "linux-aarch64-tdesc.h"
 #include "nat/aarch64-mte-linux-ptrace.h"
-#include "nat/aarch64-sve-linux-ptrace.h"
+#include "nat/aarch64-scalable-linux-ptrace.h"
 #include "tdesc.h"
 
 #ifdef HAVE_SYS_REG_H