Currently the debugger is usable for certain tasks by members of the development team.
The debugger is for C/C++ code running on Fuchsia compiled in-tree for either CPU (ARM64 or x64). Rust almost works if you compile with symbols (which we don’t). I don’t know how to test Go. Please contact brettw if you’re interested in helping with these.
The debugger runs remotely only (you can't do self-hosted debug).
There is no “next” command. This is annoying but can be worked around since “step” and “finish” both work, or you can do things like “u 43” to get to a certain line.
Be aware that our debug build is compiled with some optimizations which means stepping may not work the way you would want even if the debugger was perfect (see “Getting less optimization” below).
Variables in non-top stack frames aren't available as often as they could be.
“step” steps into syscalls which end up as a few assembly instructions you have to step through.
Boot the target system with networing support. For QEMU support you may get some prompts for extra steps required:
fx run -N -u scripts/start-dhcp-server.sh
You will also want to note the target's IP address (run ifconfig
on the target to see this).
On the target system pick a port and run the debug agent:
debug_agent --port=2345
On the host system (where you do the build), run the client. Use the IP address of the target and the port you picked above in the connect
command.
out/x64/host_x64/zxdb [zxdb] connect 192.168.3.20:2345
(Substitute your build directory as-needed).
If you're launching many times, there is also a command-line switch zxdb --connect=192.168.3.53:2345
.
See help connect
for more examples, including IPv6 syntax.
From within the debugger:
[zxdb] run /path/to/some/program
or
[zxdb] ps ...process tree... [zxdb] attach 3452
Type “help” for commands, there is an extensive built-in help system. Some examples of stuff you can do:
[zxdb] b main Breakpoint 1 on Global, Enabled, stop=All, @ main Pending: No matches for location, it will be pending library loads. [zxdb] r /foo/bar/myapp Process 1 Running koid=7537 /foo/bar/myapp Thread 1 stopped on breakpoint 1 at main() • ps.c:257 255 } 256 ▶ 257 int main(int argc, char** argv) { 258 bool with_threads = false; 259 for (int i = 1; i < argc; ++i) { [zxdb] s 257 int main(int argc, char** argv) { 258 bool with_threads = false; ▶ 259 for (int i = 1; i < argc; ++i) { 260 const char* arg = argv[i]; 261 if (!strcmp(arg, "--help")) { [zxdb] l ...source code... [zxdb] f ▶ 0 main() • ps.c:259 1 start_main() • __libc_start_main.c:49 2 0x0 [zxdb] c Exited with code 0: Process 1 Not running /foo/bar/myapp [zxdb] q
[zxdb] bt ▶ 0 main() • ps.c:282 IP=0x1a77a1f9b991, BP=0x6db4c69eff0, SP=0x6db4c69efd0 argc = 1 argv = (char**) 0x49d00d252eac 1 start_main() • __libc_start_main.c:49 IP=0x598098780d2f, BP=0x6db4c69eff0, SP=0x6db4c69efe0 p = <no type> [zxdb] locals arg = <invalid pointer> i = 5 options = {also_show_threads = false, only_show_jobs = false} ret = 0 status = 2 [zxdb] print ret 0 [zxdb] print options.also_show_threads false
Fuchsia's “debug” build compiles with -Og
which does some optimizations but tries to be debugger-friendly about it. Some things will still be optimized out and reordered that can make debugging more challenging.
If you‘re encountering optimization problems you can do a local build change to override the debug flag for your target only. In the target’s definition (in the BUILD.gn
file) add this code:
if (is_debug) { # Force no optimization in debug builds. configs -= [ "//build/config:debug" ] cflags = [ "-O0" ] }
It will apply only to .cc files in that target. We recommend not checking this code in. If you find yourself needing this a lot, please speak up. We can consider adding another globally build optimization level.
The debugger is currently designed to run in-tree on a system you have just built. If you build out-of-tree, you can still experiment with some extra manual; steps.
Be aware that we aren't yet treating the protocol as frozen. Ideally the debugger will be from the same build as the operating system itself (more precicely, it needs to match the debug_agent).
The main thing will be finding symbols for your binary as we have not designed the system for registering new symbols with the debugger.
zxdb will look in a file “../ids.txt” relative to its own binary for the mappings to symbolized binaries on the local dev host (symbols in the binary on the Fuchsia target are never used so the files can be stripped). It will print the path of this file when it loads it after it connects to the remote system.
The ids.txt file has one line per binary, with each line having the format:
sym-stat
. It will list the build ID and probably tell you that it couldn't find symbols for it.While there is no way to add a second ID mapping file, you can append to the existing one (watch out: it will be overwritten by the next Fuchsia build). You will need to disconnect and reconnect zxdb to re-read this file.
The best way to debug issues around finding symbols is the sym-stat
command.
There are tests for the debugger that run on the host. These are relavant if you're working on the debugger client.
fx run-host-tests zxdb_tests
or directly with
out/x64/host_tests/zxdb_tests
The debug agent tests are in
/pkgfs/packages/debug_agent_tests/0/test/debug_agent_tests