Merge pull request #13446 from JosJuice/breakpoints-delayed-update

PowerPC: Add RAII handling for breakpoint updates
This commit is contained in:
Jordan Woyak
2025-07-25 23:26:25 -05:00
committed by GitHub
4 changed files with 52 additions and 20 deletions

View File

@ -252,6 +252,7 @@ MemChecks::TMemChecksStr MemChecks::GetStrings() const
void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings) void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings)
{ {
const Core::CPUThreadGuard guard(m_system); const Core::CPUThreadGuard guard(m_system);
DelayedMemCheckUpdate delayed_update(this);
for (const std::string& mc_string : mc_strings) for (const std::string& mc_string : mc_strings)
{ {
@ -279,13 +280,11 @@ void MemChecks::AddFromStrings(const TMemChecksStr& mc_strings)
mc.condition = Expression::TryParse(condition); mc.condition = Expression::TryParse(condition);
} }
Add(std::move(mc), false); delayed_update |= Add(std::move(mc));
} }
Update();
} }
void MemChecks::Add(TMemCheck memory_check, bool update) DelayedMemCheckUpdate MemChecks::Add(TMemCheck memory_check)
{ {
const Core::CPUThreadGuard guard(m_system); const Core::CPUThreadGuard guard(m_system);
@ -304,8 +303,7 @@ void MemChecks::Add(TMemCheck memory_check, bool update)
m_mem_checks.emplace_back(std::move(memory_check)); m_mem_checks.emplace_back(std::move(memory_check));
} }
if (update) return DelayedMemCheckUpdate(this, true);
Update();
} }
bool MemChecks::ToggleEnable(u32 address) bool MemChecks::ToggleEnable(u32 address)
@ -319,20 +317,17 @@ bool MemChecks::ToggleEnable(u32 address)
return true; return true;
} }
bool MemChecks::Remove(u32 address, bool update) DelayedMemCheckUpdate MemChecks::Remove(u32 address)
{ {
const auto iter = std::ranges::find(m_mem_checks, address, &TMemCheck::start_address); const auto iter = std::ranges::find(m_mem_checks, address, &TMemCheck::start_address);
if (iter == m_mem_checks.cend()) if (iter == m_mem_checks.cend())
return false; return DelayedMemCheckUpdate(this, false);
const Core::CPUThreadGuard guard(m_system); const Core::CPUThreadGuard guard(m_system);
m_mem_checks.erase(iter); m_mem_checks.erase(iter);
if (update) return DelayedMemCheckUpdate(this, true);
Update();
return true;
} }
void MemChecks::Clear() void MemChecks::Clear()

View File

@ -97,6 +97,8 @@ private:
Core::System& m_system; Core::System& m_system;
}; };
class DelayedMemCheckUpdate;
// Memory breakpoints // Memory breakpoints
class MemChecks class MemChecks
{ {
@ -115,13 +117,13 @@ public:
TMemChecksStr GetStrings() const; TMemChecksStr GetStrings() const;
void AddFromStrings(const TMemChecksStr& mc_strings); void AddFromStrings(const TMemChecksStr& mc_strings);
void Add(TMemCheck memory_check, bool update = true); DelayedMemCheckUpdate Add(TMemCheck memory_check);
bool ToggleEnable(u32 address); bool ToggleEnable(u32 address);
TMemCheck* GetMemCheck(u32 address, size_t size = 1); TMemCheck* GetMemCheck(u32 address, size_t size = 1);
bool OverlapsMemcheck(u32 address, u32 length) const; bool OverlapsMemcheck(u32 address, u32 length) const;
bool Remove(u32 address, bool update = true); DelayedMemCheckUpdate Remove(u32 address);
void Update(); void Update();
void Clear(); void Clear();
@ -132,3 +134,39 @@ private:
Core::System& m_system; Core::System& m_system;
bool m_mem_breakpoints_set = false; bool m_mem_breakpoints_set = false;
}; };
class DelayedMemCheckUpdate final
{
public:
DelayedMemCheckUpdate(MemChecks* memchecks, bool update_needed = false)
: m_memchecks(memchecks), m_update_needed(update_needed)
{
}
DelayedMemCheckUpdate(const DelayedMemCheckUpdate&) = delete;
DelayedMemCheckUpdate(DelayedMemCheckUpdate&& other) = delete;
DelayedMemCheckUpdate& operator=(const DelayedMemCheckUpdate&) = delete;
DelayedMemCheckUpdate& operator=(DelayedMemCheckUpdate&& other) = delete;
~DelayedMemCheckUpdate()
{
if (m_update_needed)
m_memchecks->Update();
}
DelayedMemCheckUpdate& operator|=(DelayedMemCheckUpdate&& other)
{
if (m_memchecks == other.m_memchecks)
{
m_update_needed |= other.m_update_needed;
other.m_update_needed = false;
}
return *this;
}
operator bool() const { return m_update_needed; }
private:
MemChecks* m_memchecks;
bool m_update_needed;
};

View File

@ -172,12 +172,12 @@ static void RemoveBreakpoint(BreakpointType type, u32 addr, u32 len)
else else
{ {
auto& memchecks = Core::System::GetInstance().GetPowerPC().GetMemChecks(); auto& memchecks = Core::System::GetInstance().GetPowerPC().GetMemChecks();
DelayedMemCheckUpdate delayed_update(&memchecks);
while (memchecks.GetMemCheck(addr, len) != nullptr) while (memchecks.GetMemCheck(addr, len) != nullptr)
{ {
memchecks.Remove(addr, false); delayed_update |= memchecks.Remove(addr);
INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr); INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr);
} }
memchecks.Update();
} }
Host_PPCBreakpointsChanged(); Host_PPCBreakpointsChanged();
} }

View File

@ -1010,6 +1010,7 @@ void MemoryViewWidget::ToggleBreakpoint(u32 addr, bool row)
{ {
const Core::CPUThreadGuard guard(m_system); const Core::CPUThreadGuard guard(m_system);
DelayedMemCheckUpdate delayed_update(&memchecks);
for (int i = 0; i < breaks; i++) for (int i = 0; i < breaks; i++)
{ {
@ -1028,16 +1029,14 @@ void MemoryViewWidget::ToggleBreakpoint(u32 addr, bool row)
check.log_on_hit = m_do_log; check.log_on_hit = m_do_log;
check.break_on_hit = true; check.break_on_hit = true;
memchecks.Add(std::move(check), false); delayed_update |= memchecks.Add(std::move(check));
} }
else if (check_ptr != nullptr) else if (check_ptr != nullptr)
{ {
// Using the pointer fixes misaligned breakpoints (0x11 breakpoint in 0x10 aligned view). // Using the pointer fixes misaligned breakpoints (0x11 breakpoint in 0x10 aligned view).
memchecks.Remove(check_ptr->start_address, false); delayed_update |= memchecks.Remove(check_ptr->start_address);
} }
} }
memchecks.Update();
} }
emit Host::GetInstance()->PPCBreakpointsChanged(); emit Host::GetInstance()->PPCBreakpointsChanged();