2010-05-13 5 views
13

Ich konnte meinen eigenen Mach-Port registrieren, um Mach-Ausnahmen in meinen Anwendungen zu erfassen, und es funktioniert wunderbar, wenn ich 32-Bit-Ziel. Wenn ich jedoch 64 Bit anzielt, wird mein Exception-Handler catch_exception_raise() aufgerufen, aber das Array der Exception-Codes, die an den Handler übergeben werden, ist 32 Bit breit. Dies wird in einem 32-Bit-Build erwartet, aber nicht in 64-Bit.Umgang mit Mach-Ausnahmen in 64bit OS X-Anwendung

In dem Fall, in dem ich EXC_BAD_ACCESS fangen, ist der erste Code die Fehlernummer und der zweite Code sollte die Adresse des Fehlers sein. Da der zweite Code 32 Bits breit ist, werden die hohen 32 Bits der 64-Bit-Fehleradresse abgeschnitten.

fand ich eine Fahne in <mach/exception_types.h> ich passieren kann in task_set_exception_ports()MACH_EXCEPTION_CODES genannt, die an den Darwin Quellen suchen, um die Größe der Codes an die Prozedur übergeben zu steuern scheint. Es sieht so aus, als ob es mit dem in task_set_exception_ports() übergebenen Verhalten verortet werden soll.

Aber wenn ich dies mache und eine Ausnahme auslöst, wird mein Mach-Port benachrichtigt, ich rufe exc_server(), aber mein Handler wird nie aufgerufen, und wenn die Antwortnachricht an den Kernel gesendet wird, bekomme ich das Standard-Ausnahmeverhalten.

Ich bin auf das 10.6 SDK ausgerichtet.

Ich wünschte wirklich Apple würde dieses Zeug besser dokumentieren. Hat jemand irgendwelche Ideen?

+0

Ich frage mich, ob das mehr mit dem Kernel zu tun hat, den Sie gerade ausführen; Sie erhalten 32-Bit-Ausnahmen unter dem 32-Bit-Kernel und 64-Bit-Ausnahmen unter dem 64-Bit-Kernel? Der 32-Bit-Kernel ist immer noch der Standard auf 10.6, aber wenn Sie einen neuen genug Mac haben, können Sie es versuchen ... –

+0

Der 32-Bit-Kernel ist vollständig 64-Bit-bewusst und wird entweder 64-Bit oder 32 übergeben -Bit Ausnahmen zu einer Anwendung. Es hängt alles davon ab, wie Ihre App danach fragt und sie behandelt. –

Antwort

14

Nun, ich habe es herausgefunden.

Um Mach-Ausnahmen zu behandeln, müssen Sie einen Mach-Port für die Ausnahmen registrieren, die Sie interessieren. Sie warten dann auf eine Nachricht, die auf dem Port in einem anderen Thread ankommt. Wenn eine Nachricht eintrifft, rufen Sie exc_server() an, deren Implementierung von System.library bereitgestellt wird. exec_server() übernimmt die Nachricht, die angekommen ist, und ruft einen von drei Handlern auf, die Sie angeben müssen. catch_exception_raise(), catch_exception_raise_state() oder catch_exception_raise_state_identity() abhängig von den Argumenten, die Sie an task_set_exception_ports() übergeben haben. So wird es für 32-Bit-Apps gemacht.

Für 64-Bit-Anwendungen funktioniert die 32-Bit-Methode immer noch, aber die Daten, die Sie in Ihrem Handler übergeben, werden möglicherweise auf 32 Bit gekürzt. Um 64-Bit-Daten zu erhalten, die an Ihre Handler übergeben werden, ist ein wenig zusätzlicher Aufwand erforderlich, der nicht sehr geradlinig ist und, soweit ich es beurteilen kann, nicht sehr gut dokumentiert ist. Ich stolperte über die Lösung, indem ich mir die Quellen für GDB anschaute.

Anstatt exc_server() anzurufen, wenn eine Nachricht am Port ankommt, müssen Sie stattdessen mach_exc_server() anrufen. Die Handler müssen auch andere Namen haben: catch_mach_exception_raise(), catch_mach_exception_raise_state() und catch_mach_exception_raise_state_identity(). Die Parameter für die Handler sind die gleichen wie ihre 32-Bit-Gegenstücke. Das Problem ist, dass mach_exc_server() nicht für Sie zur Verfügung gestellt wird, wie exc_server() ist. Um die Implementierung für mach_exc_server() zu erhalten, muss das Dienstprogramm MIG (Mach Interface Generator) verwendet werden. MIG verwendet eine Schnittstellendefinitionsdatei und generiert eine Reihe von Quelldateien, die eine Serverfunktion enthalten, die mach-Meldungen an von Ihnen bereitgestellte Handler ausgibt. Die SDKs 10.5 und 10.6 enthalten eine MIG-Definitionsdatei <mach_exc.defs> für die Ausnahmebedingungsnachrichten und generieren die mach_exc_server()-Funktion. Sie fügen dann die generierten Quelldateien in Ihr Projekt ein und dann können Sie loslegen.

Das nette Ding ist, dass, wenn Sie 10.6+ (und vielleicht 10.5) zielen, Sie die gleiche Ausnahmebehandlung für 32 und 64 Bit verwenden können. Just OR das Ausnahmeverhalten mit MACH_EXCEPTION_CODES, wenn Sie Ihre Ausnahme-Ports festlegen.Die Ausnahmecodes werden als 64-Bit-Werte ausgegeben, Sie können sie jedoch in Ihrem 32-Bit-Build auf 32 Bit abschneiden.

Ich nahm die mach_exc.defs Datei und kopierte es in mein Quellverzeichnis, öffnete ein Terminal und verwendete den Befehl mig -v mach_exc.defs. Dies erzeugte mach_exc.h, mach_excServer.c und mach_excUser.c. Ich habe dann diese Dateien in mein Projekt eingefügt, die korrekte Deklaration für die Serverfunktion in meiner Quelldatei hinzugefügt und meine Handler implementiert. Ich habe dann meine App gebaut und war gut zu gehen.

Nun, das ist nicht die beste Beschreibung, aber hoffentlich hilft es jemand anderen aus.

+0

Danke, das ist die einzige Dokumentation, die ich dazu finden konnte. – hooleyhoop

+0

Wenn Sie die ursprüngliche Ausnahme behandelt haben, müssen Sie den ursprünglichen Thread irgendwie signalisieren, damit er fortgesetzt wird? Es scheint zu warten warten .. – hooleyhoop

+0

Prost Brad, hatte ich das gleiche Problem und das löste es. Der relevante GDB-Code ist [hier] (http://opensource.apple.com/source/gdb/gdb-1708/src/gdb/macosx/macosx-nat-excthread.c) für jeden Interessierten. –