Skip to content

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.

Code: Apache 2.0. Content: CC0 1.0. No game material: bring your own copy.