Skip to content

feat(gdb): add typed PS2 EE Workbench attach and PC preview - #29

Merged
Krilliac merged 9 commits into
mainfrom
claude/gdb-current-pc-preview
Jul 21, 2026
Merged

feat(gdb): add typed PS2 EE Workbench attach and PC preview#29
Krilliac merged 9 commits into
mainfrom
claude/gdb-current-pc-preview

Conversation

@Krilliac

Copy link
Copy Markdown
Owner

Summary

  • add a bounded read-only GNU RSP client and Workbench attach lifecycle
  • require exact typed PS2 EE target descriptions before register access
  • add an explicit capacity-one current-PC read whose raw packet remains worker-local
  • keep the observed PC out of logs and the companion console; only the scrubbed UI scalar displays it

Safety and privacy

  • read-only route: no memory/register writes or execution-control expansion
  • exact PS2 EE schema and register-layout validation
  • cancellation, disconnect, worker-loss, and session-replacement scrubbing
  • no endpoint addresses, guest values, raw packets, or proprietary inputs in repository artifacts

Verification

  • independent immutable source audit: ACCEPT
  • git diff --check origin/main...HEAD
  • cargo fmt --all -- --check
  • all eight commits carry matching DCO Signed-off-by trailers

The host is under a RAM safety stop, so Cargo build/test was intentionally left to CI.

Krilliac and others added 9 commits July 21, 2026 02:55
Signed-off-by: Krill <natew94@gmail.com>
Signed-off-by: Krill <natew94@gmail.com>
Signed-off-by: Krill <natew94@gmail.com>
Signed-off-by: Krill <natew94@gmail.com>
Signed-off-by: Krill <natew94@gmail.com>
Add one explicit, capacity-one, read-only "Read current EE PC" operation to
the outbound RSP session. It is offered only when the connected target matched
the exact canonical 109-register, 708-byte PS2 EE schema.

The schema is enforced twice: the egui-side route gate refuses submission, and
the remote-I/O worker re-derives the same decision from its own retained target
description before touching the socket. Both enforcement points resolve
"canonical EE schema" through one shared comparison so they cannot drift.

The worker reads `g`, validates the length against the connected description,
re-checks the exact canonical length, parses with the protocol crate's
ps2_ee_gpacket_to_registers, and sends only the typed u32 program counter over
the worker/UI channel. The raw packet and every other decoded register --
including the EE's 128-bit GPR, HI, and LO state -- stay worker-local and are
dropped there. The UI renders a fixed-width 0xXXXXXXXX literal.

This route is a strict narrowing of the existing read-register route: it issues
the same `g` read and adds no capability. Routing policy is unchanged -- no
polling, execution control, memory or instruction reads, disassembly,
breakpoints, writes, export, persistence, or evidence publication.

Scrubbing follows the existing session lifecycle: the preview clears on a
connection attempt, disconnect, cancellation, worker or connection loss, and
session replacement. Result staleness is factored into a pure classify_event so
a completion that lost its race with socket shutdown, or one belonging to an
already-cancelled request, never reaches presentation state.

Tests cover canonical extraction against a literal packet offset, near-schema
and foreign-target rejection, near-length packet rejection, the controller
route gate, fixed-width formatting, lifecycle scrubbing, and stale/cancelled
dispositions.

Signed-off-by: Krill <natew94@gmail.com>
Record the new capacity-one, read-only EE program-counter operation: its
exact-schema-only availability, the two enforcement points, the worker-local
parse that lets only the typed u32 cross the channel, the fixed-width display,
and the scrub and staleness rules it inherits.

Also narrow the deferred-work item so the single typed read is not mistaken
for general typed register decoding, polling, instruction reads, or
disassembly.

Signed-off-by: Krill <natew94@gmail.com>
The typed EE current-PC read retained the observed value in one place it could
never be scrubbed. On success the controller built a notice embedding the
formatted program counter, and Workbench forwards every remote notice into its
activity log and, when attached, on to the companion console process. That log
only appends and evicts its oldest entry at capacity, so it has no scrub at all,
and the console is a separate process the session cannot reach. A value the
route promises to drop on a connection attempt, disconnect, cancellation, worker
or connection loss, and session replacement therefore outlived every one of
them, and stayed attributable to an endpoint after that connection was gone.

Make the success notice value-free. The completed read is still announced, but
with a constant message identical for every observed program counter, so the
log-facing payload encodes nothing about the value. The program counter now
exists only as the typed u32 scalar in RemoteSessionView, which the existing
clear_observations and clear_session scrubs own, and is rendered only by the
session panel's explicit "Current EE PC" property row.

The transition is extracted into a pure apply_program_counter so the retention
invariant is unit-testable without a controller or a worker thread. The
regression test applies the outcome across the 32-bit range and asserts that the
whole log-facing payload -- level and message -- is identical for every value
and carries no fixed-width literal, bare hexadecimal, decimal rendering, or hex
prefix, while the view still stores the typed scalar and still answers to the
scrub.

The docs claimed the value was ephemeral UI state on the same terms as every
other observation, which was untrue while the notice carried it. They now state
that the property row is the value's only presentation and that the notice is
deliberately value-free.

No route, capability, schema gate, decode path, or worker/UI channel payload
changes.

Signed-off-by: Krill <natew94@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Krill <natew94@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7a548c4168

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// Propagates I/O errors.
pub fn query_supported(&mut self) -> io::Result<Vec<u8>> {
self.transact(b"qSupported:multiprocess+;swbreak+")
let reply = self.transact(b"qSupported:multiprocess+;swbreak+;qXfer:features:read+")?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Request XML register descriptions during negotiation

This sends qXfer:features:read+ as if it were a client feature, but the target-description negotiation that many stubs key off is the client xmlRegisters=... gdbfeature; qXfer:features:read+ is the stub feature returned in the response. With stubs that only advertise/serve target XML after seeing xmlRegisters (the same handshake GDB uses), Workbench reaches require_target_description and fails attach even though the target can provide the XML schema.

Useful? React with 👍 / 👎.

self.view.last_error = None;
notices.push(RemoteSessionNotice {
level: RemoteNoticeLevel::Success,
message: format!("Read {} remote byte(s) at {address:#x}", bytes.len()),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep guest addresses out of remote notices

When a memory read succeeds, this notice includes the guest address; WorkbenchApp::poll_remote_session forwards notices to self.log, which appends them to the activity ring and companion console. Unlike view.memory_summary, those log entries are not scrubbed on disconnect, cancellation, or connection loss, so reading a proprietary guest location leaves the address attributable after the remote session is cleared.

Useful? React with 👍 / 👎.

@Krilliac
Krilliac merged commit 63a48d8 into main Jul 21, 2026
15 checks passed
@Krilliac
Krilliac deleted the claude/gdb-current-pc-preview branch July 21, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant