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?

Karoy Lorentey
quelle
2
Denken Sie daran, dass die Ausnahme gerade ausgelöst wurde und die Beschreibung noch nicht auf der Konsole gedruckt wurde.
Karoy Lorentey
Schauen Sie sich diese Frage an: stackoverflow.com/questions/711650
Nikolai

Antworten:

162

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:

(lldb) po *(id *)($esp + 4)
Karoy Lorentey
quelle
6
Wie würde man das in lldb machen? Ich erhalte die Fehlermeldung "Fehler: Verweis auf 'id' ist nicht eindeutig"
offex
2
Können Sie die Quelle dieser Informationen angeben? Ich würde gerne mehr darüber lesen
João Nunes
3
Derzeit funktioniert für mich vor dem Prolog Folgendes, wenn ich objc_exception_throw in der LLDB weiterbringe : po *(id *)($esp + 4).
wbyoung
7
Das hat funktioniert! Aber es hat nicht funktioniert , bis ich Stack - Frame 0 ausgewählt . ( objc_exception_throw).
Funroll
7
po $eaxfunktioniert für mich im simulator als anhänger an das $r0wenn auf gerät.
Monkeydom
10

auf neuen Simulatoren (iOS 8, 64bit) xcode 6 verwende ich im Ausnahmerahmen: objc_exception_throw

po $rax

in 32bit:

po $eax

Was ist Rax?

Rax ist ein 64-Bit-Register, das das alte eax ersetzt

Wie finde ich alle Register?

register read

Quelle Wikipedia

João Nunes
quelle
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.

Jeff
quelle
1

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.

Funroll
quelle