From 2d28509afbfaaf187508a0c85ae3fb98d96d185b Mon Sep 17 00:00:00 2001 From: Andrew Cagney Date: Wed, 13 Nov 2002 17:59:40 +0000 Subject: [PATCH] 2002-11-13 Andrew Cagney * regcache.c (struct regcache): Replace passthough_p with readonly_p. (regcache_xmalloc): Initialize readonly_p. (build_regcache): Initialize readonly_p. (regcache_save): New function. (regcache_restore): New function. (regcache_cpy): Re-implement using regcache_save and regcache_restore. (regcache_raw_read): Update. (regcache_cooked_read): When a read-only cache, checked for cached pseudo register values. (regcache_raw_write): Assert that the cache is not read-only. Remove code handling a non-passthrough cache. * regcache.h (regcache_save): Declare. (regcache_restore): Declare. --- gdb/ChangeLog | 18 +++++++ gdb/regcache.c | 126 +++++++++++++++++++++++++++++++------------------ gdb/regcache.h | 10 ++++ 3 files changed, 108 insertions(+), 46 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3cbfc3075d9..8b2617ec2e5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,21 @@ +2002-11-13 Andrew Cagney + + * regcache.c (struct regcache): Replace passthough_p with + readonly_p. + (regcache_xmalloc): Initialize readonly_p. + (build_regcache): Initialize readonly_p. + (regcache_save): New function. + (regcache_restore): New function. + (regcache_cpy): Re-implement using regcache_save and + regcache_restore. + (regcache_raw_read): Update. + (regcache_cooked_read): When a read-only cache, checked for cached + pseudo register values. + (regcache_raw_write): Assert that the cache is not read-only. + Remove code handling a non-passthrough cache. + * regcache.h (regcache_save): Declare. + (regcache_restore): Declare. + 2002-11-13 Andrew Cagney * regcache.c (struct regcache_descr): Add fields diff --git a/gdb/regcache.c b/gdb/regcache.c index 6d290a506c2..0e5dae6e104 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -295,9 +295,13 @@ struct regcache register cache can only hold [0 .. NUM_REGS). */ char *registers; char *register_valid_p; - /* If a value isn't in the cache should the corresponding target be - queried for a value. */ - int passthrough_p; + /* Is this a read-only cache? A read-only cache is used for saving + the target's register state (e.g, across an inferior function + call or just before forcing a function return). A read-only + cache can only be updated via the methods regcache_dup() and + regcache_cpy(). The actual contents are determined by the + reggroup_save and reggroup_restore methods. */ + int readonly_p; }; struct regcache * @@ -313,7 +317,7 @@ regcache_xmalloc (struct gdbarch *gdbarch) = XCALLOC (descr->sizeof_raw_registers, char); regcache->register_valid_p = XCALLOC (descr->sizeof_raw_register_valid_p, char); - regcache->passthrough_p = 0; + regcache->readonly_p = 1; return regcache; } @@ -347,6 +351,60 @@ register_buffer (struct regcache *regcache, int regnum) return regcache->registers + regcache->descr->register_offset[regnum]; } +void +regcache_save (struct regcache *dst, struct regcache *src) +{ + struct gdbarch *gdbarch = dst->descr->gdbarch; + int regnum; + /* The SRC and DST register caches had better belong to the same + architecture. */ + gdb_assert (src->descr->gdbarch == dst->descr->gdbarch); + /* The DST should be `read-only', if it wasn't then the save would + end up trying to write the register values out through to the + target. */ + gdb_assert (!src->readonly_p); + gdb_assert (dst->readonly_p); + /* Clear the dest. */ + memset (dst->registers, 0, dst->descr->sizeof_cooked_registers); + memset (dst->register_valid_p, 0, dst->descr->sizeof_cooked_register_valid_p); + /* Copy over any registers (identified by their membership in the + save_reggroup) and mark them as valid. The full [0 + .. NUM_REGS+NUM_PSEUDO_REGS) range is checked since some + architectures need to save/restore `cooked' registers that live + in memory. */ + for (regnum = 0; regnum < dst->descr->nr_cooked_registers; regnum++) + { + if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup)) + { + regcache_cooked_read (src, regnum, register_buffer (dst, regnum)); + dst->register_valid_p[regnum] = 1; + } + } +} + +void +regcache_restore (struct regcache *dst, struct regcache *src) +{ + struct gdbarch *gdbarch = dst->descr->gdbarch; + int regnum; + gdb_assert (src->descr->gdbarch == dst->descr->gdbarch); + gdb_assert (!dst->readonly_p); + gdb_assert (src->readonly_p); + /* Copy over any registers, being careful to only restore those that + were both saved and need to be restored. The full [0 + .. NUM_REGS+NUM_PSEUDO_REGS) range is checked since some + architectures need to save/restore `cooked' registers that live + in memory. */ + for (regnum = 0; regnum < src->descr->nr_cooked_registers; regnum++) + { + if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup) + && src->register_valid_p[regnum]) + { + regcache_cooked_write (dst, regnum, register_buffer (src, regnum)); + } + } +} + void regcache_cpy (struct regcache *dst, struct regcache *src) { @@ -355,33 +413,13 @@ regcache_cpy (struct regcache *dst, struct regcache *src) gdb_assert (src != NULL && dst != NULL); gdb_assert (src->descr->gdbarch == dst->descr->gdbarch); gdb_assert (src != dst); - /* FIXME: cagney/2002-05-17: To say this bit is bad is being polite. - It keeps the existing code working where things rely on going - through to the register cache. */ - if (src == current_regcache && src->descr->legacy_p) - { - /* ULGH!!!! Old way. Use REGISTER bytes and let code below - untangle fetch. */ - read_register_bytes (0, dst->registers, REGISTER_BYTES); - return; - } - /* FIXME: cagney/2002-05-17: To say this bit is bad is being polite. - It keeps the existing code working where things rely on going - through to the register cache. */ - if (dst == current_regcache && dst->descr->legacy_p) - { - /* ULGH!!!! Old way. Use REGISTER bytes and let code below - untangle fetch. */ - write_register_bytes (0, src->registers, REGISTER_BYTES); - return; - } - buf = alloca (src->descr->max_register_size); - for (i = 0; i < src->descr->nr_raw_registers; i++) - { - /* Should we worry about the valid bit here? */ - regcache_raw_read (src, i, buf); - regcache_raw_write (dst, i, buf); - } + gdb_assert (src->readonly_p || dst->readonly_p); + if (!src->readonly_p) + regcache_save (dst, src); + else if (!dst->readonly_p) + regcache_restore (dst, src); + else + regcache_cpy_no_passthrough (dst, src); } void @@ -675,7 +713,7 @@ regcache_raw_read (struct regcache *regcache, int regnum, void *buf) gdb_assert (regcache != NULL && buf != NULL); gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers); if (regcache->descr->legacy_p - && regcache->passthrough_p) + && !regcache->readonly_p) { gdb_assert (regcache == current_regcache); /* For moment, just use underlying legacy code. Ulgh!!! This @@ -688,7 +726,7 @@ regcache_raw_read (struct regcache *regcache, int regnum, void *buf) to the current thread. This switching shouldn't be necessary only there is still only one target side register cache. Sigh! On the bright side, at least there is a regcache object. */ - if (regcache->passthrough_p) + if (!regcache->readonly_p) { gdb_assert (regcache == current_regcache); if (! ptid_equal (registers_ptid, inferior_ptid)) @@ -772,6 +810,12 @@ regcache_cooked_read (struct regcache *regcache, int regnum, void *buf) gdb_assert (regnum < regcache->descr->nr_cooked_registers); if (regnum < regcache->descr->nr_raw_registers) regcache_raw_read (regcache, regnum, buf); + else if (regcache->readonly_p + && regnum < regcache->descr->nr_cooked_registers + && regcache->register_valid_p[regnum]) + /* Read-only register cache, perhaphs the cooked value was cached? */ + memcpy (buf, register_buffer (regcache, regnum), + regcache->descr->sizeof_register[regnum]); else gdbarch_pseudo_register_read (regcache->descr->gdbarch, regcache, regnum, buf); @@ -848,9 +892,9 @@ regcache_raw_write (struct regcache *regcache, int regnum, const void *buf) { gdb_assert (regcache != NULL && buf != NULL); gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers); + gdb_assert (!regcache->readonly_p); - if (regcache->passthrough_p - && regcache->descr->legacy_p) + if (regcache->descr->legacy_p) { /* For moment, just use underlying legacy code. Ulgh!!! This silently and very indirectly updates the regcache's buffers @@ -865,16 +909,6 @@ regcache_raw_write (struct regcache *regcache, int regnum, const void *buf) if (CANNOT_STORE_REGISTER (regnum)) return; - /* Handle the simple case first -> not write through so just store - value in cache. */ - if (!regcache->passthrough_p) - { - memcpy (register_buffer (regcache, regnum), buf, - regcache->descr->sizeof_register[regnum]); - regcache->register_valid_p[regnum] = 1; - return; - } - /* Make certain that the correct cache is selected. */ gdb_assert (regcache == current_regcache); if (! ptid_equal (registers_ptid, inferior_ptid)) @@ -1378,7 +1412,7 @@ static void build_regcache (void) { current_regcache = regcache_xmalloc (current_gdbarch); - current_regcache->passthrough_p = 1; + current_regcache->readonly_p = 0; registers = deprecated_grub_regcache_for_registers (current_regcache); deprecated_register_valid = deprecated_grub_regcache_for_register_valid (current_regcache); } diff --git a/gdb/regcache.h b/gdb/regcache.h index ad70298a6b9..a1ea2fadfb5 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -134,6 +134,16 @@ extern int max_register_size (struct gdbarch *gdbarch); extern char *registers; +/* Save/restore a register cache. The registers saved/restored is + determined by the save_reggroup and restore_reggroup (although you + can't restore a register that wasn't saved as well :-). You can + only save to a read-only cache (default from regcache_xmalloc()) + from a live cache and you can only restore from a read-only cache + to a live cache. */ + +extern void regcache_save (struct regcache *dst, struct regcache *src); +extern void regcache_restore (struct regcache *dst, struct regcache *src); + /* Copy/duplicate the contents of a register cache. By default, the operation is pass-through. Writes to DST and reads from SRC will go through to the target. -- 2.30.2