Debug Adapter Protocol (DAP)

Debug Adapter Protocol (DAP)

A wire format. JSON over stdio (or TCP). Defines messages a generic debugger frontend sends to a generic debugger backend.

Designed by Microsoft. Same idea as LSP but for debuggers instead of language servers. The point: an editor doesn't have to integrate with each debugger separately. It speaks DAP; the debugger ships an adapter that speaks DAP.

What DAP is

What DAP is NOT

Layer position

Frontend (lazydap, VS Code) ── DAP ──> Adapter (codelldb, debugpy) ── ... ──> Debuggee

DAP sits between the frontend and the adapter. Above it: UI concerns. Below it: real debugging via DAP Adapter → real debugger → ptrace / runtime hooks.

Concrete example

// Frontend → adapter
{ "seq": 1, "type": "request", "command": "setBreakpoints",
  "arguments": { "source": {"path": "main.c"}, "breakpoints": [{"line": 42}] } }

// Adapter → frontend
{ "seq": 2, "type": "response", "request_seq": 1, "command": "setBreakpoints",
  "success": true, "body": { "breakpoints": [{"verified": true, "line": 42, "id": 1}] } }

// Adapter → frontend (asynchronous event)
{ "seq": 3, "type": "event", "event": "stopped",
  "body": { "threadId": 1, "reason": "breakpoint", "hitBreakpointIds": [1] } }

That's three messages. The first two are request/response (correlated by request_seq). The third is an event — push, no client request triggered it.

Why DAP exists

Pre-DAP: every editor wrote custom integration with every debugger. VS Code with GDB, VS Code with LLDB, Vim with GDB, Vim with LLDB, etc — N×M problem.

Post-DAP: write one DAP client (your editor) and one DAP adapter per debugger. N+M problem. Same architectural insight as LSP.

DAP's blind spot

DAP assumes one IDE-style client per session. Doesn't natively support multi-client subscription, agent-friendly synchronous wrappers, or shell-style scripting. That's the gap Lazydap fills with its own protocol layered on top.

See also