Xcode / LLDB: Wie erhalte ich Informationen zu einer Ausnahme, die gerade ausgelöst wurde?
83
OK, stellen Sie sich vor, mein Haltepunkt in objc_exception_throwwurde gerade ausgelöst. Ich sitze an der Debugger-Eingabeaufforderung und möchte weitere Informationen zum Ausnahmeobjekt erhalten. Wo finde ich es?
Das Ausnahmeobjekt wird als erstes Argument an übergeben objc_exception_throw. LLDB bietet $arg1.. $argnVariablen, die auf Argumente in der richtigen Aufrufkonvention verweisen, wodurch das Drucken der Ausnahmedetails vereinfacht wird:
(lldb) po $arg1
(lldb) po [$arg1 name](lldb) po [$arg1 reason]
Stellen Sie sicher, dass Sie den objc_exception_throwFrame im Aufrufstapel auswählen , bevor Sie diese Befehle ausführen. Weitere Informationen zum Ausführen auf der Bühne finden Sie unter "Erweitertes Debugging und Adressbereinigung" in den WWDC15-Sitzungsvideos.
Veraltete Informationen
Wenn Sie GDB verwenden, hängt die Syntax für das erste Argument von den Aufrufkonventionen der Architektur ab, auf der Sie ausgeführt werden. Wenn Sie auf einem tatsächlichen iOS-Gerät debuggen, befindet sich der Zeiger auf das Objekt im Register r0. Verwenden Sie die folgende einfache Syntax, um es zu drucken oder Nachrichten an es zu senden:
(gdb) po $r0
(gdb) po [$r0 name](gdb) po [$r0 reason]
Auf dem iPhone Simulator werden alle Funktionsargumente auf dem Stapel übergeben, sodass die Syntax erheblich schrecklicher ist. Der kürzeste Ausdruck, den ich konstruieren könnte, ist *(id *)($ebp + 8). Um die Schmerzen zu lindern, schlage ich vor, eine Convenience-Variable zu verwenden:
(gdb)set $exception =*(id *)($ebp +8)(gdb) po $exception
(gdb) po [$exception name](gdb) po [$exception reason]
Sie können auch $exceptionautomatisch festlegen , wann immer der Haltepunkt ausgelöst wird, indem Sie dem Haltepunkt eine Befehlsliste hinzufügen objc_exception_throw.
(Beachten Sie, dass in allen von mir getesteten Fällen das Ausnahmeobjekt zum Zeitpunkt des Haltepunkttreffens auch in den Registern eaxund vorhanden war edx. Ich bin mir jedoch nicht sicher, ob dies immer der Fall sein wird.)
Hinzugefügt von Kommentar unten:
Wählen Sie in lldb den Stapelrahmen für aus objc_exception_throwund geben Sie den folgenden Befehl ein:
Hmm ... In Xcode 6.1 erhalte ich: (lldb) po $ rax-Fehler: Konnte nicht auftreten: Der Wert des Registers rax konnte nicht gelesen werden. Fehler beim Ausführen, PrepareToExecuteJITExpression
bradheintz
@ Radheintz Simulator oder Gerät? Ich versuchte dies mit 6.0.1
João Nunes
Können Sie dafür einen Link zu Ihrer Quelle angeben? Vielen Dank!
Chris Conover
Ich habe gerade in lldb geschrieben: register read. Mit diesen Informationen wissen wir dann, dass das erste Register im Ausnahmerahmen die Ausnahmemeldung enthält.
João Nunes
Ok, ich habe einige Dokumente gefunden: rax ist ein 64-Bit-Register: Im 64-Bit-Modus können Sie 64-Bit-Register verwenden (z. B. rax anstelle von eax, rbx anstelle von ebx usw.)
João Nunes
6
Zum Zeitpunkt dieses Schreibens ist dieser Beitrag mein Top-Google-Hit für: lldb print exception . Daher füge ich diese Antwort hinzu, um lldb und x86_64 zu berücksichtigen.
Meine Versuche, die Ausnahme mit zu finden, sind mit po $eaxfehlgeschlagen error: Couldn't materialize struct: Couldn't read eax (materialize). Andere Versuche, die in verknüpften Dokumenten aus früheren Antworten beschrieben wurden, schlugen ebenfalls fehl.
Der Schlüssel war, dass ich zuerst auf den objc_exception_throwRahmen in meinem Haupt-Thread klicken musste . lldb startet nicht in diesem Frame.
In all meinen Such- und folgenden Beispielen war dieser Blogeintrag der erste, der Dinge auf eine Weise erklärte, die für mich funktionierte. Es ist moderner und wird im August 2012 veröffentlicht.
Wenn Sie eine catch-Anweisung haben, fügen Sie dort einen Haltepunkt ein, und Sie können das Ausnahmeobjekt an diesem Punkt überprüfen.
Wenn Sie keine catch-Anweisung haben, fahren Sie fort.
In Ihrem Terminal wird folgende Nachricht angezeigt:
Beenden der App aufgrund der nicht erfassten Ausnahme 'NSInvalidArgumentException', Grund: ' * - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: Versuch, kein Objekt aus Objekten einzufügen [0]'
Sie suchen jedoch wahrscheinlich nach einer Möglichkeit, es zu überprüfen, ohne fortzufahren, da Sie Ihre schöne Stapelverfolgung verlieren, wenn die Anwendung beendet wird.
Dafür klingt es so, als wäre Fnords Antwort die beste, aber ich konnte sie in LLDB nicht zum Laufen bringen.
Antworten:
Das Ausnahmeobjekt wird als erstes Argument an übergeben
objc_exception_throw
. LLDB bietet$arg1
..$argn
Variablen, die auf Argumente in der richtigen Aufrufkonvention verweisen, wodurch das Drucken der Ausnahmedetails vereinfacht wird:Stellen Sie sicher, dass Sie den
objc_exception_throw
Frame im Aufrufstapel auswählen , bevor Sie diese Befehle ausführen. Weitere Informationen zum Ausführen auf der Bühne finden Sie unter "Erweitertes Debugging und Adressbereinigung" in den WWDC15-Sitzungsvideos.Veraltete Informationen
Wenn Sie GDB verwenden, hängt die Syntax für das erste Argument von den Aufrufkonventionen der Architektur ab, auf der Sie ausgeführt werden. Wenn Sie auf einem tatsächlichen iOS-Gerät debuggen, befindet sich der Zeiger auf das Objekt im Register
r0
. Verwenden Sie die folgende einfache Syntax, um es zu drucken oder Nachrichten an es zu senden:Auf dem iPhone Simulator werden alle Funktionsargumente auf dem Stapel übergeben, sodass die Syntax erheblich schrecklicher ist. Der kürzeste Ausdruck, den ich konstruieren könnte, ist
*(id *)($ebp + 8)
. Um die Schmerzen zu lindern, schlage ich vor, eine Convenience-Variable zu verwenden:Sie können auch
$exception
automatisch festlegen , wann immer der Haltepunkt ausgelöst wird, indem Sie dem Haltepunkt eine Befehlsliste hinzufügenobjc_exception_throw
.(Beachten Sie, dass in allen von mir getesteten Fällen das Ausnahmeobjekt zum Zeitpunkt des Haltepunkttreffens auch in den Registern
eax
und vorhanden waredx
. Ich bin mir jedoch nicht sicher, ob dies immer der Fall sein wird.)Hinzugefügt von Kommentar unten:
Wählen Sie in lldb den Stapelrahmen für aus
objc_exception_throw
und geben Sie den folgenden Befehl ein:quelle
objc_exception_throw
in der LLDB weiterbringe :po *(id *)($esp + 4)
.objc_exception_throw
).po $eax
funktioniert für mich im simulator als anhänger an das$r0
wenn auf gerät.auf neuen Simulatoren (iOS 8, 64bit) xcode 6 verwende ich im Ausnahmerahmen:
objc_exception_throw
in 32bit:
Was ist Rax?
Rax ist ein 64-Bit-Register, das das alte eax ersetzt
Wie finde ich alle Register?
Quelle Wikipedia
quelle
Zum Zeitpunkt dieses Schreibens ist dieser Beitrag mein Top-Google-Hit für: lldb print exception . Daher füge ich diese Antwort hinzu, um lldb und x86_64 zu berücksichtigen.
Meine Versuche, die Ausnahme mit zu finden, sind mit
po $eax
fehlgeschlagenerror: Couldn't materialize struct: Couldn't read eax (materialize)
. Andere Versuche, die in verknüpften Dokumenten aus früheren Antworten beschrieben wurden, schlugen ebenfalls fehl.Der Schlüssel war, dass ich zuerst auf den
objc_exception_throw
Rahmen in meinem Haupt-Thread klicken musste . lldb startet nicht in diesem Frame.In all meinen Such- und folgenden Beispielen war dieser Blogeintrag der erste, der Dinge auf eine Weise erklärte, die für mich funktionierte. Es ist moderner und wird im August 2012 veröffentlicht.
quelle
Wenn Sie eine catch-Anweisung haben, fügen Sie dort einen Haltepunkt ein, und Sie können das Ausnahmeobjekt an diesem Punkt überprüfen.
Wenn Sie keine catch-Anweisung haben, fahren Sie fort.
In Ihrem Terminal wird folgende Nachricht angezeigt:
Beenden der App aufgrund der nicht erfassten Ausnahme 'NSInvalidArgumentException', Grund: ' * - [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: Versuch, kein Objekt aus Objekten einzufügen [0]'
Sie suchen jedoch wahrscheinlich nach einer Möglichkeit, es zu überprüfen, ohne fortzufahren, da Sie Ihre schöne Stapelverfolgung verlieren, wenn die Anwendung beendet wird.
Dafür klingt es so, als wäre Fnords Antwort die beste, aber ich konnte sie in LLDB nicht zum Laufen bringen.
quelle