cpp-debugger-cli

Debug and explore C and C++ runtime behavior through the cpp-debugger-cli JSON interface and Debug Adapter Protocol. Use whenever Codex needs to launch or attach to a native process, set breakpoints, pause or step execution, inspect threads and call stacks, read local variables, evaluate watch expressions, capture target output, send stdin, or diagnose a runtime failure with lldb-dap.

lin-weichen-taiwan/cpp-debugger-cli2 installsMITSynced Aug 26

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: cpp-debugger-cli
description: Debug and explore C and C++ runtime behavior through the cpp-debugger-cli JSON interface and Debug Adapter Protocol. Use whenever Codex needs to launch or attach to a native process, set breakpoints, pause or step execution, inspect threads and call stacks, read local variables, evaluate watch expressions, capture target output, send stdin, or diagnose a runtime failure with lldb-dap.
license: MIT
---

# cpp-debugger-cli

Use `cpp-debugger-cli` as a stateful native debugger. Send one JSON request on stdin per CLI invocation and parse the single JSON response from stdout. Preserve the returned `sessionId`; a detached daemon owns the adapter and target between invocations.

## Prepare

1. Confirm `cpp-debugger-cli --version` and `lldb-dap --version` succeed.
2. Build the target with debug information and low optimization (`-g -O0`, a Debug CMake configuration, or the toolchain equivalent).
3. Resolve program and source paths to absolute paths. Use 1-based source lines and columns.
4. If the packaged CLI is unavailable but this repository is present, run `npm run build` and invoke `node dist/cli.js` from the repository root.

On Windows, an LLVM installation may require `python311.dll`. If `lldb-dap --version` exits with `0xC0000135`, add a Python 3.11 runtime directory to `PATH` before launching the session.

## Send Requests

In PowerShell, construct JSON structurally instead of escaping it by hand:

```powershell
$request = @{
  version = 1
  operation = "status"
  sessionId = $sessionId
} | ConvertTo-Json -Depth 12 -Compress

$response = $request | cpp-debugger-cli | ConvertFrom-Json
if (-not $response.ok) { throw "$($response.error.code): $($response.error.message)" }
```

Never mix human-readable output into the request stream. Treat nonzero exit status and `ok: false` as failures; report `error.code`, `error.message`, and useful `error.details`.

## Start a Session

Launch an executable with initial source breakpoints:

```json
{
  "version": 1,
  "operation": "launch",
  "timeoutMs": 20000,
  "params": {
    "program": "C:/project/build/app.exe",
    "args": [],
    "cwd": "C:/project",
    "stopOnEntry": false,
    "waitForStop": true,
    "breakpoints": [
      {
        "file": "C:/project/src/main.cpp",
        "breakpoints": [{ "line": 12 }]
      }
    ]
  }
}
```

Save `response.sessionId` immediately. Expect `state: stopped` when a breakpoint is hit. A successful running response means no stop has occurred yet; use `waitForEvent`, `pause`, or `status` rather than starting another session.

Attach to an existing process with:

```json
{
  "version": 1,
  "operation": "attach",
  "params": { "processId": 1234, "waitForStop": false }
}
```

Use `adapterPath`, `adapterArgs`, or `adapterConfig` inside `params` only when the default `lldb-dap` configuration is insufficient.

## Inspect a Stop

Follow this order after every breakpoint, pause, or step:

1. Call `status` and read `result.stoppedThreadId`.
2. Call `stackTrace` with that `threadId`; choose the relevant frame and save its `id`.
3. Call `scopes` with `frameId`; select `Locals` or another appropriate scope.
4. Call `variables` with the scope's `variablesReference`.
5. Call `evaluate` with the current `frameId` for watch expressions.

Examples:

```json
{"version":1,"operation":"stackTrace","sessionId":"SESSION","params":{"threadId":42,"limit":50}}
```

```json
{"version":1,"operation":"scopes","sessionId":"SESSION","params":{"frameId":524288}}
```

```json
{"version":1,"operation":"variables","sessionId":"SESSION","params":{"variablesReference":1,"limit":200}}
```

```json
{"version":1,"operation":"evaluate","sessionId":"SESSION","params":{"frameId":524288,"expression":"node->value","context":"watch"}}
```

Do not trust an uninitialized local merely because the debugger can display its memory. Correlate the current source line with whether the assignment has executed.

Frame IDs and variable references are valid only for the current stop. After `continue`, `next`, `stepIn`, or `stepOut`, reacquire stack frames, scopes, and variables before inspecting again.

## Control Execution

Use `continue`, `pause`, `next`, `stepIn`, and `stepOut`. Provide `threadId` from the latest stop when required.

Execution operations default to `waitForStop: true` and return after `stopped` or `terminated`. Set `waitForStop: false` for long-running targets, then use:

```json
{"version":1,"operation":"waitForEvent","sessionId":"SESSION","timeoutMs":30000,"params":{"events":["stopped","terminated"]}}
```

A response with `waitTimedOut: true` means the target is still running; it does not mean the target or session was terminated.

`setBreakpoints` replaces every breakpoint for the specified file. Include all breakpoints that should remain in that file:

```json
{
  "version": 1,
  "operation": "setBreakpoints",
  "sessionId": "SESSION",
  "params": {
    "file": "C:/project/src/main.cpp",
    "breakpoints": [
      { "line": 12 },
      { "line": 30, "condition": "count > 10" }
    ]
  }
}
```

Check each returned breakpoint's `verified` field and message.

## Read Output and Input

Read events with a sequence cursor so output is not reread or missed:

```json
{"version":1,"operation":"events","sessionId":"SESSION","params":{"afterSequence":0,"limit":200}}
```

Save `result.latestSequence` and use it as the next `afterSequence`. Inspect `output`, `stopped`, `process`, `exited`, and `terminated` events.

Use `sendStdin` only when the session was launched with `runInTerminal: true` and the adapter accepted the reverse terminal request. Handle `STDIN_UNAVAILABLE` as an adapter capability limitation.

## Recover and Clean Up

- Use `sessions` to recover a lost session ID and identify live sessions.
- Use `status` before issuing control commands when the target state is uncertain.
- Treat `ADAPTER_EXITED` as terminal. Do not retry by recreating the adapter and pretending debugger state survived.
- Use `terminate` to stop the debuggee, then `disconnect` to close the daemon.
- Use `disconnect` alone when detaching without requesting target termination.
- Always clean up sessions in a `finally` path, even after inspection or command failure.

Use `rawRequest` only for non-lifecycle DAP capabilities not exposed by the stable operations. Never send `initialize`, `launch`, `attach`, `configurationDone`, `terminate`, or `disconnect` through it.

Do not use this tool for source navigation, definitions, references, or diagnostics; use an LSP tool such as `clangd-cli` for those tasks.

More Debugging skills

← All Debugging skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY