从网络、邮件列表、书籍(如《Mac OS X Internals》)以及源代码中可获取的材料相当有限。
现在我知道xnu内核会引发一个EXC_CRASH,通知启动“Problem Reporter.app”(之前是Crash Reporter.app)。这个应用程序是否使用某种调试接口来生成崩溃报告?还是内核已经生成了报告,并只通知应用程序打开已经生成的报告?
从网络、邮件列表、书籍(如《Mac OS X Internals》)以及源代码中可获取的材料相当有限。
现在我知道xnu内核会引发一个EXC_CRASH,通知启动“Problem Reporter.app”(之前是Crash Reporter.app)。这个应用程序是否使用某种调试接口来生成崩溃报告?还是内核已经生成了报告,并只通知应用程序打开已经生成的报告?
每个 Mach 线程和/或任务(在其上实现 BSD 层进程的基础内核对象)都有异常端口。三个端口级别可用:线程、任务和主机。当发生异常时,会发送 Mach 消息 - 首先是发送到线程端口,然后是发送到任务端口,最后是发送到主机端口。如果获取了端口,则可以捕获异常,调试它(如 OS X 上的 gdb 所做的那样),或生成崩溃转储文件(如 Crash Reporter 所做的那样)。具体而言,所有 OS X 系统任务的父级 launchd 注册其异常端口,因此它接收消息,然后触发 CrashReporter(从 launchd 的 ReportCrash plist 中可以看出):
<key>MachServices</key>
<dict>
<key>com.apple.ReportCrash.DirectoryService</key>
<dict>
<key>DrainMessagesOnCrash</key>
<string>All</string>
<key>ExceptionServer</key>
<dict/>
</dict>
</dict>
XNU内核代码负责在EXC_CRASH上发送消息。具体而言,proc_prepareexit执行此操作:
/* If a core should be generated, notify crash reporter */
if (hassigprop(WTERMSIG(rv), SA_CORE) || ((p->p_csflags & CS_KILLED) != 0)) {
/*
* Workaround for processes checking up on PT_DENY_ATTACH:
* should be backed out post-Leopard (details in 5431025).
*/
if ((SIGSEGV == WTERMSIG(rv)) &&
(p->p_pptr->p_lflag & P_LNOATTACH)) {
goto skipcheck;
}
/*
* Crash Reporter looks for the signal value, original exception
* type, and low 20 bits of the original code in code[0]
* (8, 4, and 20 bits respectively). code[1] is unmodified.
*/
code = ((WTERMSIG(rv) & 0xff) << 24) |
((ut->uu_exception & 0x0f) << 20) |
((int)ut->uu_code & 0xfffff);
subcode = ut->uu_subcode;
(void) task_exception_notify(EXC_CRASH, code, subcode); // <-- Sends the msg
}