This tutorial explains the concepts and workflow of agent debugging mode in fx test and how to manage symbol loading and breakpoint resolution when integrating with automated scripts or IDE debuggers.
Agent debugging mode is designed for headless automation, IDE integration (like VS Code), and scripts. It runs zxdb as a background server exposing a Debug Adapter Protocol (DAP) endpoint on a Unix domain socket at /tmp/fx-debug-daemon.sock.
To start a test suite in this mode:
fx test <TEST_SUITE_NAME> --agent-debugging-mode
When you run fx test --agent-debugging-mode without any breakpoint arguments, the testing framework attaches zxdb to the target process “weakly” (using the attach --weak command).
Weak attachment optimizes startup performance by preventing zxdb from proactively querying modules and loading symbol indexes for the process.
zxdb does not load symbols upon the initial attach.file:line or symbolic breakpoints registered dynamically through the DAP UDS interface after the test starts will remain “pending” and cannot be verified or resolved.If you need to debug a passing path, or if you want to ensure your breakpoints are active and verified before execution starts, you must specify them on the fx test command line:
fx test <TEST_SUITE_NAME> --agent-debugging-mode --breakpoint <SOURCE_FILE>:<LINE>
--breakpoint option tells the fxtest framework to attach zxdb normally (omitting the --weak flag).zxdb immediately loads symbols for the target process.zxdb installs and resolves the specified breakpoints upfront during the initialization handshake."stopped" event with "reason": "breakpoint" to the DAP client.Once the execution stops at a breakpoint or exception, you can interact with the debugger from a second terminal using the fx debug cli wrapper tool.
To connect and retrieve the current debugger state:
fx debug cli --json '{"command": "get-state"}'
The tool returns a JSON response listing active processes and threads:
{ "success": true, "body": { "threads": [ { "id": 1, "name": "initial-thread" } ], "processes": { "12345": "my_test_binary" } } }
To retrieve a stack trace for a specific thread, pass the thread_id:
fx debug cli --json '{"command": "stackTrace", "thread_id": 1}'
The tool returns the stack frame details:
{ "success": true, "body": { "stackFrames": [ { "id": 0, "name": "my_test_function", "source": { "name": "main_test.cc", "path": "/src/main_test.cc" }, "line": 42, "column": 1 } ], "totalFrames": 1 } }
Once diagnostic inspection is complete, resume the execution of the thread:
fx debug cli --json '{"command": "continue", "thread_id": 1}'
Use fx debug cli help to get a list of all commands you can run.