* Makefile.in (i386nbsd-tdep.o): Add $(arch_utils_h),
[deliverable/binutils-gdb.git] / gdb / regcache.c
index ba6f547573f922fec2cd56d9b6e69ff949b97380..ab65c67a47b7c1293bf9958bc9921537a5aab33e 100644 (file)
@@ -27,6 +27,8 @@
 #include "gdbcmd.h"
 #include "regcache.h"
 #include "gdb_assert.h"
+#include "gdb_string.h"
+#include "gdbcmd.h"            /* For maintenanceprintlist.  */
 
 /*
  * DATA STRUCTURE
@@ -56,62 +58,65 @@ struct regcache_descr
   long sizeof_raw_registers;
   long sizeof_raw_register_valid_p;
 
-  /* Offset, in bytes, of reach register in the raw register cache.
-     Pseudo registers have an offset even though they don't
-     (shouldn't) have a correspoinding space in the register cache.
-     It is to keep existing code, that relies on
-     write/write_register_bytes working.  */
+  /* 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 regiters) are mapped onto
+     both raw registers and memory by the architecture methods
+     gdbarch_register_read and gdbarch_register_write.  */
+  int nr_cooked_registers;
+
+  /* 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;
-
-  /* The cooked / frame / virtual register space.  The registers in
-     the range [0..NR_RAW_REGISTERS) should be mapped directly onto
-     the corresponding raw register.  The next [NR_RAW_REGISTERS
-     .. NR_REGISTERS) should have been mapped, via
-     gdbarch_register_read/write onto either raw registers or memory.  */
-  int nr_registers;
   long *sizeof_register;
+
+  /* Useful constant.  Largest of all the registers.  */
   long max_register_size;
 
+  /* Cached table containing the type of each register.  */
+  struct type **register_type;
 };
 
-static void *
-init_legacy_regcache_descr (struct gdbarch *gdbarch)
+void
+init_legacy_regcache_descr (struct gdbarch *gdbarch,
+                           struct regcache_descr *descr)
 {
   int i;
-  struct regcache_descr *descr;
   /* FIXME: cagney/2002-05-11: gdbarch_data() should take that
      ``gdbarch'' as a parameter.  */
   gdb_assert (gdbarch != NULL);
 
-  descr = XMALLOC (struct regcache_descr);
-  descr->gdbarch = gdbarch;
-  descr->legacy_p = 1;
-
   /* FIXME: cagney/2002-05-11: Shouldn't be including pseudo-registers
      in the register buffer.  Unfortunatly some architectures do.  */
-  descr->nr_registers = NUM_REGS + NUM_PSEUDO_REGS;
-  descr->nr_raw_registers = descr->nr_registers;
-  descr->sizeof_raw_register_valid_p = descr->nr_registers;
+  descr->nr_raw_registers = descr->nr_cooked_registers;
+  descr->sizeof_raw_register_valid_p = descr->nr_cooked_registers;
 
   /* FIXME: cagney/2002-05-11: Instead of using REGISTER_BYTE() this
      code should compute the offets et.al. at runtime.  This currently
      isn't possible because some targets overlap register locations -
      see the mess in read_register_bytes() and write_register_bytes()
      registers.  */
-  descr->sizeof_register = XCALLOC (descr->nr_registers, long);
-  descr->register_offset = XCALLOC (descr->nr_registers, long);
+  descr->sizeof_register = XCALLOC (descr->nr_cooked_registers, long);
+  descr->register_offset = XCALLOC (descr->nr_cooked_registers, long);
   descr->max_register_size = 0;
-  for (i = 0; i < descr->nr_registers; i++)
+  for (i = 0; i < descr->nr_cooked_registers; i++)
     {
       descr->register_offset[i] = REGISTER_BYTE (i);
       descr->sizeof_register[i] = REGISTER_RAW_SIZE (i);
       if (descr->max_register_size < REGISTER_RAW_SIZE (i))
        descr->max_register_size = REGISTER_RAW_SIZE (i);
+      if (descr->max_register_size < REGISTER_VIRTUAL_SIZE (i))
+       descr->max_register_size = REGISTER_VIRTUAL_SIZE (i);
     }
 
   /* Come up with the real size of the registers buffer.  */
   descr->sizeof_raw_registers = REGISTER_BYTES; /* OK use.  */
-  for (i = 0; i < descr->nr_registers; i++)
+  for (i = 0; i < descr->nr_cooked_registers; i++)
     {
       long regend;
       /* Keep extending the buffer so that there is always enough
@@ -128,7 +133,6 @@ init_legacy_regcache_descr (struct gdbarch *gdbarch)
       if (descr->sizeof_raw_registers < regend)
        descr->sizeof_raw_registers = regend;
     }
-  return descr;
 }
 
 static void *
@@ -138,44 +142,61 @@ init_regcache_descr (struct gdbarch *gdbarch)
   struct regcache_descr *descr;
   gdb_assert (gdbarch != NULL);
 
-  /* If an old style architecture, construct the register cache
-     description using all the register macros.  */
-  if (!gdbarch_register_read_p (gdbarch)
-      && !gdbarch_register_write_p (gdbarch))
-    return init_legacy_regcache_descr (gdbarch);
-
-  descr = XMALLOC (struct regcache_descr);
+  /* Create an initial, zero filled, table.  */
+  descr = XCALLOC (1, struct regcache_descr);
   descr->gdbarch = gdbarch;
-  descr->legacy_p = 0;
 
-  /* Total size of the register space.  The raw registers should
-     directly map onto the raw register cache while the pseudo's are
+  /* 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_registers = NUM_REGS + NUM_PSEUDO_REGS;
+  descr->nr_cooked_registers = NUM_REGS + NUM_PSEUDO_REGS;
+
+  /* Fill in a table of register types.  */
+  descr->register_type = XCALLOC (descr->nr_cooked_registers,
+                                 struct type *);
+  for (i = 0; i < descr->nr_cooked_registers; i++)
+    {
+      descr->register_type[i] = REGISTER_VIRTUAL_TYPE (i);
+    }
+
+  /* If an old style architecture, fill in the remainder of the
+     register cache descriptor using the register macros.  */
+  if (!gdbarch_pseudo_register_read_p (gdbarch)
+      && !gdbarch_pseudo_register_write_p (gdbarch))
+    {
+      descr->legacy_p = 1;
+      init_legacy_regcache_descr (gdbarch, descr);
+      return descr;
+    }
 
   /* Construct a strictly RAW register cache.  Don't allow pseudo's
      into the register cache.  */
   descr->nr_raw_registers = NUM_REGS;
-  descr->sizeof_raw_register_valid_p = 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 = NUM_REGS + NUM_PSEUDO_REGS;
 
   /* Lay out the register cache.  The pseud-registers are included in
      the layout even though their value isn't stored in the register
      cache.  Some code, via read_register_bytes() access a register
      using an offset/length rather than a register number.
 
-     NOTE: cagney/2002-05-22: Only REGISTER_VIRTUAL_TYPE() needs to be
-     used when constructing the register cache.  It is assumed that
-     register raw size, virtual size and type length of the type are
-     all the same.  */
+     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 = XCALLOC (descr->nr_registers, long);
-    descr->register_offset = XCALLOC (descr->nr_registers, long);
+    descr->sizeof_register = XCALLOC (descr->nr_cooked_registers, long);
+    descr->register_offset = XCALLOC (descr->nr_cooked_registers, long);
     descr->max_register_size = 0;
-    for (i = 0; i < descr->nr_registers; i++)
+    for (i = 0; i < descr->nr_cooked_registers; i++)
       {
-       descr->sizeof_register[i] = TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (i));
+       descr->sizeof_register[i] = TYPE_LENGTH (descr->register_type[i]);
        descr->register_offset[i] = offset;
        offset += descr->sizeof_register[i];
        if (descr->max_register_size < descr->sizeof_register[i])
@@ -198,7 +219,7 @@ init_regcache_descr (struct gdbarch *gdbarch)
      don't go into infinite recursion trying to, again, create the
      regcache.  */
   set_gdbarch_data (gdbarch, regcache_descr_handle, descr);
-  for (i = 0; i < descr->nr_registers; i++)
+  for (i = 0; i < descr->nr_cooked_registers; i++)
     {
       gdb_assert (descr->sizeof_register[i] == REGISTER_RAW_SIZE (i));
       gdb_assert (descr->sizeof_register[i] == REGISTER_VIRTUAL_SIZE (i));
@@ -229,6 +250,27 @@ xfree_regcache_descr (struct gdbarch *gdbarch, void *ptr)
   xfree (descr);
 }
 
+/* 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
+max_register_size (struct gdbarch *gdbarch)
+{
+  struct regcache_descr *descr = regcache_descr (gdbarch);
+  return descr->max_register_size;
+}
+
 /* The register cache for storing raw register values.  */
 
 struct regcache
@@ -268,6 +310,18 @@ regcache_xfree (struct regcache *regcache)
   xfree (regcache);
 }
 
+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);
+}
+
 void
 regcache_cpy (struct regcache *dst, struct regcache *src)
 {
@@ -300,8 +354,8 @@ regcache_cpy (struct regcache *dst, struct regcache *src)
   for (i = 0; i < src->descr->nr_raw_registers; i++)
     {
       /* Should we worry about the valid bit here?  */
-      regcache_read (src, i, buf);
-      regcache_write (dst, i, buf);
+      regcache_raw_read (src, i, buf);
+      regcache_raw_write (dst, i, buf);
     }
 }
 
@@ -349,17 +403,6 @@ regcache_valid_p (struct regcache *regcache, int regnum)
   return regcache->raw_register_valid_p[regnum];
 }
 
-CORE_ADDR
-regcache_read_as_address (struct regcache *regcache, int regnum)
-{
-  char *buf;
-  gdb_assert (regcache != NULL);
-  gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
-  buf = alloca (regcache->descr->sizeof_register[regnum]);
-  regcache_read (regcache, regnum, buf);
-  return extract_address (buf, regcache->descr->sizeof_register[regnum]);
-}
-
 char *
 deprecated_grub_regcache_for_registers (struct regcache *regcache)
 {
@@ -425,7 +468,9 @@ register_cached (int regnum)
 void
 set_register_cached (int regnum, int state)
 {
-  register_valid[regnum] = state;
+  gdb_assert (regnum >= 0);
+  gdb_assert (regnum < current_regcache->descr->nr_raw_registers);
+  current_regcache->raw_register_valid_p[regnum] = state;
 }
 
 /* REGISTER_CHANGED
@@ -454,46 +499,6 @@ real_register (int regnum)
   return regnum >= 0 && regnum < NUM_REGS;
 }
 
-/* Return whether register REGNUM is a pseudo register.  */
-
-static int
-pseudo_register (int regnum)
-{
-  return regnum >= NUM_REGS && regnum < NUM_REGS + NUM_PSEUDO_REGS;
-}
-
-/* Fetch register REGNUM into the cache.  */
-
-static void
-fetch_register (int regnum)
-{
-  /* NOTE: cagney/2001-12-04: Legacy targets were using fetch/store
-     pseudo-register as a way of handling registers that needed to be
-     constructed from one or more raw registers.  New targets instead
-     use gdbarch register read/write.  */
-  if (FETCH_PSEUDO_REGISTER_P ()
-      && pseudo_register (regnum))
-    FETCH_PSEUDO_REGISTER (regnum);
-  else
-    target_fetch_registers (regnum);
-}
-
-/* Write register REGNUM cached value to the target.  */
-
-static void
-store_register (int regnum)
-{
-  /* NOTE: cagney/2001-12-04: Legacy targets were using fetch/store
-     pseudo-register as a way of handling registers that needed to be
-     constructed from one or more raw registers.  New targets instead
-     use gdbarch register read/write.  */
-  if (STORE_PSEUDO_REGISTER_P ()
-      && pseudo_register (regnum))
-    STORE_PSEUDO_REGISTER (regnum);
-  else
-    target_store_registers (regnum);
-}
-
 /* Low level examining and depositing of registers.
 
    The caller is responsible for making sure that the inferior is
@@ -519,7 +524,7 @@ registers_changed (void)
      gdb gives control to the user (ie watchpoints).  */
   alloca (0);
 
-  for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+  for (i = 0; i < current_regcache->descr->nr_raw_registers; i++)
     set_register_cached (i, 0);
 
   if (registers_changed_hook)
@@ -652,14 +657,14 @@ legacy_read_register_gen (int regnum, char *myaddr)
     }
 
   if (!register_cached (regnum))
-    fetch_register (regnum);
+    target_fetch_registers (regnum);
 
   memcpy (myaddr, register_buffer (current_regcache, regnum),
          REGISTER_RAW_SIZE (regnum));
 }
 
 void
-regcache_read (struct regcache *regcache, int regnum, char *buf)
+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);
@@ -686,7 +691,7 @@ regcache_read (struct regcache *regcache, int regnum, char *buf)
          registers_ptid = inferior_ptid;
        }
       if (!register_cached (regnum))
-       fetch_register (regnum);
+       target_fetch_registers (regnum);
     }
   /* Copy the value directly into the register cache.  */
   memcpy (buf, (regcache->raw_registers
@@ -694,6 +699,54 @@ regcache_read (struct regcache *regcache, int regnum, char *buf)
          regcache->descr->sizeof_register[regnum]);
 }
 
+void
+regcache_raw_read_signed (struct regcache *regcache, int regnum, LONGEST *val)
+{
+  char *buf;
+  gdb_assert (regcache != NULL);
+  gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  regcache_raw_read (regcache, regnum, buf);
+  (*val) = extract_signed_integer (buf,
+                                  regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
+                           ULONGEST *val)
+{
+  char *buf;
+  gdb_assert (regcache != NULL);
+  gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  regcache_raw_read (regcache, regnum, buf);
+  (*val) = extract_unsigned_integer (buf,
+                                    regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_raw_write_signed (struct regcache *regcache, int regnum, LONGEST val)
+{
+  void *buf;
+  gdb_assert (regcache != NULL);
+  gdb_assert (regnum >=0 && regnum < regcache->descr->nr_raw_registers);
+  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  store_signed_integer (buf, regcache->descr->sizeof_register[regnum], val);
+  regcache_raw_write (regcache, regnum, buf);
+}
+
+void
+regcache_raw_write_unsigned (struct regcache *regcache, int regnum,
+                            ULONGEST val)
+{
+  void *buf;
+  gdb_assert (regcache != NULL);
+  gdb_assert (regnum >=0 && regnum < regcache->descr->nr_raw_registers);
+  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  store_unsigned_integer (buf, regcache->descr->sizeof_register[regnum], val);
+  regcache_raw_write (regcache, regnum, buf);
+}
+
 void
 read_register_gen (int regnum, char *buf)
 {
@@ -704,15 +757,52 @@ read_register_gen (int regnum, char *buf)
       legacy_read_register_gen (regnum, buf);
       return;
     }
-  gdbarch_register_read (current_gdbarch, regnum, buf);
+  regcache_cooked_read (current_regcache, regnum, buf);
+}
+
+void
+regcache_cooked_read (struct regcache *regcache, int regnum, void *buf)
+{
+  gdb_assert (regnum >= 0);
+  gdb_assert (regnum < regcache->descr->nr_cooked_registers);
+  if (regnum < regcache->descr->nr_raw_registers)
+    regcache_raw_read (regcache, regnum, buf);
+  else
+    gdbarch_pseudo_register_read (regcache->descr->gdbarch, regcache,
+                                 regnum, buf);
 }
 
+void
+regcache_cooked_read_signed (struct regcache *regcache, int regnum,
+                            LONGEST *val)
+{
+  char *buf;
+  gdb_assert (regcache != NULL);
+  gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  regcache_cooked_read (regcache, regnum, buf);
+  (*val) = extract_signed_integer (buf,
+                                  regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_cooked_read_unsigned (struct regcache *regcache, int regnum,
+                              ULONGEST *val)
+{
+  char *buf;
+  gdb_assert (regcache != NULL);
+  gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  regcache_cooked_read (regcache, regnum, buf);
+  (*val) = extract_unsigned_integer (buf,
+                                    regcache->descr->sizeof_register[regnum]);
+}
 
 /* Write register REGNUM at MYADDR to the target.  MYADDR points at
    REGISTER_RAW_BYTES(REGNUM), which must be in target byte-order.  */
 
 static void
-legacy_write_register_gen (int regnum, char *myaddr)
+legacy_write_register_gen (int regnum, const void *myaddr)
 {
   int size;
   gdb_assert (regnum >= 0 && regnum < (NUM_REGS + NUM_PSEUDO_REGS));
@@ -745,11 +835,11 @@ legacy_write_register_gen (int regnum, char *myaddr)
   memcpy (register_buffer (current_regcache, regnum), myaddr, size);
 
   set_register_cached (regnum, 1);
-  store_register (regnum);
+  target_store_registers (regnum);
 }
 
 void
-regcache_write (struct regcache *regcache, int regnum, char *buf)
+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);
@@ -800,7 +890,7 @@ regcache_write (struct regcache *regcache, int regnum, char *buf)
   memcpy (register_buffer (regcache, regnum), buf,
          regcache->descr->sizeof_register[regnum]);
   regcache->raw_register_valid_p[regnum] = 1;
-  store_register (regnum);
+  target_store_registers (regnum);
 }
 
 void
@@ -813,7 +903,19 @@ write_register_gen (int regnum, char *buf)
       legacy_write_register_gen (regnum, buf);
       return;
     }
-  gdbarch_register_write (current_gdbarch, regnum, buf);
+  regcache_cooked_write (current_regcache, regnum, buf);
+}
+
+void
+regcache_cooked_write (struct regcache *regcache, int regnum, const void *buf)
+{
+  gdb_assert (regnum >= 0);
+  gdb_assert (regnum < regcache->descr->nr_cooked_registers);
+  if (regnum < regcache->descr->nr_raw_registers)
+    regcache_raw_write (regcache, regnum, buf);
+  else
+    gdbarch_pseudo_register_write (regcache->descr->gdbarch, regcache,
+                                  regnum, buf);
 }
 
 /* Copy INLEN bytes of consecutive data from memory at MYADDR
@@ -864,11 +966,180 @@ write_register_bytes (int myregstart, char *myaddr, int inlen)
                  myaddr + (overlapstart - myregstart),
                  overlapend - overlapstart);
 
-         store_register (regnum);
+         target_store_registers (regnum);
        }
     }
 }
 
+/* Perform a partial register transfer using a read, modify, write
+   operation.  */
+
+typedef void (regcache_read_ftype) (struct regcache *regcache, int regnum,
+                                   void *buf);
+typedef void (regcache_write_ftype) (struct regcache *regcache, int regnum,
+                                    const void *buf);
+
+void
+regcache_xfer_part (struct regcache *regcache, int regnum,
+                   int offset, int len, void *in, const void *out,
+                   regcache_read_ftype *read, regcache_write_ftype *write)
+{
+  struct regcache_descr *descr = regcache->descr;
+  bfd_byte *reg = alloca (descr->max_register_size);
+  gdb_assert (offset >= 0 && offset <= descr->sizeof_register[regnum]);
+  gdb_assert (len >= 0 && offset + len <= descr->sizeof_register[regnum]);
+  /* Something to do?  */
+  if (offset + len == 0)
+    return;
+  /* Read (when needed) ... */
+  if (in != NULL
+      || offset > 0
+      || offset + len < descr->sizeof_register[regnum])
+    {
+      gdb_assert (read != NULL);
+      read (regcache, regnum, reg);
+    }
+  /* ... modify ... */
+  if (in != NULL)
+    memcpy (in, reg + offset, len);
+  if (out != NULL)
+    memcpy (reg + offset, out, len);
+  /* ... write (when needed).  */
+  if (out != NULL)
+    {
+      gdb_assert (write != NULL);
+      write (regcache, regnum, reg);
+    }
+}
+
+void
+regcache_raw_read_part (struct regcache *regcache, int regnum,
+                       int offset, int len, void *buf)
+{
+  struct regcache_descr *descr = regcache->descr;
+  gdb_assert (regnum >= 0 && regnum < descr->nr_raw_registers);
+  regcache_xfer_part (regcache, regnum, offset, len, buf, NULL,
+                     regcache_raw_read, regcache_raw_write);
+}
+
+void
+regcache_raw_write_part (struct regcache *regcache, int regnum,
+                        int offset, int len, const void *buf)
+{
+  struct regcache_descr *descr = regcache->descr;
+  gdb_assert (regnum >= 0 && regnum < descr->nr_raw_registers);
+  regcache_xfer_part (regcache, regnum, offset, len, NULL, buf,
+                     regcache_raw_read, regcache_raw_write);
+}
+
+void
+regcache_cooked_read_part (struct regcache *regcache, int regnum,
+                          int offset, int len, void *buf)
+{
+  struct regcache_descr *descr = regcache->descr;
+  gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+  regcache_xfer_part (regcache, regnum, offset, len, buf, NULL,
+                     regcache_cooked_read, regcache_cooked_write);
+}
+
+void
+regcache_cooked_write_part (struct regcache *regcache, int regnum,
+                           int offset, int len, const void *buf)
+{
+  struct regcache_descr *descr = regcache->descr;
+  gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+  regcache_xfer_part (regcache, regnum, offset, len, NULL, buf,
+                     regcache_cooked_read, regcache_cooked_write);
+}
+
+/* Hack to keep code that view the register buffer as raw bytes
+   working.  */
+
+int
+register_offset_hack (struct gdbarch *gdbarch, int regnum)
+{
+  struct regcache_descr *descr = regcache_descr (gdbarch);
+  gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+  return descr->register_offset[regnum];
+}
+
+static void
+cooked_xfer_using_offset_hack (struct regcache *regcache,
+                              int buf_start, int buf_len, void *in_b,
+                              const void *out_b)
+{
+  struct regcache_descr *descr = regcache->descr;
+  struct gdbarch *gdbarch = descr->gdbarch;
+  bfd_byte *in_buf = in_b;
+  const bfd_byte *out_buf = out_b;
+  int buf_end = buf_start + buf_len;
+  int regnum;
+  char *reg_buf = alloca (descr->max_register_size);
+
+  /* NOTE: cagney/2002-08-17: This code assumes that the register
+     offsets are strictly increasing and do not overlap.  If this
+     isn't the case then the bug is in the target architecture and NOT
+     this code.  */
+
+  /* NOTE: cagney/2002-08-17: This code assumes that only the
+     registers covered by BUF_START:BUF_LEN should be transfered.  If,
+     for some reason, there is a gap between two registers, then that
+     gap isn't transfered.  (The gap shouldn't be there but that is
+     another story.)  */
+
+  /* Iterate through all registers looking for those that lie within
+     BUF_START:BUF_LEN.  */
+
+  for (regnum = 0; regnum < descr->nr_cooked_registers; regnum++)
+    {
+      /* The register's location.  */
+      int reg_start = descr->register_offset[regnum];
+      int reg_len = descr->sizeof_register[regnum];
+      int reg_end = reg_start + reg_len;
+
+      /* The START, END and LEN that falls within the current
+         register.  */
+      int xfer_start;
+      int xfer_end;
+      int xfer_len;
+
+      /* start = max (reg_start, buf_start) */
+      if (reg_start > buf_start)
+       xfer_start = reg_start;
+      else
+       xfer_start = buf_start;
+      
+      /* end = min (reg_end, buf_end) */
+      if (reg_end < buf_end)
+       xfer_end = reg_end;
+      else
+       xfer_end = buf_end;
+      
+      /* The number of bytes to transfer.  If there isn't anything to
+         transfer (the end is before the start) this will be -ve.  */
+      xfer_len = xfer_end - xfer_start;
+
+      if (xfer_len > 0)
+       regcache_xfer_part (regcache, regnum, xfer_start - reg_start,
+                           xfer_len, in_b, out_b, regcache_cooked_read,
+                           regcache_cooked_write);
+    }
+}
+
+void
+regcache_cooked_read_using_offset_hack (struct regcache *regcache,
+                                       int buf_start, int buf_len, void *b)
+{
+  cooked_xfer_using_offset_hack (regcache, buf_start, buf_len, b, NULL);
+}
+
+void
+regcache_cooked_write_using_offset_hack (struct regcache *regcache,
+                                        int buf_start, int buf_len,
+                                        const void *b)
+{
+  cooked_xfer_using_offset_hack (regcache, buf_start, buf_len, NULL, b);
+}
 
 /* Return the contents of register REGNUM as an unsigned integer.  */
 
@@ -975,7 +1246,7 @@ write_register_pid (int regnum, CORE_ADDR val, ptid_t ptid)
    fact, and report it to the users of read_register and friends.  */
 
 void
-supply_register (int regnum, char *val)
+supply_register (int regnum, const void *val)
 {
 #if 1
   if (! ptid_equal (registers_ptid, inferior_ptid))
@@ -999,11 +1270,12 @@ supply_register (int regnum, char *val)
   /* NOTE: cagney/2001-03-16: The macro CLEAN_UP_REGISTER_VALUE is
      going to be deprecated.  Instead architectures will leave the raw
      register value as is and instead clean things up as they pass
-     through the method gdbarch_register_read() clean up the
+     through the method gdbarch_pseudo_register_read() clean up the
      values. */
 
 #ifdef DEPRECATED_CLEAN_UP_REGISTER_VALUE
-  DEPRECATED_CLEAN_UP_REGISTER_VALUE (regnum, register_buffer (regnum));
+  DEPRECATED_CLEAN_UP_REGISTER_VALUE \
+    (regnum, register_buffer (current_regcache, regnum));
 #endif
 }
 
@@ -1185,6 +1457,245 @@ build_regcache (void)
   register_valid = deprecated_grub_regcache_for_register_valid (current_regcache);
 }
 
+static void
+dump_endian_bytes (struct ui_file *file, enum bfd_endian endian,
+                  const unsigned char *buf, long len)
+{
+  int i;
+  switch (endian)
+    {
+    case BFD_ENDIAN_BIG:
+      for (i = 0; i < len; i++)
+       fprintf_unfiltered (file, "%02x", buf[i]);
+      break;
+    case BFD_ENDIAN_LITTLE:
+      for (i = len - 1; i >= 0; i--)
+       fprintf_unfiltered (file, "%02x", buf[i]);
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, "Bad switch");
+    }
+}
+
+enum regcache_dump_what
+{
+  regcache_dump_none, regcache_dump_raw, regcache_dump_cooked
+};
+
+static void
+regcache_dump (struct regcache *regcache, struct ui_file *file,
+              enum regcache_dump_what what_to_dump)
+{
+  struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+  int regnum;
+  int footnote_nr = 0;
+  int footnote_register_size = 0;
+  int footnote_register_offset = 0;
+  int footnote_register_type_name_null = 0;
+  long register_offset = 0;
+  unsigned char *buf = alloca (regcache->descr->max_register_size);
+
+#if 0
+  fprintf_unfiltered (file, "legacy_p %d\n", regcache->descr->legacy_p);
+  fprintf_unfiltered (file, "nr_raw_registers %d\n",
+                     regcache->descr->nr_raw_registers);
+  fprintf_unfiltered (file, "nr_cooked_registers %d\n",
+                     regcache->descr->nr_cooked_registers);
+  fprintf_unfiltered (file, "sizeof_raw_registers %ld\n",
+                     regcache->descr->sizeof_raw_registers);
+  fprintf_unfiltered (file, "sizeof_raw_register_valid_p %ld\n",
+                     regcache->descr->sizeof_raw_register_valid_p);
+  fprintf_unfiltered (file, "max_register_size %ld\n",
+                     regcache->descr->max_register_size);
+  fprintf_unfiltered (file, "NUM_REGS %d\n", NUM_REGS);
+  fprintf_unfiltered (file, "NUM_PSEUDO_REGS %d\n", NUM_PSEUDO_REGS);
+#endif
+
+  gdb_assert (regcache->descr->nr_cooked_registers
+             == (NUM_REGS + NUM_PSEUDO_REGS));
+
+  for (regnum = -1; regnum < regcache->descr->nr_cooked_registers; regnum++)
+    {
+      /* Name.  */
+      if (regnum < 0)
+       fprintf_unfiltered (file, " %-10s", "Name");
+      else
+       {
+         const char *p = REGISTER_NAME (regnum);
+         if (p == NULL)
+           p = "";
+         else if (p[0] == '\0')
+           p = "''";
+         fprintf_unfiltered (file, " %-10s", p);
+       }
+
+      /* Number.  */
+      if (regnum < 0)
+       fprintf_unfiltered (file, " %4s", "Nr");
+      else
+       fprintf_unfiltered (file, " %4d", regnum);
+
+      /* Relative number.  */
+      if (regnum < 0)
+       fprintf_unfiltered (file, " %4s", "Rel");
+      else if (regnum < NUM_REGS)
+       fprintf_unfiltered (file, " %4d", regnum);
+      else
+       fprintf_unfiltered (file, " %4d", (regnum - NUM_REGS));
+
+      /* Offset.  */
+      if (regnum < 0)
+       fprintf_unfiltered (file, " %6s  ", "Offset");
+      else
+       {
+         fprintf_unfiltered (file, " %6ld",
+                             regcache->descr->register_offset[regnum]);
+         if (register_offset != regcache->descr->register_offset[regnum]
+             || register_offset != REGISTER_BYTE (regnum)
+             || (regnum > 0
+                 && (regcache->descr->register_offset[regnum]
+                     != (regcache->descr->register_offset[regnum - 1]
+                         + regcache->descr->sizeof_register[regnum - 1])))
+             )
+           {
+             if (!footnote_register_offset)
+               footnote_register_offset = ++footnote_nr;
+             fprintf_unfiltered (file, "*%d", footnote_register_offset);
+           }
+         else
+           fprintf_unfiltered (file, "  ");
+         register_offset = (regcache->descr->register_offset[regnum]
+                            + regcache->descr->sizeof_register[regnum]);
+       }
+
+      /* Size.  */
+      if (regnum < 0)
+       fprintf_unfiltered (file, " %5s ", "Size");
+      else
+       {
+         fprintf_unfiltered (file, " %5ld",
+                             regcache->descr->sizeof_register[regnum]);
+         if ((regcache->descr->sizeof_register[regnum]
+              != REGISTER_RAW_SIZE (regnum))
+             || (regcache->descr->sizeof_register[regnum]
+                 != REGISTER_VIRTUAL_SIZE (regnum))
+             || (regcache->descr->sizeof_register[regnum]
+                 != TYPE_LENGTH (register_type (regcache->descr->gdbarch,
+                                                regnum)))
+             )
+           {
+             if (!footnote_register_size)
+               footnote_register_size = ++footnote_nr;
+             fprintf_unfiltered (file, "*%d", footnote_register_size);
+           }
+         else
+           fprintf_unfiltered (file, " ");
+       }
+
+      /* Type.  */
+      if (regnum < 0)
+       fprintf_unfiltered (file, " %-20s", "Type");
+      else
+       {
+         static const char blt[] = "builtin_type";
+         const char *t = TYPE_NAME (register_type (regcache->descr->gdbarch,
+                                                   regnum));
+         if (t == NULL)
+           {
+             char *n;
+             if (!footnote_register_type_name_null)
+               footnote_register_type_name_null = ++footnote_nr;
+             xasprintf (&n, "*%d", footnote_register_type_name_null);
+             make_cleanup (xfree, n);
+             t = n;
+           }
+         /* Chop a leading builtin_type.  */
+         if (strncmp (t, blt, strlen (blt)) == 0)
+           t += strlen (blt);
+         fprintf_unfiltered (file, " %-20s", t);
+       }
+
+      /* Value, raw.  */
+      if (what_to_dump == regcache_dump_raw)
+       {
+         if (regnum < 0)
+           fprintf_unfiltered (file, "Raw value");
+         else if (regnum >= regcache->descr->nr_raw_registers)
+           fprintf_unfiltered (file, "<cooked>");
+         else if (!regcache_valid_p (regcache, regnum))
+           fprintf_unfiltered (file, "<invalid>");
+         else
+           {
+             regcache_raw_read (regcache, regnum, buf);
+             fprintf_unfiltered (file, "0x");
+             dump_endian_bytes (file, TARGET_BYTE_ORDER, buf,
+                                REGISTER_RAW_SIZE (regnum));
+           }
+       }
+
+      /* Value, cooked.  */
+      if (what_to_dump == regcache_dump_cooked)
+       {
+         if (regnum < 0)
+           fprintf_unfiltered (file, "Cooked value");
+         else
+           {
+             regcache_cooked_read (regcache, regnum, buf);
+             fprintf_unfiltered (file, "0x");
+             dump_endian_bytes (file, TARGET_BYTE_ORDER, buf,
+                                REGISTER_VIRTUAL_SIZE (regnum));
+           }
+       }
+
+      fprintf_unfiltered (file, "\n");
+    }
+
+  if (footnote_register_size)
+    fprintf_unfiltered (file, "*%d: Inconsistent register sizes.\n",
+                       footnote_register_size);
+  if (footnote_register_offset)
+    fprintf_unfiltered (file, "*%d: Inconsistent register offsets.\n",
+                       footnote_register_offset);
+  if (footnote_register_type_name_null)
+    fprintf_unfiltered (file, 
+                       "*%d: Register type's name NULL.\n",
+                       footnote_register_type_name_null);
+  do_cleanups (cleanups);
+}
+
+static void
+regcache_print (char *args, enum regcache_dump_what what_to_dump)
+{
+  if (args == NULL)
+    regcache_dump (current_regcache, gdb_stdout, what_to_dump);
+  else
+    {
+      struct ui_file *file = gdb_fopen (args, "w");
+      if (file == NULL)
+       perror_with_name ("maintenance print architecture");
+      regcache_dump (current_regcache, file, what_to_dump);    
+      ui_file_delete (file);
+    }
+}
+
+static void
+maintenance_print_registers (char *args, int from_tty)
+{
+  regcache_print (args, regcache_dump_none);
+}
+
+static void
+maintenance_print_raw_registers (char *args, int from_tty)
+{
+  regcache_print (args, regcache_dump_raw);
+}
+
+static void
+maintenance_print_cooked_registers (char *args, int from_tty)
+{
+  regcache_print (args, regcache_dump_cooked);
+}
+
 void
 _initialize_regcache (void)
 {
@@ -1201,4 +1712,21 @@ _initialize_regcache (void)
    /* Initialize the thread/process associated with the current set of
       registers.  For now, -1 is special, and means `no current process'.  */
   registers_ptid = pid_to_ptid (-1);
+
+  add_cmd ("registers", class_maintenance,
+          maintenance_print_registers,
+          "Print the internal register configuration.\
+Takes an optional file parameter.",
+          &maintenanceprintlist);
+  add_cmd ("raw-registers", class_maintenance,
+          maintenance_print_raw_registers,
+          "Print the internal register configuration including raw values.\
+Takes an optional file parameter.",
+          &maintenanceprintlist);
+  add_cmd ("cooked-registers", class_maintenance,
+          maintenance_print_cooked_registers,
+          "Print the internal register configuration including cooked values.\
+Takes an optional file parameter.",
+          &maintenanceprintlist);
+
 }
This page took 0.035416 seconds and 4 git commands to generate.