Обработка ошибок mach в 64-битном приложении OS X

Я смог зарегистрировать свой собственный порт mach для захвата исключений mach в моих приложениях, и он прекрасно работает, когда я нацелен на 32 бит. Однако, когда я нацелен на 64-разрядный бит, вызывается мой обработчик исключений catch_exception_raise(), но массив кодов исключений, передаваемых обработчику, имеет ширину 32 бит. Это ожидается в 32-битной сборке, но не в 64-битной версии.

В случае, когда я поймаю EXC_BAD_ACCESS, первым кодом является номер ошибки, а второй код должен быть адресом ошибки. Поскольку второй код имеет ширину в 32 бита, высокие 32 бита адреса 64-разрядной ошибки усекаются.

Я нашел флаг в <mach/exception_types.h>, который можно передать в task_set_exception_ports() под названием MACH_EXCEPTION_CODES, который, глядя на источники Дарвина, управляет размером кодов, переданных обработчику. Похоже, что оно предназначено для использования с поведением, переданным в task_set_exception_ports().

Однако когда я это делаю и запускаю исключение, мой mach-порт получает уведомление, я вызываю exc_server(), но мой обработчик никогда не вызывается, а когда ответное сообщение отправляется обратно в ядро, я получаю поведение исключения по умолчанию.

Я нацелен на 10.6 SDK.

Я действительно хочу, чтобы яблоко лучше документировало это. У кого-нибудь есть идеи?

Ответы

Ответ 1

Ну, я понял это.

Чтобы обрабатывать исключения 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.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.c и mach_excUser.c. Затем я включил эти файлы в свой проект, добавил правильное объявление для функции сервера в исходном файле и реализовал мои обработчики. Затем я построил приложение и был готов пойти.

Ну, это не лучшее описание, но, надеюсь, это помогает кому-то другому.