summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 209bc256f35..6f0f5c69168 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -2971,7 +2971,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. */
@@ -2979,7 +3003,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 69e7d93c87e..a54bd014a49 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7689,9 +7689,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 087de141f7f..a56a38ad97d 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