/* Cache and manage the values of registers for GDB, the GNU debugger.
- Copyright (C) 1986-2020 Free Software Foundation, Inc.
+ Copyright (C) 1986-2022 Free Software Foundation, Inc.
This file is part of GDB.
#include "observable.h"
#include "regset.h"
#include <unordered_map>
+#include "cli/cli-cmds.h"
/*
* DATA STRUCTURE
/* Per-architecture object describing the layout of a register cache.
Computed once when the architecture is created. */
-struct gdbarch_data *regcache_descr_handle;
+static struct gdbarch_data *regcache_descr_handle;
struct regcache_descr
{
gdb_assert (gdbarch != NULL);
m_descr = regcache_descr (gdbarch);
+ /* We don't zero-initialize the M_REGISTERS array, as the bytes it contains
+ aren't meaningful as long as the corresponding register status is not
+ REG_VALID. */
if (has_pseudo)
{
- m_registers.reset (new gdb_byte[m_descr->sizeof_cooked_registers] ());
+ m_registers.reset (new gdb_byte[m_descr->sizeof_cooked_registers]);
m_register_status.reset
(new register_status[m_descr->nr_cooked_registers] ());
}
else
{
- m_registers.reset (new gdb_byte[m_descr->sizeof_raw_registers] ());
+ m_registers.reset (new gdb_byte[m_descr->sizeof_raw_registers]);
m_register_status.reset
(new register_status[gdbarch_num_regs (gdbarch)] ());
}
using ptid_regcache_map
= std::unordered_multimap<ptid_t, regcache_up, hash_ptid>;
-/* Type to map a target to a ptid_regcache_map, holding the regcaches for the
- threads defined by that target. */
+/* Type holding regcaches for a given pid. */
-using target_ptid_regcache_map
- = std::unordered_map<process_stratum_target *, ptid_regcache_map>;
+using pid_ptid_regcache_map = std::unordered_map<int, ptid_regcache_map>;
+
+/* Type holding regcaches for a given target. */
+
+using target_pid_ptid_regcache_map
+ = std::unordered_map<process_stratum_target *, pid_ptid_regcache_map>;
/* Global structure containing the existing regcaches. */
recording if the register values have been changed (eg. by the
user). Therefore all registers must be written back to the
target when appropriate. */
-static target_ptid_regcache_map regcaches;
+static target_pid_ptid_regcache_map regcaches;
struct regcache *
get_thread_arch_aspace_regcache (process_stratum_target *target,
{
gdb_assert (target != nullptr);
- /* Find the ptid -> regcache map for this target. */
- auto &ptid_regc_map = regcaches[target];
+ /* Find the map for this target. */
+ pid_ptid_regcache_map &pid_ptid_regc_map = regcaches[target];
+
+ /* Find the map for this pid. */
+ ptid_regcache_map &ptid_regc_map = pid_ptid_regc_map[ptid.pid ()];
/* Check first if a regcache for this arch already exists. */
auto range = ptid_regc_map.equal_range (ptid);
/* It does not exist, create it. */
regcache *new_regcache = new regcache (target, arch, aspace);
new_regcache->set_ptid (ptid);
- ptid_regc_map.insert (std::make_pair (ptid, new_regcache));
+ /* Work around a problem with g++ 4.8 (PR96537): Call the regcache_up
+ constructor explictly instead of implicitly. */
+ ptid_regc_map.insert (std::make_pair (ptid, regcache_up (new_regcache)));
return new_regcache;
}
regcache_thread_ptid_changed (process_stratum_target *target,
ptid_t old_ptid, ptid_t new_ptid)
{
- auto ptid_regc_map_it = regcaches.find (target);
+ /* Look up map for target. */
+ auto pid_ptid_regc_map_it = regcaches.find (target);
+ if (pid_ptid_regc_map_it == regcaches.end ())
+ return;
- if (ptid_regc_map_it == regcaches.end ())
+ /* Look up map for pid. */
+ pid_ptid_regcache_map &pid_ptid_regc_map = pid_ptid_regc_map_it->second;
+ auto ptid_regc_map_it = pid_ptid_regc_map.find (old_ptid.pid ());
+ if (ptid_regc_map_it == pid_ptid_regc_map.end ())
return;
- auto &ptid_regc_map = ptid_regc_map_it->second;
+ /* Update all regcaches belonging to old_ptid. */
+ ptid_regcache_map &ptid_regc_map = ptid_regc_map_it->second;
auto range = ptid_regc_map.equal_range (old_ptid);
for (auto it = range.first; it != range.second;)
{
/* Delete all the regcaches of all targets. */
regcaches.clear ();
}
+ else if (ptid.is_pid ())
+ {
+ /* Non-NULL target and pid ptid, delete all regcaches belonging
+ to this (TARGET, PID). */
+
+ /* Look up map for target. */
+ auto pid_ptid_regc_map_it = regcaches.find (target);
+ if (pid_ptid_regc_map_it != regcaches.end ())
+ {
+ pid_ptid_regcache_map &pid_ptid_regc_map
+ = pid_ptid_regc_map_it->second;
+
+ pid_ptid_regc_map.erase (ptid.pid ());
+ }
+ }
else if (ptid != minus_one_ptid)
{
/* Non-NULL target and non-minus_one_ptid, delete all regcaches belonging
- to this (TARGET, PTID). */
- auto ptid_regc_map_it = regcaches.find (target);
- if (ptid_regc_map_it != regcaches.end ())
+ to this (TARGET, PTID). */
+
+ /* Look up map for target. */
+ auto pid_ptid_regc_map_it = regcaches.find (target);
+ if (pid_ptid_regc_map_it != regcaches.end ())
{
- auto &ptid_regc_map = ptid_regc_map_it->second;
- ptid_regc_map.erase (ptid);
+ pid_ptid_regcache_map &pid_ptid_regc_map
+ = pid_ptid_regc_map_it->second;
+
+ /* Look up map for pid. */
+ auto ptid_regc_map_it
+ = pid_ptid_regc_map.find (ptid.pid ());
+ if (ptid_regc_map_it != pid_ptid_regc_map.end ())
+ {
+ ptid_regcache_map &ptid_regc_map
+ = ptid_regc_map_it->second;
+
+ ptid_regc_map.erase (ptid);
+ }
}
}
else
enum register_status
readable_regcache::raw_read (int regnum, T *val)
{
- gdb_byte *buf;
- enum register_status status;
-
assert_regnum (regnum);
- buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]);
- status = raw_read (regnum, buf);
+ size_t len = m_descr->sizeof_register[regnum];
+ gdb_byte *buf = (gdb_byte *) alloca (len);
+ register_status status = raw_read (regnum, buf);
if (status == REG_VALID)
- *val = extract_integer<T> (buf,
- m_descr->sizeof_register[regnum],
+ *val = extract_integer<T> ({buf, len},
gdbarch_byte_order (m_descr->gdbarch));
else
*val = 0;
computed = gdbarch_pseudo_register_read_value (m_descr->gdbarch,
this, regnum);
if (value_entirely_available (computed))
- memcpy (buf, value_contents_raw (computed),
+ memcpy (buf, value_contents_raw (computed).data (),
m_descr->sizeof_register[regnum]);
else
{
direction than in the other one, even though the value-based
API is preferred. */
if (cooked_read (regnum,
- value_contents_raw (result)) == REG_UNAVAILABLE)
+ value_contents_raw (result).data ()) == REG_UNAVAILABLE)
mark_value_bytes_unavailable (result, 0,
TYPE_LENGTH (value_type (result)));
enum register_status
readable_regcache::cooked_read (int regnum, T *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);
+ size_t len = m_descr->sizeof_register[regnum];
+ gdb_byte *buf = (gdb_byte *) alloca (len);
+ register_status status = cooked_read (regnum, buf);
if (status == REG_VALID)
- *val = extract_integer<T> (buf, m_descr->sizeof_register[regnum],
+ *val = extract_integer<T> ({buf, len},
gdbarch_byte_order (m_descr->gdbarch));
else
*val = 0;
memset (out_buf + offs + reg_size, 0, slot_size - reg_size);
}
else if (in_buf != nullptr)
- out_regcache->raw_supply_part (regnum, 0, reg_size, in_buf + offs);
+ {
+ /* Zero-extend the register value if the slot is smaller than the register. */
+ if (slot_size < register_size (gdbarch, regnum))
+ out_regcache->raw_supply_zeroed (regnum);
+ out_regcache->raw_supply_part (regnum, 0, reg_size, in_buf + offs);
+ }
else
{
/* Invalidate the register. */
transfer_regset (regset, nullptr, regnum, nullptr, (gdb_byte *) buf, size);
}
+/* See regcache.h */
+
+bool
+regcache_map_supplies (const struct regcache_map_entry *map, int regnum,
+ struct gdbarch *gdbarch, size_t size)
+{
+ int offs = 0, count;
+
+ for (; (count = map->count) != 0; map++)
+ {
+ int regno = map->regno;
+ int slot_size = map->size;
+
+ if (slot_size == 0 && regno != REGCACHE_MAP_SKIP)
+ slot_size = register_size (gdbarch, regno);
+
+ if (regno != REGCACHE_MAP_SKIP && regnum >= regno
+ && regnum < regno + count)
+ return offs + (regnum - regno + 1) * slot_size <= size;
+
+ offs += count * slot_size;
+ if (offs >= size)
+ return false;
+ }
+ return false;
+}
+
/* See gdbsupport/common-regcache.h. */
bool
{
struct gdbarch *gdbarch = arch ();
- fprintf_unfiltered (gdb_stdlog, "%s ", func);
+ gdb_printf (gdb_stdlog, "%s ", func);
if (regno >= 0 && regno < gdbarch_num_regs (gdbarch)
&& gdbarch_register_name (gdbarch, regno) != NULL
&& gdbarch_register_name (gdbarch, regno)[0] != '\0')
- fprintf_unfiltered (gdb_stdlog, "(%s)",
- gdbarch_register_name (gdbarch, regno));
+ gdb_printf (gdb_stdlog, "(%s)",
+ gdbarch_register_name (gdbarch, regno));
else
- fprintf_unfiltered (gdb_stdlog, "(%d)", regno);
+ gdb_printf (gdb_stdlog, "(%d)", regno);
if (regno >= 0 && regno < gdbarch_num_regs (gdbarch))
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int size = register_size (gdbarch, regno);
gdb_byte *buf = register_buffer (regno);
- fprintf_unfiltered (gdb_stdlog, " = ");
+ gdb_printf (gdb_stdlog, " = ");
for (int i = 0; i < size; i++)
{
- fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+ gdb_printf (gdb_stdlog, "%02x", buf[i]);
}
if (size <= sizeof (LONGEST))
{
ULONGEST val = extract_unsigned_integer (buf, size, byte_order);
- fprintf_unfiltered (gdb_stdlog, " %s %s",
- core_addr_to_string_nz (val), plongest (val));
+ gdb_printf (gdb_stdlog, " %s %s",
+ core_addr_to_string_nz (val), plongest (val));
}
}
- fprintf_unfiltered (gdb_stdlog, "\n");
+ gdb_printf (gdb_stdlog, "\n");
}
+/* Implement 'maint flush register-cache' command. */
+
static void
reg_flush_command (const char *command, int from_tty)
{
/* Force-flush the register cache. */
registers_changed ();
if (from_tty)
- printf_filtered (_("Register cache flushed.\n"));
+ gdb_printf (_("Register cache flushed.\n"));
}
void
{
/* Name. */
if (regnum < 0)
- fprintf_unfiltered (file, " %-10s", "Name");
+ gdb_printf (file, " %-10s", "Name");
else
{
const char *p = gdbarch_register_name (m_gdbarch, regnum);
p = "";
else if (p[0] == '\0')
p = "''";
- fprintf_unfiltered (file, " %-10s", p);
+ gdb_printf (file, " %-10s", p);
}
/* Number. */
if (regnum < 0)
- fprintf_unfiltered (file, " %4s", "Nr");
+ gdb_printf (file, " %4s", "Nr");
else
- fprintf_unfiltered (file, " %4d", regnum);
+ gdb_printf (file, " %4d", regnum);
/* Relative number. */
if (regnum < 0)
- fprintf_unfiltered (file, " %4s", "Rel");
+ gdb_printf (file, " %4s", "Rel");
else if (regnum < gdbarch_num_regs (m_gdbarch))
- fprintf_unfiltered (file, " %4d", regnum);
+ gdb_printf (file, " %4d", regnum);
else
- fprintf_unfiltered (file, " %4d",
- (regnum - gdbarch_num_regs (m_gdbarch)));
+ gdb_printf (file, " %4d",
+ (regnum - gdbarch_num_regs (m_gdbarch)));
/* Offset. */
if (regnum < 0)
- fprintf_unfiltered (file, " %6s ", "Offset");
+ gdb_printf (file, " %6s ", "Offset");
else
{
- fprintf_unfiltered (file, " %6ld",
- descr->register_offset[regnum]);
+ gdb_printf (file, " %6ld",
+ descr->register_offset[regnum]);
if (register_offset != descr->register_offset[regnum]
|| (regnum > 0
&& (descr->register_offset[regnum]
{
if (!footnote_register_offset)
footnote_register_offset = ++footnote_nr;
- fprintf_unfiltered (file, "*%d", footnote_register_offset);
+ gdb_printf (file, "*%d", footnote_register_offset);
}
else
- fprintf_unfiltered (file, " ");
+ gdb_printf (file, " ");
register_offset = (descr->register_offset[regnum]
+ descr->sizeof_register[regnum]);
}
/* Size. */
if (regnum < 0)
- fprintf_unfiltered (file, " %5s ", "Size");
+ gdb_printf (file, " %5s ", "Size");
else
- fprintf_unfiltered (file, " %5ld", descr->sizeof_register[regnum]);
+ gdb_printf (file, " %5ld", descr->sizeof_register[regnum]);
/* Type. */
{
if (startswith (t, blt))
t += strlen (blt);
}
- fprintf_unfiltered (file, " %-15s", t);
+ gdb_printf (file, " %-15s", t);
}
/* Leading space always present. */
- fprintf_unfiltered (file, " ");
+ gdb_printf (file, " ");
dump_reg (file, regnum);
- fprintf_unfiltered (file, "\n");
+ gdb_printf (file, "\n");
}
if (footnote_register_offset)
- fprintf_unfiltered (file, "*%d: Inconsistent register offsets.\n",
- footnote_register_offset);
+ gdb_printf (file, "*%d: Inconsistent register offsets.\n",
+ footnote_register_offset);
if (footnote_register_type_name_null)
- fprintf_unfiltered (file,
- "*%d: Register type's name NULL.\n",
- footnote_register_type_name_null);
+ gdb_printf (file,
+ "*%d: Register type's name NULL.\n",
+ footnote_register_type_name_null);
}
#if GDB_SELF_TEST
regcaches_size ()
{
size_t size = 0;
- for (auto it = regcaches.begin (); it != regcaches.end (); ++it)
+
+ for (auto pid_ptid_regc_map_it = regcaches.cbegin ();
+ pid_ptid_regc_map_it != regcaches.cend ();
+ ++pid_ptid_regc_map_it)
{
- auto &ptid_regc_map = it->second;
- size += ptid_regc_map.size ();
+ const pid_ptid_regcache_map &pid_ptid_regc_map
+ = pid_ptid_regc_map_it->second;
+
+ for (auto ptid_regc_map_it = pid_ptid_regc_map.cbegin ();
+ ptid_regc_map_it != pid_ptid_regc_map.cend ();
+ ++ptid_regc_map_it)
+ {
+ const ptid_regcache_map &ptid_regc_map
+ = ptid_regc_map_it->second;
+
+ size += ptid_regc_map.size ();
+ }
}
return size;
}
+/* Return the count of regcaches for (TARGET, PTID) in REGCACHES. */
+
+static int
+regcache_count (process_stratum_target *target, ptid_t ptid)
+{
+ /* Look up map for target. */
+ auto pid_ptid_regc_map_it = regcaches.find (target);
+ if (pid_ptid_regc_map_it != regcaches.end ())
+ {
+ pid_ptid_regcache_map &pid_ptid_regc_map = pid_ptid_regc_map_it->second;
+
+ /* Look map for pid. */
+ auto ptid_regc_map_it = pid_ptid_regc_map.find (ptid.pid ());
+ if (ptid_regc_map_it != pid_ptid_regc_map.end ())
+ {
+ ptid_regcache_map &ptid_regc_map = ptid_regc_map_it->second;
+ auto range = ptid_regc_map.equal_range (ptid);
+
+ return std::distance (range.first, range.second);
+ }
+ }
+
+ return 0;
+};
+
/* Wrapper around get_thread_arch_aspace_regcache that does some self checks. */
static void
-test_get_thread_arch_aspace_regcache (process_stratum_target *target,
- ptid_t ptid, struct gdbarch *gdbarch,
- address_space *aspace)
+get_thread_arch_aspace_regcache_and_check (process_stratum_target *target,
+ ptid_t ptid)
{
- struct regcache *regcache
- = get_thread_arch_aspace_regcache (target, ptid, gdbarch, aspace);
+ /* We currently only test with a single gdbarch. Any gdbarch will do, so use
+ the current inferior's gdbarch. Also use the current inferior's address
+ space. */
+ gdbarch *arch = current_inferior ()->gdbarch;
+ address_space *aspace = current_inferior ()->aspace;
+ regcache *regcache
+ = get_thread_arch_aspace_regcache (target, ptid, arch, aspace);
+
SELF_CHECK (regcache != NULL);
SELF_CHECK (regcache->target () == target);
SELF_CHECK (regcache->ptid () == ptid);
+ SELF_CHECK (regcache->arch () == arch);
SELF_CHECK (regcache->aspace () == aspace);
}
-static void
-regcaches_test ()
+/* The data that the regcaches selftests must hold onto for the duration of the
+ test. */
+
+struct regcache_test_data
{
- /* It is empty at the start. */
- SELF_CHECK (regcaches_size () == 0);
+ regcache_test_data ()
+ {
+ /* Ensure the regcaches container is empty at the start. */
+ registers_changed ();
+ }
- ptid_t ptid1 (1), ptid2 (2), ptid3 (3);
+ ~regcache_test_data ()
+ {
+ /* Make sure to leave the global regcaches container empty. */
+ registers_changed ();
+ }
test_target_ops test_target1;
test_target_ops test_target2;
+};
+
+using regcache_test_data_up = std::unique_ptr<regcache_test_data>;
+
+/* Set up a few regcaches from two different targets, for use in
+ regcache-management tests.
+
+ Return a pointer, because the `regcache_test_data` type is not moveable. */
+
+static regcache_test_data_up
+populate_regcaches_for_test ()
+{
+ regcache_test_data_up data (new regcache_test_data);
+ size_t expected_regcache_size = 0;
+
+ SELF_CHECK (regcaches_size () == 0);
+
+ /* Populate the regcache container with a few regcaches for the two test
+ targets. */
+ for (int pid : { 1, 2 })
+ {
+ for (long lwp : { 1, 2, 3 })
+ {
+ get_thread_arch_aspace_regcache_and_check
+ (&data->test_target1, ptid_t (pid, lwp));
+ expected_regcache_size++;
+ SELF_CHECK (regcaches_size () == expected_regcache_size);
+
+ get_thread_arch_aspace_regcache_and_check
+ (&data->test_target2, ptid_t (pid, lwp));
+ expected_regcache_size++;
+ SELF_CHECK (regcaches_size () == expected_regcache_size);
+ }
+ }
+
+ return data;
+}
+
+static void
+get_thread_arch_aspace_regcache_test ()
+{
+ /* populate_regcaches_for_test already tests most of the
+ get_thread_arch_aspace_regcache functionality. */
+ regcache_test_data_up data = populate_regcaches_for_test ();
+ size_t regcaches_size_before = regcaches_size ();
+
+ /* Test that getting an existing regcache doesn't create a new one. */
+ get_thread_arch_aspace_regcache_and_check (&data->test_target1, ptid_t (2, 2));
+ SELF_CHECK (regcaches_size () == regcaches_size_before);
+}
+
+ /* Test marking all regcaches of all targets as changed. */
+
+static void
+registers_changed_ptid_all_test ()
+{
+ regcache_test_data_up data = populate_regcaches_for_test ();
- /* Get regcache from (target1,ptid1), a new regcache is added to
- REGCACHES. */
- test_get_thread_arch_aspace_regcache (&test_target1, ptid1,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcaches_size () == 1);
-
- /* Get regcache from (target1,ptid2), a new regcache is added to
- REGCACHES. */
- test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcaches_size () == 2);
-
- /* Get regcache from (target1,ptid3), a new regcache is added to
- REGCACHES. */
- test_get_thread_arch_aspace_regcache (&test_target1, ptid3,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcaches_size () == 3);
-
- /* Get regcache from (target1,ptid2) again, nothing is added to
- REGCACHES. */
- test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcaches_size () == 3);
-
- /* Get regcache from (target2,ptid2), a new regcache is added to
- REGCACHES, since this time we're using a different target. */
- test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcaches_size () == 4);
-
- /* Mark that (target1,ptid2) changed. The regcache of (target1,
- ptid2) should be removed from REGCACHES. */
- registers_changed_ptid (&test_target1, ptid2);
- SELF_CHECK (regcaches_size () == 3);
-
- /* Get the regcache from (target2,ptid2) again, confirming the
- registers_changed_ptid call above did not delete it. */
- test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
- target_gdbarch (),
- NULL);
- SELF_CHECK (regcaches_size () == 3);
-
- /* Confirm that marking all regcaches of all targets as changed
- clears REGCACHES. */
registers_changed_ptid (nullptr, minus_one_ptid);
SELF_CHECK (regcaches_size () == 0);
}
+/* Test marking regcaches of a specific target as changed. */
+
+static void
+registers_changed_ptid_target_test ()
+{
+ regcache_test_data_up data = populate_regcaches_for_test ();
+
+ registers_changed_ptid (&data->test_target1, minus_one_ptid);
+ SELF_CHECK (regcaches_size () == 6);
+
+ /* Check that we deleted the regcache for the right target. */
+ SELF_CHECK (regcache_count (&data->test_target1, ptid_t (2, 2)) == 0);
+ SELF_CHECK (regcache_count (&data->test_target2, ptid_t (2, 2)) == 1);
+}
+
+/* Test marking regcaches of a specific (target, pid) as changed. */
+
+static void
+registers_changed_ptid_target_pid_test ()
+{
+ regcache_test_data_up data = populate_regcaches_for_test ();
+
+ registers_changed_ptid (&data->test_target1, ptid_t (2));
+ SELF_CHECK (regcaches_size () == 9);
+
+ /* Regcaches from target1 should not exist, while regcaches from target2
+ should exist. */
+ SELF_CHECK (regcache_count (&data->test_target1, ptid_t (2, 2)) == 0);
+ SELF_CHECK (regcache_count (&data->test_target2, ptid_t (2, 2)) == 1);
+}
+
+/* Test marking regcaches of a specific (target, ptid) as changed. */
+
+static void
+registers_changed_ptid_target_ptid_test ()
+{
+ regcache_test_data_up data = populate_regcaches_for_test ();
+
+ registers_changed_ptid (&data->test_target1, ptid_t (2, 2));
+ SELF_CHECK (regcaches_size () == 11);
+
+ /* Check that we deleted the regcache for the right target. */
+ SELF_CHECK (regcache_count (&data->test_target1, ptid_t (2, 2)) == 0);
+ SELF_CHECK (regcache_count (&data->test_target2, ptid_t (2, 2)) == 1);
+}
+
class target_ops_no_register : public test_target_ops
{
public:
static void
cooked_write_test (struct gdbarch *gdbarch)
{
- /* Error out if debugging something, because we're going to push the
- test target, which would pop any existing target. */
- if (current_top_target ()->stratum () >= process_stratum)
- error (_("target already pushed"));
-
/* Create a mock environment. A process_stratum target pushed. */
-
- target_ops_no_register mock_target;
-
- /* Push the process_stratum target so we can mock accessing
- registers. */
- push_target (&mock_target);
-
- /* Pop it again on exit (return/exception). */
- struct on_exit
- {
- ~on_exit ()
- {
- pop_all_targets_at_and_above (process_stratum);
- }
- } pop_targets;
-
- readwrite_regcache readwrite (&mock_target, gdbarch);
-
+ scoped_mock_context<target_ops_no_register> ctx (gdbarch);
+ readwrite_regcache readwrite (&ctx.mock_target, gdbarch);
const int num_regs = gdbarch_num_cooked_regs (gdbarch);
for (auto regnum = 0; regnum < num_regs; regnum++)
/* Prepare two targets with one thread each, with the same ptid. */
scoped_mock_context<test_target_ops> target1 (arch);
scoped_mock_context<test_target_ops> target2 (arch);
- target2.mock_inferior.next = &target1.mock_inferior;
ptid_t old_ptid (111, 222);
ptid_t new_ptid (111, 333);
target1.mock_inferior.pid = old_ptid.pid ();
target1.mock_thread.ptid = old_ptid;
+ target1.mock_inferior.ptid_thread_map.clear ();
+ target1.mock_inferior.ptid_thread_map[old_ptid] = &target1.mock_thread;
+
target2.mock_inferior.pid = old_ptid.pid ();
target2.mock_thread.ptid = old_ptid;
+ target2.mock_inferior.ptid_thread_map.clear ();
+ target2.mock_inferior.ptid_thread_map[old_ptid] = &target2.mock_thread;
gdb_assert (regcaches.empty ());
get_thread_arch_aspace_regcache (&target2.mock_target, old_ptid, arch,
nullptr);
- /* Return the count of regcaches for (TARGET, PTID) in REGCACHES. */
- auto regcache_count = [] (process_stratum_target *target, ptid_t ptid)
- -> int
- {
- auto ptid_regc_map_it = regcaches.find (target);
- if (ptid_regc_map_it != regcaches.end ())
- {
- auto &ptid_regc_map = ptid_regc_map_it->second;
- auto range = ptid_regc_map.equal_range (ptid);
- return std::distance (range.first, range.second);
- }
- return 0;
- };
-
gdb_assert (regcaches.size () == 2);
gdb_assert (regcache_count (&target1.mock_target, old_ptid) == 1);
gdb_assert (regcache_count (&target1.mock_target, new_ptid) == 0);
void
_initialize_regcache ()
{
+ struct cmd_list_element *c;
+
regcache_descr_handle
= gdbarch_data_register_post_init (init_regcache_descr);
- gdb::observers::target_changed.attach (regcache_observer_target_changed);
- gdb::observers::thread_ptid_changed.attach (regcache_thread_ptid_changed);
+ gdb::observers::target_changed.attach (regcache_observer_target_changed,
+ "regcache");
+ gdb::observers::thread_ptid_changed.attach (regcache_thread_ptid_changed,
+ "regcache");
- add_com ("flushregs", class_maintenance, reg_flush_command,
- _("Force gdb to flush its register cache (maintainer command)."));
+ cmd_list_element *maintenance_flush_register_cache_cmd
+ = add_cmd ("register-cache", class_maintenance, reg_flush_command,
+ _("Force gdb to flush its register and frame cache."),
+ &maintenanceflushlist);
+ c = add_com_alias ("flushregs", maintenance_flush_register_cache_cmd,
+ class_maintenance, 0);
+ deprecate_cmd (c, "maintenance flush register-cache");
#if GDB_SELF_TEST
- selftests::register_test ("regcaches", selftests::regcaches_test);
+ selftests::register_test ("get_thread_arch_aspace_regcache",
+ selftests::get_thread_arch_aspace_regcache_test);
+ selftests::register_test ("registers_changed_ptid_all",
+ selftests::registers_changed_ptid_all_test);
+ selftests::register_test ("registers_changed_ptid_target",
+ selftests::registers_changed_ptid_target_test);
+ selftests::register_test ("registers_changed_ptid_target_pid",
+ selftests::registers_changed_ptid_target_pid_test);
+ selftests::register_test ("registers_changed_ptid_target_ptid",
+ selftests::registers_changed_ptid_target_ptid_test);
selftests::register_test_foreach_arch ("regcache::cooked_read_test",
selftests::cooked_read_test);