AArch64 SVE: Check for vector length change when getting gdbarch
authorAlan Hayward <alan.hayward@arm.com>
Mon, 15 Apr 2019 11:29:40 +0000 (12:29 +0100)
committerAlan Hayward <alan.hayward@arm.com>
Mon, 15 Apr 2019 14:12:43 +0000 (15:12 +0100)
Override the thread_architecture method, similar to SPU.  If the vector
length has changed, then find the arch using info, making sure the vector
length is passed down to the init routine.

In the init routine, ensure the arch has the correct vector length.

Example output. Program is stopped in thread 2, just before it calls prctl
to change the vector length

(gdb) info threads
  Id   Target Id                                     Frame
  1    Thread 0xffffbf6f4000 (LWP 3188) "sve_change" 0x0000ffffbf6ae130 in pthread_join ()
* 2    Thread 0xffffbf55e200 (LWP 3189) "sve_change" thread1 (arg=0xfeedface) at sve_change_size.c:28
(gdb) print $vg
$1 = 8
(gdb) print $z0.s.u
$2 = {623191333623191333623191333623191333, 0 <repeats 12 times>}
(gdb) n
29   int ret = prctl(PR_SVE_SET_VL, vl/2);
(gdb) n
30   printf ("Changed: ret\n", ret);
(gdb) print $vg
$4 = 4
(gdb) print $z0.s.u
$5 = {623191333623191333623191333623191333, 0, 0, 0, 0}
(gdb) thr 1
[Switching to thread 1 (Thread 0xffffbf6f4000 (LWP 3181))]
(gdb) print $vg
$6 = 8
(gdb) print $z0.s.u
$7 = {623191333623191333623191333623191333, 0 <repeats 12 times>}

gdb/ChangeLog:

* aarch64-linux-nat.c
(aarch64_linux_nat_target::thread_architecture): Add override.
* aarch64-tdep.c (aarch64_gdbarch_init): Ensure different tdesc for
each VQ.

gdb/ChangeLog
gdb/aarch64-linux-nat.c
gdb/aarch64-tdep.c

index 02e8feaca73df32359f9da969206f1c08ff59624..b3155ad744394d3bd4bc5ad7133ef21e4aeff8bc 100644 (file)
@@ -1,3 +1,10 @@
+2019-04-15  Alan Hayward  <alan.hayward@arm.com>
+
+       * aarch64-linux-nat.c
+       (aarch64_linux_nat_target::thread_architecture): Add override.
+       * aarch64-tdep.c (aarch64_gdbarch_init): Ensure different tdesc for
+       each VQ.
+
 2019-04-15  Alan Hayward  <alan.hayward@arm.com>
 
        * aarch64-tdep.c (aarch64_gdbarch_init): Move gdbarch lookup.
index 6d43eb7070f17768f324fe950bc7a0f278d190d8..c5070c8590d12f7cfe6ce0baa6497d5123a39074 100644 (file)
@@ -46,6 +46,7 @@
 
 /* Defines ps_err_e, struct ps_prochandle.  */
 #include "gdb_proc_service.h"
+#include "arch-utils.h"
 
 #ifndef TRAP_HWBKPT
 #define TRAP_HWBKPT 0x0004
@@ -95,6 +96,8 @@ public:
   /* Add our siginfo layout converter.  */
   bool low_siginfo_fixup (siginfo_t *ptrace, gdb_byte *inf, int direction)
     override;
+
+  struct gdbarch *thread_architecture (ptid_t) override;
 };
 
 static aarch64_linux_nat_target the_aarch64_linux_nat_target;
@@ -939,6 +942,34 @@ aarch64_linux_nat_target::can_do_single_step ()
   return 1;
 }
 
+/* Implement the "thread_architecture" target_ops method.  */
+
+struct gdbarch *
+aarch64_linux_nat_target::thread_architecture (ptid_t ptid)
+{
+  /* Return the gdbarch for the current thread.  If the vector length has
+     changed since the last time this was called, then do a further lookup.  */
+
+  uint64_t vq = aarch64_sve_get_vq (ptid.lwp ());
+
+  /* Find the current gdbarch the same way as process_stratum_target.  Only
+     return it if the current vector length matches the one in the tdep.  */
+  inferior *inf = find_inferior_ptid (ptid);
+  gdb_assert (inf != NULL);
+  if (vq == gdbarch_tdep (inf->gdbarch)->vq)
+    return inf->gdbarch;
+
+  /* We reach here if the vector length for the thread is different from its
+     value at process start.  Lookup gdbarch via info (potentially creating a
+     new one), stashing the vector length inside id.  Use -1 for when SVE
+     unavailable, to distinguish from an unset value of 0.  */
+  struct gdbarch_info info;
+  gdbarch_info_init (&info);
+  info.bfd_arch_info = bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu);
+  info.id = (int *) (vq == 0 ? -1 : vq);
+  return gdbarch_find_by_info (info);
+}
+
 /* Define AArch64 maintenance commands.  */
 
 static void
index ea3f5ec5427233a6861b8c95f0672598c6844a90..cb185ee337fe54ff65722a3fc01f2c60200241e0 100644 (file)
@@ -3198,20 +3198,36 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   int i, num_regs = 0, num_pseudo_regs = 0;
   int first_pauth_regnum = -1, pauth_ra_state_offset = -1;
 
+  /* Use the vector length passed via the target info.  Here -1 is used for no
+     SVE, and 0 is unset.  If unset then use the vector length from the existing
+     tdesc.  */
+  uint64_t vq = 0;
+  if (info.id == (int *) -1)
+    vq = 0;
+  else if (info.id != 0)
+    vq = (uint64_t) info.id;
+  else
+    vq = aarch64_get_tdesc_vq (info.target_desc);
+
+  if (vq > AARCH64_MAX_SVE_VQ)
+    internal_error (__FILE__, __LINE__, _("VQ out of bounds: %ld (max %d)"),
+                   vq, AARCH64_MAX_SVE_VQ);
+
   /* If there is already a candidate, use it.  */
   for (gdbarch_list *best_arch = gdbarch_list_lookup_by_info (arches, &info);
        best_arch != nullptr;
        best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
     {
       struct gdbarch_tdep *tdep = gdbarch_tdep (best_arch->gdbarch);
-      if (tdep)
+      if (tdep && tdep->vq == vq)
        return best_arch->gdbarch;
     }
 
-  /* Ensure we always have a target description.  */
+  /* Ensure we always have a target descriptor, and that it is for the given VQ
+     value.  */
   const struct target_desc *tdesc = info.target_desc;
-  if (!tdesc_has_registers (tdesc))
-    tdesc = aarch64_read_description (0, false);
+  if (!tdesc_has_registers (tdesc) || vq != aarch64_get_tdesc_vq (tdesc))
+    tdesc = aarch64_read_description (vq, false);
   gdb_assert (tdesc);
 
   feature_core = tdesc_find_feature (tdesc,"org.gnu.gdb.aarch64.core");
@@ -3304,7 +3320,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->lowest_pc = 0x20;
   tdep->jb_pc = -1;            /* Longjump support not enabled by default.  */
   tdep->jb_elt_size = 8;
-  tdep->vq = aarch64_get_tdesc_vq (tdesc);
+  tdep->vq = vq;
   tdep->pauth_reg_base = first_pauth_regnum;
   tdep->pauth_ra_state_regnum = (feature_pauth == NULL) ? -1
                                : pauth_ra_state_offset + num_regs;