/* Cache and manage the values of registers for GDB, the GNU debugger.
Copyright (C) 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001,
- 2002, 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2002, 2004, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of GDB.
*/
/* Per-architecture object describing the layout of a register cache.
- Computed once when the architecture is created */
+ Computed once when the architecture is created. */
struct gdbarch_data *regcache_descr_handle;
/* Fill in a table of register types. */
descr->register_type
- = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, struct type *);
+ = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers,
+ struct type *);
for (i = 0; i < descr->nr_cooked_registers; i++)
descr->register_type[i] = gdbarch_register_type (gdbarch, i);
{
long offset = 0;
+
descr->sizeof_register
= GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long);
descr->register_offset
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];
}
{
struct regcache_descr *descr = regcache_descr (gdbarch);
int size;
+
gdb_assert (regnum >= 0
&& regnum < (gdbarch_num_regs (gdbarch)
+ gdbarch_num_pseudo_regs (gdbarch)));
};
struct regcache *
-regcache_xmalloc (struct gdbarch *gdbarch)
+regcache_xmalloc (struct gdbarch *gdbarch, struct address_space *aspace)
{
struct regcache_descr *descr;
struct regcache *regcache;
+
gdb_assert (gdbarch != NULL);
descr = regcache_descr (gdbarch);
regcache = XMALLOC (struct regcache);
= XCALLOC (descr->sizeof_raw_registers, gdb_byte);
regcache->register_valid_p
= XCALLOC (descr->sizeof_raw_register_valid_p, gdb_byte);
- regcache->aspace = NULL;
+ regcache->aspace = aspace;
regcache->readonly_p = 1;
regcache->ptid = minus_one_ptid;
return regcache;
struct gdbarch *gdbarch = dst->descr->gdbarch;
gdb_byte buf[MAX_REGISTER_SIZE];
int regnum;
+
/* The DST should be `read-only', if it wasn't then the save would
end up trying to write the register values back out to the
target. */
gdb_assert (dst->readonly_p);
/* Clear the dest. */
memset (dst->registers, 0, dst->descr->sizeof_cooked_registers);
- memset (dst->register_valid_p, 0, dst->descr->sizeof_cooked_register_valid_p);
+ memset (dst->register_valid_p, 0,
+ dst->descr->sizeof_cooked_register_valid_p);
/* Copy over any registers (identified by their membership in the
save_reggroup) and mark them as valid. The full [0 .. gdbarch_num_regs +
gdbarch_num_pseudo_regs) range is checked since some architectures need
if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup))
{
int valid = cooked_read (src, regnum, buf);
+
if (valid)
{
memcpy (register_buffer (dst, regnum), buf,
struct gdbarch *gdbarch = dst->descr->gdbarch;
gdb_byte buf[MAX_REGISTER_SIZE];
int regnum;
+
/* The dst had better not be read-only. If it is, the `restore'
doesn't make much sense. */
gdb_assert (!dst->readonly_p);
if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup))
{
int valid = cooked_read (cooked_read_context, regnum, buf);
+
if (valid)
regcache_cooked_write (dst, regnum, buf);
}
do_cooked_read (void *src, int regnum, gdb_byte *buf)
{
struct regcache *regcache = src;
+
if (!regcache->register_valid_p[regnum] && regcache->readonly_p)
/* Don't even think about fetching a register from a read-only
cache when the register isn't yet valid. There isn't a target
void
regcache_cpy (struct regcache *dst, struct regcache *src)
{
- int i;
- gdb_byte *buf;
-
gdb_assert (src != NULL && dst != NULL);
gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
gdb_assert (src != dst);
gdb_assert (src->readonly_p || dst->readonly_p);
- dst->aspace = src->aspace;
-
if (!src->readonly_p)
regcache_save (dst, do_cooked_read, src);
else if (!dst->readonly_p)
void
regcache_cpy_no_passthrough (struct regcache *dst, struct regcache *src)
{
- int i;
gdb_assert (src != NULL && dst != NULL);
gdb_assert (src->descr->gdbarch == dst->descr->gdbarch);
/* NOTE: cagney/2002-05-17: Don't let the caller do a no-passthrough
silly - it would mean that valid_p would be completely invalid. */
gdb_assert (dst->readonly_p);
- dst->aspace = src->aspace;
memcpy (dst->registers, src->registers, dst->descr->sizeof_raw_registers);
memcpy (dst->register_valid_p, src->register_valid_p,
dst->descr->sizeof_raw_register_valid_p);
regcache_dup (struct regcache *src)
{
struct regcache *newbuf;
- newbuf = regcache_xmalloc (src->descr->gdbarch);
+
+ newbuf = regcache_xmalloc (src->descr->gdbarch, get_regcache_aspace (src));
regcache_cpy (newbuf, src);
return newbuf;
}
regcache_dup_no_passthrough (struct regcache *src)
{
struct regcache *newbuf;
- newbuf = regcache_xmalloc (src->descr->gdbarch);
+
+ newbuf = regcache_xmalloc (src->descr->gdbarch, get_regcache_aspace (src));
regcache_cpy_no_passthrough (newbuf, src);
return newbuf;
}
&& get_regcache_arch (list->regcache) == gdbarch)
return list->regcache;
- new_regcache = regcache_xmalloc (gdbarch);
+ new_regcache = regcache_xmalloc (gdbarch,
+ target_thread_address_space (ptid));
new_regcache->readonly_p = 0;
new_regcache->ptid = ptid;
- new_regcache->aspace = target_thread_address_space (ptid);
gdb_assert (new_regcache->aspace != NULL);
list = xmalloc (sizeof (struct regcache_list));
Indicate that registers may have changed, so invalidate the cache. */
void
-registers_changed (void)
+registers_changed_ptid (ptid_t ptid)
{
- struct regcache_list *list, *next;
+ struct regcache_list *list, **list_link;
- for (list = current_regcache; list; list = next)
+ list = current_regcache;
+ list_link = ¤t_regcache;
+ while (list)
{
- next = list->next;
- regcache_xfree (list->regcache);
- xfree (list);
+ if (ptid_match (list->regcache->ptid, ptid))
+ {
+ struct regcache_list *dead = list;
+
+ *list_link = list->next;
+ regcache_xfree (list->regcache);
+ list = *list_link;
+ xfree (dead);
+ continue;
+ }
+
+ list_link = &list->next;
+ list = *list_link;
}
current_regcache = NULL;
current_thread_ptid = null_ptid;
current_thread_arch = NULL;
- /* Need to forget about any frames we have cached, too. */
+ /* Need to forget about any frames we have cached, too. */
reinit_frame_cache ();
/* Force cleanup of any alloca areas if using C alloca instead of
alloca (0);
}
+void
+registers_changed (void)
+{
+ registers_changed_ptid (minus_one_ptid);
+}
void
regcache_raw_read (struct regcache *regcache, int regnum, gdb_byte *buf)
if (!regcache_valid_p (regcache, regnum))
{
struct cleanup *old_chain = save_inferior_ptid ();
+
inferior_ptid = regcache->ptid;
target_fetch_registers (regcache, regnum);
do_cleanups (old_chain);
regcache_raw_read_signed (struct regcache *regcache, int regnum, LONGEST *val)
{
gdb_byte *buf;
+
gdb_assert (regcache != NULL);
gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
buf = alloca (regcache->descr->sizeof_register[regnum]);
ULONGEST *val)
{
gdb_byte *buf;
+
gdb_assert (regcache != NULL);
gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
buf = alloca (regcache->descr->sizeof_register[regnum]);
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]);
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]);
LONGEST *val)
{
gdb_byte *buf;
+
gdb_assert (regcache != NULL);
gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_cooked_registers);
buf = alloca (regcache->descr->sizeof_register[regnum]);
ULONGEST *val)
{
gdb_byte *buf;
+
gdb_assert (regcache != NULL);
gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_cooked_registers);
buf = alloca (regcache->descr->sizeof_register[regnum]);
LONGEST val)
{
void *buf;
+
gdb_assert (regcache != NULL);
gdb_assert (regnum >=0 && regnum < regcache->descr->nr_cooked_registers);
buf = alloca (regcache->descr->sizeof_register[regnum]);
ULONGEST val)
{
void *buf;
+
gdb_assert (regcache != NULL);
gdb_assert (regnum >=0 && regnum < regcache->descr->nr_cooked_registers);
buf = alloca (regcache->descr->sizeof_register[regnum]);
return;
/* If we have a valid copy of the register, and new value == old
- value, then don't bother doing the actual store. */
+ value, then don't bother doing the actual store. */
if (regcache_valid_p (regcache, regnum)
&& (memcmp (register_buffer (regcache, regnum), buf,
regcache->descr->sizeof_register[regnum]) == 0))
{
struct regcache_descr *descr = regcache->descr;
gdb_byte reg[MAX_REGISTER_SIZE];
+
gdb_assert (offset >= 0 && offset <= descr->sizeof_register[regnum]);
gdb_assert (len >= 0 && offset + len <= descr->sizeof_register[regnum]);
/* Something to do? */
if (offset + len == 0)
return;
- /* Read (when needed) ... */
+ /* Read (when needed) ... */
if (in != NULL
|| offset > 0
|| offset + len < descr->sizeof_register[regnum])
gdb_assert (read != NULL);
read (regcache, regnum, reg);
}
- /* ... modify ... */
+ /* ... modify ... */
if (in != NULL)
memcpy (in, reg + offset, len);
if (out != NULL)
int offset, int len, gdb_byte *buf)
{
struct regcache_descr *descr = regcache->descr;
+
gdb_assert (regnum >= 0 && regnum < descr->nr_raw_registers);
regcache_xfer_part (regcache, regnum, offset, len, buf, NULL,
regcache_raw_read, regcache_raw_write);
int offset, int len, const gdb_byte *buf)
{
struct regcache_descr *descr = regcache->descr;
+
gdb_assert (regnum >= 0 && regnum < descr->nr_raw_registers);
regcache_xfer_part (regcache, regnum, offset, len, NULL, buf,
regcache_raw_read, regcache_raw_write);
int offset, int len, gdb_byte *buf)
{
struct regcache_descr *descr = regcache->descr;
+
gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
regcache_xfer_part (regcache, regnum, offset, len, buf, NULL,
regcache_cooked_read, regcache_cooked_write);
int offset, int len, const gdb_byte *buf)
{
struct regcache_descr *descr = regcache->descr;
+
gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
regcache_xfer_part (regcache, regnum, offset, len, NULL, buf,
regcache_cooked_read, regcache_cooked_write);
else if (gdbarch_pc_regnum (gdbarch) >= 0)
{
ULONGEST raw_val;
+
regcache_cooked_read_unsigned (regcache,
gdbarch_pc_regnum (gdbarch),
&raw_val);
const unsigned char *buf, long len)
{
int i;
+
switch (endian)
{
case BFD_ENDIAN_BIG:
enum regcache_dump_what
{
- regcache_dump_none, regcache_dump_raw, regcache_dump_cooked, regcache_dump_groups
+ regcache_dump_none, regcache_dump_raw,
+ regcache_dump_cooked, regcache_dump_groups
};
static void
else
{
const char *p = gdbarch_register_name (gdbarch, regnum);
+
if (p == NULL)
p = "";
else if (p[0] == '\0')
/* Type. */
{
const char *t;
+
if (regnum < 0)
t = "Type";
else
{
static const char blt[] = "builtin_type";
+
t = TYPE_NAME (register_type (regcache->descr->gdbarch, regnum));
if (t == NULL)
{
char *n;
+
if (!footnote_register_type_name_null)
footnote_register_type_name_null = ++footnote_nr;
n = xstrprintf ("*%d", footnote_register_type_name_null);
{
const char *sep = "";
struct reggroup *group;
+
for (group = reggroup_next (gdbarch, NULL);
group != NULL;
group = reggroup_next (gdbarch, group))
{
if (gdbarch_register_reggroup_p (gdbarch, regnum, group))
{
- fprintf_unfiltered (file, "%s%s", sep, reggroup_name (group));
+ fprintf_unfiltered (file,
+ "%s%s", sep, reggroup_name (group));
sep = ",";
}
}
{
struct cleanup *cleanups;
struct ui_file *file = gdb_fopen (args, "w");
+
if (file == NULL)
perror_with_name (_("maintenance print architecture"));
cleanups = make_cleanup_ui_file_delete (file);
void
_initialize_regcache (void)
{
- regcache_descr_handle = gdbarch_data_register_post_init (init_regcache_descr);
+ regcache_descr_handle
+ = 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);
add_com ("flushregs", class_maintenance, reg_flush_command,
_("Force gdb to flush its register cache (maintainer command)"));
- add_cmd ("registers", class_maintenance, maintenance_print_registers, _("\
-Print the internal register configuration.\n\
-Takes an optional file parameter."), &maintenanceprintlist);
+ add_cmd ("registers", class_maintenance, maintenance_print_registers,
+ _("Print the internal register configuration.\n"
+ "Takes an optional file parameter."), &maintenanceprintlist);
add_cmd ("raw-registers", class_maintenance,
- maintenance_print_raw_registers, _("\
-Print the internal register configuration including raw values.\n\
-Takes an optional file parameter."), &maintenanceprintlist);
+ maintenance_print_raw_registers,
+ _("Print the internal register configuration "
+ "including raw values.\n"
+ "Takes an optional file parameter."), &maintenanceprintlist);
add_cmd ("cooked-registers", class_maintenance,
- maintenance_print_cooked_registers, _("\
-Print the internal register configuration including cooked values.\n\
-Takes an optional file parameter."), &maintenanceprintlist);
+ maintenance_print_cooked_registers,
+ _("Print the internal register configuration "
+ "including cooked values.\n"
+ "Takes an optional file parameter."), &maintenanceprintlist);
add_cmd ("register-groups", class_maintenance,
- maintenance_print_register_groups, _("\
-Print the internal register configuration including each register's group.\n\
-Takes an optional file parameter."),
+ maintenance_print_register_groups,
+ _("Print the internal register configuration "
+ "including each register's group.\n"
+ "Takes an optional file parameter."),
&maintenanceprintlist);
}