diff --git a/Source/Core/Core/PowerPC/BreakPoints.cpp b/Source/Core/Core/PowerPC/BreakPoints.cpp index 19ceac7b3f..bb3c683fb4 100644 --- a/Source/Core/Core/PowerPC/BreakPoints.cpp +++ b/Source/Core/Core/PowerPC/BreakPoints.cpp @@ -255,6 +255,8 @@ MemChecks::TMemChecksStr MemChecks::GetStrings() const void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings) { + const Core::CPUThreadGuard guard(m_system); + for (const std::string& mc_string : mc_strings) { TMemCheck mc; @@ -281,15 +283,16 @@ void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings) mc.condition = Expression::TryParse(condition); } - Add(std::move(mc)); + Add(std::move(mc), false); } + + Update(); } -void MemChecks::Add(TMemCheck memory_check) +void MemChecks::Add(TMemCheck memory_check, bool update) { - bool had_any = HasAny(); - const Core::CPUThreadGuard guard(m_system); + // Check for existing breakpoint, and overwrite with new info. // This is assuming we usually want the new breakpoint over an old one. const u32 address = memory_check.start_address; @@ -306,11 +309,9 @@ void MemChecks::Add(TMemCheck memory_check) { m_mem_checks.emplace_back(std::move(memory_check)); } - // If this is the first one, clear the JIT cache so it can switch to - // watchpoint-compatible code. - if (!had_any) - m_system.GetJitInterface().ClearCache(guard); - m_system.GetMMU().DBATUpdated(); + + if (update) + Update(); } bool MemChecks::ToggleEnable(u32 address) @@ -325,7 +326,7 @@ bool MemChecks::ToggleEnable(u32 address) return true; } -bool MemChecks::Remove(u32 address) +bool MemChecks::Remove(u32 address, bool update) { const auto iter = std::find_if(m_mem_checks.cbegin(), m_mem_checks.cend(), @@ -336,9 +337,10 @@ bool MemChecks::Remove(u32 address) const Core::CPUThreadGuard guard(m_system); m_mem_checks.erase(iter); - if (!HasAny()) - m_system.GetJitInterface().ClearCache(guard); - m_system.GetMMU().DBATUpdated(); + + if (update) + Update(); + return true; } @@ -346,7 +348,20 @@ void MemChecks::Clear() { const Core::CPUThreadGuard guard(m_system); m_mem_checks.clear(); - m_system.GetJitInterface().ClearCache(guard); + Update(); +} + +void MemChecks::Update() +{ + const Core::CPUThreadGuard guard(m_system); + + // Clear the JIT cache so it can switch the watchpoint-compatible mode. + if (m_mem_breakpoints_set != HasAny()) + { + m_system.GetJitInterface().ClearCache(guard); + m_mem_breakpoints_set = HasAny(); + } + m_system.GetMMU().DBATUpdated(); } diff --git a/Source/Core/Core/PowerPC/BreakPoints.h b/Source/Core/Core/PowerPC/BreakPoints.h index 9b07fb53c0..6b08c25c8d 100644 --- a/Source/Core/Core/PowerPC/BreakPoints.h +++ b/Source/Core/Core/PowerPC/BreakPoints.h @@ -115,19 +115,20 @@ public: TMemChecksStr GetStrings() const; void AddFromStrings(const TMemChecksStr& mc_strings); - void Add(TMemCheck memory_check); + void Add(TMemCheck memory_check, bool update = true); bool ToggleEnable(u32 address); TMemCheck* GetMemCheck(u32 address, size_t size = 1); bool OverlapsMemcheck(u32 address, u32 length) const; - // Remove Breakpoint. Returns whether it was removed. - bool Remove(u32 address); + bool Remove(u32 address, bool update = true); + void Update(); void Clear(); bool HasAny() const { return !m_mem_checks.empty(); } private: TMemChecks m_mem_checks; Core::System& m_system; + bool m_mem_breakpoints_set = false; }; diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 349f35254c..c9875a99db 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -174,9 +174,10 @@ static void RemoveBreakpoint(BreakpointType type, u32 addr, u32 len) auto& memchecks = Core::System::GetInstance().GetPowerPC().GetMemChecks(); while (memchecks.GetMemCheck(addr, len) != nullptr) { - memchecks.Remove(addr); + memchecks.Remove(addr, false); INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr); } + memchecks.Update(); } Host_PPCBreakpointsChanged(); } diff --git a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp index fcf57c8acf..9553bf1bb9 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp @@ -817,31 +817,36 @@ void MemoryViewWidget::ToggleBreakpoint(u32 addr, bool row) if (row && memchecks.OverlapsMemcheck(addr, m_bytes_per_row)) overlap = true; - for (int i = 0; i < breaks; i++) { - u32 address = addr + length * i; - TMemCheck* check_ptr = memchecks.GetMemCheck(address, length); - - if (check_ptr == nullptr && !overlap) + const Core::CPUThreadGuard guard(m_system); + for (int i = 0; i < breaks; i++) { - TMemCheck check; - check.start_address = address; - check.end_address = check.start_address + length - 1; - check.is_ranged = length > 0; - check.is_break_on_read = (m_bp_type == BPType::ReadOnly || m_bp_type == BPType::ReadWrite); - check.is_break_on_write = (m_bp_type == BPType::WriteOnly || m_bp_type == BPType::ReadWrite); - check.log_on_hit = m_do_log; - check.break_on_hit = true; + u32 address = addr + length * i; + TMemCheck* check_ptr = memchecks.GetMemCheck(address, length); - memchecks.Add(std::move(check)); - } - else if (check_ptr != nullptr) - { - // Using the pointer fixes misaligned breakpoints (0x11 breakpoint in 0x10 aligned view). - memchecks.Remove(check_ptr->start_address); + if (check_ptr == nullptr && !overlap) + { + TMemCheck check; + check.start_address = address; + check.end_address = check.start_address + length - 1; + check.is_ranged = length > 0; + check.is_break_on_read = (m_bp_type == BPType::ReadOnly || m_bp_type == BPType::ReadWrite); + check.is_break_on_write = + (m_bp_type == BPType::WriteOnly || m_bp_type == BPType::ReadWrite); + check.log_on_hit = m_do_log; + check.break_on_hit = true; + + memchecks.Add(std::move(check), false); + } + else if (check_ptr != nullptr) + { + // Using the pointer fixes misaligned breakpoints (0x11 breakpoint in 0x10 aligned view). + memchecks.Remove(check_ptr->start_address, false); + } } } + memchecks.Update(); emit Host::GetInstance()->PPCBreakpointsChanged(); }