Put selftests api into selftests namespace
[deliverable/binutils-gdb.git] / gdb / regcache.c
index 07b1c97fd3092459d01f962124583a2e7780a880..dcbcedd7a3b545f99820221533c4fc2cd3697b9e 100644 (file)
@@ -28,6 +28,7 @@
 #include "remote.h"
 #include "valprint.h"
 #include "regset.h"
+#include <forward_list>
 
 /*
  * DATA STRUCTURE
@@ -327,7 +328,6 @@ regcache::save (regcache_cooked_read_ftype *cooked_read,
                void *src)
 {
   struct gdbarch *gdbarch = m_descr->gdbarch;
-  gdb_byte buf[MAX_REGISTER_SIZE];
   int regnum;
 
   /* The DST should be `read-only', if it wasn't then the save would
@@ -345,18 +345,14 @@ regcache::save (regcache_cooked_read_ftype *cooked_read,
     {
       if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup))
        {
-         enum register_status status = cooked_read (src, regnum, buf);
+         gdb_byte *dst_buf = register_buffer (regnum);
+         enum register_status status = cooked_read (src, regnum, dst_buf);
 
-         if (status == REG_VALID)
-           memcpy (register_buffer (regnum), buf,
-                   register_size (gdbarch, regnum));
-         else
-           {
-             gdb_assert (status != REG_UNKNOWN);
+         gdb_assert (status != REG_UNKNOWN);
+
+         if (status != REG_VALID)
+           memset (dst_buf, 0, register_size (gdbarch, regnum));
 
-             memset (register_buffer (regnum), 0,
-                     register_size (gdbarch, regnum));
-           }
          m_register_status[regnum] = status;
        }
     }
@@ -392,36 +388,9 @@ regcache_cpy (struct regcache *dst, struct regcache *src)
   gdb_assert (src != NULL && dst != NULL);
   gdb_assert (src->m_descr->gdbarch == dst->m_descr->gdbarch);
   gdb_assert (src != dst);
-  gdb_assert (src->m_readonly_p || dst->m_readonly_p);
+  gdb_assert (src->m_readonly_p && !dst->m_readonly_p);
 
-  if (!src->m_readonly_p)
-    regcache_save (dst, do_cooked_read, src);
-  else if (!dst->m_readonly_p)
-    dst->restore (src);
-  else
-    dst->cpy_no_passthrough (src);
-}
-
-/* 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.  */
-
-void
-regcache::cpy_no_passthrough (struct regcache *src)
-{
-  gdb_assert (src != NULL);
-  gdb_assert (src->m_descr->gdbarch == m_descr->gdbarch);
-  /* NOTE: cagney/2002-05-17: Don't let the caller do a no-passthrough
-     move of data into a thread's regcache.  Doing this would be silly
-     - it would mean that regcache->register_status would be
-     completely invalid.  */
-  gdb_assert (m_readonly_p && src->m_readonly_p);
-
-  memcpy (m_registers, src->m_registers,
-         m_descr->sizeof_cooked_registers);
-  memcpy (m_register_status, src->m_register_status,
-         m_descr->sizeof_cooked_register_status);
+  dst->restore (src);
 }
 
 struct regcache *
@@ -471,35 +440,21 @@ regcache::invalidate (int regnum)
    recording if the register values have been changed (eg. by the
    user).  Therefore all registers must be written back to the
    target when appropriate.  */
-
-struct regcache_list
-{
-  struct regcache *regcache;
-  struct regcache_list *next;
-};
-
-static struct regcache_list *current_regcache;
+std::forward_list<regcache *> regcache::current_regcache;
 
 struct regcache *
 get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
                                 struct address_space *aspace)
 {
-  struct regcache_list *list;
-  struct regcache *new_regcache;
+  for (const auto &regcache : regcache::current_regcache)
+    if (ptid_equal (regcache->ptid (), ptid) && regcache->arch () == gdbarch)
+      return regcache;
 
-  for (list = current_regcache; list; list = list->next)
-    if (ptid_equal (list->regcache->ptid (), ptid)
-       && get_regcache_arch (list->regcache) == gdbarch)
-      return list->regcache;
+  regcache *new_regcache = new regcache (gdbarch, aspace, false);
 
-  new_regcache = new regcache (gdbarch, aspace, false);
+  regcache::current_regcache.push_front (new_regcache);
   new_regcache->set_ptid (ptid);
 
-  list = XNEW (struct regcache_list);
-  list->regcache = new_regcache;
-  list->next = current_regcache;
-  current_regcache = list;
-
   return new_regcache;
 }
 
@@ -560,14 +515,14 @@ regcache_observer_target_changed (struct target_ops *target)
 
 /* Update global variables old ptids to hold NEW_PTID if they were
    holding OLD_PTID.  */
-static void
-regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
+void
+regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
 {
-  struct regcache_list *list;
-
-  for (list = current_regcache; list; list = list->next)
-    if (ptid_equal (list->regcache->ptid (), old_ptid))
-      list->regcache->set_ptid (new_ptid);
+  for (auto &regcache : regcache::current_regcache)
+    {
+      if (ptid_equal (regcache->ptid (), old_ptid))
+       regcache->set_ptid (new_ptid);
+    }
 }
 
 /* Low level examining and depositing of registers.
@@ -584,25 +539,18 @@ regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
 void
 registers_changed_ptid (ptid_t ptid)
 {
-  struct regcache_list *list, **list_link;
-
-  list = current_regcache;
-  list_link = &current_regcache;
-  while (list)
+  for (auto oit = regcache::current_regcache.before_begin (),
+        it = std::next (oit);
+       it != regcache::current_regcache.end ();
+       )
     {
-      if (ptid_match (list->regcache->ptid (), ptid))
+      if (ptid_match ((*it)->ptid (), ptid))
        {
-         struct regcache_list *dead = list;
-
-         *list_link = list->next;
-         regcache_xfree (list->regcache);
-         list = *list_link;
-         xfree (dead);
-         continue;
+         delete *it;
+         it = regcache::current_regcache.erase_after (oit);
        }
-
-      list_link = &list->next;
-      list = *list_link;
+      else
+       oit = it++;
     }
 
   if (ptid_match (current_thread_ptid, ptid))
@@ -687,11 +635,12 @@ enum register_status
 regcache_raw_read_signed (struct regcache *regcache, int regnum, LONGEST *val)
 {
   gdb_assert (regcache != NULL);
-  return regcache->raw_read_signed (regnum, val);
+  return regcache->raw_read (regnum, val);
 }
 
+template<typename T, typename>
 enum register_status
-regcache::raw_read_signed (int regnum, LONGEST *val)
+regcache::raw_read (int regnum, T *val)
 {
   gdb_byte *buf;
   enum register_status status;
@@ -700,9 +649,9 @@ regcache::raw_read_signed (int regnum, LONGEST *val)
   buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
   status = raw_read (regnum, buf);
   if (status == REG_VALID)
-    *val = extract_signed_integer
-      (buf, m_descr->sizeof_register[regnum],
-       gdbarch_byte_order (m_descr->gdbarch));
+    *val = extract_integer<T> (buf,
+                              m_descr->sizeof_register[regnum],
+                              gdbarch_byte_order (m_descr->gdbarch));
   else
     *val = 0;
   return status;
@@ -713,44 +662,26 @@ regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
                            ULONGEST *val)
 {
   gdb_assert (regcache != NULL);
-  return regcache->raw_read_unsigned (regnum, val);
-}
-
-
-enum register_status
-regcache::raw_read_unsigned (int regnum, ULONGEST *val)
-{
-  gdb_byte *buf;
-  enum register_status status;
-
-  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
-  buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
-  status = raw_read (regnum, buf);
-  if (status == REG_VALID)
-    *val = extract_unsigned_integer
-      (buf, m_descr->sizeof_register[regnum],
-       gdbarch_byte_order (m_descr->gdbarch));
-  else
-    *val = 0;
-  return status;
+  return regcache->raw_read (regnum, val);
 }
 
 void
 regcache_raw_write_signed (struct regcache *regcache, int regnum, LONGEST val)
 {
   gdb_assert (regcache != NULL);
-  regcache->raw_write_signed (regnum, val);
+  regcache->raw_write (regnum, val);
 }
 
+template<typename T, typename>
 void
-regcache::raw_write_signed (int regnum, LONGEST val)
+regcache::raw_write (int regnum, T val)
 {
   gdb_byte *buf;
 
   gdb_assert (regnum >=0 && regnum < m_descr->nr_raw_registers);
   buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
-  store_signed_integer (buf, m_descr->sizeof_register[regnum],
-                       gdbarch_byte_order (m_descr->gdbarch), val);
+  store_integer (buf, m_descr->sizeof_register[regnum],
+                gdbarch_byte_order (m_descr->gdbarch), val);
   raw_write (regnum, buf);
 }
 
@@ -759,19 +690,7 @@ regcache_raw_write_unsigned (struct regcache *regcache, int regnum,
                             ULONGEST val)
 {
   gdb_assert (regcache != NULL);
-  regcache->raw_write_unsigned (regnum, val);
-}
-
-void
-regcache::raw_write_unsigned (int regnum, ULONGEST val)
-{
-  gdb_byte *buf;
-
-  gdb_assert (regnum >=0 && regnum < m_descr->nr_raw_registers);
-  buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
-  store_unsigned_integer (buf, m_descr->sizeof_register[regnum],
-                         gdbarch_byte_order (m_descr->gdbarch), val);
-  raw_write (regnum, buf);
+  regcache->raw_write (regnum, val);
 }
 
 LONGEST
@@ -882,11 +801,12 @@ regcache_cooked_read_signed (struct regcache *regcache, int regnum,
                             LONGEST *val)
 {
   gdb_assert (regcache != NULL);
-  return regcache->cooked_read_signed (regnum, val);
+  return regcache->cooked_read (regnum, val);
 }
 
+template<typename T, typename>
 enum register_status
-regcache::cooked_read_signed (int regnum, LONGEST *val)
+regcache::cooked_read (int regnum, T *val)
 {
   enum register_status status;
   gdb_byte *buf;
@@ -895,9 +815,8 @@ regcache::cooked_read_signed (int regnum, LONGEST *val)
   buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
   status = cooked_read (regnum, buf);
   if (status == REG_VALID)
-    *val = extract_signed_integer
-      (buf, m_descr->sizeof_register[regnum],
-       gdbarch_byte_order (m_descr->gdbarch));
+    *val = extract_integer<T> (buf, m_descr->sizeof_register[regnum],
+                              gdbarch_byte_order (m_descr->gdbarch));
   else
     *val = 0;
   return status;
@@ -908,25 +827,7 @@ regcache_cooked_read_unsigned (struct regcache *regcache, int regnum,
                               ULONGEST *val)
 {
   gdb_assert (regcache != NULL);
-  return regcache->cooked_read_unsigned (regnum, val);
-}
-
-enum register_status
-regcache::cooked_read_unsigned (int regnum, ULONGEST *val)
-{
-  enum register_status status;
-  gdb_byte *buf;
-
-  gdb_assert (regnum >= 0 && regnum < m_descr->nr_cooked_registers);
-  buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
-  status = cooked_read (regnum, buf);
-  if (status == REG_VALID)
-    *val = extract_unsigned_integer
-      (buf, m_descr->sizeof_register[regnum],
-       gdbarch_byte_order (m_descr->gdbarch));
-  else
-    *val = 0;
-  return status;
+  return regcache->cooked_read (regnum, val);
 }
 
 void
@@ -934,18 +835,19 @@ regcache_cooked_write_signed (struct regcache *regcache, int regnum,
                              LONGEST val)
 {
   gdb_assert (regcache != NULL);
-  regcache->cooked_write_signed (regnum, val);
+  regcache->cooked_write (regnum, val);
 }
 
+template<typename T, typename>
 void
-regcache::cooked_write_signed (int regnum, LONGEST val)
+regcache::cooked_write (int regnum, T val)
 {
   gdb_byte *buf;
 
   gdb_assert (regnum >=0 && regnum < m_descr->nr_cooked_registers);
   buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
-  store_signed_integer (buf, m_descr->sizeof_register[regnum],
-                       gdbarch_byte_order (m_descr->gdbarch), val);
+  store_integer (buf, m_descr->sizeof_register[regnum],
+                gdbarch_byte_order (m_descr->gdbarch), val);
   cooked_write (regnum, buf);
 }
 
@@ -954,19 +856,7 @@ regcache_cooked_write_unsigned (struct regcache *regcache, int regnum,
                                ULONGEST val)
 {
   gdb_assert (regcache != NULL);
-  regcache->cooked_write_unsigned (regnum, val);
-}
-
-void
-regcache::cooked_write_unsigned (int regnum, ULONGEST val)
-{
-  gdb_byte *buf;
-
-  gdb_assert (regnum >=0 && regnum < m_descr->nr_cooked_registers);
-  buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
-  store_unsigned_integer (buf, m_descr->sizeof_register[regnum],
-                         gdbarch_byte_order (m_descr->gdbarch), val);
-  cooked_write (regnum, buf);
+  regcache->cooked_write (regnum, val);
 }
 
 /* See regcache.h.  */
@@ -1199,6 +1089,31 @@ regcache::raw_supply (int regnum, const void *buf)
     }
 }
 
+/* Supply register REGNUM to REGCACHE.  Value to supply is an integer stored at
+   address ADDR, in target endian, with length ADDR_LEN and sign IS_SIGNED.  If
+   the register size is greater than ADDR_LEN, then the integer will be sign or
+   zero extended.  If the register size is smaller than the integer, then the
+   most significant bytes of the integer will be truncated.  */
+
+void
+regcache::raw_supply_integer (int regnum, const gdb_byte *addr, int addr_len,
+                             bool is_signed)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+  gdb_byte *regbuf;
+  size_t regsize;
+
+  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+  gdb_assert (!m_readonly_p);
+
+  regbuf = register_buffer (regnum);
+  regsize = m_descr->sizeof_register[regnum];
+
+  copy_integer_to_size (regbuf, regsize, addr, addr_len, is_signed,
+                       byte_order);
+  m_register_status[regnum] = REG_VALID;
+}
+
 /* Supply register REGNUM with zeroed value to REGCACHE.  This is not the same
    as calling raw_supply with NULL (which will set the state to
    unavailable).  */
@@ -1246,6 +1161,29 @@ regcache::raw_collect (int regnum, void *buf) const
    set to or from a buffer.  This is the main worker function for
    regcache_supply_regset and regcache_collect_regset.  */
 
+/* Collect register REGNUM from REGCACHE.  Store collected value as an integer
+   at address ADDR, in target endian, with length ADDR_LEN and sign IS_SIGNED.
+   If ADDR_LEN is greater than the register size, then the integer will be sign
+   or zero extended.  If ADDR_LEN is smaller than the register size, then the
+   most significant bytes of the integer will be truncated.  */
+
+void
+regcache::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len,
+                              bool is_signed) const
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+  const gdb_byte *regbuf;
+  size_t regsize;
+
+  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+
+  regbuf = register_buffer (regnum);
+  regsize = m_descr->sizeof_register[regnum];
+
+  copy_integer_to_size (addr, addr_len, regbuf, regsize, is_signed,
+                       byte_order);
+}
+
 void
 regcache::transfer_regset (const struct regset *regset,
                           struct regcache *out_regcache,
@@ -1443,7 +1381,6 @@ regcache::dump (ui_file *file, enum regcache_dump_what what_to_dump)
   int footnote_register_offset = 0;
   int footnote_register_type_name_null = 0;
   long register_offset = 0;
-  gdb_byte buf[MAX_REGISTER_SIZE];
 
 #if 0
   fprintf_unfiltered (file, "nr_raw_registers %d\n",
@@ -1569,10 +1506,10 @@ regcache::dump (ui_file *file, enum regcache_dump_what what_to_dump)
            fprintf_unfiltered (file, "<unavailable>");
          else
            {
-             raw_read (regnum, buf);
-             print_hex_chars (file, buf,
+             raw_update (regnum);
+             print_hex_chars (file, register_buffer (regnum),
                               m_descr->sizeof_register[regnum],
-                              gdbarch_byte_order (gdbarch));
+                              gdbarch_byte_order (gdbarch), true);
            }
        }
 
@@ -1583,9 +1520,30 @@ regcache::dump (ui_file *file, enum regcache_dump_what what_to_dump)
            fprintf_unfiltered (file, "Cooked value");
          else
            {
+             const gdb_byte *buf = NULL;
              enum register_status status;
+             struct value *value = NULL;
+
+             if (regnum < m_descr->nr_raw_registers)
+               {
+                 raw_update (regnum);
+                 status = get_register_status (regnum);
+                 buf = register_buffer (regnum);
+               }
+             else
+               {
+                 value = cooked_read_value (regnum);
+
+                 if (!value_optimized_out (value)
+                     && value_entirely_available (value))
+                   {
+                     status = REG_VALID;
+                     buf = value_contents_all (value);
+                   }
+                 else
+                   status = REG_UNAVAILABLE;
+               }
 
-             status = cooked_read (regnum, buf);
              if (status == REG_UNKNOWN)
                fprintf_unfiltered (file, "<invalid>");
              else if (status == REG_UNAVAILABLE)
@@ -1593,7 +1551,13 @@ regcache::dump (ui_file *file, enum regcache_dump_what what_to_dump)
              else
                print_hex_chars (file, buf,
                                 m_descr->sizeof_register[regnum],
-                                gdbarch_byte_order (gdbarch));
+                                gdbarch_byte_order (gdbarch), true);
+
+             if (value != NULL)
+               {
+                 release_value (value);
+                 value_free (value);
+               }
            }
        }
 
@@ -1704,23 +1668,25 @@ maintenance_print_remote_registers (char *args, int from_tty)
 
 namespace selftests {
 
-/* Return the number of elements in current_regcache.  */
-
-static size_t
-current_regcache_size ()
+class regcache_access : public regcache
 {
-  size_t i = 0;
-  for (auto list = current_regcache; list; list = list->next)
-    i++;
+public:
 
-  return i;
-}
+  /* Return the number of elements in current_regcache.  */
+
+  static size_t
+  current_regcache_size ()
+  {
+    return std::distance (regcache::current_regcache.begin (),
+                         regcache::current_regcache.end ());
+  }
+};
 
 static void
 current_regcache_test (void)
 {
   /* It is empty at the start.  */
-  SELF_CHECK (current_regcache_size () == 0);
+  SELF_CHECK (regcache_access::current_regcache_size () == 0);
 
   ptid_t ptid1 (1), ptid2 (2), ptid3 (3);
 
@@ -1732,7 +1698,7 @@ current_regcache_test (void)
 
   SELF_CHECK (regcache != NULL);
   SELF_CHECK (regcache->ptid () == ptid1);
-  SELF_CHECK (current_regcache_size () == 1);
+  SELF_CHECK (regcache_access::current_regcache_size () == 1);
 
   /* Get regcache from ptid2, a new regcache is added to
      current_regcache.  */
@@ -1741,7 +1707,7 @@ current_regcache_test (void)
                                              NULL);
   SELF_CHECK (regcache != NULL);
   SELF_CHECK (regcache->ptid () == ptid2);
-  SELF_CHECK (current_regcache_size () == 2);
+  SELF_CHECK (regcache_access::current_regcache_size () == 2);
 
   /* Get regcache from ptid3, a new regcache is added to
      current_regcache.  */
@@ -1750,7 +1716,7 @@ current_regcache_test (void)
                                              NULL);
   SELF_CHECK (regcache != NULL);
   SELF_CHECK (regcache->ptid () == ptid3);
-  SELF_CHECK (current_regcache_size () == 3);
+  SELF_CHECK (regcache_access::current_regcache_size () == 3);
 
   /* Get regcache from ptid2 again, nothing is added to
      current_regcache.  */
@@ -1759,12 +1725,12 @@ current_regcache_test (void)
                                              NULL);
   SELF_CHECK (regcache != NULL);
   SELF_CHECK (regcache->ptid () == ptid2);
-  SELF_CHECK (current_regcache_size () == 3);
+  SELF_CHECK (regcache_access::current_regcache_size () == 3);
 
   /* Mark ptid2 is changed, so regcache of ptid2 should be removed from
      current_regcache.  */
   registers_changed_ptid (ptid2);
-  SELF_CHECK (current_regcache_size () == 2);
+  SELF_CHECK (regcache_access::current_regcache_size () == 2);
 }
 
 } // namespace selftests
@@ -1779,7 +1745,7 @@ _initialize_regcache (void)
     = gdbarch_data_register_post_init (init_regcache_descr);
 
   observer_attach_target_changed (regcache_observer_target_changed);
-  observer_attach_thread_ptid_changed (regcache_thread_ptid_changed);
+  observer_attach_thread_ptid_changed (regcache::regcache_thread_ptid_changed);
 
   add_com ("flushregs", class_maintenance, reg_flush_command,
           _("Force gdb to flush its register cache (maintainer command)"));
@@ -1810,6 +1776,6 @@ remote register number and buffer offset in the g/G packets.\n\
 Takes an optional file parameter."),
           &maintenanceprintlist);
 #if GDB_SELF_TEST
-  register_self_test (selftests::current_regcache_test);
+  selftests::register_test (selftests::current_regcache_test);
 #endif
 }
This page took 0.032846 seconds and 4 git commands to generate.