处理 64 位 OS X 应用程序中的马赫异常

发布于 2024-09-01 21:03:22 字数 695 浏览 10 评论 0原文

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

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

我在 中发现了一个标志,我可以通过查看 Darwin 源代码传入 task_set_exception_ports() 名为 MACH_EXCEPTION_CODES 的标志似乎控制传递给处理程序的代码的大小。看起来它应该与传入 task_set_exception_ports() 的行为进行处理。

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

我的目标是 10.6 SDK。

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

I have been able to register my own mach port to capture mach exceptions in my applications and it works beautifully when I target 32 bit. However when I target 64 bit, my exception handler catch_exception_raise() gets called but the array of exception codes that is passed to the handler are 32 bits wide. This is expected in a 32 bit build but not in 64 bit.

In the case where I catch EXC_BAD_ACCESS the first code is the error number and the second code should be the address of the fault. Since the second code is 32 bits wide the high 32 bits of the 64 bit fault address is truncated.

I found a flag in <mach/exception_types.h> I can pass in task_set_exception_ports() called MACH_EXCEPTION_CODES which from looking at the Darwin sources appears to control the size of the codes passed to the handler. It looks like it is meant to be ored with the behavior passed in to task_set_exception_ports().

However when I do this and trigger an exception, my mach port gets notified, I call exc_server() but my handler never gets called, and when the reply message is sent back to the kernel I get the default exception behavior.

I am targeting the 10.6 SDK.

I really wish apple would document this stuff better. Any one have any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

吖咩 2024-09-08 21:03:22

好吧,我想通了。

要处理 mach 异常,您必须为您感兴趣的异常注册一个 mach 端口。然后,您在另一个线程中等待消息到达该端口。当消息到达时,您调用 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 Interface Generator)实用程序。 MIG 采用接口定义文件并生成一组源文件,其中包括一个服务器函数,该函数将 mach 消息分派到您提供的处理程序。 10.5 和 10.6 SDK 包括 MIG 定义文件用于获取异常消息,并将生成 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.hmach_excServer.cmach_excUser.c。然后,我将这些文件包含在我的项目中,在我的源文件中添加了服务器函数的正确声明并实现了我的处理程序。然后我构建了我的应用程序并且一切顺利。

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

Well, I figured it out.

To handle mach exceptions, you have to register a mach port for the exceptions you are interested in. You then wait for a message to arrive on the port in another thread. When a message arrives, you call exc_server() whose implementation is provided by System.library. exec_server() takes the message that arrived and calls one of three handlers that you must provide. catch_exception_raise(), catch_exception_raise_state(), or catch_exception_raise_state_identity() depending on the arguments you passed to task_set_exception_ports(). This is how it is done for 32 bit apps.

For 64 bit apps, the 32 bit method still works but the data passed to you in your handler may be truncated to 32 bits. To get 64 bit data passed to your handlers requires a little extra work that is not very straight forward and as far as I can tell not very well documented. I stumbled onto the solution by looking at the sources for GDB.

Instead of calling exc_server() when a message arrives at the port, you have to call mach_exc_server() instead. The handlers also have to have different names as well catch_mach_exception_raise(), catch_mach_exception_raise_state(), and catch_mach_exception_raise_state_identity(). The parameters for the handlers are the same as their 32 bit counterparts.
The problem is that mach_exc_server() is not provided for you the way exc_server() is. To get the implementation for mach_exc_server() requires the use of the MIG (Mach Interface Generator) utility. MIG takes an interface definition file and generates a set of source files that include a server function that dispatches mach messages to handlers you provide. The 10.5 and 10.6 SDKs include a MIG definition file <mach_exc.defs> for the exception messages and will generate the mach_exc_server() function. You then include the generated source files in your project and then you are good to go.

The nice thing is that if you are targeting 10.6+ (and maybe 10.5) you can use the same exception handling for both 32 and 64 bit. Just OR the exception behavior with MACH_EXCEPTION_CODES when you set your exception ports. The exception codes will come through as 64 bit values but you can truncate them to 32 bits in your 32 bit build.

I took the mach_exc.defs file and copied it to my source directory, opened a terminal and used the command mig -v mach_exc.defs. This generated mach_exc.h, mach_excServer.c, and mach_excUser.c. I then included those files in my project, added the correct declaration for the server function in my source file and implemented my handlers. I then built my app and was good to go.

Well, this not the best description, but hopefully it helps someone else out.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文