Files
Henrik Rydgård 1e35f00965 wsdbg: add :snapshot/:snapshots/:diff for quick memory comparisons
New REPL-only commands, kept entirely client-side (no new PPSSPP-side
event) since a snapshot is a debugging-session-scoped concept with no
real emulator-side meaning - memory.read's existing base64 response is
already the only primitive actually needed:

- :snapshot <name> <address> <size> - blocks on a memory.read (unlike the
  rest of the REPL, which is fire-and-forget or just waits without
  looking at the payload) and stores the decoded bytes locally under
  <name>. address/size are passed through to the server exactly as
  typed, same as any other event param.
- :snapshots - list what's been captured so far.
- :diff <name1> <name2> - byte-compare two snapshots, printing each
  differing run as "+offset (N bytes): old_hex -> new_hex".

Replaces the throwaway PowerShell/Bash diffing scripts written by hand at
least twice during the VSH boot investigation (see
docs/VSHBootInvestigation.md - the sceBSMan before/after test, and the GE
display list re-checks) with one correct, reusable implementation. In
memory only for now (lives as long as the wsdbg process does, which is
fine for the actual usage pattern - one piped batch of commands per
invocation, same as everything else in this tool); can add disk
persistence later if a real need for cross-invocation snapshots comes up.

Verified live against PPSSPPHeadless: snapshot/list/diff (both a
real detected difference and an identical-buffer comparison) all produce
correct output.
2026-08-14 11:04:32 +02:00
..

wsdbg - WebSocket debugger CLI

A small standalone client for talking directly to PPSSPP's WebSocket debugger interface (see docs/WebSocketDebugger.md in the root of the repo for the full protocol reference and event catalog).

To install Rust and cargo, go here.

To run, with rust installed, change to this Tools/wsdbg directory, then:

cargo run -- <port>

(Or build once with cargo build --release and run the binary directly from target/release/.)

Usage

Start PPSSPP with the remote debugger enabled (--debugger on the command line, or Settings > Tools > Developer Tools > Allow remote debugger) and note the port it's listening on (shown in that same settings screen, and logged at startup).

Interactive REPL - type an event name and key=value params, get responses and broadcasts (log messages, stepping notifications, etc.) printed as they arrive:

cargo run -- 12345
> game.status
-> (ticket 2) {"event":"game.status","ticket":2}

<- {
  "event": "game.status",
  "game": null,
  "paused": false
}

One-shot mode - send a single event and exit after a short wait, handy for scripting:

cargo run -- 12345 gpu.stats.get
cargo run -- 12345 cpu.setReg thread=0 name=4 value=1000
cargo run -- 12345 --raw '{"event":"cpu.evaluate","expression":"pc"}'

Type :help in the REPL for a quick reminder, :quit to disconnect.

Scripting a multi-step sequence

Piping several commands into the REPL ((echo cmd1; echo cmd2; ...) | wsdbg PORT) sends them all immediately by default - nothing waits for a response before moving to the next line, so scripts traditionally needed sleep N between commands to guess how long each one takes. Pass --sync to remove the guessing: each line blocks until its own response arrives (matched by ticket) before the next line is read, and for cpu.resume/cpu.stepInto/cpu.stepOver/cpu.stepOut/ cpu.runUntil/cpu.nextHLE it also waits for the following cpu.stepping broadcast - the actual "the CPU stopped again" signal those commands imply. Everything still prints as it arrives; this only changes when the next line gets sent. A breakpoint that never trips would otherwise hang the script forever, so it gives up after --sync-timeout seconds (default 30) and moves on.

(
  echo 'cpu.breakpoint.add address=134348800 enabled=true'
  echo 'cpu.resume'
  echo 'cpu.getAllRegs'
) | cargo run -- 12345 --sync