diff options
-rw-r--r-- | gdb/aarch64-tdep.c | 42 | ||||
-rw-r--r-- | gdb/gdbserver/linux-aarch64-low.c | 21 | ||||
-rw-r--r-- | gdb/gdbserver/regcache.c | 12 | ||||
-rw-r--r-- | gdb/remote.c | 17 | ||||
-rw-r--r-- | gdb/target-descriptions.c | 9 | ||||
-rw-r--r-- | gdb/target-descriptions.h | 5 |
6 files changed, 97 insertions, 9 deletions
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 209bc25..6f0f5c69 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 dcc19ce..6cea4b2 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 0ffec53..7b879be 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 69e7d93..a54bd01 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 087de14..a56a38a 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 96290b7..1376b02 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 |