+/* Per-architecture object describing the layout of a register cache.
+ Computed once when the architecture is created */
+
+struct gdbarch_data *regcache_descr_handle;
+
+struct regcache_descr
+{
+ /* The architecture this descriptor belongs to. */
+ struct gdbarch *gdbarch;
+
+ /* The raw register cache. Each raw (or hard) register is supplied
+ by the target interface. The raw cache should not contain
+ redundant information - if the PC is constructed from two
+ registers then those regigisters and not the PC lives in the raw
+ cache. */
+ int nr_raw_registers;
+ long sizeof_raw_registers;
+ long sizeof_raw_register_valid_p;
+
+ /* The cooked register space. Each cooked register in the range
+ [0..NR_RAW_REGISTERS) is direct-mapped onto the corresponding raw
+ register. The remaining [NR_RAW_REGISTERS
+ .. NR_COOKED_REGISTERS) (a.k.a. pseudo registers) are mapped onto
+ both raw registers and memory by the architecture methods
+ gdbarch_pseudo_register_read and gdbarch_pseudo_register_write. */
+ int nr_cooked_registers;
+ long sizeof_cooked_registers;
+ long sizeof_cooked_register_valid_p;
+
+ /* Offset and size (in 8 bit bytes), of reach register in the
+ register cache. All registers (including those in the range
+ [NR_RAW_REGISTERS .. NR_COOKED_REGISTERS) are given an offset.
+ Assigning all registers an offset makes it possible to keep
+ legacy code, such as that found in read_register_bytes() and
+ write_register_bytes() working. */
+ long *register_offset;
+ long *sizeof_register;
+
+ /* Cached table containing the type of each register. */
+ struct type **register_type;
+};
+
+static void *
+init_regcache_descr (struct gdbarch *gdbarch)
+{
+ int i;
+ struct regcache_descr *descr;
+ gdb_assert (gdbarch != NULL);
+
+ /* Create an initial, zero filled, table. */
+ descr = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct regcache_descr);
+ descr->gdbarch = gdbarch;
+
+ /* Total size of the register space. The raw registers are mapped
+ directly onto the raw register cache while the pseudo's are
+ either mapped onto raw-registers or memory. */
+ descr->nr_cooked_registers = NUM_REGS + NUM_PSEUDO_REGS;
+ descr->sizeof_cooked_register_valid_p = NUM_REGS + NUM_PSEUDO_REGS;
+
+ /* Fill in a table of register types. */
+ descr->register_type
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, struct type *);
+ for (i = 0; i < descr->nr_cooked_registers; i++)
+ descr->register_type[i] = gdbarch_register_type (gdbarch, i);
+
+ /* Construct a strictly RAW register cache. Don't allow pseudo's
+ into the register cache. */
+ descr->nr_raw_registers = NUM_REGS;
+
+ /* FIXME: cagney/2002-08-13: Overallocate the register_valid_p
+ array. This pretects GDB from erant code that accesses elements
+ of the global register_valid_p[] array in the range [NUM_REGS
+ .. NUM_REGS + NUM_PSEUDO_REGS). */
+ descr->sizeof_raw_register_valid_p = descr->sizeof_cooked_register_valid_p;
+
+ /* Lay out the register cache.
+
+ NOTE: cagney/2002-05-22: Only register_type() is used when
+ constructing the register cache. It is assumed that the
+ register's raw size, virtual size and type length are all the
+ same. */
+
+ {
+ long offset = 0;
+ descr->sizeof_register
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
+ descr->register_offset
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
+ for (i = 0; i < descr->nr_cooked_registers; i++)
+ {
+ descr->sizeof_register[i] = TYPE_LENGTH (descr->register_type[i]);
+ descr->register_offset[i] = offset;
+ offset += descr->sizeof_register[i];
+ gdb_assert (MAX_REGISTER_SIZE >= descr->sizeof_register[i]);
+ }
+ /* Set the real size of the register cache buffer. */
+ descr->sizeof_cooked_registers = offset;
+ }
+
+ /* FIXME: cagney/2002-05-22: Should only need to allocate space for
+ the raw registers. Unfortunately some code still accesses the
+ register array directly using the global registers[]. Until that
+ code has been purged, play safe and over allocating the register
+ buffer. Ulgh! */
+ descr->sizeof_raw_registers = descr->sizeof_cooked_registers;
+
+ return descr;
+}
+
+static struct regcache_descr *
+regcache_descr (struct gdbarch *gdbarch)
+{
+ return gdbarch_data (gdbarch, regcache_descr_handle);
+}
+
+/* Utility functions returning useful register attributes stored in
+ the regcache descr. */
+
+struct type *
+register_type (struct gdbarch *gdbarch, int regnum)
+{
+ struct regcache_descr *descr = regcache_descr (gdbarch);
+ gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+ return descr->register_type[regnum];
+}
+
+/* Utility functions returning useful register attributes stored in
+ the regcache descr. */
+
+int
+register_size (struct gdbarch *gdbarch, int regnum)
+{
+ struct regcache_descr *descr = regcache_descr (gdbarch);
+ int size;
+ gdb_assert (regnum >= 0 && regnum < (NUM_REGS + NUM_PSEUDO_REGS));
+ size = descr->sizeof_register[regnum];
+ return size;
+}
+
+/* The register cache for storing raw register values. */
+
+struct regcache
+{
+ struct regcache_descr *descr;
+ /* The register buffers. A read-only register cache can hold the
+ full [0 .. NUM_REGS + NUM_PSEUDO_REGS) while a read/write
+ register cache can only hold [0 .. NUM_REGS). */
+ char *registers;
+ char *register_valid_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 *
+regcache_xmalloc (struct gdbarch *gdbarch)
+{
+ struct regcache_descr *descr;
+ struct regcache *regcache;
+ gdb_assert (gdbarch != NULL);
+ descr = regcache_descr (gdbarch);
+ regcache = XMALLOC (struct regcache);
+ regcache->descr = descr;
+ regcache->registers
+ = XCALLOC (descr->sizeof_raw_registers, char);
+ regcache->register_valid_p
+ = XCALLOC (descr->sizeof_raw_register_valid_p, char);
+ regcache->readonly_p = 1;
+ return regcache;
+}
+
+void
+regcache_xfree (struct regcache *regcache)
+{
+ if (regcache == NULL)
+ return;
+ xfree (regcache->registers);
+ xfree (regcache->register_valid_p);
+ xfree (regcache);
+}
+
+static void
+do_regcache_xfree (void *data)
+{
+ regcache_xfree (data);
+}
+
+struct cleanup *
+make_cleanup_regcache_xfree (struct regcache *regcache)
+{
+ return make_cleanup (do_regcache_xfree, regcache);
+}
+
+/* Return REGCACHE's architecture. */
+
+struct gdbarch *
+get_regcache_arch (const struct regcache *regcache)
+{
+ return regcache->descr->gdbarch;
+}
+
+/* Return a pointer to register REGNUM's buffer cache. */
+
+static char *
+register_buffer (const struct regcache *regcache, int regnum)
+{
+ return regcache->registers + regcache->descr->register_offset[regnum];
+}
+
+void
+regcache_save (struct regcache *dst, regcache_cooked_read_ftype *cooked_read,
+ void *src)
+{
+ struct gdbarch *gdbarch = dst->descr->gdbarch;
+ char buf[MAX_REGISTER_SIZE];
+ int regnum;
+ /* The DST should be `read-only', if it wasn't then the save would
+ end up trying to write the register values back out to the
+ target. */
+ 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))
+ {
+ 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,
+ regcache_cooked_read_ftype *cooked_read,
+ void *src)
+{
+ struct gdbarch *gdbarch = dst->descr->gdbarch;
+ char buf[MAX_REGISTER_SIZE];
+ int regnum;
+ /* The dst had better not be read-only. If it is, the `restore'
+ doesn't make much sense. */
+ gdb_assert (!dst->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 < dst->descr->nr_cooked_registers; regnum++)
+ {
+ if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup))
+ {
+ 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->register_valid_p[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)
+{
+ int i;
+ char *buf;
+ gdb_assert (src != NULL && dst != NULL);
+ gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
+ gdb_assert (src != dst);
+ gdb_assert (src->readonly_p || dst->readonly_p);
+ if (!src->readonly_p)
+ regcache_save (dst, do_cooked_read, src);
+ else if (!dst->readonly_p)
+ regcache_restore (dst, do_cooked_read, src);
+ else
+ regcache_cpy_no_passthrough (dst, src);
+}
+
+void
+regcache_cpy_no_passthrough (struct regcache *dst, struct regcache *src)
+{
+ int i;
+ gdb_assert (src != NULL && dst != NULL);
+ gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
+ /* NOTE: cagney/2002-05-17: Don't let the caller do a no-passthrough
+ move of data into the current_regcache(). Doing this would be
+ silly - it would mean that valid_p would be completely invalid. */
+ gdb_assert (dst != current_regcache);
+ memcpy (dst->registers, src->registers, dst->descr->sizeof_raw_registers);
+ memcpy (dst->register_valid_p, src->register_valid_p,
+ dst->descr->sizeof_raw_register_valid_p);
+}
+
+struct regcache *
+regcache_dup (struct regcache *src)
+{
+ struct regcache *newbuf;
+ gdb_assert (current_regcache != NULL);
+ newbuf = regcache_xmalloc (src->descr->gdbarch);
+ regcache_cpy (newbuf, src);
+ return newbuf;
+}
+
+struct regcache *
+regcache_dup_no_passthrough (struct regcache *src)
+{
+ struct regcache *newbuf;
+ gdb_assert (current_regcache != NULL);
+ newbuf = regcache_xmalloc (src->descr->gdbarch);
+ regcache_cpy_no_passthrough (newbuf, src);
+ return newbuf;
+}
+
+int
+regcache_valid_p (struct regcache *regcache, int regnum)
+{
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ return regcache->register_valid_p[regnum];
+}
+
+char *
+deprecated_grub_regcache_for_registers (struct regcache *regcache)
+{
+ return regcache->registers;
+}
+
+/* Global structure containing the current regcache. */
+/* FIXME: cagney/2002-05-11: The two global arrays registers[] and
+ deprecated_register_valid[] currently point into this structure. */
+struct regcache *current_regcache;
+