From 4e2fa31fae673fa415c3f2e5cf47609ae8866fe2 Mon Sep 17 00:00:00 2001 From: Thiago Jung Bauermann Date: Sat, 26 Apr 2025 23:28:10 -0300 Subject: [PATCH] GDB: regcache: Invalidate variable-size registers ... ... if register-based parameter changes. --- gdb/aarch64-tdep.c | 18 ++++++++++++++++++ gdb/arch-utils.c | 7 +++++++ gdb/gdbarch-gen.c | 22 ++++++++++++++++++++++ gdb/gdbarch-gen.h | 8 ++++++++ gdb/gdbarch_components.py | 13 +++++++++++++ gdb/regcache.c | 31 +++++++++++++++++++++++++++++++ gdb/regcache.h | 3 +++ 7 files changed, 102 insertions(+) diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index c119554bb06..b719c8547a2 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -4337,6 +4337,22 @@ aarch64_fetch_tdesc_parameter (gdbarch *gdbarch, readable_regcache *regcache, } } +static bool +aarch64_invalidate_tdesc_parameters (struct gdbarch *gdbarch, int regno, + reg_buffer *regcache) +{ + /* All current AArch64 parameters depend on VG. */ + if (tdesc_num_parameters (gdbarch) == 0 || regno != AARCH64_SVE_VG_REGNUM) + return false; + + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + regcache->invalidate_tdesc_parameter (tdep->param_sve_vector_length); + regcache->invalidate_tdesc_parameter (tdep->param_sve_predicate_length); + + return true; +} + /* Given NAMES, a vector of strings, initialize it with all the SME pseudo-register names for the current streaming vector length. */ @@ -4882,6 +4898,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->param_sve_predicate_length = *param_id; set_gdbarch_fetch_tdesc_parameter (gdbarch, aarch64_fetch_tdesc_parameter); + set_gdbarch_invalidate_tdesc_parameters (gdbarch, + aarch64_invalidate_tdesc_parameters); return gdbarch; } diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 6fe727fa021..2b934acb5fd 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -1145,6 +1145,13 @@ default_register_is_variable_size (struct gdbarch *gdbarch, int regno) return false; } +static bool +default_invalidate_tdesc_parameters (struct gdbarch *gdbarch, int regno, + reg_buffer *regcache) +{ + return false; +} + /* Non-zero if we want to trace architecture code. */ #ifndef GDBARCH_DEBUG diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c index 275145d69a0..ea6371c1cf3 100644 --- a/gdb/gdbarch-gen.c +++ b/gdb/gdbarch-gen.c @@ -264,6 +264,7 @@ struct gdbarch gdbarch_core_parse_exec_context_ftype *core_parse_exec_context = default_core_parse_exec_context; gdbarch_fetch_tdesc_parameter_ftype *fetch_tdesc_parameter = default_fetch_tdesc_parameter; gdbarch_register_is_variable_size_ftype *register_is_variable_size = default_register_is_variable_size; + gdbarch_invalidate_tdesc_parameters_ftype *invalidate_tdesc_parameters = default_invalidate_tdesc_parameters; }; /* Create a new ``struct gdbarch'' based on information provided by @@ -539,6 +540,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of core_parse_exec_context, invalid_p == 0. */ /* Skip verify of fetch_tdesc_parameter, invalid_p == 0. */ /* Skip verify of register_is_variable_size, invalid_p == 0. */ + /* Skip verify of invalidate_tdesc_parameters, invalid_p == 0. */ if (!log.empty ()) internal_error (_("verify_gdbarch: the following are invalid ...%s"), log.c_str ()); @@ -1416,6 +1418,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) gdb_printf (file, "gdbarch_dump: register_is_variable_size = <%s>\n", host_address_to_string (gdbarch->register_is_variable_size)); + gdb_printf (file, + "gdbarch_dump: invalidate_tdesc_parameters = <%s>\n", + host_address_to_string (gdbarch->invalidate_tdesc_parameters)); if (gdbarch->dump_tdep != NULL) gdbarch->dump_tdep (gdbarch, file); } @@ -5595,3 +5600,20 @@ set_gdbarch_register_is_variable_size (struct gdbarch *gdbarch, { gdbarch->register_is_variable_size = register_is_variable_size; } + +bool +gdbarch_invalidate_tdesc_parameters (struct gdbarch *gdbarch, int regno, reg_buffer *regcache) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->invalidate_tdesc_parameters != NULL); + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_invalidate_tdesc_parameters called\n"); + return gdbarch->invalidate_tdesc_parameters (gdbarch, regno, regcache); +} + +void +set_gdbarch_invalidate_tdesc_parameters (struct gdbarch *gdbarch, + gdbarch_invalidate_tdesc_parameters_ftype invalidate_tdesc_parameters) +{ + gdbarch->invalidate_tdesc_parameters = invalidate_tdesc_parameters; +} diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h index d6058da93be..8cc807c32d3 100644 --- a/gdb/gdbarch-gen.h +++ b/gdb/gdbarch-gen.h @@ -1813,3 +1813,11 @@ extern void set_gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch, gdbarch_ typedef bool (gdbarch_register_is_variable_size_ftype) (struct gdbarch *gdbarch, int regno); extern bool gdbarch_register_is_variable_size (struct gdbarch *gdbarch, int regno); extern void set_gdbarch_register_is_variable_size (struct gdbarch *gdbarch, gdbarch_register_is_variable_size_ftype *register_is_variable_size); + +/* Invalidate all target description parameters in REGCACHE which depend on the + value of REGNO. Returns true if any parameter was invalidated, false + otherwise. */ + +typedef bool (gdbarch_invalidate_tdesc_parameters_ftype) (struct gdbarch *gdbarch, int regno, reg_buffer *regcache); +extern bool gdbarch_invalidate_tdesc_parameters (struct gdbarch *gdbarch, int regno, reg_buffer *regcache); +extern void set_gdbarch_invalidate_tdesc_parameters (struct gdbarch *gdbarch, gdbarch_invalidate_tdesc_parameters_ftype *invalidate_tdesc_parameters); diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py index c893d5c941a..a158d85956b 100644 --- a/gdb/gdbarch_components.py +++ b/gdb/gdbarch_components.py @@ -2873,3 +2873,16 @@ Can the size of this register change during runtime? predefault="default_register_is_variable_size", invalid=False, ) + +Method( + comment=""" +Invalidate all target description parameters in REGCACHE which depend on the +value of REGNO. Returns true if any parameter was invalidated, false +otherwise. +""", + type="bool", + name="invalidate_tdesc_parameters", + params=[("int", "regno"), ("reg_buffer *", "regcache")], + predefault="default_invalidate_tdesc_parameters", + invalid=False, +) diff --git a/gdb/regcache.c b/gdb/regcache.c index ce99d4f5979..eff4267fda8 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -394,6 +394,26 @@ reg_buffer::initialize_variable_size_registers () /* See regcache.h. */ +void +reg_buffer::invalidate_variable_size_registers () +{ + /* There's nothing to do if there are already no variable-size register + contents. */ + if (m_variable_size_registers == nullptr) + return; + + for (unsigned int i = 0; i < m_descr->nr_cooked_registers; i++) + if (m_descr->register_is_variable_size[i]) + invalidate (i); + + m_variable_size_registers = nullptr; + m_variable_size_register_type.clear (); + m_variable_size_register_sizeof.clear (); + m_variable_size_register_offset.clear (); +} + +/* See regcache.h. */ + bool reg_buffer::has_variable_size_registers () { @@ -1439,6 +1459,12 @@ reg_buffer::raw_supply (int regnum, gdb::array_view src) if (src.data () != nullptr) { + if (memcmp (src.data (), dst.data (), dst.size ()) + && gdbarch_invalidate_tdesc_parameters (m_descr->gdbarch, regnum, + this)) + /* Invalidate variable-size registers. */ + this->invalidate_variable_size_registers (); + copy (src, dst); m_register_status[regnum] = REG_VALID; } @@ -1472,6 +1498,11 @@ reg_buffer::raw_supply_integer (int regnum, const gdb_byte *addr, int addr_len, gdb::array_view dst = register_buffer (regnum); bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); + if (memcmp (addr, dst.data (), dst.size ()) + && gdbarch_invalidate_tdesc_parameters (m_descr->gdbarch, regnum, this)) + /* Invalidate variable-size registers. */ + this->invalidate_variable_size_registers (); + copy_integer_to_size (dst.data (), dst.size (), addr, addr_len, is_signed, byte_order); m_register_status[regnum] = REG_VALID; diff --git a/gdb/regcache.h b/gdb/regcache.h index f62d67c4f84..7fa40e06e3c 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -293,6 +293,9 @@ protected: reg_buffer. */ void initialize_variable_size_registers (); + /* Reset information about variable-size registers in this reg_buffer. */ + void invalidate_variable_size_registers (); + /* Return a view on register REGNUM's buffer cache. */ template gdb::array_view register_buffer (int regnum) const; -- 2.47.2