即时调试

概览

借助即时调试 (JITD), Fuchsia 可以挂起崩溃的进程,以便相关方稍后可以对其进行调试/处理。这允许进行感兴趣的流程,例如将 zxdb 连接到在调试程序未连接/运行时在一夜崩溃的程序。

为此,我们将进程存储在名为“Process Limbo”的特殊位置。此位置将使这些进程保持暂停状态,直到其他代理来释放它们。

如需详细了解其工作原理,请参阅实现

启用方法

Process Limbo 的一大优势是能够自然捕获崩溃的进程,而无需已经运行调试程序。这在调试程序无法运行的情况下(例如驱动程序启动)特别有用。对于这种情况,拥有有效的 Process Limbo 可以提供宝贵的调试信息来源。

启用 Process 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.

启动时启用

只有当您能够向系统发送命令时,手动激活才会起作用。但某些开发环境会更早运行软件,用户可与之互动(或运行调试程序)。驱动程序就是一个很好的例子。对于这些情况,让 Process 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 时,它会自动附加到在 limbo 中等待的进程:

$ 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 服务

Process Limbo 将自身显示为 FIDL 服务,这也是 Process Limbo CLI 工具和 zxdb 使用的 FIDL 服务。FIDL 协议在 //sdk/fidl/fuchsia.exception/process_limbo.fidl 中定义。

实现

崩溃服务

当进程抛出异常时,Zircon 会生成关联的 exception handle。然后,它会查看任何关联的异常渠道中是否有任何可能想要处理该异常的监听器。zxdb 等调试程序就是这样从正在运行的进程中获取异常的。如需了解详情,请参阅异常处理

但是,当不再需要异常处理程序时(无论是因为没有异常处理程序,还是由于它们都决定传递异常处理程序),根作业就会拥有一个名为 crashsvc 的独占处理程序。当异常到达崩溃服务后,可以将其理解为已“崩溃”,并且没有任何程序可处理该异常。然后,崩溃服务会将崩溃堆栈轨迹转储到日志,并将异常传递给 Exception Broker

异常代理

异常代理负责根据实际的系统配置,决定如何处理崩溃的异常。它可能会决定创建一个小型转储文件并转储崩溃报告,将异常发送到 Process Limbo 或终止该进程。

异常代理了解 Process Limbo 及其是否处于活跃状态。在收到异常时,它会检查 Process Limbo 是否已启用。如果是,它会将异常处理传递给它。这就是 FIDL 服务公开的同一 Process Limbo。