| <!--* freshness: { reviewed: '2026-10-12' } *--> |
| |
| # Zxdb Debug Adapter Request Handlers (`zxdb/debug_adapter/handlers`) |
| |
| ## Overview |
| |
| `//src/developer/debug/zxdb/debug_adapter/handlers` implements Debug Adapter |
| Protocol (DAP) request handlers and custom `zxdb` extensions. These handlers |
| manage target attach and launch, thread stepping, breakpoints and watchpoints, |
| stack and async backtraces, variable scopes, and REPL evaluation. |
| |
| ## Interface |
| |
| Public headers group DAP request records and handlers into these areas: |
| |
| - Target attach, launch, and process queries (`request_attach.h`, |
| `request_launch.h`, `request_process.h`, `request_terminate.h`, |
| `request_zxdb_detach.h`): `dap::AttachRequestZxdb`, |
| `zxdb::OnRequestAttach(DebugAdapterContext*, const dap::AttachRequestZxdb&)`, |
| `dap::LaunchRequestZxdb`, `zxdb::SplitDapCommand(const dap::string&, |
| dap::array<dap::string>&)`, `zxdb::OnRequestLaunch(DebugAdapterContext*, const |
| dap::LaunchRequestZxdb&)`, `dap::ZxdbProcessInfo`, `dap::ZxdbProcessRequest`, |
| `dap::ZxdbProcessResponse`, and |
| `zxdb::OnRequestZxdbProcess(DebugAdapterContext*, const |
| dap::ZxdbProcessRequest&)`. |
| - Execution control and thread stepping (`request_continue.h`, |
| `request_pause.h`, `request_next.h`, `request_step_in.h`, |
| `request_step_out.h`, `request_threads.h`): |
| `zxdb::OnRequestContinue(DebugAdapterContext*, const dap::ContinueRequest&)`, |
| `dap::PauseRequestZxdb`, `dap::PauseResponseZxdb`, |
| `dap::ProcessStoppedEventZxdb`, and `zxdb::OnRequestPause`. Also exposes |
| `zxdb::OnRequestNext`, `zxdb::OnRequestStepIn`, `zxdb::OnRequestStepOut`, |
| `dap::ThreadZxdb`, `dap::ThreadEventZxdb`, `dap::ThreadsResponseZxdb`, and |
| `zxdb::OnRequestThreads`. |
| - Source, function, and data breakpoints (`request_breakpoint.h`, |
| `request_function_breakpoint.h`, `request_data_breakpoint.h`): |
| `zxdb::OnRequestBreakpoint`, `zxdb::OnRequestFunctionBreakpoint`, |
| `zxdb::OnRequestDataBreakpointInfo`, and `zxdb::OnRequestSetDataBreakpoints`. |
| - Stack traces and async backtraces (`request_stacktrace.h`, |
| `request_async_backtrace.h`): `dap::StackTraceRequestZxdb`, |
| `zxdb::OnRequestStackTrace`, `dap::ZxdbAsyncBacktraceRequest`, |
| `dap::ZxdbAsyncBacktraceResponse`, and `zxdb::OnRequestZxdbAsyncBacktrace`. |
| - Scopes, variables, and REPL evaluation (`request_scopes.h`, |
| `request_variables.h`, `request_evaluate.h`): `zxdb::OnRequestScopes`, |
| `zxdb::OnRequestVariables`, and `zxdb::OnRequestEvaluate`. |
| |
| ## Invariants |
| |
| Handler implementations must preserve these invariants: |
| |
| - `OnRequestAttach` requires a non-empty process pattern. It parses decimal |
| strings as `uint64_t` KOIDs for direct attach and resolves symbolic patterns |
| via `debug_ipc::ResolveFilterType`. |
| - Without client `RunInTerminal` support, `OnRequestLaunch` requires |
| `req.process` to contain `://` and end with `.cm`. |
| - `OnRequestBreakpoint` requires `req.source.path` to be present, absolute, and |
| canonicalizable via `std::filesystem::weakly_canonical`. |
| - `OnRequestDataBreakpointInfo` and `OnRequestSetDataBreakpoints` format |
| `DataId` as `<process_koid>:0x<address_hex>:<byte_size>` with `process_koid > |
| 0` and `address <= UINT64_MAX - byte_size`. The watched value must reside in |
| memory (not registers or bitfields), and `byte_size` must pass |
| `BreakpointSettings::ValidateSize`. Access must be `write` or `readWrite`, and |
| `hitCondition` must be empty. |
| - Stepping (`OnRequestNext`, `OnRequestStepIn`, `OnRequestStepOut`), variable |
| queries (`OnRequestScopes`, `OnRequestVariables`), and |
| `OnRequestDataBreakpointInfo` require a stopped thread via |
| `DebugAdapterContext::CheckStoppedThread`. |
| - `OnRequestVariables` requires `VariableResponseContext` to finish all pending |
| evaluations (`FX_CHECK(!pending_evals)`) before calling the response callback, |
| and requires a non-null `Frame` for every valid `VariablesRecord`. |
| - `OnRequestZxdbAsyncBacktrace` requires `threadId > 0` and requires |
| `process->AllThreadsStopped()` to return `true`. |
| - `OnRequestPause` rejects requests that set both `processId` and `threadId`, |
| and requires `processId > 0` when present. |
| - `OnRequestZxdbProcess` requires `req.pid > 0` when present. |
| - `OnRequestEvaluate` accepts only requests where `req.context` equals `repl`. |
| - Per the DAP specification, handlers must send the command `Response` (such as |
| `PauseResponse`) **before** any resulting `Event` (such as `StoppedEvent` or |
| `ProcessStoppedEventZxdb`). Never emit events inside `debug_ipc` reply |
| callbacks before the request handler sends its `Response`. |
| - New and refactored DAP handlers must call the `zxdb::client` object model |
| directly instead of building `Console` command strings or reading stateful |
| `ConsoleContext` selections. |
| - Use custom `*Zxdb` request types (such as `TerminateRequestZxdb` or |
| `StackTraceRequestZxdb`) only when a request needs custom fields. Declare all |
| extension fields as `std::optional<T>` with explicit defaults for standard DAP |
| clients. |
| |
| ## Side Effects |
| |
| Executing DAP request handlers produces these session and IPC side effects: |
| |
| - Mutates `zxdb::System` state by creating and attaching `Target` instances, |
| updating `Filter` and `Breakpoint` objects, and pausing or continuing |
| `System`, `Process`, or `Thread` execution. |
| - Mutates `DebugAdapterContext` state by storing and deleting connection-scoped |
| filters, breakpoints, frame IDs, and variable records, and by running |
| `OnProcessPaused` and `OnThreadPaused` callbacks. |
| - Sends asynchronous DAP requests and events via |
| `DebugAdapterContext::dap().send()`, including `dap::RunInTerminalRequest`, |
| `dap::StoppedEvent`, and `dap::ProcessStoppedEventZxdb`. |
| - Sends `RemoteAPI::RunComponent` IPC requests when launching components without |
| `RunInTerminal` support. |
| - Updates `ConsoleContext` active selections and runs console commands via |
| `Console::ProcessInputLine` during `repl` `OnRequestEvaluate` calls. |
| - Triggers asynchronous stack syncing (`Stack::EnsureFrames`), async task tree |
| syncing (`AsyncTaskTree::Sync`), and expression evaluation (`EvalExpression`, |
| `FillFormatNodeValue`, `FillFormatNodeDescription`). |
| |
| ## Verification |
| |
| Run these commands to build and test `zxdb/debug_adapter/handlers`: |
| |
| - Build: `fx build //src/developer/debug/zxdb/debug_adapter` |
| - Test: `fx test zxdb_tests` |