dbx_control
Tool
tools/dos/dbx_control.py(program, 16-bit DOS). Drive DOSBox-X's built-in debugger from a script, through its debugger control channel.
Run it with ./gameframe run dbx_control ARGS or python3 tools/dos/dbx_control.py. Source on GitHub.
Its own help
This is the help text in the tool itself, as ./gameframe tool dbx_control prints it.
text
Drive DOSBox-X's built-in debugger from a script, through its debugger control channel.
DOSBox-X (2026.10 and later, built with the debugger) connects to 127.0.0.1:<mcp_server> when
the [dosbox] setting mcp_server is set, and accepts one debugger command at a time over a
line-based text protocol (README.debugger in DOSBox-X). The agent-facing side of the same
channel is the dosbox-x-mcp-server program (registered in .mcp.json as "dosbox"); this module
is the script-facing side, for repeatable ground-truth runs and tests.
from dbx_control import Debugger
with Debugger(port=0) as dbx: # listen first, on a free port...
dbx.launch([os.path.abspath('scripts/dosbox-run.sh'), '--break', '--mcp', str(dbx.port), GAME, 'GAME.EXE'])
dbx.wait_connected() # DOSBox-X connected
dbx.wait_break() # DEBUGBOX stopped at the first instruction
dbx.exec('BPINT 21 3D') # any debugger command; returns its output lines
dbx.run() # resume
regs = dbx.wait_break() # stopped again: registers (EV), one step taken
data = dbx.memdump('DS', 0x12DE, 4) # bytes, through MEMDUMPBIN
Debugger commands that draw into the debugger window (CPU, D) return no text: use EV for
registers and MEMDUMPBIN for memory (these helpers do).
Command line: dbx_control.py --port P [--timeout S] COMMAND ... waits for DOSBox-X to connect,
runs each debugger COMMAND (for example BREAK "EXEC CPU" "EXEC D 0040:0000"), prints the replies.
Addresses are what the running program uses: real-mode segments, or the DPMI host's selectors
for a protected-mode program, which are NOT Ghidra's 1000/1008 numbering. Find a segment's
selector with the debugger's LDT command, or match its bytes (see docs/DOS.md).
Use port=0 (a free port) for scripts and tests: a DOSBox-X left from another run, or another
session's, may still be trying to connect to a fixed port, and the listener would accept it.
close() ends the whole process group that launch() started.
Standard library only. It does not start DOSBox-X itself unless you call launch().Named by
Skills: re-setup, re-observe, re-emulate, re-verify.