# DAP Remote Debugging Example A minimal example showing how to debug a C++ program running in a **remote** container from any DAP-compatible client — Neovim, VSCode, Emacs, and others. ``` ┌──────────────────────┐ ┌──────────────────────┐ │ YOUR EDITOR │ DAP over TCP │ REMOTE │ │ (Neovim, VSCode,…) │ ◀──────────────────── ▶│ (Alpine container) │ │ │ port 13000 │ │ │ • source code │ │ • codelldb DAP │ │ • breakpoints │ │ server │ │ • variable inspection │ │ • debugapp (C++17) │ │ │ │ • socat forwarder │ └──────────────────────┘ └──────────────────────┘ ``` The remote container runs [codelldb](https://github.com/vadimcn/codelldb) as a DAP (Debug Adapter Protocol) server. Your editor connects to it over TCP, sends a `launch` request, and codelldb starts the program **on the remote**. This avoids gdbserver's entry-point assembly issue entirely and keeps source paths clean. ## Quick start (full setup) The included `docker-compose.yml` spins up both the remote container and a Neovim-based devstation: ```bash docker compose build docker compose up -d remote # start the codelldb DAP server docker compose run --rm devstation # interactive Neovim session ``` Inside Neovim, open `src/calculator.cpp`, press `db` on a line to set a breakpoint, then `dc` and select **"Remote launch (codelldb remote:13000)"**. See **[devstation/README.md](devstation/README.md)** for the full Neovim keybinding reference. ## Using your own editor You don't need the devstation container. Build and run the remote alone, then connect from whatever editor you prefer: ```bash docker build -t dap-debug-remote -f remote/Dockerfile . docker run -d --name remote \ -p 13000:13000 \ --cap-add SYS_PTRACE \ --security-opt seccomp=unconfined \ dap-debug-remote ``` Then follow the guide for your editor in **[remote/README.md](remote/README.md)** — it covers VSCode, Neovim, Emacs, and generic DAP clients. ## Repository layout ``` . ├── docker-compose.yml # Two-service compose (remote + devstation) ├── README.md # This file │ ├── common/ │ └── project/ # C++ demo project (shared by both containers) │ ├── CMakeLists.txt │ └── src/ │ ├── remote/ │ ├── Dockerfile # Alpine + codelldb + socat + project build │ ├── entrypoint.sh # codelldb DAP server + socat forwarder loop │ └── README.md # Standalone usage + VSCode/other editor guides │ └── devstation/ ├── Dockerfile # Alpine + Neovim (LazyVim) + nvim-dap ├── README.md # Neovim keybindings and setup details ├── nvim-config/ │ └── lua/plugins/ # LazyVim plugin specs (theme, lsp, dap) └── scripts/ └── precompile-treesitter.lua ``` ## How it works 1. **codelldb** runs on the remote as a DAP server (`--port 13001 --multi-session`). It binds to `127.0.0.1` only, so **socat** forwards external connections from `0.0.0.0:13000` to codelldb's listener. 2. Your editor connects to port 13000 and sends a standard DAP `launch` request. codelldb starts the program on the remote, captures stdout/stderr, and streams output events back. 3. The project source lives at `/project` on the remote (and on the devstation if you use it), so debug-info paths match and editors open source files correctly when stopped at a breakpoint. 4. The remote entrypoint restarts codelldb after each session, so you can reconnect without restarting the container. 5. `SYS_PTRACE` + `seccomp:unconfined` on the remote allow codelldb to debug the child process. > **Note:** codelldb is a glibc binary but runs on Alpine (musl) via `gcompat` > plus a tiny shim library providing the missing `__res_init` symbol.