module
Docs::M_LLDB_NATIVE_DEBUGGING_GUIDE
Overview
=========================================================================== Guide M: Native LLDB In-Editor Debugging, Tool Scripts & Multiplayer Sessions
LibGodot integrates LLDB directly into the Godot Editor's native Debugger dock, enabling in-editor breakpoints, interactive command consoles, stack traces, multiplayer multi-session coordination, and guidance for debugging live tool scripts.
1. Prerequisite Tooling
Because Crystal's compiler is built directly on LLVM, LLDB natively parses
both Microsoft .pdb (Program Database) files on Windows and DWARF debug info
on Linux and macOS without external symbol converters.
| Platform | Package Manager | Installation Command |
|---|---|---|
| Windows | Scoop / WinGet | scoop install llvm or winget install LLVM.LLVM |
| Ubuntu / Debian | APT | sudo apt install lldb |
| Arch Linux | Pacman | sudo pacman -S lldb |
| macOS | Homebrew / Xcode | brew install llvm or xcode-select --install |
Verify installation from your terminal:
lldb --version
2. Native Debug Symbols & Compilation
When compiling in development mode (make all or pressing F5 in the editor),
Crystal emits full debug symbols (--debug):
- Windows: Produces
bin/game.pdb(Microsoft Program Database). LLDB reads this directly to map machine instructions to Crystal source files and line numbers. - Linux / macOS: Produces standard DWARF debug info embedded within
game.soorgame.dylib.
3. In-Editor Breakpoint Synchronization & Navigation
- Open any Crystal source file (e.g.
src/player.cr) in Godot's Script Editor. - Click the gutter next to any line number to set a red breakpoint marker.
- Godot's
EditorDebuggerPlugin._breakpoint_set_in_treeintercepts the event, translatesres://paths to absolute filesystem paths, and pushesbreakpoint set --file <file> --line <line>to all active LLDB sessions. - When execution hits the breakpoint, the Godot Script Editor automatically navigates to the file and line, highlighting the current execution frame.
| Control | Shortcut | Description |
|---|---|---|
| Continue | F5 |
Resumes process execution until the next breakpoint or signal. |
| Step Over | F10 |
Executes the current line without stepping inside function calls. |
| Step Into | F11 |
Steps into the method or function called on the current line. |
| Step Out | Shift + F11 |
Finishes executing the current function and returns to the caller. |
| Pause | — | Interrupts execution immediately via process interrupt. |
4. Multiplayer Multi-Session Coordination & Lockstep Break Mode
When running multiple game instances simultaneously in the Godot Editor (via Debug > Run Multiple Instances):
| Feature | Mechanic | Multiplayer Benefit |
|---|---|---|
| Per-Session Isolation | Each instance connects to its own independent LLDB controller bound to that child PID. | Prevents breakpoints or inspect commands in Client 1 from interfering with Server or Client 2. |
| Role Badging | Instances report their multiplayer role (Server, Client 1, etc.) on startup. |
Developers immediately know which debugger tab corresponds to which game window. |
| Lockstep Break Mode | When any peer hits a breakpoint, all other peers are cooperatively interrupted via process interrupt. |
Eliminates network heartbeat timeout disconnections and physics state desynchronization. |
5. Tool Scripts (@[Tool]) Debugging Architecture
Developers frequently ask: "If I set a breakpoint in a tool script, will it trigger?"
| Context | Will Breakpoint Trigger in Editor Tab? | Reason |
|---|---|---|
| Running Game Project (F5 / F6) | YES | The tool script runs inside the spawned child game process where LLDB is actively attached. |
| Live In-Editor Viewport / Inspector | NO | The script executes inside the parent Godot Editor process, not a child game process. |
Why In-Editor Execution Does Not Trigger in the In-Editor Tab:
-
Target Process Boundary: When working inside the editor (e.g. custom docks, inspectors, editor gizmos, or
_processrunning in the 2D/3D viewport), that code executes inside the host Godot Editor process itself (godot.exe), rather than in a child game process. Godot'sEditorDebuggerPluginonly opens debug sessions when you launch game scenes. -
The Host Deadlock Paradox (Native vs Interpreted Execution): Unlike GDScript, which runs in an interpreted virtual machine and can pause execution within its own bytecode loop, Crystal compiles to native machine code. Native breakpoints trigger OS-level interrupts (
SIGTRAP/int 3). Because the in-editor debugger tab and UI controls run on the Godot Editor's own GUI thread:- If the in-editor LLDB attached to the editor process itself, hitting a breakpoint would freeze the entire Godot Editor window.
- The editor would be unable to process mouse clicks or keyboard events, making it impossible to click Continue, Step, or view the call stack in the debugger panel!
6. How to Debug Live Tool Scripts with an External Debugger
If you need to step through a @[Tool] script executing inside the editor itself (such as a custom inspector plugin,
dock UI, or tool script logic running in the editor viewport), attach an external debugger to the Godot Editor process.
Option A: External Terminal LLDB
Launch the Godot Editor directly under LLDB in an independent terminal window:
lldb -- godot.exe --editor --path test
(lldb) breakpoint set -f tool_tester_2d.cr -l 42
(lldb) run
Or attach to an already-running editor instance by its Process ID:
lldb -p <godot_editor_pid>
Option B: VS Code with CodeLLDB Extension
Add a launch target to .vscode/launch.json in your project root:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Live Editor Tool Scripts",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/godot.exe",
"args": ["--editor", "--path", "${workspaceFolder}/test"],
"cwd": "${workspaceFolder}"
},
{
"name": "Attach to Godot Editor (PID)",
"type": "lldb",
"request": "attach",
"pid": "${command:pickProcess}"
}
]
}
In this workflow, the external VS Code or terminal window maintains control while the Godot Editor window is safely paused.
7. Interactive LLDB Console Commands Reference
Inside the in-editor Crystal LLDB tab console, you can enter native LLDB commands directly:
| Command | Description |
|---|---|
thread backtrace (or bt) |
Prints the entire call stack for the current thread. |
frame variable (or v) |
Displays all local variables in the current stack frame. |
expression <expr> (or p) |
Evaluates an arbitrary expression or inspects memory. |
breakpoint list |
Lists all active breakpoints and hit counts. |
process status |
Shows the current execution state, stop reason, and thread ID. |