Debugger: track hit counts on address breakpoints, expose via cpu.breakpoint.list

BreakPoint (cpu.breakpoint.*) had no hit-count tracking at all, unlike
MemCheck (memory.breakpoint.*), which already tracks numHits. This made it
genuinely hard to tell "this breakpoint is never being reached" apart from
"it's being reached but I'm not seeing the log/pause where I'm looking" -
directly informed by repeatedly hitting exactly that ambiguity while
debugging the VSH boot path this session (see docs/VSHBootInvestigation.md).

Added BreakPoint::numHits, incremented in BreakpointManager::ExecBreakPoint()
whenever a breakpoint's address is hit and any condition passes (matching
MemCheck::Apply()'s existing semantics - counts real triggers, not just
"execution passed through here"). Exposed as a new "hits" field in
cpu.breakpoint.list's response.

Verified live via PPSSPPHeadless + wsdbg: hits reads 0 before the CPU
resumes, 1 after the breakpoint fires once. UnitTest.exe all: 49/49 passed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
This commit is contained in:
Henrik Rydgård
2026-08-14 11:04:32 +02:00
co-authored by Claude Sonnet 5
parent 4389f706b9
commit 3edea91c8e
3 changed files with 12 additions and 1 deletions
@@ -247,6 +247,9 @@ void WebSocketCPUBreakpointRemove(DebuggerRequest &req) {
// - logFormat: null, or string to log when breakpoint trips, may include {expression} parts.
// - symbol: null, or string label or symbol at breakpoint address.
// - code: string disassembly of breakpoint address.
// - hits: unsigned integer, how many times this breakpoint's address has been reached
// (and any condition passed) since it was added - useful for confirming a breakpoint is
// actually being reached at all, independently of whether log/enabled is set.
void WebSocketCPUBreakpointList(DebuggerRequest &req) {
if (!currentDebugMIPS->isAlive()) {
return req.Fail("CPU not started");
@@ -266,6 +269,7 @@ void WebSocketCPUBreakpointList(DebuggerRequest &req) {
json.writeUint("address", bp.addr);
json.writeBool("enabled", bp.IsEnabled());
json.writeBool("log", (bp.result & BREAK_ACTION_LOG) != 0);
json.writeUint("hits", bp.numHits);
if (bp.hasCond)
json.writeString("condition", bp.cond.expressionString);
else