[PATCH v3 02/13] regcache: Add functions suitable for regset_supply/collect.

Andreas Arnez <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <[email protected]>
These functions are intended to suit all targets that don't require too
special logic in their regset supply/collect methods.  Having such
generic functions helps reducing target-specific complexity.

gdb/
	* regcache.c: Include "regset.h".
	(regcache_transfer_regset): New local function.
	(regcache_supply_regset, regcache_collect_regset): New functions.
	* regcache.h (struct regcache_map_entry): New structure.
	(REGCACHE_MAP_SKIP): New enum value.
	(regcache_supply_regset, regcache_collect_regset): New prototypes.
---
 gdb/regcache.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/regcache.h | 45 ++++++++++++++++++++++++++++++
 2 files changed, 132 insertions(+)

diff --git a/gdb/regcache.c b/gdb/regcache.c
index 5ee90b0..d5f8e2f 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -30,6 +30,7 @@
 #include "exceptions.h"
 #include "remote.h"
 #include "valprint.h"
+#include "regset.h"
 
 /*
  * DATA STRUCTURE
@@ -1068,6 +1069,92 @@ 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 = 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.  */
 
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 8423f57..0361f22 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -147,6 +147,51 @@ extern void regcache_raw_supply (struct regcache *regcache,
 extern void regcache_raw_collect (const struct regcache *regcache,
 				  int regnum, void *buf);
 
+/* Mapping between register numbers and offsets in a buffer, for use
+   in the '*regset' functions below.  In an array of
+   'regcache_map_entry' each element is interpreted like follows:
+
+   - If 'regno' is a register number: Map register 'regno' to the
+     current offset (starting with 0) and increase the current offset
+     by 'size' (or the register's size, if 'size' is zero).  Repeat
+     this with consecutive register numbers up to 'regno+count-1'.
+
+   - If 'regno' is REGCACHE_MAP_SKIP: Add 'count*size' to the current
+     offset.
+
+   - If count=0: End of the map.  */
+
+struct regcache_map_entry
+{
+  int count;
+  int regno;
+  int size;
+};
+
+/* Special value for the 'regno' field in the struct above.  */
+
+enum
+  {
+    REGCACHE_MAP_SKIP = -1,
+  };
+
+/* Transfer a set of registers (as described by REGSET) between
+   REGCACHE and BUF.  If REGNUM == -1, transfer all registers
+   belonging to the regset, otherwise just the register numbered
+   REGNUM.  The REGSET's 'regmap' field must point to an array of
+   'struct regcache_map_entry'.
+
+   These functions are suitable for the 'regset_supply' and
+   'regset_collect' fields in a regset structure.  */
+
+extern void regcache_supply_regset (const struct regset *regset,
+				    struct regcache *regcache,
+				    int regnum, const void *buf,
+				    size_t size);
+extern void regcache_collect_regset (const struct regset *regset,
+				     const struct regcache *regcache,
+				     int regnum, void *buf, size_t size);
+
 
 /* The type of a register.  This function is slightly more efficient
    then its gdbarch vector counterpart since it returns a precomputed
-- 
1.8.4.2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.