[ARC] Add checking for LP_COUNT reg usage, improve error reporting.
[deliverable/binutils-gdb.git] / gdb / regcache.c
index 449f68215b91237f21d57befb7b38450df7a62b7..1fcf93386f7d3d4180ab6dad4f228566563855b2 100644 (file)
@@ -1,7 +1,6 @@
 /* Cache and manage the values of registers for GDB, the GNU debugger.
 
-   Copyright (C) 1986-1987, 1989, 1991, 1994-1996, 1998, 2000-2002,
-   2004, 2007-2012 Free Software Foundation, Inc.
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "gdbcmd.h"
 #include "regcache.h"
 #include "reggroups.h"
-#include "gdb_assert.h"
-#include "gdb_string.h"
-#include "gdbcmd.h"            /* For maintenanceprintlist.  */
 #include "observer.h"
-#include "exceptions.h"
 #include "remote.h"
+#include "valprint.h"
+#include "regset.h"
 
 /*
  * DATA STRUCTURE
@@ -150,7 +147,8 @@ init_regcache_descr (struct gdbarch *gdbarch)
 static struct regcache_descr *
 regcache_descr (struct gdbarch *gdbarch)
 {
-  return gdbarch_data (gdbarch, regcache_descr_handle);
+  return (struct regcache_descr *) gdbarch_data (gdbarch,
+                                                regcache_descr_handle);
 }
 
 /* Utility functions returning useful register attributes stored in
@@ -181,6 +179,14 @@ register_size (struct gdbarch *gdbarch, int regnum)
   return size;
 }
 
+/* See common/common-regcache.h.  */
+
+int
+regcache_register_size (const struct regcache *regcache, int n)
+{
+  return register_size (get_regcache_arch (regcache), n);
+}
+
 /* The register cache for storing raw register values.  */
 
 struct regcache
@@ -218,22 +224,22 @@ regcache_xmalloc_1 (struct gdbarch *gdbarch, struct address_space *aspace,
 
   gdb_assert (gdbarch != NULL);
   descr = regcache_descr (gdbarch);
-  regcache = XMALLOC (struct regcache);
+  regcache = XNEW (struct regcache);
   regcache->descr = descr;
   regcache->readonly_p = readonly_p;
   if (readonly_p)
     {
       regcache->registers
-       = XCALLOC (descr->sizeof_cooked_registers, gdb_byte);
+       = XCNEWVEC (gdb_byte, descr->sizeof_cooked_registers);
       regcache->register_status
-       = XCALLOC (descr->sizeof_cooked_register_status, gdb_byte);
+       = XCNEWVEC (signed char, descr->sizeof_cooked_register_status);
     }
   else
     {
       regcache->registers
-       = XCALLOC (descr->sizeof_raw_registers, gdb_byte);
+       = XCNEWVEC (gdb_byte, descr->sizeof_raw_registers);
       regcache->register_status
-       = XCALLOC (descr->sizeof_raw_register_status, gdb_byte);
+       = XCNEWVEC (signed char, descr->sizeof_raw_register_status);
     }
   regcache->aspace = aspace;
   regcache->ptid = minus_one_ptid;
@@ -259,7 +265,7 @@ regcache_xfree (struct regcache *regcache)
 static void
 do_regcache_xfree (void *data)
 {
-  regcache_xfree (data);
+  regcache_xfree ((struct regcache *) data);
 }
 
 struct cleanup *
@@ -268,6 +274,32 @@ make_cleanup_regcache_xfree (struct regcache *regcache)
   return make_cleanup (do_regcache_xfree, regcache);
 }
 
+/* Cleanup routines for invalidating a register.  */
+
+struct register_to_invalidate
+{
+  struct regcache *regcache;
+  int regnum;
+};
+
+static void
+do_regcache_invalidate (void *data)
+{
+  struct register_to_invalidate *reg = (struct register_to_invalidate *) data;
+
+  regcache_invalidate (reg->regcache, reg->regnum);
+}
+
+static struct cleanup *
+make_cleanup_regcache_invalidate (struct regcache *regcache, int regnum)
+{
+  struct register_to_invalidate* reg = XNEW (struct register_to_invalidate);
+
+  reg->regcache = regcache;
+  reg->regnum = regnum;
+  return make_cleanup_dtor (do_regcache_invalidate, (void *) reg, xfree);
+}
+
 /* Return REGCACHE's architecture.  */
 
 struct gdbarch *
@@ -363,11 +395,14 @@ regcache_restore (struct regcache *dst,
 static enum register_status
 do_cooked_read (void *src, int regnum, gdb_byte *buf)
 {
-  struct regcache *regcache = src;
+  struct regcache *regcache = (struct regcache *) src;
 
   return regcache_cooked_read (regcache, regnum, buf);
 }
 
+static void regcache_cpy_no_passthrough (struct regcache *dst,
+                                        struct regcache *src);
+
 void
 regcache_cpy (struct regcache *dst, struct regcache *src)
 {
@@ -384,7 +419,12 @@ regcache_cpy (struct regcache *dst, struct regcache *src)
     regcache_cpy_no_passthrough (dst, src);
 }
 
-void
+/* Copy/duplicate the contents of a register cache.  Unlike regcache_cpy,
+   which is pass-through, this does not go through to the target.
+   Only values values already in the cache are transferred.  The SRC and DST
+   buffers must not overlap.  */
+
+static void
 regcache_cpy_no_passthrough (struct regcache *dst, struct regcache *src)
 {
   gdb_assert (src != NULL && dst != NULL);
@@ -421,7 +461,7 @@ regcache_register_status (const struct regcache *regcache, int regnum)
   else
     gdb_assert (regnum < regcache->descr->nr_raw_registers);
 
-  return regcache->register_status[regnum];
+  return (enum register_status) regcache->register_status[regnum];
 }
 
 void
@@ -465,7 +505,7 @@ get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
   new_regcache = regcache_xmalloc_1 (gdbarch, aspace, 0);
   new_regcache->ptid = ptid;
 
-  list = xmalloc (sizeof (struct regcache_list));
+  list = XNEW (struct regcache_list);
   list->regcache = new_regcache;
   list->next = current_regcache;
   current_regcache = list;
@@ -512,6 +552,13 @@ get_current_regcache (void)
   return get_thread_regcache (inferior_ptid);
 }
 
+/* See common/common-regcache.h.  */
+
+struct regcache *
+get_thread_regcache_for_ptid (ptid_t ptid)
+{
+  return get_thread_regcache (ptid);
+}
 
 /* Observer for the target_changed event.  */
 
@@ -626,7 +673,7 @@ regcache_raw_read (struct regcache *regcache, int regnum, gdb_byte *buf)
     memcpy (buf, register_buffer (regcache, regnum),
            regcache->descr->sizeof_register[regnum]);
 
-  return regcache->register_status[regnum];
+  return (enum register_status) regcache->register_status[regnum];
 }
 
 enum register_status
@@ -637,7 +684,7 @@ regcache_raw_read_signed (struct regcache *regcache, int regnum, LONGEST *val)
 
   gdb_assert (regcache != NULL);
   gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
-  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  buf = (gdb_byte *) alloca (regcache->descr->sizeof_register[regnum]);
   status = regcache_raw_read (regcache, regnum, buf);
   if (status == REG_VALID)
     *val = extract_signed_integer
@@ -657,7 +704,7 @@ regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
 
   gdb_assert (regcache != NULL);
   gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
-  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  buf = (gdb_byte *) alloca (regcache->descr->sizeof_register[regnum]);
   status = regcache_raw_read (regcache, regnum, buf);
   if (status == REG_VALID)
     *val = extract_unsigned_integer
@@ -671,11 +718,11 @@ regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
 void
 regcache_raw_write_signed (struct regcache *regcache, int regnum, LONGEST val)
 {
-  void *buf;
+  gdb_byte *buf;
 
   gdb_assert (regcache != NULL);
   gdb_assert (regnum >=0 && regnum < regcache->descr->nr_raw_registers);
-  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  buf = (gdb_byte *) alloca (regcache->descr->sizeof_register[regnum]);
   store_signed_integer (buf, regcache->descr->sizeof_register[regnum],
                        gdbarch_byte_order (regcache->descr->gdbarch), val);
   regcache_raw_write (regcache, regnum, buf);
@@ -685,16 +732,29 @@ void
 regcache_raw_write_unsigned (struct regcache *regcache, int regnum,
                             ULONGEST val)
 {
-  void *buf;
+  gdb_byte *buf;
 
   gdb_assert (regcache != NULL);
   gdb_assert (regnum >=0 && regnum < regcache->descr->nr_raw_registers);
-  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  buf = (gdb_byte *) alloca (regcache->descr->sizeof_register[regnum]);
   store_unsigned_integer (buf, regcache->descr->sizeof_register[regnum],
                          gdbarch_byte_order (regcache->descr->gdbarch), val);
   regcache_raw_write (regcache, regnum, buf);
 }
 
+LONGEST
+regcache_raw_get_signed (struct regcache *regcache, int regnum)
+{
+  LONGEST value;
+  enum register_status status;
+
+  status = regcache_raw_read_signed (regcache, regnum, &value);
+  if (status == REG_UNAVAILABLE)
+    throw_error (NOT_AVAILABLE_ERROR,
+                _("Register %d is not available"), regnum);
+  return value;
+}
+
 enum register_status
 regcache_cooked_read (struct regcache *regcache, int regnum, gdb_byte *buf)
 {
@@ -707,15 +767,13 @@ regcache_cooked_read (struct regcache *regcache, int regnum, gdb_byte *buf)
     {
       /* Read-only register cache, perhaps the cooked value was
         cached?  */
-      struct gdbarch *gdbarch = regcache->descr->gdbarch;
-
       if (regcache->register_status[regnum] == REG_VALID)
        memcpy (buf, register_buffer (regcache, regnum),
                regcache->descr->sizeof_register[regnum]);
       else
        memset (buf, 0, regcache->descr->sizeof_register[regnum]);
 
-      return regcache->register_status[regnum];
+      return (enum register_status) regcache->register_status[regnum];
     }
   else if (gdbarch_pseudo_register_read_value_p (regcache->descr->gdbarch))
     {
@@ -786,7 +844,7 @@ regcache_cooked_read_signed (struct regcache *regcache, int regnum,
 
   gdb_assert (regcache != NULL);
   gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_cooked_registers);
-  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  buf = (gdb_byte *) alloca (regcache->descr->sizeof_register[regnum]);
   status = regcache_cooked_read (regcache, regnum, buf);
   if (status == REG_VALID)
     *val = extract_signed_integer
@@ -806,7 +864,7 @@ regcache_cooked_read_unsigned (struct regcache *regcache, int regnum,
 
   gdb_assert (regcache != NULL);
   gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_cooked_registers);
-  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  buf = (gdb_byte *) alloca (regcache->descr->sizeof_register[regnum]);
   status = regcache_cooked_read (regcache, regnum, buf);
   if (status == REG_VALID)
     *val = extract_unsigned_integer
@@ -821,11 +879,11 @@ void
 regcache_cooked_write_signed (struct regcache *regcache, int regnum,
                              LONGEST val)
 {
-  void *buf;
+  gdb_byte *buf;
 
   gdb_assert (regcache != NULL);
   gdb_assert (regnum >=0 && regnum < regcache->descr->nr_cooked_registers);
-  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  buf = (gdb_byte *) alloca (regcache->descr->sizeof_register[regnum]);
   store_signed_integer (buf, regcache->descr->sizeof_register[regnum],
                        gdbarch_byte_order (regcache->descr->gdbarch), val);
   regcache_cooked_write (regcache, regnum, buf);
@@ -835,21 +893,33 @@ void
 regcache_cooked_write_unsigned (struct regcache *regcache, int regnum,
                                ULONGEST val)
 {
-  void *buf;
+  gdb_byte *buf;
 
   gdb_assert (regcache != NULL);
   gdb_assert (regnum >=0 && regnum < regcache->descr->nr_cooked_registers);
-  buf = alloca (regcache->descr->sizeof_register[regnum]);
+  buf = (gdb_byte *) alloca (regcache->descr->sizeof_register[regnum]);
   store_unsigned_integer (buf, regcache->descr->sizeof_register[regnum],
                          gdbarch_byte_order (regcache->descr->gdbarch), val);
   regcache_cooked_write (regcache, regnum, buf);
 }
 
+/* See regcache.h.  */
+
+void
+regcache_raw_set_cached_value (struct regcache *regcache, int regnum,
+                              const gdb_byte *buf)
+{
+  memcpy (register_buffer (regcache, regnum), buf,
+         regcache->descr->sizeof_register[regnum]);
+  regcache->register_status[regnum] = REG_VALID;
+}
+
 void
 regcache_raw_write (struct regcache *regcache, int regnum,
                    const gdb_byte *buf)
 {
-  struct cleanup *old_chain;
+  struct cleanup *chain_before_save_inferior;
+  struct cleanup *chain_before_invalidate_register;
 
   gdb_assert (regcache != NULL && buf != NULL);
   gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
@@ -867,16 +937,24 @@ regcache_raw_write (struct regcache *regcache, int regnum,
                  regcache->descr->sizeof_register[regnum]) == 0))
     return;
 
-  old_chain = save_inferior_ptid ();
+  chain_before_save_inferior = save_inferior_ptid ();
   inferior_ptid = regcache->ptid;
 
   target_prepare_to_store (regcache);
-  memcpy (register_buffer (regcache, regnum), buf,
-         regcache->descr->sizeof_register[regnum]);
-  regcache->register_status[regnum] = REG_VALID;
+  regcache_raw_set_cached_value (regcache, regnum, buf);
+
+  /* Register a cleanup function for invalidating the register after it is
+     written, in case of a failure.  */
+  chain_before_invalidate_register
+    = make_cleanup_regcache_invalidate (regcache, regnum);
+
   target_store_registers (regcache, regnum);
 
-  do_cleanups (old_chain);
+  /* The target did not throw an error so we can discard invalidating the
+     register and restore the cleanup chain to what it was.  */
+  discard_cleanups (chain_before_invalidate_register);
+
+  do_cleanups (chain_before_save_inferior);
 }
 
 void
@@ -1034,6 +1112,94 @@ regcache_raw_collect (const struct regcache *regcache, int regnum, void *buf)
   memcpy (buf, regbuf, size);
 }
 
+/* Transfer a single or all registers belonging to a certain register
+   set to or from a buffer.  This is the main worker function for
+   regcache_supply_regset and regcache_collect_regset.  */
+
+static void
+regcache_transfer_regset (const struct regset *regset,
+                         const struct regcache *regcache,
+                         struct regcache *out_regcache,
+                         int regnum, const void *in_buf,
+                         void *out_buf, size_t size)
+{
+  const struct regcache_map_entry *map;
+  int offs = 0, count;
+
+  for (map = (const struct regcache_map_entry *) regset->regmap;
+       (count = map->count) != 0;
+       map++)
+    {
+      int regno = map->regno;
+      int slot_size = map->size;
+
+      if (slot_size == 0 && regno != REGCACHE_MAP_SKIP)
+       slot_size = regcache->descr->sizeof_register[regno];
+
+      if (regno == REGCACHE_MAP_SKIP
+         || (regnum != -1
+             && (regnum < regno || regnum >= regno + count)))
+         offs += count * slot_size;
+
+      else if (regnum == -1)
+       for (; count--; regno++, offs += slot_size)
+         {
+           if (offs + slot_size > size)
+             break;
+
+           if (out_buf)
+             regcache_raw_collect (regcache, regno,
+                                   (gdb_byte *) out_buf + offs);
+           else
+             regcache_raw_supply (out_regcache, regno, in_buf
+                                  ? (const gdb_byte *) in_buf + offs
+                                  : NULL);
+         }
+      else
+       {
+         /* Transfer a single register and return.  */
+         offs += (regnum - regno) * slot_size;
+         if (offs + slot_size > size)
+           return;
+
+         if (out_buf)
+           regcache_raw_collect (regcache, regnum,
+                                 (gdb_byte *) out_buf + offs);
+         else
+           regcache_raw_supply (out_regcache, regnum, in_buf
+                                ? (const gdb_byte *) in_buf + offs
+                                : NULL);
+         return;
+       }
+    }
+}
+
+/* Supply register REGNUM from BUF to REGCACHE, using the register map
+   in REGSET.  If REGNUM is -1, do this for all registers in REGSET.
+   If BUF is NULL, set the register(s) to "unavailable" status. */
+
+void
+regcache_supply_regset (const struct regset *regset,
+                       struct regcache *regcache,
+                       int regnum, const void *buf, size_t size)
+{
+  regcache_transfer_regset (regset, regcache, regcache, regnum,
+                           buf, NULL, size);
+}
+
+/* Collect register REGNUM from REGCACHE to BUF, using the register
+   map in REGSET.  If REGNUM is -1, do this for all registers in
+   REGSET.  */
+
+void
+regcache_collect_regset (const struct regset *regset,
+                        const struct regcache *regcache,
+                        int regnum, void *buf, size_t size)
+{
+  regcache_transfer_regset (regset, regcache, NULL, regnum,
+                           NULL, buf, size);
+}
+
 
 /* Special handling for register PC.  */
 
@@ -1093,27 +1259,6 @@ reg_flush_command (char *command, int from_tty)
     printf_filtered (_("Register cache flushed.\n"));
 }
 
-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,
@@ -1133,7 +1278,7 @@ regcache_dump (struct regcache *regcache, struct ui_file *file,
   int footnote_register_offset = 0;
   int footnote_register_type_name_null = 0;
   long register_offset = 0;
-  unsigned char buf[MAX_REGISTER_SIZE];
+  gdb_byte buf[MAX_REGISTER_SIZE];
 
 #if 0
   fprintf_unfiltered (file, "nr_raw_registers %d\n",
@@ -1238,7 +1383,7 @@ regcache_dump (struct regcache *regcache, struct ui_file *file,
                t = n;
              }
            /* Chop a leading builtin_type.  */
-           if (strncmp (t, blt, strlen (blt)) == 0)
+           if (startswith (t, blt))
              t += strlen (blt);
          }
        fprintf_unfiltered (file, " %-15s", t);
@@ -1261,10 +1406,9 @@ regcache_dump (struct regcache *regcache, struct ui_file *file,
          else
            {
              regcache_raw_read (regcache, regnum, buf);
-             fprintf_unfiltered (file, "0x");
-             dump_endian_bytes (file,
-                                gdbarch_byte_order (gdbarch), buf,
-                                regcache->descr->sizeof_register[regnum]);
+             print_hex_chars (file, buf,
+                              regcache->descr->sizeof_register[regnum],
+                              gdbarch_byte_order (gdbarch));
            }
        }
 
@@ -1283,12 +1427,9 @@ regcache_dump (struct regcache *regcache, struct ui_file *file,
              else if (status == REG_UNAVAILABLE)
                fprintf_unfiltered (file, "<unavailable>");
              else
-               {
-                 fprintf_unfiltered (file, "0x");
-                 dump_endian_bytes (file,
-                                    gdbarch_byte_order (gdbarch), buf,
-                                    regcache->descr->sizeof_register[regnum]);
-               }
+               print_hex_chars (file, buf,
+                                regcache->descr->sizeof_register[regnum],
+                                gdbarch_byte_order (gdbarch));
            }
        }
 
This page took 0.030394 seconds and 4 git commands to generate.