Xcode / LLDB: come ottenere informazioni su un’eccezione appena lanciata?

OK, quindi immagina che il mio punto di interruzione in objc_exception_throw sia appena stato triggersto. Sono seduto al prompt del debugger e desidero ottenere ulteriori informazioni sull’object exception. Dove lo trovo?

L’object eccezione viene passato come primo argomento a objc_exception_throw . LLDB fornisce variabili $arg1 .. $argn per fare riferimento agli argomenti nella convenzione di chiamata corretta, semplificando la stampa dei dettagli delle eccezioni:

 (lldb) po $arg1 (lldb) po [$arg1 name] (lldb) po [$arg1 reason] 

Assicurati di selezionare il frame objc_exception_throw nello stack di chiamate prima di eseguire questi comandi. Vedi “Advanced Debugging and the Address Sanitizer” nei video della sessione WWDC15 per vederlo eseguito sul palco.

Informazioni obsolete

Se sei su GDB, la syntax per fare riferimento al primo argomento dipende dalle convenzioni di chiamata dell’architettura su cui stai lavorando. Se esegui il debug su un dispositivo iOS reale, il puntatore all’object si trova nel registro r0 . Per stamparlo o inviare messaggi ad esso, usa la seguente semplice syntax:

 (gdb) po $r0 (gdb) po [$r0 name] (gdb) po [$r0 reason] 

Su iPhone Simulator, tutti gli argomenti della funzione vengono passati in pila, quindi la syntax è notevolmente più orribile. L’espressione più corta che potrei build per *(id *)($ebp + 8) è *(id *)($ebp + 8) . Per rendere le cose meno dolorose, suggerisco di utilizzare una variabile di convenienza:

 (gdb) set $exception = *(id *)($ebp + 8) (gdb) po $exception (gdb) po [$exception name] (gdb) po [$exception reason] 

È anche ansible impostare $exception automaticamente ogni volta che il punto di interruzione viene triggersto aggiungendo un elenco di comandi al punto di interruzione objc_exception_throw .

(Si noti che in tutti i casi che ho provato, l’object eccezione era presente anche nei registri eax ed edx nel momento in cui il punto di interruzione ha colpito. Non sono sicuro che sarà sempre così, però.)

Aggiunto dal commento qui sotto:

In lldb , seleziona lo stack frame per objc_exception_throw e poi inserisci questo comando:

 (lldb) po *(id *)($esp + 4) 

su nuovi simulatori (iOS 8, 64 bit) xcode 6 im usando nel frame di eccezione: objc_exception_throw

 po $rax 

in 32 bit:

 po $eax 

Cos’è rax?

Rax è un registro a 64 bit che sostituisce il vecchio eax

Come trovare tutti i registri?

 register read 

Fonte wikipedia

Al momento della stesura di questo post, questo post è il mio principale hit di Google per: lldb print exception . Quindi, sto aggiungendo questa risposta per conto di lldb e x86_64.

I miei tentativi di trovare l’eccezione usando po $eax falliti con error: Couldn't materialize struct: Couldn't read eax (materialize) . Anche altri tentativi descritti in documenti collegati da precedenti risposte fallirono.

La chiave era che dovevo prima cliccare sul frame objc_exception_throw nel mio thread principale. lldb non inizia in quella cornice.

In tutti i miei esempi di ricerca e di seguito, questo post di blog è stato il primo a spiegare le cose in un modo che ha funzionato per me. È più moderno, essendo pubblicato in agosto 2012.

Se si dispone di un’istruzione catch, inserire un punto di interruzione e controllare l’object di eccezione in quel punto.

Se non hai una dichiarazione di cattura, continua.

Riceverai un messaggio nel tuo terminale in questo modo:

Terminazione dell’app a causa dell’eccezione non rilevata ‘NSInvalidArgumentException’, motivo: ‘ * – [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: tentativo di inserire nil object dagli oggetti [0]’

Tuttavia , probabilmente stai cercando un modo per controllarlo senza continuare poiché perderai la tua bella traccia di stack quando l’applicazione viene terminata.

Per questo sembra che la risposta di Fnord sia la migliore, ma non sono riuscito a farlo funzionare in LLDB.