From b022f6fb9e84f1c7d6ed998257d68c8a06afb956 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Tue, 27 Jan 2026 14:55:53 -0700 Subject: [PATCH] Switch to lokkju/dosbox-x-remotedebug fork for working GDB server - Use remotedebug branch which adds GDB/QMP server support - Build with --enable-remotedebug configure flag - Add proper GDB handshake (qSupported) to gdb_client.py - Support no-ack mode for faster communication - Expose QMP port 4444 in addition to GDB port 1234 The GDB server is configured via [dosbox] section: gdbserver = true gdbserver port = 1234 qmpserver = true qmpserver port = 4444 Tested features: register read, memory read, breakpoints --- Dockerfile | 34 +++++++++++++++++++++------------- docker-compose.yml | 9 +++++---- src/dosbox_mcp/gdb_client.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7e72af5..5c9a368 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,18 +29,21 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ && rm -rf /var/lib/apt/lists/* -# Clone DOSBox-X (main repo - check for GDB support) -# Note: If hezi/dosbox-x-gdb is stale, main DOSBox-X may have debugger support +# Clone DOSBox-X with remote debugging support (GDB server + QMP) +# This fork adds --enable-remotedebug which compiles in gdbserver.cpp and qmp.cpp +# See: https://github.com/joncampbell123/dosbox-x/issues/752 WORKDIR /build -RUN git clone --depth 1 https://github.com/joncampbell123/dosbox-x.git +RUN git clone --branch remotedebug --depth 1 https://github.com/lokkju/dosbox-x-remotedebug.git dosbox-x WORKDIR /build/dosbox-x -# Configure and build -# DOSBox-X has built-in debugger that can be enabled +# Configure and build with GDB server support +# --enable-remotedebug: Enables C_REMOTEDEBUG flag for GDB/QMP servers +# --enable-debug: Enables internal debugger (Alt+Pause) RUN ./autogen.sh && \ ./configure \ --prefix=/opt/dosbox-x \ + --enable-remotedebug \ --enable-debug \ --enable-sdl2 \ --disable-printer \ @@ -65,6 +68,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libavformat59 \ libavutil57 \ libswscale6 \ + libgl1 \ + libx11-6 \ + libncurses6 \ + libxkbcommon0 \ + libxrandr2 \ + libxi6 \ && rm -rf /var/lib/apt/lists/* # Copy DOSBox-X from builder @@ -76,7 +85,8 @@ RUN ln -s /opt/dosbox-x/bin/dosbox-x /usr/local/bin/dosbox-x # Create directories for config and DOS files RUN mkdir -p /config /dos -# Default configuration with GDB stub enabled +# Default configuration for DOSBox-X +# GDB server is enabled via --enable-remotedebug at compile time RUN cat > /config/dosbox.conf << 'EOF' [sdl] fullscreen=false @@ -91,11 +101,6 @@ cycles=auto [dosbox] memsize=16 -[debugger] -# Enable GDB server stub -gdbserver=true -gdbport=1234 - [serial] serial1=disabled serial2=disabled @@ -106,8 +111,10 @@ MOUNT C /dos C: EOF -# Expose GDB port -EXPOSE 1234 +# Expose ports: +# - 1234: GDB server (standard GDB remote protocol) +# - 4444: QMP server (QEMU Machine Protocol for control) +EXPOSE 1234 4444 # Set working directory WORKDIR /dos @@ -116,5 +123,6 @@ WORKDIR /dos ENV DISPLAY=:0 # Entry point +# Note: GDB/QMP servers are enabled via config file [dosbox] section ENTRYPOINT ["dosbox-x", "-conf", "/config/dosbox.conf"] CMD [] diff --git a/docker-compose.yml b/docker-compose.yml index 81cf62e..d46ee20 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,10 +16,10 @@ services: dockerfile: Dockerfile container_name: dosbox-mcp - # Ports + # Ports (remotedebug fork exposes these when built with --enable-remotedebug) ports: - - "${GDB_PORT:-1234}:1234" # GDB stub - - "${SERIAL_PORT:-5555}:5555" # Serial (optional) + - "${GDB_PORT:-1234}:1234" # GDB server (standard GDB remote protocol) + - "${QMP_PORT:-4444}:4444" # QMP server (QEMU Machine Protocol) # X11 forwarding for display environment: @@ -74,7 +74,8 @@ services: - headless ports: - - "${GDB_PORT_HEADLESS:-1235}:1234" + - "${GDB_PORT_HEADLESS:-1235}:1234" # GDB server + - "${QMP_PORT_HEADLESS:-4445}:4444" # QMP server environment: # Use virtual framebuffer for headless diff --git a/src/dosbox_mcp/gdb_client.py b/src/dosbox_mcp/gdb_client.py index 8468476..4fd75ad 100644 --- a/src/dosbox_mcp/gdb_client.py +++ b/src/dosbox_mcp/gdb_client.py @@ -120,10 +120,43 @@ class GDBClient: finally: self._socket.settimeout(self.timeout) + # Perform GDB protocol handshake (required by some stubs) + self._handshake() + except OSError as e: self._connected = False raise GDBError(f"Failed to connect to {host}:{port}: {e}") from e + def _handshake(self) -> None: + """Perform GDB protocol handshake. + + Some GDB stubs (like lokkju/dosbox-x-remotedebug) require qSupported + as the first packet to establish the session. + """ + try: + # Send qSupported to establish capabilities + features = "qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+" + response = self._command(features) + logger.debug(f"qSupported response: {response}") + + # Parse supported features + if response: + supported = response.split(';') + logger.info(f"GDB stub supports: {supported[:5]}...") # First 5 + + # Enable no-ack mode if supported (faster communication) + if "QStartNoAckMode+" in supported: + try: + ack_response = self._command("QStartNoAckMode") + if ack_response == "OK": + logger.info("No-ack mode enabled") + except GDBError: + pass # Not critical + + except GDBError as e: + # Handshake failure - stub may not support qSupported + logger.warning(f"Handshake failed (may be normal): {e}") + def disconnect(self) -> None: """Disconnect from GDB stub.""" if self._socket: