Godot Debugger Architecture: How Debug Adapters Work with the Debug Adapter Protocol
Godot's debugger implements the Debug Adapter Protocol (DAP) through a three-layer TCP server architecture that translates IDE requests into engine debugger commands without duplicating debugging logic.
The godotengine/godot repository provides a complete DAP implementation that allows any compatible IDE to debug GDScript and C# projects. This architecture separates network handling, protocol parsing, and message generation into distinct components that interface with Godot's core debugger systems.
Core Components of the Godot Debug Adapter
The implementation resides in editor/debugger/debug_adapter/ and consists of three primary classes that form an event-driven pipeline.
DebugAdapterServer: TCP Socket Management
DebugAdapterServer (defined in editor/debugger/debug_adapter/debug_adapter_server.cpp) manages the TCP socket lifecycle. It listens on a configurable port—defaulting to 6006—and accepts incoming DAP client connections. The server reads the port from EditorSettings under network/debug_adapter/remote_port and supports command-line overrides via --debug-adapter-port handled in main/main.cpp at line 1975.
DebugAdapterProtocol: Request Processing Pipeline
DebugAdapterProtocol (in editor/debugger/debug_adapter/debug_adapter_protocol.cpp) serves as the translation layer. It parses incoming JSON messages using the Content-Length header protocol, dispatches requests to the appropriate handlers, and converts engine debugger events back into DAP-compliant responses. The class connects to Godot's internal signals such as breakpoint_toggled and stack_dump to receive notifications from the core debugger.
DebugAdapterParser: DAP Message Builders
DebugAdapterParser (declared in editor/debugger/debug_adapter/debug_adapter_parser.h and implemented in the corresponding .cpp file) contains the concrete implementations for building protocol messages. It provides methods like req_initialize, req_setBreakpoints, and ev_stopped_breakpoint that construct the specific JSON structures required by the DAP specification. This separation keeps protocol-specific formatting isolated from the core translation logic.
How the Debug Adapter Protocol Works in Godot
The DAP implementation follows a strict request-response cycle that bridges external IDEs with Godot's internal debugging systems.
Server Initialization
When the editor loads, DebuggerEditorPlugin (in editor/debugger/debugger_editor_plugin.cpp) instantiates DebugAdapterServer as an editor plugin. The server binds to the configured TCP port and begins listening for connections. This occurs automatically when the editor starts, requiring no manual intervention unless changing the default port.
Client Connection and Session Creation
When a DAP client (such as VS Code) connects, DebugAdapterProtocol::poll() accepts the connection through on_client_connected and creates a DAPeer session object. This peer maintains the connection state and message buffers for that specific debugging session.
Message Reception and Parsing
The peer reads raw bytes from the socket in DAPeer::handle_data (lines 46-78 in debug_adapter_protocol.cpp). It parses the DAP envelope format, which uses a Content-Length header followed by JSON content. Once a complete message is assembled, it passes to DebugAdapterProtocol::process_message.
Request Dispatch to Engine
process_message constructs the handler name by prefixing the DAP command with req_ and invokes the corresponding method on DebugAdapterParser using parser->callv(command, args). For example, a setBreakpoints request becomes req_setBreakpoints. This handler interacts with EditorDebuggerNode and the core debugger to perform actions like setting breakpoints via EditorDebuggerNode::get_default_debugger()->_set_breakpoint (lines 92-100).
Event Generation and Response
When the engine triggers debugging events (breakpoint hit, stack frame changes, output messages), DebugAdapterProtocol receives notifications through signal connections established in its constructor (lines 55-66). Handlers like on_debug_breakpoint_toggled translate engine data into DAP-compliant events using ev_stopped_breakpoint or similar methods from the parser. These events are queued for transmission.
Response Transmission
DAPeer::send_data formats the queued Dictionary objects into JSON payloads with proper Content-Length headers (lines 14-30) and writes them to the TCP socket. The DAP client receives the response and updates its debugging UI accordingly.
DAP Data Structures and Core Types
The protocol implementation defines specific data structures in editor/debugger/debug_adapter/debug_adapter_types.h that map directly to the DAP specification.
Source and Breakpoint Types
The Source struct holds file metadata including absolute paths and checksums (MD5 and SHA-256) computed by Source::compute_checksums (lines 67-84). This enables source verification between the IDE and the running project. Breakpoint and BreakpointLocation structs track line numbers, column positions, and verification states.
Stack and Variable Types
StackFrame represents individual frames in the call stack with associated Source references and line numbers. Variable handles value representation through parse_variant, which recursively creates nested variable references for complex Godot types like Vectors, Arrays, and Objects. Scope and Thread types complete the debugging context representation.
Integration with Godot's Core Debugger
The debug adapter acts as a thin façade over the core debugger located in core/debugger/. This separation ensures that the DAP implementation does not duplicate debugging logic but instead translates protocol commands into existing engine capabilities.
ScriptDebugger and RemoteDebugger Interfaces
The ScriptDebugger class (core/debugger/script_debugger.h) manages breakpoint states and execution control (pause, step, continue). RemoteDebugger (core/debugger/remote_debugger.h) provides the network bridge that the adapter uses to communicate with running game instances. When DebugAdapterParser::req_pause executes, it ultimately invokes ScriptDebugger::debug through EditorDebuggerNode.
EditorDebuggerNode Coordination
EditorDebuggerNode serves as the central hub in the editor. The adapter calls methods like EditorDebuggerNode::get_default_debugger()->_set_breakpoint (lines 92-100 in debug_adapter_protocol.cpp) to manipulate breakpoints. Stack dumps and variable inspections flow from the core debugger through EditorDebuggerNode to the adapter, which then formats them for DAP clients.
Configuring the Debug Adapter
Godot exposes DAP settings through editor settings and command-line arguments, allowing seamless integration with various development workflows.
Editor Settings and Network Configuration
The adapter reads configuration from EditorSettings under the network/debug_adapter/ category. The remote_port setting (default 6006) defines the TCP listening port. Additional settings include request timeouts and breakpoint synchronization options. These appear in the editor UI under Project Settings → Network → Debug Adapter.
Command-Line Overrides
Users can override the port when launching Godot from the terminal using the --debug-adapter-port flag. This sets the static DebugAdapterServer::port_override variable processed in main/main.cpp at line 1975. This is particularly useful for CI/CD pipelines or when running multiple Godot instances simultaneously.
VS Code Integration Example
To connect VS Code to Godot's DAP server, configure .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Godot Debug",
"type": "godot",
"request": "launch",
"project": "${workspaceFolder}",
"address": "127.0.0.1",
"port": 6006,
"launch_scene": "res://main.tscn",
"stop_on_start": true
}
]
}
The type: "godot" extension communicates with the running editor via the DAP implementation on the configured port.
Custom DAP Events from GDScript
Developers can emit custom debugging events from scripts that flow through the adapter to the IDE:
# GDScript running in the editor
RemoteDebugger.get_singleton().send_message("my_custom_event", ["payload"])
The adapter receives this in DebugAdapterProtocol::on_debug_data (lines 169-176) and emits it as ev_custom_data, allowing IDE extensions to handle application-specific debugging information.
Summary
Godot's debugger architecture implements the Debug Adapter Protocol through a clean three-layer design that separates networking, protocol translation, and message construction:
- DebugAdapterServer manages TCP connections and client sessions in
editor/debugger/debug_adapter/debug_adapter_server.cpp - DebugAdapterProtocol handles JSON parsing and request dispatch in
editor/debugger/debug_adapter/debug_adapter_protocol.cpp - DebugAdapterParser builds DAP-compliant messages in
editor/debugger/debug_adapter/debug_adapter_parser.h
The adapter acts as a thin façade over Godot's core debugger (core/debugger/script_debugger.h and remote_debugger.h), translating DAP requests into engine debugger calls without duplicating logic. Configuration occurs through editor settings or the --debug-adapter-port command-line option, enabling seamless integration with VS Code and other DAP-aware IDEs.
Frequently Asked Questions
What is the Debug Adapter Protocol in Godot?
The Debug Adapter Protocol (DAP) is an open standard that allows Godot to communicate with any compatible IDE using JSON messages over TCP. Godot's implementation in editor/debugger/debug_adapter/ translates DAP requests into the engine's internal debugger commands, enabling breakpoint management, stack inspection, and variable evaluation from external editors like VS Code without requiring IDE-specific plugins.
How do I configure the debug adapter port in Godot?
You can configure the port through the editor settings under Project Settings → Network → Debug Adapter by modifying the remote_port value (default 6006). Alternatively, launch Godot from the command line with the --debug-adapter-port flag to override the setting, which sets DebugAdapterServer::port_override as processed in main/main.cpp at line 1975. This is useful when running multiple Godot instances or integrating with automated testing pipelines.
What are the main components of Godot's debug adapter architecture?
The architecture consists of three primary components located in editor/debugger/debug_adapter/: DebugAdapterServer handles TCP socket connections and client lifecycle; DebugAdapterProtocol parses JSON requests and translates them into calls to the core debugger; and DebugAdapterParser constructs DAP-compliant response messages. These components interface with EditorDebuggerNode and the core debugger (core/debugger/script_debugger.h) to perform actual debugging operations without duplicating engine logic.
Can I send custom debug events from GDScript to the DAP client?
Yes, you can emit custom events using RemoteDebugger.get_singleton().send_message("event_name", [data]) from GDScript. The adapter receives these messages in DebugAdapterProtocol::on_debug_data (lines 169-176) and forwards them as ev_custom_data events to the DAP client. This allows IDE extensions to handle application-specific debugging information, such as custom profiling data or game state snapshots, alongside standard debugging features.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →