diff options
author | Luis Machado <luis.machado@linaro.org> | 2021-12-15 10:24:35 -0300 |
---|---|---|
committer | Luis Machado <luis.machado@linaro.org> | 2021-12-20 10:54:49 -0300 |
commit | 3904c2a5518b6616a4b4b53e3525fa54a6838f16 (patch) | |
tree | 22ee74e194ba47447a1ced19b896f65fa089b0c2 | |
parent | 3f6d78d98442668ff8685864a7599d905412203f (diff) | |
download | binutils-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.cc | 28 | ||||
-rw-r--r-- | gdbserver/regcache.cc | 7 |
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, ®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 |