regcache: Add functions suitable for regset_supply/collect.

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.
This commit is contained in:
Andreas Arnez 2014-07-22 10:28:32 +00:00 committed by Ulrich Weigand
parent 7fefa8d7d6
commit 0b3092721e
3 changed files with 141 additions and 0 deletions

View file

@ -1,3 +1,12 @@
2014-08-07 Andreas Arnez <arnez@linux.vnet.ibm.com>
* 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.
2014-08-07 Andreas Arnez <arnez@linux.vnet.ibm.com>
* regset.h (struct regset): Rename 'descr' field to 'regmap'.

View file

@ -28,6 +28,7 @@
#include "exceptions.h"
#include "remote.h"
#include "valprint.h"
#include "regset.h"
/*
* DATA STRUCTURE
@ -1066,6 +1067,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. */

View file

@ -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