通过过滤器附加到进程
在 Fuchsia 上运行进程比在其他系统中更复杂,因为没有默认环境(请参阅下文的“关于启动器环境的说明”)。
可靠地调试所有类型的进程的唯一方法是通过“附加”创建一个过滤器,并以在调试程序之外启动该进程的常规方式启动它。调试程序支持以下过滤条件。
- 组件名称(v2 组件)。
- 组件网址(v2 组件)。
- 进程名称、完全匹配或部分匹配。
“Attach”命令根据格式对输入内容进行不同解读。例如,attach /core/feedback
会被解读为组件名称,因此会创建一个匹配该组件中的所有进程的过滤器,而 attach fuchsia-boot:///#meta/archivist.cm
会被解读为组件网址,并可能会匹配多个组件中的进程。
为方便起见,允许只将组件网址的最后一部分传递给“Attach”命令。
因此,attach archivist.cm
的功能与 attach fuchsia-boot:///#meta/archivist.cm
相同。
如果输入项看起来不像某个组件,系统会将其解读为进程名称。进程的启动器可以自由设置进程名称。如需查看这是什么,请在调试程序中运行(在调试程序中或在系统 shell 中使用)“ps”并让其运行。
以下示例在 main
上设置一个待处理断点,使其在执行开始时停止,并等待“my_app.cm”组件中的进程启动:
[zxdb] attach my_app.cm
Waiting for process matching "my_app.cm".
[zxdb] break main
Created Breakpoint 1 @ main
Pending: No current matches for location. It will be matched against new
processes and shared libraries.
然后,按照您正常使用方式(直接在命令行上,通过 fx test
、ffx component run /core/... fuchsia-pkg://...
或其他方式)运行该进程。然后,调试程序应该会立即在 main
上中断(加载符号可能需要一些时间,因此,在显示源代码之前,您可能会看到延迟):
Attached Process 1 [Running] koid=51590 my_app.cm
🛑 on bp 1 main(…) • main.cc:222
220 }
221
▶ 222 int main(int argc, const char* argv[]) {
223 foo::CommandLineOptions options;
224 cmdline::Status status = ParseCommandLine(argc, argv, &options);
然后,您可以执行类似于 GDB 的基本命令:
next
step
print argv[1]
continue
quit
直接在调试程序中启动
您可以直接启动调试程序中的可执行文件、组件或测试。
启动可执行文件
使用 run <executable>
从调试程序启动可执行文件。请注意,在 Fuchsia 中,所有进程都需要在命名空间中运行。run
将在 debug_agent 的命名空间中启动进程,这意味着只有 debug_agent 软件包中的可执行文件和 bootfs 中的可执行文件可用。由于它们在 debug_agent 的命名空间中运行,因此这些进程还将共享 debug_agent 相同的功能。
由于上述限制,run
只能用于运行某些演示程序。
启动组件
使用 run-component <component url>
启动组件。V2 组件将在 ffx-laboratory
集合中创建,类似于 ffx component run --recreate
的行为。系统不会重定向组件的输出。
由于应用了 ffx-laboratory
的所有限制,因此 run-component
通常仅用于启动演示程序。
启动测试
使用 run-test <test url>
启动测试,类似于 ffx test run
。您可以提供可选的 case 过滤条件来指定要运行的测试用例。
由于 Fuchsia 测试运行程序会为每个测试用例启动一个进程,因此调试程序中可能会启动多个进程。这些进程的名称将替换为测试用例的名称,以便更轻松地在测试用例之间导航。这些进程的输出将在调试程序中重定向,并可由 stdout
或 stderr
重放。
附加到现有进程
您可以根据进程的 koid(内核对象 ID,在应用于进程时,此 ID 相当于其他系统上的进程 ID)附加到大多数正在运行的进程。您可以通过在目标 Fuchsia 系统上运行 ps
或使用 zxdb 的内置 ps
命令来获取 koid:
[zxdb] ps
j: 1030 root
j: 1079 zircon-drivers
p: 1926 driver_host
...
在此列表中,“j:”表示作业(进程的容器),“p:”表示进程。类型前缀后面的数字是对象的 koid。
然后附加:
[zxdb] attach 3517
Process 1 Running koid=1249 pwrbtn-monitor
操作完成后,您可以选择 detach
(继续运行)或 kill
(终止)进程。
附加到特定作业中的进程
您可以将过滤器范围限定为特定作业。在这种情况下,过滤器可以为空,这意味着附加到所有已应用的进程。例如,
[zxdb] ps
j: 1033 root
j: 2057
p: 2274 foobar.cm
j: 2301
p: 2307 foo
p: 2318 bar
attach -j 2301 foo
将仅附加到进程 2307。attach -j 2057
将附加到所有 3 个进程。
调试驱动程序
目前,无法在系统启动中尽早设置调试程序来调试大多数驱动程序初始化。此外,由于 zxdb 本身使用网络和文件系统,因此无法调试与网络通信关联的驱动程序,也无法调试与存储或其他关键系统功能相关的许多驱动程序。
您可以通过附加到驱动程序主机(可由 ffx driver list-hosts
列出)来调试正在运行的驱动程序。驱动程序的初始化可通过调用 WaitForDebugger()
延迟,前提是驱动程序不依赖于调试程序。在 C++ 中,使用
// Add //src/lib/debug to the dependency.
#include "src/lib/debug/debug.h"
debug::WaitForDebugger();
而在 Rust 中:
// Add //src/lib/debug/rust to the dependency.
debug::wait_for_debugger(60);
连接调试程序后,WaitForDebugger()
将触发软件断点。执行必要的设置后,请输入 continue
以继续执行。
调试崩溃转储
Zxdb 支持加载由崩溃报告生成的小型转储。使用“opendump”动词并提供转储的本地文件名。调试程序不得连接到其他转储或正在运行的系统(如果是,请先使用“断开连接”)。
[zxdb] opendump upload_file_minidump-e71256ba30163a0.dmp
Opening dump file
Dump loaded successfully.
现在,可以使用线程、堆栈和内存命令检查程序的状态。使用 disconnect
关闭转储。
您也可以使用 ffx debug core
命令,例如:
ffx debug core upload_file_minidump-e71256ba30163a0.dmp
正在下载符号
Zxdb 会自动搜索在 symbol-index 中注册的服务器,查找在任何本地配置的符号目录中找不到的符号。您可以使用以下命令查看在您的符号索引中注册的符号服务器的完整列表:
ffx debug symbol-index list -a
这将以递归方式遍历和解析全局 Symbol-index 中包含的所有符号索引文件。如需了解详情,请参阅关于符号设置
显示的服务器将用于下载符号文件并将其异步加载到调试程序。对于特别大的 debuginfo 文件,您可能会在 zxdb 中的 sym-stat
中看到如下输出:
[zxdb] sym-stat
...
Base: 0xc37e9000
Build ID: ba17ef8c43bccf5fb6bf84f9a8d83d9cf3be8976 (Downloading...)
Symbols loaded: No
...
表示正在进行下载。文件下载完毕后,zxdb 会将新下载文件中的符号编入索引,并且可以继续调试。
调试多个进程
您可以同时调试多个任意进程。如果附加或运行已在调试程序中的进程,则只会并行创建一个新进程。
回想一下“互动模型”部分的内容,您可以通过以下代码列出当前进程:
[zxdb] process
# State Koid Name
▶ 1 Running 1249 pwrbtn-monitor
2 Not running 7235 pwrbtn-monitor
通过提供索引(而不是 koid)选择其中一个作为默认视图:
[zxdb] process 2
或者,使用以下命令将命令应用于特定进程(即使它不是默认进程):
[zxdb] process 2 pause