Make get_image_name static
[deliverable/binutils-gdb.git] / gdb / nat / aarch64-sve-linux-ptrace.c
index 635b4c9d68a7f90bd8f5e40efb6117fbb0d57f96..f344f9225d87036f49f342f31c3b8f9de81717d7 100644 (file)
@@ -1,6 +1,6 @@
 /* Common target dependent for AArch64 systems.
 
-   Copyright (C) 2018-2019 Free Software Foundation, Inc.
+   Copyright (C) 2018-2021 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 
 #include <sys/utsname.h>
 #include <sys/uio.h>
-#include "common/common-defs.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 "common/common-regcache.h"
-#include "common/byte-vector.h"
+#include "gdbsupport/common-regcache.h"
+#include "gdbsupport/byte-vector.h"
+#include <endian.h>
 
 /* See nat/aarch64-sve-linux-ptrace.h.  */
 
@@ -92,11 +93,26 @@ aarch64_sve_set_vq (int tid, uint64_t vq)
 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)
-    return false;
+  {
+    /* 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);
 
-  uint64_t reg_vg = 0;
-  reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &reg_vg);
+    /* 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));
 }
@@ -127,6 +143,24 @@ aarch64_sve_get_sveregs (int tid)
   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
@@ -169,34 +203,50 @@ aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common *reg_buf,
     }
   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.  */
 
-      char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
+      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.  */
 
-      memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
-
       for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
        {
-         memcpy (zero_reg, &fpsimd->vregs[i], sizeof (__int128_t));
-         reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
+         /* 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, zero_reg);
+       reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, reg);
 
-      reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, zero_reg);
+      reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, reg);
     }
 }
 
@@ -225,11 +275,11 @@ aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
         kernel, which is why we try to avoid it.  */
 
       bool has_sve_state = false;
-      char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
+      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 (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
+      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.  */
@@ -237,7 +287,7 @@ aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
       for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
        {
          has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i,
-                                                zero_reg, sizeof (__int128_t));
+                                                reg, sizeof (__int128_t));
          if (has_sve_state)
            break;
        }
@@ -246,19 +296,31 @@ aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
        for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
          {
            has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i,
-                                                  zero_reg, 0);
+                                                  reg, 0);
            if (has_sve_state)
              break;
          }
 
       if (!has_sve_state)
          has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM,
-                                                zero_reg, 0);
+                                                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
@@ -269,8 +331,10 @@ aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
              if (REG_VALID
                  == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
                {
-                 reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
-                 memcpy (&fpsimd->vregs[i], zero_reg, sizeof (__int128_t));
+                 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);
                }
            }
 
This page took 0.031877 seconds and 4 git commands to generate.