diff options
Diffstat (limited to 'gdb/regcache.c')
-rw-r--r-- | gdb/regcache.c | 146 |
1 files changed, 72 insertions, 74 deletions
diff --git a/gdb/regcache.c b/gdb/regcache.c index 8ca59fd..394efdf 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -313,41 +313,17 @@ reg_buffer::assert_regnum (int regnum) const gdb_assert (regnum < gdbarch_num_regs (arch ())); } -/* Key type for target_ptid_regcache_map. */ +/* Type to map a ptid to a list of regcaches (one thread may have multiple + regcaches, associated to different gdbarches). */ -struct target_ptid -{ - target_ptid (process_stratum_target *target, ptid_t ptid) - : target (target), ptid (ptid) - {} - - process_stratum_target *target; - ptid_t ptid; - - bool operator== (const target_ptid &other) const - { - return (this->target == other.target - && this->ptid == other.ptid); - } -}; - -/* Hash function for target_ptid. */ +using ptid_regcache_map + = std::unordered_multimap<ptid_t, regcache_up, hash_ptid>; -struct hash_target_ptid -{ - size_t operator() (const target_ptid &val) const - { - std::hash<process_stratum_target *> h_ptr; - hash_ptid h_ptid; - - return h_ptr (val.target) + h_ptid (val.ptid); - } -}; - -/* Type to map a (target, ptid) tuple to a regcache. */ +/* 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_multimap<target_ptid, regcache_up, hash_target_ptid>; + = std::unordered_map<process_stratum_target *, ptid_regcache_map>; /* Global structure containing the existing regcaches. */ @@ -364,9 +340,11 @@ get_thread_arch_aspace_regcache (process_stratum_target *target, { gdb_assert (target != nullptr); - /* Look up the regcache for this (target, ptid, arch). */ - target_ptid key (target, ptid); - auto range = regcaches.equal_range (key); + /* Find the ptid -> regcache map for this target. */ + auto &ptid_regc_map = regcaches[target]; + + /* 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) @@ -374,11 +352,9 @@ get_thread_arch_aspace_regcache (process_stratum_target *target, } /* It does not exist, create it. */ - regcache *new_regcache = new regcache (target, arch, aspace); + regcache *new_regcache (new regcache (target, arch, aspace)); new_regcache->set_ptid (ptid); - - /* Insert it in the map. */ - regcaches.insert (std::make_pair (key, new_regcache)); + ptid_regc_map.insert (std::make_pair (ptid, new_regcache)); return new_regcache; } @@ -458,19 +434,22 @@ static void regcache_thread_ptid_changed (process_stratum_target *target, ptid_t old_ptid, ptid_t new_ptid) { - target_ptid old_key (target, old_ptid); - target_ptid new_key (target, new_ptid); + auto ptid_regc_map_it = regcaches.find (target); - auto range = regcaches.equal_range (old_key); + 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;) { regcache_up rc = std::move (it->second); rc->set_ptid (new_ptid); - /* Remove old before inserting new, to avoid rehashing, which would - invalidate iterators. */ - it = regcaches.erase (it); - regcaches.insert (std::make_pair (new_key, std::move (rc))); + /* 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))); } } @@ -495,29 +474,31 @@ registers_changed_ptid (process_stratum_target *target, ptid_t ptid) gdb_assert (ptid == minus_one_ptid); /* Delete all the regcaches. */ - regcaches.clear (); + 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). */ - regcaches.erase (target_ptid (target, ptid)); + to this (TARGET, PTID). */ + 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.erase (ptid); + } } else { - /* Non-NULL target and minus_one_ptid, delete all regcaches associated - to this target. - - We unfortunately don't have an efficient way to do this. Fall back - to iterating all items to find all those belonging to TARGET. */ - for (auto it = regcaches.begin (); it != regcaches.end ();) - { - if (it->second->target () == target) - it = regcaches.erase (it); - else - it++; - } - } + /* 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 (); + } + } if ((target == nullptr || current_thread_target == target) && current_thread_ptid.matches (ptid)) @@ -1498,6 +1479,18 @@ register_dump::dump (ui_file *file) namespace selftests { +static size_t +regcaches_size () +{ + size_t size = 0; + for (auto it = regcaches.begin (); it != regcaches.end (); ++it) + { + auto &ptid_regc_map = it->second; + size += ptid_regc_map.size (); + } + return size; +} + /* Wrapper around get_thread_arch_aspace_regcache that does some self checks. */ static void @@ -1517,7 +1510,7 @@ static void regcaches_test (void) { /* It is empty at the start. */ - SELF_CHECK (regcaches.size () == 0); + SELF_CHECK (regcaches_size () == 0); ptid_t ptid1 (1), ptid2 (2), ptid3 (3); @@ -1529,52 +1522,52 @@ regcaches_test (void) test_get_thread_arch_aspace_regcache (&test_target1, ptid1, target_gdbarch (), NULL); - SELF_CHECK (regcaches.size () == 1); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + SELF_CHECK (regcaches_size () == 0); } class target_ops_no_register : public test_target_ops @@ -1911,11 +1904,16 @@ regcache_thread_ptid_changed () /* Return the count of regcaches for (TARGET, PTID) in REGCACHES. */ auto regcache_count = [] (process_stratum_target *target, ptid_t ptid) + -> int { - target_ptid key (target, ptid); - - auto range = regcaches.equal_range (key); - return std::distance (range.first, range.second); + 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); |