Я смог зарегистрировать свой собственный порт Маха для получения исключений Маха в моих приложениях, и он работает красиво, когда я нацелен на 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
то, которое от рассмотрения источников Darwin, кажется, управляет размером кодов, передало обработчику. Похоже, что это предназначено, чтобы быть ореадой с поведением, переданным в к task_set_exception_ports()
.
Однако, когда я делаю это и инициировал исключение, мой порт Маха уведомляется, я звоню exc_server()
но мой обработчик никогда не называют, и когда ответное сообщение передают обратно ядру, я получаю поведение исключения по умолчанию.
Я нацелен на 10,6 SDK.
Я действительно желаю, чтобы яблоко зарегистрировало бы этот материал лучше. У кого-либо есть какие-либо идеи?
Ну, я разобрался.
Для обработки исключений 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 предоставленным вами обработчикам. Пакеты SDK 10.5 и 10.6 включают файл определения 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.h
, mach_excServer.c
и mach_excUser.c
. Затем я включил эти файлы в свой проект, добавил правильное объявление для функции сервера в исходный файл и реализовал свои обработчики. Затем я создал свое приложение, и все готово.
Ну, это не лучшее описание, но, надеюсь, поможет кому-то другому.