From 4da037ef9dba6c17089250d228efdbe6f7d830c9 Mon Sep 17 00:00:00 2001 From: Alan Hayward Date: Mon, 15 Apr 2019 12:29:40 +0100 Subject: [PATCH] AArch64 SVE: Check for vector length change when getting gdbarch 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 = {623191333, 623191333, 623191333, 623191333, 0 } (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 = {623191333, 623191333, 623191333, 623191333, 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 = {623191333, 623191333, 623191333, 623191333, 0 } 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 | 7 +++++++ gdb/aarch64-linux-nat.c | 31 +++++++++++++++++++++++++++++++ gdb/aarch64-tdep.c | 26 +++++++++++++++++++++----- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 02e8feaca7..b3155ad744 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2019-04-15 Alan Hayward + + * 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 * aarch64-tdep.c (aarch64_gdbarch_init): Move gdbarch lookup. diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index 6d43eb7070..c5070c8590 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -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 diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index ea3f5ec542..cb185ee337 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -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; -- 2.34.1