概览
即时调试 (JITD) 是 Fuchsia 暂停崩溃进程的一种方式,以便相关方稍后可以调试/处理这些进程。这样一来,就可以实现一些有趣的工作流程,例如在调试器未附加/运行的情况下,将 zxdb 附加到夜间崩溃的程序。
这是通过将进程存储在异常中的一个特殊位置(称为“进程暂留区”)来完成的。此位置会使这些进程保持暂停状态,直到有其他代理来释放它们。
如需详细了解其运作方式,请参阅实现。
如何启用
进程 Limbo 的一大好处是能够捕获实际运行中崩溃的进程,而无需预先运行调试器。这对于调试器无法运行的情况(例如驱动程序启动)特别有用。在这种情况下,拥有有效的进程 Limbo 可以提供宝贵的调试信息来源。
您可以通过以下两种方式启用进程 Limbo:
手动启用
有一个 ffx 插件允许用户查询 limbo 的当前状态:
$ ffx debug limbo --help
Usage: ffx debug limbo <command> [<args>]
control the process limbo on the target
Options:
--help display usage information
Commands:
status query the status of the process limbo.
enable enable the process limbo. It will now begin to capture
crashing processes.
disable disable the process limbo. Will free any pending processes
waiting in it.
list lists the processes currently waiting on limbo. The limbo
must be active.
release release a process from limbo. The limbo must be active.
See 'ffx help <command>' for more information on a specific command.
在启动时启用
注意:此功能目前已损坏。如果您需要使用该功能,请与 //src/developer/forensics/OWNERS 中的某位人员联系。
只有在您能够向系统发送命令的情况下,手动激活才能正常运行。但有些开发环境运行的软件比用户可与之互动的软件更早(或运行调试器)。驱动程序就是一个很好的例子。对于这些情况,从一开始就启用进程 Limbo 可让您在驱动程序启动时捕获驱动程序崩溃,而这通常是最难调试的部分。
为此,您需要在 build 中设置一项配置:
fx set <YOUR CONFIG> --with-base //src/developer/forensics:exceptions_enable_jitd_on_startup
或者,将此标签添加到 build 实参中的 base_package_labels
。您仍然可以使用 Process Limbo CLI 工具来停用和操纵 limbo。然后,您需要向设备推送更新,才能使此设置生效。
注意:驱动程序初始化非常棘手,冻结崩溃进程可能会使系统处于未定义状态并“挂起”,因此在使用此功能时,您的里程可能会有所不同,尤其是对于非常早期的驱动程序。
使用方式
zxdb
JITD 的主要用户是 zxdb,它能够附加到处于 limbo 状态的等待进程。启动 zxdb 时,它会自动附加到处于中间状态的等待进程:
$ ffx debug connect
Connecting (use "disconnect" to cancel)...
Connected successfully.
👉 To get started, try "status" or "help".
Processes attached from limbo:
48487: crasher
Type "detach <pid>" to send back to Process Limbo if attached,
type "detach <pid>" again to terminate the process if not attached, or
type "process <process context #> kill" to terminate the process if attached.
See "help jitd" for more information on Just-In-Time-Debugging.
Process "crasher" (48487) crashed and has been automatically attached.
Type "status" for more information.
Attached Process 1 state=Running koid=48487 name=crasher component=sshd-host.cm
Loading 9 modules for crasher Done.
23
24 int blind_write(volatile unsigned int* addr) {
▶ 25 *addr = 0xBAD1DEA;
26 return 0;
27 }
════════════════════════════════════════════════════════════════════════════
Data fault writing address 0x0 (translation fault level 2) (second chance)
════════════════════════════════════════════════════════════════════════════
Process 1 (koid=48487) thread 1 (koid=48489)
Faulting instruction: 0x642ff060
🛑 blind_write(volatile unsigned int*) • crasher.c:25
[zxdb] thread
# state koid name
▶ 1 Blocked (Exception) 58692 initial-thread
[zxdb] frame
▶ 0 blind_write(…) • crasher.c:25
1 main(…) • crasher.c:356
2…4 «libc startup» (-r expands)
[zxdb] list
20 int (*func)(volatile unsigned int*);
21 const char* desc;
22 } command_t;
23
24 int blind_write(volatile unsigned int* addr) {
▶ 25 *addr = 0xBAD1DEA;
26 return 0;
27 }
28
29 int blind_read(volatile unsigned int* addr) { return (int)(*addr); }
30
31 int blind_execute(volatile unsigned int* addr) {
32 void (*func)(void) = (void*)addr;
33 func();
34 return 0;
35 }
在 zxdb 中,您还可以执行 help jitd
以详细了解如何使用它。
进程 Limbo FIDL 服务
进程 Limbo 以 FIDL 服务形式呈现,这是进程 Limbo CLI 工具和 zxdb 使用的。FIDL 协议在 //sdk/fidl/fuchsia.exception/process_limbo.fidl
中定义。
实现
崩溃服务
当进程抛出异常时,Zircon 会生成关联的 exception handle
。然后,它会查看任何关联的异常渠道中是否有任何监听器可能对处理该异常感兴趣。这就是 zxdb 等调试器从正在运行的进程中获取异常的方式。如需了解详情,请参阅异常处理。
但是,如果没有剩余的异常处理程序(要么是因为根本没有,要么是因为所有处理程序都决定不处理该异常),根作业会有一个名为 crashsvc
的专属处理程序。一旦异常到达崩溃服务,系统就会认为该异常已“崩溃”,并且没有任何程序能够处理它。然后,崩溃服务会将崩溃堆栈轨迹转储到日志中,并将异常传递给 Exception Broker
。
异常代理
异常代理负责根据实际系统配置来决定如何处理崩溃异常。它可能会决定创建 minidump 文件并转储崩溃报告、将异常发送到进程 Limbo 或终止进程。
异常代理会感知进程 Limbo 以及它是否处于活动状态。当它收到异常时,会检查进程 Limbo 是否已启用。如果存在,则会将异常句柄传递给该处理程序。这与 FIDL 服务公开的进程 Limbo 相同。