* Makefile.in (i386nbsd-tdep.o): Add $(arch_utils_h),
[deliverable/binutils-gdb.git] / gdb / regcache.c
index e483de08cfd72ad5fff83192e0a68523a23face7..ab65c67a47b7c1293bf9958bc9921537a5aab33e 100644 (file)
@@ -77,24 +77,22 @@ struct regcache_descr
 
   /* 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_cooked_registers = NUM_REGS + NUM_PSEUDO_REGS;
   descr->nr_raw_registers = descr->nr_cooked_registers;
   descr->sizeof_raw_register_valid_p = descr->nr_cooked_registers;
 
@@ -112,6 +110,8 @@ init_legacy_regcache_descr (struct gdbarch *gdbarch)
       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.  */
@@ -133,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 *
@@ -143,21 +142,33 @@ 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_pseudo_register_read_p (gdbarch)
-      && !gdbarch_pseudo_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 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;
 
+  /* 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;
@@ -173,10 +184,10 @@ init_regcache_descr (struct gdbarch *gdbarch)
      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;
@@ -185,7 +196,7 @@ init_regcache_descr (struct gdbarch *gdbarch)
     descr->max_register_size = 0;
     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])
@@ -239,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
@@ -692,6 +724,29 @@ regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
                                     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)
 {
@@ -997,6 +1052,95 @@ regcache_cooked_write_part (struct regcache *regcache, int regnum,
                      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.  */
 
 ULONGEST
@@ -1407,7 +1551,12 @@ regcache_dump (struct regcache *regcache, struct ui_file *file,
          fprintf_unfiltered (file, " %6ld",
                              regcache->descr->register_offset[regnum]);
          if (register_offset != regcache->descr->register_offset[regnum]
-             || register_offset != REGISTER_BYTE (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;
@@ -1431,7 +1580,8 @@ regcache_dump (struct regcache *regcache, struct ui_file *file,
              || (regcache->descr->sizeof_register[regnum]
                  != REGISTER_VIRTUAL_SIZE (regnum))
              || (regcache->descr->sizeof_register[regnum]
-                 != TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (regnum)))
+                 != TYPE_LENGTH (register_type (regcache->descr->gdbarch,
+                                                regnum)))
              )
            {
              if (!footnote_register_size)
@@ -1448,7 +1598,8 @@ regcache_dump (struct regcache *regcache, struct ui_file *file,
       else
        {
          static const char blt[] = "builtin_type";
-         const char *t = TYPE_NAME (REGISTER_VIRTUAL_TYPE (regnum));
+         const char *t = TYPE_NAME (register_type (regcache->descr->gdbarch,
+                                                   regnum));
          if (t == NULL)
            {
              char *n;
This page took 0.026299 seconds and 4 git commands to generate.