summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuis Machado <luis.machado@linaro.org>2021-12-15 10:24:35 -0300
committerLuis Machado <luis.machado@linaro.org>2021-12-20 10:54:49 -0300
commit3904c2a5518b6616a4b4b53e3525fa54a6838f16 (patch)
tree22ee74e194ba47447a1ced19b896f65fa089b0c2
parent3f6d78d98442668ff8685864a7599d905412203f (diff)
downloadbinutils-gdb-3904c2a5518b6616a4b4b53e3525fa54a6838f16.tar.gz
Workaround GDBserver register cache management
Given X and C registers have an overlap, if we write to an X register, we need to fetch the C registers again so we get updated values (side effects). The same happens when we attempt to write to the lower half of C registers, we need to fetch the X registers again so we get updated values. This patch forces the register cache to get updated values after a register store request.
-rw-r--r--gdbserver/linux-aarch64-low.cc28
-rw-r--r--gdbserver/regcache.cc7
2 files changed, 35 insertions, 0 deletions
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 85313789ce8..b2c631ae4b0 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -202,12 +202,32 @@ is_sve_tdesc (void)
return tdesc_contains_feature (regcache->tdesc, "org.gnu.gdb.aarch64.sve");
}
+static bool gpr_changed = false;
+
+static bool
+gpr_set_changed (struct regcache *regcache, void *buf)
+{
+ size_t gpr_size = (AARCH64_X_REGS_NUM + 2) * 8 + 4;
+ bool changed
+ = memcmp (regcache->registers, buf, gpr_size) != 0;
+
+ return changed;
+}
+
static void
aarch64_fill_gregset (struct regcache *regcache, void *buf)
{
struct user_pt_regs *regset = (struct user_pt_regs *) buf;
int i;
+ /* Right now, regcache contains the updated contents of the registers.
+ Check if anything has changed in the GPR's. If nothing has changed,
+ don't update anything.
+
+ Otherwise, update the contents. */
+
+ gpr_changed = gpr_set_changed (regcache, buf);
+
for (i = 0; i < AARCH64_X_REGS_NUM; i++)
collect_register (regcache, AARCH64_X0_REGNUM + i, &regset->regs[i]);
collect_register (regcache, AARCH64_SP_REGNUM, &regset->sp);
@@ -275,6 +295,14 @@ aarch64_store_pauthregset (struct regcache *regcache, const void *buf)
static void
aarch64_fill_cregset (struct regcache *regcache, void *buf)
{
+ /* If the GPR's have changed, don't attempt to change the C registers. */
+ if (gpr_changed)
+ {
+ /* Reset the flag. */
+ gpr_changed = false;
+ return;
+ }
+
struct user_morello_state *cregset
= (struct user_morello_state *) buf;
diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc
index add826b2897..c3bcb669a2f 100644
--- a/gdbserver/regcache.cc
+++ b/gdbserver/regcache.cc
@@ -244,6 +244,13 @@ registers_from_string (struct regcache *regcache, char *buf)
len = tdesc->registers_size * 2;
}
hex2bin (buf, registers, len / 2);
+
+ /* Force registers to be written via ptrace requests. This ensures
+ any register write side effects happen correctly. */
+ regcache_invalidate ();
+ /* Force a register set read from ptrace, to get the side effects back,
+ if any. */
+ get_thread_regcache (current_thread, 1);
}
int