Обработка исключений Mach в 64-битном приложении OS X - PullRequest
15 голосов
/ 13 мая 2010

Мне удалось зарегистрировать свой собственный порт Маха для регистрации исключений Маха в моих приложениях, и он прекрасно работает, когда я нацеливаюсь на 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().

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

Я нацеливаюсь на 10.6 SDK.

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

1 Ответ

15 голосов
/ 15 мая 2010

Ну, я понял.

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

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

...