forked from Imagelibrary/binutils-gdb
Compare commits
5 Commits
gdb-10-bra
...
users/sima
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe0e47ac81 | ||
|
|
5672720dd1 | ||
|
|
2dd1cd011c | ||
|
|
7e17ef8ca4 | ||
|
|
5c879edf04 |
@@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <forward_list>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|||||||
78
gdb/infrun.c
78
gdb/infrun.c
@@ -67,6 +67,9 @@
|
|||||||
#include "gdbsupport/gdb_select.h"
|
#include "gdbsupport/gdb_select.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "async-event.h"
|
#include "async-event.h"
|
||||||
|
#include "gdbsupport/selftest.h"
|
||||||
|
#include "scoped-mock-context.h"
|
||||||
|
#include "test-target.h"
|
||||||
|
|
||||||
/* Prototypes for local functions */
|
/* Prototypes for local functions */
|
||||||
|
|
||||||
@@ -2068,9 +2071,11 @@ start_step_over (void)
|
|||||||
/* Update global variables holding ptids to hold NEW_PTID if they were
|
/* Update global variables holding ptids to hold NEW_PTID if they were
|
||||||
holding OLD_PTID. */
|
holding OLD_PTID. */
|
||||||
static void
|
static void
|
||||||
infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
|
infrun_thread_ptid_changed (process_stratum_target *target,
|
||||||
|
ptid_t old_ptid, ptid_t new_ptid)
|
||||||
{
|
{
|
||||||
if (inferior_ptid == old_ptid)
|
if (inferior_ptid == old_ptid
|
||||||
|
&& current_inferior ()->process_target () == target)
|
||||||
inferior_ptid = new_ptid;
|
inferior_ptid = new_ptid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9455,6 +9460,70 @@ infrun_async_inferior_event_handler (gdb_client_data data)
|
|||||||
inferior_event_handler (INF_REG_EVENT);
|
inferior_event_handler (INF_REG_EVENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace selftests
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Verify that when two threads with the same ptid exist (from two different
|
||||||
|
targets) and one of them changes ptid, we only update inferior_ptid if
|
||||||
|
it is appropriate. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
infrun_thread_ptid_changed ()
|
||||||
|
{
|
||||||
|
gdbarch *arch = current_inferior ()->gdbarch;
|
||||||
|
|
||||||
|
/* The thread which inferior_ptid represents changes ptid. */
|
||||||
|
{
|
||||||
|
scoped_restore_current_pspace_and_thread restore;
|
||||||
|
|
||||||
|
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;
|
||||||
|
target2.mock_inferior.pid = old_ptid.pid ();
|
||||||
|
target2.mock_thread.ptid = old_ptid;
|
||||||
|
|
||||||
|
auto restore_inferior_ptid = make_scoped_restore (&inferior_ptid, old_ptid);
|
||||||
|
set_current_inferior (&target1.mock_inferior);
|
||||||
|
|
||||||
|
thread_change_ptid (&target1.mock_target, old_ptid, new_ptid);
|
||||||
|
|
||||||
|
gdb_assert (inferior_ptid == new_ptid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A thread with the same ptid as inferior_ptid, but from another target,
|
||||||
|
changes ptid. */
|
||||||
|
{
|
||||||
|
scoped_restore_current_pspace_and_thread restore;
|
||||||
|
|
||||||
|
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;
|
||||||
|
target2.mock_inferior.pid = old_ptid.pid ();
|
||||||
|
target2.mock_thread.ptid = old_ptid;
|
||||||
|
|
||||||
|
auto restore_inferior_ptid = make_scoped_restore (&inferior_ptid, old_ptid);
|
||||||
|
set_current_inferior (&target2.mock_inferior);
|
||||||
|
|
||||||
|
thread_change_ptid (&target1.mock_target, old_ptid, new_ptid);
|
||||||
|
|
||||||
|
gdb_assert (inferior_ptid == old_ptid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace selftests */
|
||||||
|
|
||||||
void _initialize_infrun ();
|
void _initialize_infrun ();
|
||||||
void
|
void
|
||||||
_initialize_infrun ()
|
_initialize_infrun ()
|
||||||
@@ -9756,4 +9825,9 @@ or signalled."),
|
|||||||
show_observer_mode,
|
show_observer_mode,
|
||||||
&setlist,
|
&setlist,
|
||||||
&showlist);
|
&showlist);
|
||||||
|
|
||||||
|
#if GDB_SELF_TEST
|
||||||
|
selftests::register_test ("infrun_thread_ptid_changed",
|
||||||
|
selftests::infrun_thread_ptid_changed);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ struct so_list;
|
|||||||
struct objfile;
|
struct objfile;
|
||||||
struct thread_info;
|
struct thread_info;
|
||||||
struct inferior;
|
struct inferior;
|
||||||
|
struct process_stratum_target;
|
||||||
struct trace_state_variable;
|
struct trace_state_variable;
|
||||||
|
|
||||||
namespace gdb
|
namespace gdb
|
||||||
@@ -165,8 +166,9 @@ extern observable<struct gdbarch */* newarch */> architecture_changed;
|
|||||||
|
|
||||||
/* The thread's ptid has changed. The OLD_PTID parameter specifies
|
/* The thread's ptid has changed. The OLD_PTID parameter specifies
|
||||||
the old value, and NEW_PTID specifies the new value. */
|
the old value, and NEW_PTID specifies the new value. */
|
||||||
extern observable<ptid_t /* old_ptid */, ptid_t /* new_ptid */>
|
extern observable<process_stratum_target * /* target */,
|
||||||
thread_ptid_changed;
|
ptid_t /* old_ptid */, ptid_t /* new_ptid */>
|
||||||
|
thread_ptid_changed;
|
||||||
|
|
||||||
/* The inferior INF has been added to the list of inferiors. At
|
/* The inferior INF has been added to the list of inferiors. At
|
||||||
this point, it might not be associated with any process. */
|
this point, it might not be associated with any process. */
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
#include "gdbarch.h"
|
#include "gdbarch.h"
|
||||||
#include "cli/cli-style.h"
|
#include "cli/cli-style.h"
|
||||||
#include "async-event.h"
|
#include "async-event.h"
|
||||||
|
#include <forward_list>
|
||||||
|
|
||||||
static const target_info record_btrace_target_info = {
|
static const target_info record_btrace_target_info = {
|
||||||
"record-btrace",
|
"record-btrace",
|
||||||
|
|||||||
228
gdb/regcache.c
228
gdb/regcache.c
@@ -29,7 +29,7 @@
|
|||||||
#include "reggroups.h"
|
#include "reggroups.h"
|
||||||
#include "observable.h"
|
#include "observable.h"
|
||||||
#include "regset.h"
|
#include "regset.h"
|
||||||
#include <forward_list>
|
#include <unordered_map>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DATA STRUCTURE
|
* DATA STRUCTURE
|
||||||
@@ -313,31 +313,48 @@ reg_buffer::assert_regnum (int regnum) const
|
|||||||
gdb_assert (regnum < gdbarch_num_regs (arch ()));
|
gdb_assert (regnum < gdbarch_num_regs (arch ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Global structure containing the current regcache. */
|
/* Type to map a ptid to a list of regcaches (one thread may have multiple
|
||||||
|
regcaches, associated to different gdbarches). */
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
using target_ptid_regcache_map
|
||||||
|
= std::unordered_map<process_stratum_target *, ptid_regcache_map>;
|
||||||
|
|
||||||
|
/* Global structure containing the existing regcaches. */
|
||||||
|
|
||||||
/* NOTE: this is a write-through cache. There is no "dirty" bit for
|
/* NOTE: this is a write-through cache. There is no "dirty" bit for
|
||||||
recording if the register values have been changed (eg. by the
|
recording if the register values have been changed (eg. by the
|
||||||
user). Therefore all registers must be written back to the
|
user). Therefore all registers must be written back to the
|
||||||
target when appropriate. */
|
target when appropriate. */
|
||||||
std::forward_list<regcache *> regcache::current_regcache;
|
static target_ptid_regcache_map regcaches;
|
||||||
|
|
||||||
struct regcache *
|
struct regcache *
|
||||||
get_thread_arch_aspace_regcache (process_stratum_target *target,
|
get_thread_arch_aspace_regcache (process_stratum_target *target,
|
||||||
ptid_t ptid, struct gdbarch *gdbarch,
|
ptid_t ptid, gdbarch *arch,
|
||||||
struct address_space *aspace)
|
struct address_space *aspace)
|
||||||
{
|
{
|
||||||
gdb_assert (target != nullptr);
|
gdb_assert (target != nullptr);
|
||||||
|
|
||||||
for (const auto ®cache : regcache::current_regcache)
|
/* Find the ptid -> regcache map for this target. */
|
||||||
if (regcache->target () == target
|
auto &ptid_regc_map = regcaches[target];
|
||||||
&& regcache->ptid () == ptid
|
|
||||||
&& regcache->arch () == gdbarch)
|
|
||||||
return regcache;
|
|
||||||
|
|
||||||
regcache *new_regcache = new regcache (target, gdbarch, aspace);
|
/* Check first if a regcache for this arch already exists. */
|
||||||
|
auto range = ptid_regc_map.equal_range (ptid);
|
||||||
|
for (auto it = range.first; it != range.second; it++)
|
||||||
|
{
|
||||||
|
if (it->second->arch () == arch)
|
||||||
|
return it->second.get ();
|
||||||
|
}
|
||||||
|
|
||||||
regcache::current_regcache.push_front (new_regcache);
|
/* It does not exist, create it. */
|
||||||
|
regcache *new_regcache (new regcache (target, arch, aspace));
|
||||||
new_regcache->set_ptid (ptid);
|
new_regcache->set_ptid (ptid);
|
||||||
|
ptid_regc_map.insert (std::make_pair (ptid, new_regcache));
|
||||||
|
|
||||||
return new_regcache;
|
return new_regcache;
|
||||||
}
|
}
|
||||||
@@ -412,15 +429,27 @@ regcache_observer_target_changed (struct target_ops *target)
|
|||||||
registers_changed ();
|
registers_changed ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update global variables old ptids to hold NEW_PTID if they were
|
/* Update regcaches related to OLD_PTID to now use NEW_PTID. */
|
||||||
holding OLD_PTID. */
|
static void
|
||||||
void
|
regcache_thread_ptid_changed (process_stratum_target *target,
|
||||||
regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
|
ptid_t old_ptid, ptid_t new_ptid)
|
||||||
{
|
{
|
||||||
for (auto ®cache : regcache::current_regcache)
|
auto ptid_regc_map_it = regcaches.find (target);
|
||||||
|
|
||||||
|
if (ptid_regc_map_it == regcaches.end ())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto &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;)
|
||||||
{
|
{
|
||||||
if (regcache->ptid () == old_ptid)
|
regcache_up rc = std::move (it->second);
|
||||||
regcache->set_ptid (new_ptid);
|
rc->set_ptid (new_ptid);
|
||||||
|
|
||||||
|
/* Remove old before inserting new, to avoid rehashing,
|
||||||
|
which would invalidate iterators. */
|
||||||
|
it = ptid_regc_map.erase (it);
|
||||||
|
ptid_regc_map.insert (std::make_pair (new_ptid, std::move (rc)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,20 +467,37 @@ regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
|
|||||||
void
|
void
|
||||||
registers_changed_ptid (process_stratum_target *target, ptid_t ptid)
|
registers_changed_ptid (process_stratum_target *target, ptid_t ptid)
|
||||||
{
|
{
|
||||||
for (auto oit = regcache::current_regcache.before_begin (),
|
if (target == nullptr)
|
||||||
it = std::next (oit);
|
|
||||||
it != regcache::current_regcache.end ();
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
struct regcache *regcache = *it;
|
/* Since there can be ptid clashes between targets, it's not valid to
|
||||||
if ((target == nullptr || regcache->target () == target)
|
pass a ptid without saying to which target it belongs. */
|
||||||
&& regcache->ptid ().matches (ptid))
|
gdb_assert (ptid == minus_one_ptid);
|
||||||
|
|
||||||
|
/* Delete all the regcaches. */
|
||||||
|
for (auto &pair : regcaches)
|
||||||
|
pair.second.clear ();
|
||||||
|
}
|
||||||
|
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 ())
|
||||||
{
|
{
|
||||||
delete regcache;
|
auto &ptid_regc_map = ptid_regc_map_it->second;
|
||||||
it = regcache::current_regcache.erase_after (oit);
|
ptid_regc_map.erase (ptid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Non-NULL target and minus_one_ptid, delete all regcaches
|
||||||
|
associated to this target. */
|
||||||
|
auto ptid_regc_map_it = regcaches.find (target);
|
||||||
|
if (ptid_regc_map_it != regcaches.end ())
|
||||||
|
{
|
||||||
|
auto &ptid_regc_map = ptid_regc_map_it->second;
|
||||||
|
ptid_regc_map.clear ();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
oit = it++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((target == nullptr || current_thread_target == target)
|
if ((target == nullptr || current_thread_target == target)
|
||||||
@@ -1433,19 +1479,17 @@ register_dump::dump (ui_file *file)
|
|||||||
|
|
||||||
namespace selftests {
|
namespace selftests {
|
||||||
|
|
||||||
class regcache_access : public regcache
|
static size_t
|
||||||
|
regcaches_size ()
|
||||||
{
|
{
|
||||||
public:
|
size_t size = 0;
|
||||||
|
for (auto it = regcaches.begin (); it != regcaches.end (); ++it)
|
||||||
/* Return the number of elements in current_regcache. */
|
{
|
||||||
|
auto &ptid_regc_map = it->second;
|
||||||
static size_t
|
size += ptid_regc_map.size ();
|
||||||
current_regcache_size ()
|
}
|
||||||
{
|
return size;
|
||||||
return std::distance (regcache::current_regcache.begin (),
|
}
|
||||||
regcache::current_regcache.end ());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Wrapper around get_thread_arch_aspace_regcache that does some self checks. */
|
/* Wrapper around get_thread_arch_aspace_regcache that does some self checks. */
|
||||||
|
|
||||||
@@ -1463,10 +1507,10 @@ test_get_thread_arch_aspace_regcache (process_stratum_target *target,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
current_regcache_test (void)
|
regcaches_test (void)
|
||||||
{
|
{
|
||||||
/* It is empty at the start. */
|
/* It is empty at the start. */
|
||||||
SELF_CHECK (regcache_access::current_regcache_size () == 0);
|
SELF_CHECK (regcaches_size () == 0);
|
||||||
|
|
||||||
ptid_t ptid1 (1), ptid2 (2), ptid3 (3);
|
ptid_t ptid1 (1), ptid2 (2), ptid3 (3);
|
||||||
|
|
||||||
@@ -1474,57 +1518,56 @@ current_regcache_test (void)
|
|||||||
test_target_ops test_target2;
|
test_target_ops test_target2;
|
||||||
|
|
||||||
/* Get regcache from (target1,ptid1), a new regcache is added to
|
/* Get regcache from (target1,ptid1), a new regcache is added to
|
||||||
current_regcache. */
|
REGCACHES. */
|
||||||
test_get_thread_arch_aspace_regcache (&test_target1, ptid1,
|
test_get_thread_arch_aspace_regcache (&test_target1, ptid1,
|
||||||
target_gdbarch (),
|
target_gdbarch (),
|
||||||
NULL);
|
NULL);
|
||||||
SELF_CHECK (regcache_access::current_regcache_size () == 1);
|
SELF_CHECK (regcaches_size () == 1);
|
||||||
|
|
||||||
/* Get regcache from (target1,ptid2), a new regcache is added to
|
/* Get regcache from (target1,ptid2), a new regcache is added to
|
||||||
current_regcache. */
|
REGCACHES. */
|
||||||
test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
|
test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
|
||||||
target_gdbarch (),
|
target_gdbarch (),
|
||||||
NULL);
|
NULL);
|
||||||
SELF_CHECK (regcache_access::current_regcache_size () == 2);
|
SELF_CHECK (regcaches_size () == 2);
|
||||||
|
|
||||||
/* Get regcache from (target1,ptid3), a new regcache is added to
|
/* Get regcache from (target1,ptid3), a new regcache is added to
|
||||||
current_regcache. */
|
REGCACHES. */
|
||||||
test_get_thread_arch_aspace_regcache (&test_target1, ptid3,
|
test_get_thread_arch_aspace_regcache (&test_target1, ptid3,
|
||||||
target_gdbarch (),
|
target_gdbarch (),
|
||||||
NULL);
|
NULL);
|
||||||
SELF_CHECK (regcache_access::current_regcache_size () == 3);
|
SELF_CHECK (regcaches_size () == 3);
|
||||||
|
|
||||||
/* Get regcache from (target1,ptid2) again, nothing is added to
|
/* Get regcache from (target1,ptid2) again, nothing is added to
|
||||||
current_regcache. */
|
REGCACHES. */
|
||||||
test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
|
test_get_thread_arch_aspace_regcache (&test_target1, ptid2,
|
||||||
target_gdbarch (),
|
target_gdbarch (),
|
||||||
NULL);
|
NULL);
|
||||||
SELF_CHECK (regcache_access::current_regcache_size () == 3);
|
SELF_CHECK (regcaches_size () == 3);
|
||||||
|
|
||||||
/* Get regcache from (target2,ptid2), a new regcache is added to
|
/* Get regcache from (target2,ptid2), a new regcache is added to
|
||||||
current_regcache, since this time we're using a differen
|
REGCACHES, since this time we're using a different target. */
|
||||||
target. */
|
|
||||||
test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
|
test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
|
||||||
target_gdbarch (),
|
target_gdbarch (),
|
||||||
NULL);
|
NULL);
|
||||||
SELF_CHECK (regcache_access::current_regcache_size () == 4);
|
SELF_CHECK (regcaches_size () == 4);
|
||||||
|
|
||||||
/* Mark that (target1,ptid2) changed. The regcache of (target1,
|
/* Mark that (target1,ptid2) changed. The regcache of (target1,
|
||||||
ptid2) should be removed from current_regcache. */
|
ptid2) should be removed from REGCACHES. */
|
||||||
registers_changed_ptid (&test_target1, ptid2);
|
registers_changed_ptid (&test_target1, ptid2);
|
||||||
SELF_CHECK (regcache_access::current_regcache_size () == 3);
|
SELF_CHECK (regcaches_size () == 3);
|
||||||
|
|
||||||
/* Get the regcache from (target2,ptid2) again, confirming the
|
/* Get the regcache from (target2,ptid2) again, confirming the
|
||||||
registers_changed_ptid call above did not delete it. */
|
registers_changed_ptid call above did not delete it. */
|
||||||
test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
|
test_get_thread_arch_aspace_regcache (&test_target2, ptid2,
|
||||||
target_gdbarch (),
|
target_gdbarch (),
|
||||||
NULL);
|
NULL);
|
||||||
SELF_CHECK (regcache_access::current_regcache_size () == 3);
|
SELF_CHECK (regcaches_size () == 3);
|
||||||
|
|
||||||
/* Confirm that marking all regcaches of all targets as changed
|
/* Confirm that marking all regcaches of all targets as changed
|
||||||
clears current_regcache. */
|
clears REGCACHES. */
|
||||||
registers_changed_ptid (nullptr, minus_one_ptid);
|
registers_changed_ptid (nullptr, minus_one_ptid);
|
||||||
SELF_CHECK (regcache_access::current_regcache_size () == 0);
|
SELF_CHECK (regcaches_size () == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
class target_ops_no_register : public test_target_ops
|
class target_ops_no_register : public test_target_ops
|
||||||
@@ -1828,6 +1871,66 @@ cooked_write_test (struct gdbarch *gdbarch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Verify that when two threads with the same ptid exist (from two different
|
||||||
|
targets) and one of them changes ptid, we only update the appropriate
|
||||||
|
regcaches. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
regcache_thread_ptid_changed ()
|
||||||
|
{
|
||||||
|
/* Any arch will do. */
|
||||||
|
gdbarch *arch = current_inferior ()->gdbarch;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
target2.mock_inferior.pid = old_ptid.pid ();
|
||||||
|
target2.mock_thread.ptid = old_ptid;
|
||||||
|
|
||||||
|
gdb_assert (regcaches.empty ());
|
||||||
|
|
||||||
|
/* Populate the regcaches container. */
|
||||||
|
get_thread_arch_aspace_regcache (&target1.mock_target, old_ptid, arch,
|
||||||
|
nullptr);
|
||||||
|
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);
|
||||||
|
gdb_assert (regcache_count (&target2.mock_target, old_ptid) == 1);
|
||||||
|
gdb_assert (regcache_count (&target2.mock_target, new_ptid) == 0);
|
||||||
|
|
||||||
|
thread_change_ptid (&target1.mock_target, old_ptid, new_ptid);
|
||||||
|
|
||||||
|
gdb_assert (regcaches.size () == 2);
|
||||||
|
gdb_assert (regcache_count (&target1.mock_target, old_ptid) == 0);
|
||||||
|
gdb_assert (regcache_count (&target1.mock_target, new_ptid) == 1);
|
||||||
|
gdb_assert (regcache_count (&target2.mock_target, old_ptid) == 1);
|
||||||
|
gdb_assert (regcache_count (&target2.mock_target, new_ptid) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace selftests
|
} // namespace selftests
|
||||||
#endif /* GDB_SELF_TEST */
|
#endif /* GDB_SELF_TEST */
|
||||||
|
|
||||||
@@ -1839,18 +1942,19 @@ _initialize_regcache ()
|
|||||||
= gdbarch_data_register_post_init (init_regcache_descr);
|
= gdbarch_data_register_post_init (init_regcache_descr);
|
||||||
|
|
||||||
gdb::observers::target_changed.attach (regcache_observer_target_changed);
|
gdb::observers::target_changed.attach (regcache_observer_target_changed);
|
||||||
gdb::observers::thread_ptid_changed.attach
|
gdb::observers::thread_ptid_changed.attach (regcache_thread_ptid_changed);
|
||||||
(regcache::regcache_thread_ptid_changed);
|
|
||||||
|
|
||||||
add_com ("flushregs", class_maintenance, reg_flush_command,
|
add_com ("flushregs", class_maintenance, reg_flush_command,
|
||||||
_("Force gdb to flush its register cache (maintainer command)."));
|
_("Force gdb to flush its register cache (maintainer command)."));
|
||||||
|
|
||||||
#if GDB_SELF_TEST
|
#if GDB_SELF_TEST
|
||||||
selftests::register_test ("current_regcache", selftests::current_regcache_test);
|
selftests::register_test ("regcaches", selftests::regcaches_test);
|
||||||
|
|
||||||
selftests::register_test_foreach_arch ("regcache::cooked_read_test",
|
selftests::register_test_foreach_arch ("regcache::cooked_read_test",
|
||||||
selftests::cooked_read_test);
|
selftests::cooked_read_test);
|
||||||
selftests::register_test_foreach_arch ("regcache::cooked_write_test",
|
selftests::register_test_foreach_arch ("regcache::cooked_write_test",
|
||||||
selftests::cooked_write_test);
|
selftests::cooked_write_test);
|
||||||
|
selftests::register_test ("regcache_thread_ptid_changed",
|
||||||
|
selftests::regcache_thread_ptid_changed);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include "gdbsupport/common-regcache.h"
|
#include "gdbsupport/common-regcache.h"
|
||||||
#include "gdbsupport/function-view.h"
|
#include "gdbsupport/function-view.h"
|
||||||
#include <forward_list>
|
|
||||||
|
|
||||||
struct regcache;
|
struct regcache;
|
||||||
struct regset;
|
struct regset;
|
||||||
@@ -397,13 +396,10 @@ public:
|
|||||||
debug. */
|
debug. */
|
||||||
void debug_print_register (const char *func, int regno);
|
void debug_print_register (const char *func, int regno);
|
||||||
|
|
||||||
static void regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid);
|
|
||||||
protected:
|
protected:
|
||||||
regcache (process_stratum_target *target, gdbarch *gdbarch,
|
regcache (process_stratum_target *target, gdbarch *gdbarch,
|
||||||
const address_space *aspace);
|
const address_space *aspace);
|
||||||
|
|
||||||
static std::forward_list<regcache *> current_regcache;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/* Helper function for transfer_regset. Copies across a single register. */
|
/* Helper function for transfer_regset. Copies across a single register. */
|
||||||
@@ -437,11 +433,10 @@ private:
|
|||||||
get_thread_arch_aspace_regcache (process_stratum_target *target, ptid_t ptid,
|
get_thread_arch_aspace_regcache (process_stratum_target *target, ptid_t ptid,
|
||||||
struct gdbarch *gdbarch,
|
struct gdbarch *gdbarch,
|
||||||
struct address_space *aspace);
|
struct address_space *aspace);
|
||||||
|
|
||||||
friend void
|
|
||||||
registers_changed_ptid (process_stratum_target *target, ptid_t ptid);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using regcache_up = std::unique_ptr<regcache>;
|
||||||
|
|
||||||
class readonly_detached_regcache : public readable_regcache
|
class readonly_detached_regcache : public readable_regcache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -33,8 +33,8 @@
|
|||||||
#include "target-descriptions.h"
|
#include "target-descriptions.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
|
||||||
#include "sparc64-tdep.h"
|
#include "sparc64-tdep.h"
|
||||||
|
#include <forward_list>
|
||||||
|
|
||||||
/* This file implements the SPARC 64-bit ABI as defined by the
|
/* This file implements the SPARC 64-bit ABI as defined by the
|
||||||
section "Low-Level System Information" of the SPARC Compliance
|
section "Low-Level System Information" of the SPARC Compliance
|
||||||
|
|||||||
@@ -775,7 +775,7 @@ thread_change_ptid (process_stratum_target *targ,
|
|||||||
tp = find_thread_ptid (inf, old_ptid);
|
tp = find_thread_ptid (inf, old_ptid);
|
||||||
tp->ptid = new_ptid;
|
tp->ptid = new_ptid;
|
||||||
|
|
||||||
gdb::observers::thread_ptid_changed.notify (old_ptid, new_ptid);
|
gdb::observers::thread_ptid_changed.notify (targ, old_ptid, new_ptid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See gdbthread.h. */
|
/* See gdbthread.h. */
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
thread_stratum target that might want to sit on top.
|
thread_stratum target that might want to sit on top.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
class ptid_t
|
class ptid_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -143,6 +145,20 @@ private:
|
|||||||
long m_tid;
|
long m_tid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Functor to hash a ptid. */
|
||||||
|
|
||||||
|
struct hash_ptid
|
||||||
|
{
|
||||||
|
size_t operator() (const ptid_t &ptid) const
|
||||||
|
{
|
||||||
|
std::hash<long> long_hash;
|
||||||
|
|
||||||
|
return (long_hash (ptid.pid ())
|
||||||
|
+ long_hash (ptid.lwp ())
|
||||||
|
+ long_hash (ptid.tid ()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* The null or zero ptid, often used to indicate no process. */
|
/* The null or zero ptid, often used to indicate no process. */
|
||||||
|
|
||||||
extern const ptid_t null_ptid;
|
extern const ptid_t null_ptid;
|
||||||
|
|||||||
Reference in New Issue
Block a user