X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fregcache.c;h=2dfe8eaf5feb13b23bebbd8323c2fb6bd00d34da;hb=cd9629e1df1a280c19e1daaf6c1195afbab0aca9;hp=c51ef771be8df702a40b97b6fbb3fda10b8974e8;hpb=42a4f53d2bf8938c2aeda9f52be7a20534b214a9;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/regcache.c b/gdb/regcache.c index c51ef771be..2dfe8eaf5f 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -1,6 +1,6 @@ /* Cache and manage the values of registers for GDB, the GNU debugger. - Copyright (C) 1986-2019 Free Software Foundation, Inc. + Copyright (C) 1986-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -168,7 +168,7 @@ register_size (struct gdbarch *gdbarch, int regnum) return size; } -/* See common/common-regcache.h. */ +/* See gdbsupport/common-regcache.h. */ int regcache_register_size (const struct regcache *regcache, int n) @@ -196,10 +196,11 @@ reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo) } } -regcache::regcache (gdbarch *gdbarch, const address_space *aspace_) +regcache::regcache (process_stratum_target *target, gdbarch *gdbarch, + const address_space *aspace_) /* The register buffers. A read/write register cache can only hold [0 .. gdbarch_num_regs). */ - : detached_regcache (gdbarch, false), m_aspace (aspace_) + : detached_regcache (gdbarch, false), m_aspace (aspace_), m_target (target) { m_ptid = minus_one_ptid; } @@ -219,37 +220,6 @@ reg_buffer::arch () const return m_descr->gdbarch; } -/* Cleanup class for invalidating a register. */ - -class regcache_invalidator -{ -public: - - regcache_invalidator (struct regcache *regcache, int regnum) - : m_regcache (regcache), - m_regnum (regnum) - { - } - - ~regcache_invalidator () - { - if (m_regcache != nullptr) - m_regcache->invalidate (m_regnum); - } - - DISABLE_COPY_AND_ASSIGN (regcache_invalidator); - - void release () - { - m_regcache = nullptr; - } - -private: - - struct regcache *m_regcache; - int m_regnum; -}; - /* Return a pointer to register REGNUM's buffer cache. */ gdb_byte * @@ -315,7 +285,7 @@ regcache::restore (readonly_detached_regcache *src) } } -/* See common/common-regcache.h. */ +/* See gdbsupport/common-regcache.h. */ enum register_status reg_buffer::get_register_status (int regnum) const @@ -351,14 +321,19 @@ reg_buffer::assert_regnum (int regnum) const std::forward_list regcache::current_regcache; struct regcache * -get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch, +get_thread_arch_aspace_regcache (process_stratum_target *target, + ptid_t ptid, struct gdbarch *gdbarch, struct address_space *aspace) { + gdb_assert (target != nullptr); + for (const auto ®cache : regcache::current_regcache) - if (regcache->ptid () == ptid && regcache->arch () == gdbarch) + if (regcache->target () == target + && regcache->ptid () == ptid + && regcache->arch () == gdbarch) return regcache; - regcache *new_regcache = new regcache (gdbarch, aspace); + regcache *new_regcache = new regcache (target, gdbarch, aspace); regcache::current_regcache.push_front (new_regcache); new_regcache->set_ptid (ptid); @@ -367,26 +342,38 @@ get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch, } struct regcache * -get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch) +get_thread_arch_regcache (process_stratum_target *target, ptid_t ptid, + struct gdbarch *gdbarch) { + scoped_restore_current_inferior restore_current_inferior; + set_current_inferior (find_inferior_ptid (target, ptid)); address_space *aspace = target_thread_address_space (ptid); - return get_thread_arch_aspace_regcache (ptid, gdbarch, aspace); + return get_thread_arch_aspace_regcache (target, ptid, gdbarch, aspace); } +static process_stratum_target *current_thread_target; static ptid_t current_thread_ptid; static struct gdbarch *current_thread_arch; struct regcache * -get_thread_regcache (ptid_t ptid) +get_thread_regcache (process_stratum_target *target, ptid_t ptid) { - if (!current_thread_arch || current_thread_ptid != ptid) + if (!current_thread_arch + || target != current_thread_target + || current_thread_ptid != ptid) { + gdb_assert (ptid != null_ptid); + current_thread_ptid = ptid; + current_thread_target = target; + + scoped_restore_current_inferior restore_current_inferior; + set_current_inferior (find_inferior_ptid (target, ptid)); current_thread_arch = target_thread_architecture (ptid); } - return get_thread_arch_regcache (ptid, current_thread_arch); + return get_thread_arch_regcache (target, ptid, current_thread_arch); } /* See regcache.h. */ @@ -394,7 +381,8 @@ get_thread_regcache (ptid_t ptid) struct regcache * get_thread_regcache (thread_info *thread) { - return get_thread_regcache (thread->ptid); + return get_thread_regcache (thread->inf->process_target (), + thread->ptid); } struct regcache * @@ -403,12 +391,16 @@ get_current_regcache (void) return get_thread_regcache (inferior_thread ()); } -/* See common/common-regcache.h. */ +/* See gdbsupport/common-regcache.h. */ struct regcache * get_thread_regcache_for_ptid (ptid_t ptid) { - return get_thread_regcache (ptid); + /* This function doesn't take a process_stratum_target parameter + because it's a gdbsupport/ routine implemented by both gdb and + gdbserver. It always refers to a ptid of the current target. */ + process_stratum_target *proc_target = current_inferior ()->process_target (); + return get_thread_regcache (proc_target, ptid); } /* Observer for the target_changed event. */ @@ -443,29 +435,34 @@ regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) Indicate that registers may have changed, so invalidate the cache. */ void -registers_changed_ptid (ptid_t ptid) +registers_changed_ptid (process_stratum_target *target, ptid_t ptid) { for (auto oit = regcache::current_regcache.before_begin (), it = std::next (oit); it != regcache::current_regcache.end (); ) { - if ((*it)->ptid ().matches (ptid)) + struct regcache *regcache = *it; + if ((target == nullptr || regcache->target () == target) + && regcache->ptid ().matches (ptid)) { - delete *it; + delete regcache; it = regcache::current_regcache.erase_after (oit); } else oit = it++; } - if (current_thread_ptid.matches (ptid)) + if ((target == nullptr || current_thread_target == target) + && current_thread_ptid.matches (ptid)) { + current_thread_target = NULL; current_thread_ptid = null_ptid; current_thread_arch = NULL; } - if (inferior_ptid.matches (ptid)) + if ((target == nullptr || current_inferior ()->process_target () == target) + && inferior_ptid.matches (ptid)) { /* We just deleted the regcache of the current thread. Need to forget about any frames we have cached, too. */ @@ -478,20 +475,13 @@ registers_changed_ptid (ptid_t ptid) void registers_changed_thread (thread_info *thread) { - registers_changed_ptid (thread->ptid); + registers_changed_ptid (thread->inf->process_target (), thread->ptid); } void registers_changed (void) { - registers_changed_ptid (minus_one_ptid); - - /* Force cleanup of any alloca areas if using C alloca instead of - a builtin alloca. This particular call is used to clean up - areas allocated by low level target code which may build up - during lengthy interactions between gdb and the target before - gdb gives control to the user (ie watchpoints). */ - alloca (0); + registers_changed_ptid (nullptr, minus_one_ptid); } void @@ -769,7 +759,8 @@ regcache::raw_write (int regnum, const gdb_byte *buf) /* Invalidate the register after it is written, in case of a failure. */ - regcache_invalidator invalidator (this, regnum); + auto invalidator + = make_scope_exit ([&] { this->invalidate (regnum); }); target_store_registers (this, regnum); @@ -968,7 +959,7 @@ regcache::cooked_write_part (int regnum, int offset, int len, write_part (regnum, offset, len, buf, false); } -/* See common/common-regcache.h. */ +/* See gdbsupport/common-regcache.h. */ void reg_buffer::raw_supply (int regnum, const void *buf) @@ -1033,7 +1024,7 @@ reg_buffer::raw_supply_zeroed (int regnum) m_register_status[regnum] = REG_VALID; } -/* See common/common-regcache.h. */ +/* See gdbsupport/common-regcache.h. */ void reg_buffer::raw_collect (int regnum, void *buf) const @@ -1185,7 +1176,7 @@ regcache::collect_regset (const struct regset *regset, transfer_regset (regset, nullptr, regnum, nullptr, (gdb_byte *) buf, size); } -/* See common/common-regcache.h. */ +/* See gdbsupport/common-regcache.h. */ bool reg_buffer::raw_compare (int regnum, const void *buf, int offset) const @@ -1417,9 +1408,8 @@ register_dump::dump (ui_file *file) } #if GDB_SELF_TEST -#include "selftest.h" +#include "gdbsupport/selftest.h" #include "selftest-arch.h" -#include "gdbthread.h" #include "target-float.h" namespace selftests { @@ -1438,6 +1428,21 @@ public: } }; +/* 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) +{ + struct regcache *regcache + = get_thread_arch_aspace_regcache (target, ptid, gdbarch, aspace); + SELF_CHECK (regcache != NULL); + SELF_CHECK (regcache->target () == target); + SELF_CHECK (regcache->ptid () == ptid); + SELF_CHECK (regcache->aspace () == aspace); +} + static void current_regcache_test (void) { @@ -1446,47 +1451,61 @@ current_regcache_test (void) ptid_t ptid1 (1), ptid2 (2), ptid3 (3); - /* Get regcache from ptid1, a new regcache is added to - current_regcache. */ - regcache *regcache = get_thread_arch_aspace_regcache (ptid1, - target_gdbarch (), - NULL); + test_target_ops test_target1; + test_target_ops test_target2; - SELF_CHECK (regcache != NULL); - SELF_CHECK (regcache->ptid () == ptid1); + /* Get regcache from (target1,ptid1), a new regcache is added to + current_regcache. */ + test_get_thread_arch_aspace_regcache (&test_target1, ptid1, + target_gdbarch (), + NULL); SELF_CHECK (regcache_access::current_regcache_size () == 1); - /* Get regcache from ptid2, a new regcache is added to + /* Get regcache from (target1,ptid2), a new regcache is added to current_regcache. */ - regcache = get_thread_arch_aspace_regcache (ptid2, - target_gdbarch (), - NULL); - SELF_CHECK (regcache != NULL); - SELF_CHECK (regcache->ptid () == ptid2); + test_get_thread_arch_aspace_regcache (&test_target1, ptid2, + target_gdbarch (), + NULL); SELF_CHECK (regcache_access::current_regcache_size () == 2); - /* Get regcache from ptid3, a new regcache is added to + /* Get regcache from (target1,ptid3), a new regcache is added to current_regcache. */ - regcache = get_thread_arch_aspace_regcache (ptid3, - target_gdbarch (), - NULL); - SELF_CHECK (regcache != NULL); - SELF_CHECK (regcache->ptid () == ptid3); + test_get_thread_arch_aspace_regcache (&test_target1, ptid3, + target_gdbarch (), + NULL); SELF_CHECK (regcache_access::current_regcache_size () == 3); - /* Get regcache from ptid2 again, nothing is added to + /* Get regcache from (target1,ptid2) again, nothing is added to current_regcache. */ - regcache = get_thread_arch_aspace_regcache (ptid2, - target_gdbarch (), - NULL); - SELF_CHECK (regcache != NULL); - SELF_CHECK (regcache->ptid () == ptid2); + test_get_thread_arch_aspace_regcache (&test_target1, ptid2, + target_gdbarch (), + NULL); 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 (regcache_access::current_regcache_size () == 2); + /* Get regcache from (target2,ptid2), a new regcache is added to + current_regcache, since this time we're using a differen + target. */ + test_get_thread_arch_aspace_regcache (&test_target2, ptid2, + target_gdbarch (), + NULL); + SELF_CHECK (regcache_access::current_regcache_size () == 4); + + /* Mark that (target1,ptid2) changed. The regcache of (target1, + ptid2) should be removed from current_regcache. */ + registers_changed_ptid (&test_target1, ptid2); + SELF_CHECK (regcache_access::current_regcache_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 (regcache_access::current_regcache_size () == 3); + + /* Confirm that marking all regcaches of all targets as changed + clears current_regcache. */ + registers_changed_ptid (nullptr, minus_one_ptid); + SELF_CHECK (regcache_access::current_regcache_size () == 0); } class target_ops_no_register : public test_target_ops @@ -1547,8 +1566,9 @@ target_ops_no_register::xfer_partial (enum target_object object, class readwrite_regcache : public regcache { public: - readwrite_regcache (struct gdbarch *gdbarch) - : regcache (gdbarch, nullptr) + readwrite_regcache (process_stratum_target *target, + struct gdbarch *gdbarch) + : regcache (target, gdbarch, nullptr) {} }; @@ -1573,6 +1593,7 @@ cooked_read_test (struct gdbarch *gdbarch) mock_inferior.gdbarch = gdbarch; mock_inferior.aspace = &mock_aspace; thread_info mock_thread (&mock_inferior, mock_ptid); + mock_inferior.thread_map[mock_ptid] = &mock_thread; /* Add the mock inferior to the inferior list so that look ups by target+ptid can find it. */ @@ -1614,7 +1635,7 @@ cooked_read_test (struct gdbarch *gdbarch) break; } - readwrite_regcache readwrite (gdbarch); + readwrite_regcache readwrite (&mock_target, gdbarch); gdb::def_vector buf (register_size (gdbarch, nonzero_regnum)); readwrite.raw_read (nonzero_regnum, buf.data ()); @@ -1643,10 +1664,7 @@ cooked_read_test (struct gdbarch *gdbarch) SELF_CHECK (mock_target.fetch_registers_called == 0); SELF_CHECK (mock_target.store_registers_called == 0); - - /* Some SPU pseudo registers are got via TARGET_OBJECT_SPU. */ - if (gdbarch_bfd_arch_info (gdbarch)->arch != bfd_arch_spu) - SELF_CHECK (mock_target.xfer_partial_called == 0); + SELF_CHECK (mock_target.xfer_partial_called == 0); mock_target.reset (); } @@ -1750,7 +1768,7 @@ cooked_write_test (struct gdbarch *gdbarch) } } pop_targets; - readwrite_regcache readwrite (gdbarch); + readwrite_regcache readwrite (&mock_target, gdbarch); const int num_regs = gdbarch_num_cooked_regs (gdbarch); @@ -1762,16 +1780,12 @@ cooked_write_test (struct gdbarch *gdbarch) auto bfd_arch = gdbarch_bfd_arch_info (gdbarch)->arch; - if ((bfd_arch == bfd_arch_sparc - /* SPARC64_CWP_REGNUM, SPARC64_PSTATE_REGNUM, - SPARC64_ASI_REGNUM and SPARC64_CCR_REGNUM are hard to test. */ - && gdbarch_ptr_bit (gdbarch) == 64 - && (regnum >= gdbarch_num_regs (gdbarch) - && regnum <= gdbarch_num_regs (gdbarch) + 4)) - || (bfd_arch == bfd_arch_spu - /* SPU pseudo registers except SPU_SP_REGNUM are got by - TARGET_OBJECT_SPU. */ - && regnum >= gdbarch_num_regs (gdbarch) && regnum != 130)) + if (bfd_arch == bfd_arch_sparc + /* SPARC64_CWP_REGNUM, SPARC64_PSTATE_REGNUM, + SPARC64_ASI_REGNUM and SPARC64_CCR_REGNUM are hard to test. */ + && gdbarch_ptr_bit (gdbarch) == 64 + && (regnum >= gdbarch_num_regs (gdbarch) + && regnum <= gdbarch_num_regs (gdbarch) + 4)) continue; std::vector expected (register_size (gdbarch, regnum), 0); @@ -1851,7 +1865,7 @@ _initialize_regcache (void) (regcache::regcache_thread_ptid_changed); 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 selftests::register_test ("current_regcache", selftests::current_regcache_test);