16

我已经能够注册我自己的 mach 端口以在我的应用程序中捕获 mach 异常,并且当我以 32 位为目标时它工作得很好。但是,当我以 64 位为目标时,我的异常处理程序catch_exception_raise()被调用,但传递给处理程序的异常代码数组是 32 位宽的。这在 32 位构建中是预期的,但不是在 64 位中。

在我捕获EXC_BAD_ACCESS的第一个代码是错误号的情况下,第二个代码应该是故障的地址。由于第二个代码是 32 位宽,因此 64 位故障地址的高 32 位被截断。

<mach/exception_types.h>我在I can pass in task_set_exception_ports()called中发现了一个标志,通过MACH_EXCEPTION_CODES查看 Darwin 源代码,该标志似乎可以控制传递给处理程序的代码的大小。看起来它应该与传递给task_set_exception_ports().

但是,当我这样做并触发异常时,我的 mach 端口会收到通知,我会调用exc_server()但我的处理程序永远不会被调用,并且当回复消息被发送回内核时,我会得到默认的异常行为。

我的目标是 10.6 SDK。

我真的希望苹果能更好地记录这些东西。有人有想法么?

4

1 回答 1

17

嗯,我想通了。

要处理马赫异常,您必须为您感兴趣的异常注册一个马赫端口。然后在另一个线程中等待消息到达该端口。当消息到达时,您调用exc_server()由 System.library 提供的实现。exec_server()获取到达的消息并调用您必须提供的三个处理程序之一。catch_exception_raise(), catch_exception_raise_state(), 或catch_exception_raise_state_identity()取决于您传递给task_set_exception_ports(). 这就是 32 位应用程序的处理方式。

对于 64 位应用程序,32 位方法仍然有效,但在处理程序中传递给您的数据可能会被截断为 32 位。要将 64 位数据传递给您的处理程序,需要一些额外的工作,这不是很直接,而且据我所知,没有很好的文档记录。通过查看 GDB 的源代码,我偶然发现了解决方案。

您不必exc_server()在消息到达端口时调用,mach_exc_server()而是必须调用。处理程序也必须具有不同的名称catch_mach_exception_raise()catch_mach_exception_raise_state(), 和catch_mach_exception_raise_state_identity()。处理程序的参数与它们的 32 位对应项相同。问题是mach_exc_server()没有为您提供的方式exc_server()是。要获得实现,mach_exc_server()需要使用 MIG(Mach 接口生成器)实用程序。MIG 采用接口定义文件并生成一组源文件,其中包括一个服务器函数,该函数将 mach 消息分派给您提供的处理程序。10.5 和 10.6 SDK 包含一个用于异常消息的 MIG 定义文件 <mach_exc.defs> 并将生成mach_exc_server()功能。然后,您将生成的源文件包含在您的项目中,然后您就可以开始了。

好消息是,如果您的目标是 10.6+(也许是 10.5),您可以对 32 位和 64 位使用相同的异常处理。MACH_EXCEPTION_CODES设置异常端口时的异常行为。异常代码将以 64 位值的形式出现,但您可以在 32 位构建中将它们截断为 32 位。

我把mach_exc.defs文件复制到我的源目录,打开一个终端并使用命令mig -v mach_exc.defs。这产生mach_exc.h,mach_excServer.cmach_excUser.c。然后我将这些文件包含在我的项目中,在我的源文件中添加了服务器函数的正确声明并实现了我的处理程序。然后我构建了我的应用程序,一切顺利。

好吧,这不是最好的描述,但希望它可以帮助其他人。

于 2010-05-15T06:11:28.753 回答