From: Luis Machado Date: Wed, 15 Dec 2021 13:24:35 +0000 (-0300) Subject: Workaround GDBserver register cache management X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3904c2a5518b6616a4b4b53e3525fa54a6838f16;p=thirdparty%2Fbinutils-gdb.git 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. --- 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, ®set->regs[i]); collect_register (regcache, AARCH64_SP_REGNUM, ®set->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