]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Workaround GDBserver register cache management
authorLuis Machado <luis.machado@linaro.org>
Wed, 15 Dec 2021 13:24:35 +0000 (10:24 -0300)
committerLuis Machado <luis.machado@linaro.org>
Mon, 20 Dec 2021 13:54:49 +0000 (10:54 -0300)
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.

gdbserver/linux-aarch64-low.cc
gdbserver/regcache.cc

index 85313789ce813939e2c88f6042dd16df78713d88..b2c631ae4b083d2ede0ea0afcb698f17f647ea9c 100644 (file)
@@ -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;
 
index add826b2897052a1da11da5a893efad86441c94b..c3bcb669a2f1eb4efda467727c4aef80c83569b1 100644 (file)
@@ -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