5.9 KiB
SharpEmu.DebugClient
A small, standalone command-line client that connects to the SharpEmu
emulator's live debug server and drives it interactively. It ships as its
own executable (SharpEmu.DebugClient) and takes no dependency on the emulator
assemblies — it speaks the server's line-delimited JSON protocol directly over
TCP, so you can also drive the server from nc, a script, or your own tool.
Status: infrastructure. The transport, protocol, session model, and breakpoint store are in place. Stops are delivered at frame boundaries (process entry and each module initializer); per-instruction stepping and data watchpoints are part of the surface and become live as the CPU backend grows the corresponding hooks. See
docs/debugger-server.mdfor the architecture and protocol reference.
How it fits together
+-------------------------+ TCP (JSON lines) +----------------------+
| SharpEmu (emulator) | <------------------------------> | SharpEmu.DebugClient |
| --debug-server | | (this executable) |
| | | |
| DebuggerServerHost | | REPL / --exec |
| +- DebuggerServer | frame boundaries via ICpuDebugHook| |
| +- DebuggerSession <-+------ CPU dispatcher ------------ | |
+-------------------------+ +----------------------+
The emulator is the server; this client is a separate process that connects to it and issues commands. The two never share memory — everything crosses the socket as JSON.
Building
dotnet build src/SharpEmu.DebugClient/SharpEmu.DebugClient.csproj
Quick start
-
Launch the emulator with the debug server enabled. It listens on
127.0.0.1:5714by default and, with stop-at-entry on, parks the guest at its first frame until you continue:SharpEmu --debug-server "/path/to/game/eboot.bin" # or choose an endpoint: SharpEmu --debug-server=127.0.0.1:5714 "/path/to/game/eboot.bin" -
In another terminal, attach the client:
SharpEmu.DebugClient # defaults to 127.0.0.1:5714 SharpEmu.DebugClient 127.0.0.1:5714 # explicit endpoint -
Drive the target:
status regs break 0x00000008801234a0 continue mem 0x00000008802000000 64
Invocation
SharpEmu.DebugClient [host:port] [--exec "<command>"]... [--quiet]
| Option | Meaning |
|---|---|
host:port |
Server endpoint. Default 127.0.0.1:5714. localhost is fine. |
--exec, -e |
Run one command non-interactively, then exit. Repeatable. |
--quiet |
Suppress the connection banner. |
--help, -h |
Show usage and the command list. |
Non-interactive example (scriptable):
SharpEmu.DebugClient --exec "break 0x8801234a0" --exec "continue"
Commands
Addresses and values accept decimal or 0x-prefixed hex. Register and memory
commands only succeed while the target is paused.
| Command | Server verb | Description |
|---|---|---|
status | info |
status |
Target state plus the last stop. |
state |
state |
Run state only (Running/Paused/…). |
regs | registers |
registers |
Dump the integer registers. |
setreg <reg> <value> |
set-register |
Set rip, rflags, or a GP register. |
mem <addr> <len> | read <addr> <len> |
read-memory |
Read guest memory as hex. |
write <addr> <hex> |
write-memory |
Write guest memory from a hex string. |
break <addr> [kind] [len] | b … |
add-breakpoint |
Add a breakpoint. kind: execute (default), readwatch, writewatch, accesswatch. |
bp | breakpoints |
list-breakpoints |
List breakpoints. |
del <id> | rm <id> |
remove-breakpoint |
Remove a breakpoint. |
enable <id> / disable <id> |
enable-breakpoint |
Toggle a breakpoint. |
continue | c |
continue |
Resume a paused target. |
step | s |
step |
Resume and stop at the next frame boundary. |
pause |
pause |
Ask a running target to stop at the next boundary. |
ping |
ping |
Round-trip liveness check. |
raw <json> |
(passthrough) | Send a literal JSON request. |
help | ? |
— | Show the command list (local). |
quit | exit |
— | Disconnect and exit (local). |
Output
The client prints two kinds of lines as they arrive:
reply>— the response to a command you sent (ok, plusdataorerror).event>— an unsolicited notification:helloon connect,stoppedwhen the target hits a breakpoint / entry / step / pause,resumedon continue, andterminatedwhen the run ends.
Because replies and events share one stream, the client prints everything it
receives rather than pairing replies to requests — a stopped event may arrive
between your command and its reply.
Protocol (for building your own client)
One JSON object per line, UTF-8, \n-terminated, in both directions.
Request:
{"command":"read-memory","address":"0x8802000000","length":64}
Reply:
{"ok":true,"command":"read-memory","data":{"address":"0x0000000880200000","length":64,"bytes":"48894C24.."}}
Event:
{"event":"stopped","reason":"Breakpoint","address":"0x00000008801234A0","frameKind":"ProcessEntry","frameLabel":"eboot.bin","registers":{ ... }}
The full verb list and payload fields live in
docs/debugger-server.md.