Xcode / LLDB: ¿Cómo obtener información sobre una excepción que acaba de lanzarse?

De acuerdo, imagina que mi punto de interrupción en objc_exception_throw acaba de objc_exception_throw . Estoy sentado en el indicador del depurador, y quiero obtener más información sobre el objeto de excepción. ¿Donde lo encuentro?

El objeto de excepción se pasa como primer argumento a objc_exception_throw . LLDB proporciona $arg1 .. $argn variables para referirse a los argumentos en la convención de llamadas correcta, lo que facilita la impresión de los detalles de la excepción:

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

Asegúrese de seleccionar el marco objc_exception_throw en la stack de llamadas antes de ejecutar estos comandos. Consulte “Depuración avanzada y el desinfectante de direcciones” en los videos de la sesión WWDC15 para ver esto en el escenario.

Información desactualizada

Si está en GDB, la syntax para referirse al primer argumento depende de las convenciones de llamada de la architecture en la que se está ejecutando. Si está depurando en un dispositivo iOS real, el puntero al objeto está en el registro r0 . Para imprimirlo o enviarle mensajes, use la siguiente syntax simple:

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

En el simulador de iPhone, todos los argumentos de función se pasan a la stack, por lo que la syntax es considerablemente más horrible. La expresión más corta que podría construir es: *(id *)($ebp + 8) . Para hacer las cosas menos dolorosas, sugiero usar una variable de conveniencia:

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

También puede establecer $exception automáticamente cada vez que se desencadena el punto de interrupción agregando una lista de comandos al punto de interrupción objc_exception_throw .

(Tenga en cuenta que en todos los casos que probé, el objeto de excepción también estaba presente en los registros eax y edx en el momento en que golpeó el punto de interrupción. Sin embargo, no estoy seguro de que siempre sea el caso).

Agregado de los comentarios a continuación:

En lldb , seleccione el marco de stack para objc_exception_throw y luego ingrese este comando:

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

en nuevos simuladores (iOS 8, 64 bits) xcode 6 im usando en el marco de excepción: objc_exception_throw

 po $rax 

en 32 bits:

 po $eax 

¿Qué es rax?

Rax es un registro de 64 bits que reemplaza el viejo eax

¿Cómo encontrar todos los registros?

 register read 

Fuente wikipedia

En el momento de escribir esto, esta publicación es mi principal éxito de Google para: lldb print exception . Por lo tanto, estoy agregando esta respuesta a la cuenta para lldb y x86_64.

Mis bashs de encontrar la excepción usando po $eax fallaron con el error: Couldn't materialize struct: Couldn't read eax (materialize) . Otros bashs descritos en documentos vinculados de respuestas anteriores también fallaron.

La clave fue que primero tuve que hacer clic en el marco objc_exception_throw en mi hilo principal. lldb no comienza en ese marco.

En todos mis ejemplos de búsqueda y siguientes, esta entrada de blog fue la primera en explicar las cosas de una manera que funcionó para mí. Es más moderno, publicado en agosto de 2012.

Si tiene una statement de captura, coloque un punto de interrupción allí y puede inspeccionar el objeto de excepción en ese punto.

Si no tiene una statement catch, continúe.

Recibirás un mensaje en tu terminal así:

Aplicación de terminación debido a excepción no detectada ‘NSInvalidArgumentException’, razón: ‘ * – [__ NSPlaceholderDictionary initWithObjects: forKeys: count:]: bash de insertar nil object desde objetos [0]’

Sin embargo , probablemente esté buscando una forma de inspeccionarlo sin continuar, ya que perderá su buen seguimiento de la stack cuando finalice la aplicación.

Para eso, parece que la respuesta de Fnord es la mejor, pero no pude hacerlo funcionar en LLDB.