aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2003-03-10 21:00:56 +0000
committerAndrew Cagney <cagney@redhat.com>2003-03-10 21:00:56 +0000
commit271f220ec11e6d684deefd3462f4f2846e2fe1c2 (patch)
tree897caad12fe7c4650856a6418500abf79cb62355
parent462569a5de2e62a99f85d65a55899de2456b81be (diff)
downloadgdb-271f220ec11e6d684deefd3462f4f2846e2fe1c2.zip
gdb-271f220ec11e6d684deefd3462f4f2846e2fe1c2.tar.gz
gdb-271f220ec11e6d684deefd3462f4f2846e2fe1c2.tar.bz2
2003-03-10 Andrew Cagney <cagney@redhat.com>
* frame.c: Merge in posted frame_pop patch. * regcache.h, regcache.c: Merge with mainline.
-rw-r--r--gdb/ChangeLog6
-rw-r--r--gdb/frame.c53
-rw-r--r--gdb/regcache.c79
-rw-r--r--gdb/regcache.h22
4 files changed, 92 insertions, 68 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8b9d6f6..8a1224f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2003-03-10 Andrew Cagney <cagney@redhat.com>
+
+ * frame.c (frame_pop): Merge with mainline
+ (do_frame_unwind_register): Merge with mainline.
+ * regcache.h, regcache.c: Merge with mainline.
+
2003-03-06 Andrew Cagney <cagney@redhat.com>
* d10v-tdep.c (d10v_frame_pop): Delete function.
diff --git a/gdb/frame.c b/gdb/frame.c
index 1a1c050..b891463 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -38,7 +38,6 @@
#include "frame-unwind.h"
#include "command.h"
#include "gdbcmd.h"
-#include "reggroups.h"
/* Flag to control debugging. */
@@ -186,42 +185,44 @@ frame_pc_unwind (struct frame_info *this_frame)
return this_frame->pc_unwind_cache;
}
+static int
+do_frame_unwind_register (void *src, int regnum, void *buf)
+{
+ frame_unwind_register (src, regnum, buf);
+ return 1;
+}
+
void
frame_pop (struct frame_info *this_frame)
{
+ struct regcache *scratch_regcache;
+ struct cleanup *cleanups;
+
if (POP_FRAME_P ())
{
+ /* A legacy architecture that has implemented a custom pop
+ function. All new architectures should instead be using the
+ generic code below. */
POP_FRAME;
}
else
{
- /* Note, the dummy-frame code does something very similar to
- this. Perhaphs a common routine is in order. */
- struct regcache *scratch_regcache = regcache_xmalloc (current_gdbarch);
- struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch_regcache);
- void *buf = alloca (max_register_size (current_gdbarch));
- int regnum;
-
- /* 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 < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
- {
- if (gdbarch_register_reggroup_p (current_gdbarch, regnum,
- save_reggroup))
- {
- frame_unwind_register (this_frame, regnum, buf);
- regcache_cooked_write (scratch_regcache, regnum, buf);
- }
- }
-
- /* Now write the unwound registers, en-mass, back into the
- regcache. */
- regcache_cpy (current_regcache, scratch_regcache);
+ /* Make a copy of all the register values unwound from this
+ frame. Save them in a scratch buffer so that there isn't a
+ race betweening trying to extract the old values from the
+ current_regcache while, at the same time writing new values
+ into that same cache. */
+ struct regcache *scratch = regcache_xmalloc (current_gdbarch);
+ struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch);
+ regcache_save (scratch, do_frame_unwind_register, this_frame);
+ /* Now copy those saved registers into the current regcache.
+ Here, regcache_cpy() calls regcache_restore(). */
+ regcache_cpy (current_regcache, scratch);
do_cleanups (cleanups);
}
+ /* We've made right mess of GDB's local state, just discard
+ everything. */
+ target_store_registers (-1);
flush_cached_frames ();
}
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 1b862e1..5475cf68 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -389,59 +389,79 @@ register_buffer (struct regcache *regcache, int regnum)
}
void
-regcache_save (struct regcache *dst, struct regcache *src)
+regcache_save (struct regcache *dst, regcache_cooked_read_ftype *cooked_read,
+ void *src)
{
struct gdbarch *gdbarch = dst->descr->gdbarch;
+ void *buf = alloca (max_register_size (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
+ end up trying to write the register values back out 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. */
+ 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;
+ int valid = cooked_read (src, regnum, buf);
+ if (valid)
+ {
+ memcpy (register_buffer (dst, regnum), buf,
+ register_size (gdbarch, regnum));
+ dst->register_valid_p[regnum] = 1;
+ }
}
}
}
void
-regcache_restore (struct regcache *dst, struct regcache *src)
+regcache_restore (struct regcache *dst,
+ regcache_cooked_read_ftype *cooked_read,
+ void *src)
{
struct gdbarch *gdbarch = dst->descr->gdbarch;
+ void *buf = alloca (max_register_size (gdbarch));
int regnum;
- gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
+ /* The dst had better not be read-only. If it is, the `restore'
+ doesn't make much sense. */
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++)
+ 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 < dst->descr->nr_cooked_registers; regnum++)
{
- if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup)
- && src->register_valid_p[regnum])
+ if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup))
{
- regcache_cooked_write (dst, regnum, register_buffer (src, regnum));
+ int valid = cooked_read (src, regnum, buf);
+ if (valid)
+ regcache_cooked_write (dst, regnum, buf);
}
}
}
+static int
+do_cooked_read (void *src, int regnum, void *buf)
+{
+ struct regcache *regcache = src;
+ if (!regcache_valid_p (regcache, regnum)
+ && regcache->readonly_p)
+ /* Don't even think about fetching a register from a read-only
+ cache when the register isn't yet valid. There isn't a target
+ from which the register value can be fetched. */
+ return 0;
+ regcache_cooked_read (regcache, regnum, buf);
+ return 1;
+}
+
+
void
regcache_cpy (struct regcache *dst, struct regcache *src)
{
@@ -452,9 +472,9 @@ regcache_cpy (struct regcache *dst, struct regcache *src)
gdb_assert (src != dst);
gdb_assert (src->readonly_p || dst->readonly_p);
if (!src->readonly_p)
- regcache_save (dst, src);
+ regcache_save (dst, do_cooked_read, src);
else if (!dst->readonly_p)
- regcache_restore (dst, src);
+ regcache_restore (dst, do_cooked_read, src);
else
regcache_cpy_no_passthrough (dst, src);
}
@@ -929,14 +949,7 @@ 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);
-
- if (regcache->readonly_p)
- {
- memcpy (register_buffer (regcache, regnum), buf,
- regcache->descr->sizeof_register[regnum]);
- regcache->register_valid_p[regnum] = 1;
- return;
- }
+ gdb_assert (!regcache->readonly_p);
if (regcache->descr->legacy_p)
{
diff --git a/gdb/regcache.h b/gdb/regcache.h
index ee10505..dd62938 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -155,15 +155,19 @@ extern int max_register_size (struct gdbarch *gdbarch);
extern int register_size (struct gdbarch *gdbarch, int regnum);
-/* 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);
+/* Save/restore a register cache. The set of registers saved /
+ restored into the DST regcache determined by the save_reggroup /
+ restore_reggroup respectively. COOKED_READ returns zero iff the
+ register's value can't be returned. */
+
+typedef int (regcache_cooked_read_ftype) (void *src, int regnum, void *buf);
+
+extern void regcache_save (struct regcache *dst,
+ regcache_cooked_read_ftype *cooked_read,
+ void *src);
+extern void regcache_restore (struct regcache *dst,
+ regcache_cooked_read_ftype *cooked_read,
+ void *src);
/* Copy/duplicate the contents of a register cache. By default, the
operation is pass-through. Writes to DST and reads from SRC will