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 \
#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"
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)
--- /dev/null
+/* 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, ®_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));
+
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
+++ /dev/null
-/* 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, ®_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));
-
-}
+++ /dev/null
-/* 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 */
+++ /dev/null
-/* 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 */
$(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 \
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
#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