summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Hayward <alan.hayward@arm.com>2018-11-07 15:15:36 +0000
committerAlan Hayward <alan.hayward@arm.com>2018-11-07 15:16:30 +0000
commite8f3f2047b55760c52f786b46780de997a31d002 (patch)
tree6b53906125aad9b7e3e9b6e93af7f52e63faddd1
parent7a9abb2bce8f2f52f7f59927b18582f67a0c3208 (diff)
downloadbinutils-gdb-users/ahayward/variable_sve2.tar.gz
Aarch64 SVE: Support changing vector lengths in gdbserverusers/ahayward/variable_sve2
There are two parts to this patch - gdbserver and GDB. In gdbserver, there needs to be an equivalent of the thread_architecture method used in GDB. In regcache, validate the tdesc with the use target_validate_tdesc target function. If this fails then re-obtain the target descriptor via general setup. The aarch64 validation step simply checks the value of the VG register to see if it matches the current kernel value. In GDB, we have a similar check when receiving a stop reply. Validate the tdesc using gdbarch_target_description_changed_p. If this fails re-obtain the target descriptor via general setup - which is done by setting up an tdep info structure containing the vector length. The aarch64 validation step checks the value of VG (which is marked as an expediated register, so is in the stop reply). 2018-11-07 Alan Hayward <alan.hayward@arm.com> gdb/ * aarch64-tdep.c (aarch64_target_description_changed_p): Check vector length. (aarch64_target_get_tdep_info): Store vector length. * remote.c (remote_target::process_stop_reply): Validate tdesc. * target-descriptions.c (target_find_description): Pass through info. * target-descriptions.h (target_find_description): Add arg. gdbserver/ * linux-aarch64-low.c (aarch64_validate_tdesc): Check vector length. * regcache.c (get_thread_regcache): Validate tdesc.
-rw-r--r--gdb/aarch64-tdep.c42
-rw-r--r--gdb/gdbserver/linux-aarch64-low.c21
-rw-r--r--gdb/gdbserver/regcache.c12
-rw-r--r--gdb/remote.c17
-rw-r--r--gdb/target-descriptions.c9
-rw-r--r--gdb/target-descriptions.h5
6 files changed, 97 insertions, 9 deletions
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 6a5e712afbe..46625d93e82 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -2970,7 +2970,31 @@ aarch64_target_description_changed_p (struct gdbarch *gdbarch,
ptid_t ptid,
VEC (cached_reg_t) *registers)
{
- return false;
+ /* Return true if the VG value in the given VEC of registers list does not
+ match the VG value in the current regcache. */
+
+ cached_reg_t *reg;
+ bool regcache_has_vg = (gdbarch_num_regs (gdbarch) > AARCH64_SVE_VG_REGNUM);
+
+ for (int ix = 0; VEC_iterate (cached_reg_t, registers, ix, reg); ix++)
+ if (reg->num == AARCH64_SVE_VG_REGNUM)
+ {
+ if (!regcache_has_vg)
+ {
+ /* No VG in regcache. */
+ return true;
+ }
+
+ struct regcache *regcache = get_thread_arch_regcache (ptid, gdbarch);
+
+ if (regcache->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
+ return true;
+
+ return !regcache->raw_compare (AARCH64_SVE_VG_REGNUM, reg->data, 0);
+ }
+
+ /* VG is not in the given register list. */
+ return regcache_has_vg;
}
/* Implement the "target_get_tdep_info" gdbarch method. */
@@ -2978,7 +3002,21 @@ aarch64_target_description_changed_p (struct gdbarch *gdbarch,
static union gdbarch_target_info
aarch64_target_get_tdep_info (VEC (cached_reg_t) *registers)
{
- return {0};
+ gdbarch_target_info info = {0};
+
+ /* Use the current VQ value as the tdep info value. */
+
+ cached_reg_t *reg;
+
+ for (int ix = 0; VEC_iterate (cached_reg_t, registers, ix, reg); ix++)
+ if (reg->num == AARCH64_SVE_VG_REGNUM)
+ {
+ uint64_t vg = *(uint64_t *) reg->data;
+ info.id = (int *) sve_vq_from_vg (vg);
+ return info;
+ }
+
+ return info;
}
/* Initialize the current architecture based on INFO. If possible,
diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c
index dcc19ce18c0..6cea4b215ae 100644
--- a/gdb/gdbserver/linux-aarch64-low.c
+++ b/gdb/gdbserver/linux-aarch64-low.c
@@ -3042,7 +3042,26 @@ aarch64_supports_hardware_single_step (void)
static bool
aarch64_validate_tdesc (struct thread_info *thread)
{
- return true;
+ /* For SVE there is a target descriptor for each VL. Read the current vector
+ length and check if it matches the size of a variable register in the
+ current target descriptor. */
+
+ int tid = (ptid_of (thread)).lwp ();
+ long vl = sve_vl_from_vq (aarch64_sve_get_vq (tid));
+ struct regcache *regcache = thread_regcache_data (thread);
+ struct process_info *proc;
+
+ /* Non SVE targets always validate as true. */
+ if (vl == 0)
+ return true;
+
+ /* If there is a register cache, check the z0 register size. */
+ if (regcache)
+ return (register_size (regcache->tdesc, AARCH64_SVE_Z0_REGNUM) == vl);
+
+ /* Otherwise, check the z0 register size in the description. */
+ proc = get_thread_process (thread);
+ return (register_size (proc->tdesc, AARCH64_SVE_Z0_REGNUM) == vl);
}
struct linux_target_ops the_low_target =
diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c
index 0ffec534c36..7b879be9e21 100644
--- a/gdb/gdbserver/regcache.c
+++ b/gdb/gdbserver/regcache.c
@@ -28,6 +28,18 @@ get_thread_regcache (struct thread_info *thread, int fetch)
{
struct regcache *regcache;
+ /* Check the target descriptor is still valid for the current target. If
+ not, then clear it and create a new one. */
+ if (!target_validate_tdesc (thread))
+ {
+ /* Clear regcache. */
+ free_register_cache (thread_regcache_data (thread));
+ set_thread_regcache_data (thread, NULL);
+ regcache = NULL;
+
+ target_arch_setup ();
+ }
+
regcache = thread_regcache_data (thread);
/* Threads' regcaches are created lazily, because biarch targets add
diff --git a/gdb/remote.c b/gdb/remote.c
index c1e95bb2fce..e81b776afcc 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7686,9 +7686,24 @@ remote_target::process_stop_reply (struct stop_reply *stop_reply,
&& status->kind != TARGET_WAITKIND_SIGNALLED
&& status->kind != TARGET_WAITKIND_NO_RESUMED)
{
+ VEC (cached_reg_t) *stop_regs = stop_reply->regcache;
+
/* Expedited registers. */
- if (stop_reply->regcache)
+ if (stop_regs)
{
+ struct gdbarch *gdbarch = target_gdbarch ();
+
+ /* Check the target descriptor is still valid for the current target.
+ If not, then clear it find the correct one. */
+ if (gdbarch_target_description_changed_p (gdbarch, ptid, stop_regs))
+ {
+ gdbarch_target_info info
+ = gdbarch_target_get_tdep_info (gdbarch, stop_regs);
+ registers_changed ();
+ target_clear_description ();
+ target_find_description (info);
+ }
+
struct regcache *regcache
= get_thread_arch_regcache (ptid, stop_reply->arch);
cached_reg_t *reg;
diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c
index bdd29c0f2b5..3d50ed1e544 100644
--- a/gdb/target-descriptions.c
+++ b/gdb/target-descriptions.c
@@ -491,11 +491,12 @@ target_desc_info_free (struct target_desc_info *tdesc_info)
static char *tdesc_filename_cmd_string;
-/* Fetch the current target's description, and switch the current
- architecture to one which incorporates that description. */
+/* Fetch the current inferior's description, and switch its current
+ architecture to one which incorporates that description. If given, use the
+ tdep_info when finding the description. */
void
-target_find_description (void)
+target_find_description (gdbarch_target_info target_info)
{
/* If we've already fetched a description from the target, don't do
it again. This allows a target to fetch the description early,
@@ -534,6 +535,8 @@ target_find_description (void)
gdbarch_info_init (&info);
info.target_desc = current_target_desc;
+ info.target_info = target_info;
+
if (!gdbarch_update_p (info))
warning (_("Architecture rejected target-supplied description"));
else
diff --git a/gdb/target-descriptions.h b/gdb/target-descriptions.h
index 96290b7d97e..1376b02c425 100644
--- a/gdb/target-descriptions.h
+++ b/gdb/target-descriptions.h
@@ -31,9 +31,10 @@ struct target_desc_info;
struct inferior;
/* Fetch the current inferior's description, and switch its current
- architecture to one which incorporates that description. */
+ architecture to one which incorporates that description. If given, use the
+ tdep_info when finding the description. */
-void target_find_description (void);
+void target_find_description (gdbarch_target_info target_info = {0});
/* Discard any description fetched from the target for the current
inferior, and switch the current architecture to one with no target