2010-05-13 17 views
13

J'ai pu enregistrer mon propre port mach pour capturer les exceptions mach dans mes applications et il fonctionne parfaitement lorsque je cible 32 bits. Toutefois, lorsque je cible 64 bits, mon gestionnaire d'exceptions catch_exception_raise() est appelé mais le tableau de codes d'exception transmis au gestionnaire a une largeur de 32 bits. Cela est prévu dans une version 32 bits, mais pas dans 64 bits.Gestion des exceptions mach dans l'application 64 bits OS X

Dans le cas où je prends EXC_BAD_ACCESS le premier code est le numéro d'erreur et le deuxième code devrait être l'adresse de la faute. Comme le second code a une largeur de 32 bits, les 32 bits élevés de l'adresse de défaillance de 64 bits sont tronqués.

Je trouve un drapeau dans <mach/exception_types.h> je peux passer task_set_exception_ports() appelé MACH_EXCEPTION_CODES qui, de regarder les sources Darwin semble contrôler la taille des codes transmis au gestionnaire. On dirait qu'il est destiné à être corrigé avec le comportement transmis à task_set_exception_ports().

Cependant lorsque je fais cela et déclenche une exception, mon port mach est notifié, j'appelle exc_server() mais mon gestionnaire n'est jamais appelé, et quand le message de réponse est renvoyé au noyau, je reçois le comportement d'exception par défaut.

Je vise le SDK 10.6. J'aimerais vraiment que Apple documente mieux ce genre de choses. Quelqu'un a des idées?

+0

Je me demande si cela a plus à voir avec le noyau que vous utilisez; vous obtiendrez des exceptions 32 bits sous le noyau 32 bits et des exceptions 64 bits sous le noyau 64 bits? Le noyau 32 bits est toujours le noyau par défaut sur 10.6, mais si vous avez un Mac assez récent, vous pouvez l'essayer ... –

+0

Le noyau 32 bits est entièrement conscient de 64 bits et passera soit 64 bits ou 32 bits exceptions -bit à une application. Tout dépend de la façon dont votre application demande et les gère. –

Répondre

14

Eh bien, je l'ai compris.

Pour gérer les exceptions mach, vous devez enregistrer un port mach pour les exceptions qui vous intéressent. Vous attendez ensuite qu'un message arrive sur le port dans un autre thread. Lorsqu'un message arrive, vous appelez exc_server() dont l'implémentation est fournie par System.library. exec_server() prend le message qui est arrivé et appelle l'un des trois gestionnaires que vous devez fournir. catch_exception_raise(), catch_exception_raise_state() ou catch_exception_raise_state_identity() en fonction des arguments que vous avez passés à task_set_exception_ports(). C'est ainsi que cela est fait pour les applications 32 bits.

Pour les applications 64 bits, la méthode 32 bits fonctionne toujours mais les données qui vous sont transmises dans votre gestionnaire peuvent être tronquées à 32 bits. Pour obtenir des données 64 bits transmises à vos gestionnaires, il faut un peu de travail supplémentaire qui n'est pas très simple et pour autant que je sache, pas très bien documenté. Je suis tombé sur la solution en regardant les sources de GDB. Au lieu d'appeler exc_server() au lieu d'appeler un message au port, vous devez appeler mach_exc_server() au lieu de . Les gestionnaires doivent également avoir des noms différents ainsi catch_mach_exception_raise(), catch_mach_exception_raise_state() et catch_mach_exception_raise_state_identity(). Les paramètres pour les gestionnaires sont les mêmes que leurs homologues 32 bits. Le problème est que mach_exc_server() n'est pas fourni pour vous comme exc_server() est. Pour obtenir l'implémentation pour mach_exc_server() nécessite l'utilisation de l'utilitaire MIG (Mach Interface Generator). MIG prend un fichier de définition d'interface et génère un ensemble de fichiers source comprenant une fonction serveur qui distribue les messages mach aux gestionnaires que vous fournissez. Les SDK 10.5 et 10.6 incluent un fichier de définition MIG <mach_exc.defs> pour les messages d'exception et généreront la fonction mach_exc_server(). Vous incluez ensuite les fichiers source générés dans votre projet, puis vous êtes prêt à partir. La bonne chose est que si vous ciblez 10.6+ (et peut-être 10.5), vous pouvez utiliser la même gestion des exceptions pour les 32 et 64 bits. Juste OU le comportement d'exception avec MACH_EXCEPTION_CODES lorsque vous définissez vos ports d'exception.Les codes d'exception apparaîtront comme des valeurs de 64 bits, mais vous pouvez les tronquer à 32 bits dans votre version 32 bits.

J'ai pris le fichier mach_exc.defs et l'ai copié dans mon répertoire source, j'ai ouvert un terminal et utilisé la commande mig -v mach_exc.defs. Cela a généré mach_exc.h, mach_excServer.c et mach_excUser.c. J'ai ensuite inclus ces fichiers dans mon projet, ajouté la déclaration correcte pour la fonction serveur dans mon fichier source et implémenté mes gestionnaires. J'ai ensuite construit mon application et était bon à faire.

Eh bien, ce n'est pas la meilleure description, mais j'espère que ça aide quelqu'un d'autre.

+0

Merci, c'est la seule documentation que j'ai pu trouver à ce sujet. – hooleyhoop

+0

Lorsque vous gérez l'exception d'origine, avez-vous besoin de signaler le thread d'origine pour qu'il se poursuive? Il semble être coincé en attente .. – hooleyhoop

+0

Bravo Brad, j'ai eu le même problème et cela l'a résolu. Le code GDB correspondant est [ici] (http://opensource.apple.com/source/gdb/gdb-1708/src/gdb/macosx/macosx-nat-excthread.c) pour toute personne intéressée. –