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):


3. In-Editor Breakpoint Synchronization & Navigation

  1. Open any Crystal source file (e.g. src/player.cr) in Godot's Script Editor.
  2. Click the gutter next to any line number to set a red breakpoint marker.
  3. Godot's EditorDebuggerPlugin._breakpoint_set_in_tree intercepts the event, translates res:// paths to absolute filesystem paths, and pushes breakpoint set --file <file> --line <line> to all active LLDB sessions.
  4. 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:

  1. Target Process Boundary: When working inside the editor (e.g. custom docks, inspectors, editor gizmos, or _process running 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's EditorDebuggerPlugin only opens debug sessions when you launch game scenes.

  2. 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.

Defined in:

libgodot/docs.cr

Class Method Summary

Class Method Detail

def self.features : Array(String) #

[View source]