#include "remote.h"
#include "valprint.h"
#include "regset.h"
+#include <forward_list>
/*
* DATA STRUCTURE
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
{
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;
}
}
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 *
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 ®cache : 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;
}
/* 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 ®cache : regcache::current_regcache)
+ {
+ if (ptid_equal (regcache->ptid (), old_ptid))
+ regcache->set_ptid (new_ptid);
+ }
}
/* Low level examining and depositing of registers.
void
registers_changed_ptid (ptid_t ptid)
{
- struct regcache_list *list, **list_link;
-
- list = current_regcache;
- list_link = ¤t_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))
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;
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;
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);
}
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
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;
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;
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
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);
}
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. */
}
}
+/* 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). */
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,
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",
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);
}
}
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)
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);
+ }
}
}
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);
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. */
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. */
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. */
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
= 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)"));
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
}