La depuración de Xcode 4.2 no simboliza la llamada de la pila

140

Tengo un problema con la depuración de Xcode 4.2 en un simulador / dispositivo iOS 5. El siguiente código se bloquea, como se esperaba:

NSArray *arr=[NSArray array];
[arr objectAtIndex:100];

En iOS 4, obtengo un útil seguimiento de la pila de números hexadecimales. Pero en iOS 5, solo me da:

*** First throw call stack:
(0x16b4052 0x1845d0a 0x16a0674 0x294c 0x6f89d6 0x6f98a6 0x708743 0x7091f8 0x7fcaa9 0x2257fa9 0x16881c5 0x15ed022 0x15eb90a 0x15eadb4 0x15eaccb 0x6f02a7 0x6faa93 0x2889 0x2805)

Gracias.

cekisakurek
fuente

Respuestas:

256

Nada de lo que probé solucionaría esto (probé ambos compiladores, ambos depuradores, etc.) Después de actualizar XCode para la actualización de iOS 5, no parecía funcionar ningún seguimiento de la pila.

Sin embargo, he encontrado una solución eficaz: crear mi propio controlador de excepciones (que también es útil por otros motivos). Primero, cree una función que maneje el error y lo envíe a la consola (así como cualquier otra cosa que desee hacer con él):

void uncaughtExceptionHandler(NSException *exception) {
    NSLog(@"CRASH: %@", exception);
    NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    // Internal error reporting
}

A continuación, agregue el controlador de excepciones a su delegado de aplicaciones:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
    // Normal launch stuff
}

¡Eso es!

Si esto no funciona, solo hay dos posibles razones :

  1. Algo está sobrescribiendo su NSSetUncaughtExceptionHandlerllamada (solo puede haber un controlador para toda su aplicación). Por ejemplo, algunas bibliotecas de terceros establecen su propio UncaughtExceptionHandler. Por lo tanto, intente configurarlo al final de su didFinishLaunchingWithOptionsfunción (o deshabilite selectivamente las bibliotecas de terceros). O mejor aún, establezca un punto de interrupción simbólico NSSetUncaughtExceptionHandlerpara ver rápidamente quién lo está llamando. Lo que puede hacer es modificar su actual en lugar de agregar otro.
  2. En realidad no estás encontrando una excepción (por ejemplo, noEXC_BAD_ACCESS es una excepción; crédito a los comentarios de @Erik B, a continuación)
Zane Claes
fuente
1
Me alegra escucharlo :) Me parece útil escribir el registro de fallas en un archivo y pedirle al usuario que lo envíe en el próximo lanzamiento (solo en modo de lanzamiento, para no interferir en la depuración). Esto me permite obtener excelentes informes de errores ... y los usuarios saben que su problema se está solucionando :)
Zane Claes
2
Esto no parece funcionar: la uncaughtExceptionHandlerrutina nunca se invoca.
Hot Licks
1
¿Puede ser más específico sobre cómo usarlo? No parece funcionar para mí.
Danut Pralea
1
Bastante triste xCode no nos muestra esto.
Authman Apatira
1
¡Muy apreciado! Es desconcertante que Apple no implemente este tipo de funcionalidad rudimentaria en el IDE.
devios1
110

Hay una opción útil para agregar un punto de interrupción de excepción (usando el + en la parte inferior del navegador de punto de interrupción). Esto se romperá en cualquier Excepción (o puede establecer condiciones). No sé si esta opción es nueva en 4.2 o si finalmente me di cuenta de que estaba tratando de solucionar el problema de los símbolos faltantes.

Una vez que llegue a este punto de interrupción, puede usar el navegador de depuración para navegar por la pila de llamadas, examinar variables, etc., como de costumbre.

Si desea una pila de llamadas simbolizadas adecuada para copiar / pegar o similares, la traza inversa de gdb funcionará bien desde allí:

(gdb) bt
#0  0x01f84cf0 in objc_exception_throw ()
#1  0x019efced in -[NSObject doesNotRecognizeSelector:] ()

(etc.)

WiseOldDuck
fuente
3
Esto funciona perfectamente para mí hasta ahora. El depurador se detiene en la línea de bloqueo ahora, sin necesidad de retroceder.
Tim
1
Esto también funciona perfectamente para mí. Muchas gracias, me estaba volviendo loco sin este punto de quiebre ...
William Denniss
+1 porque funcionó. No le da un mensaje de error tan agradable que explique el motivo de la excepción, pero es un comienzo ...
Nicu Surdu
eres mi HotD @WiseOldDuck.
Maverick1st
Esto restaura el comportamiento esperado para mí. NOTA: ¡Recuerde también volver a agregar este punto de interrupción en nuevos proyectos!
MechEthan
46

Hay una nueva característica en el depurador. Puede establecer un punto de interrupción cada vez que se produce una excepción y detener la ejecución allí, tal como solía ocurrir en 4.0.

En el "Navegador de punto de interrupción", agregue un "Punto de interrupción de excepción" y simplemente presione "Listo" en la ventana emergente de opciones.

¡Eso es todo!

PD: En algunos casos sería mejor romper solo para excepciones de Objective-C.

Pedro
fuente
Definitivamente esta es la solución para mí.
bradgonesurfing 03 de
Este fue el problema para mí. Un colega y yo compartimos el mismo proyecto Xcode y le pregunté si tenía el problema, y ​​no. La diferencia era que su proyecto se estaba rompiendo en excepciones del objetivo c (objc_exception_throw)
horseshoe7
Acabas de ayudar a encontrar un error imposible de rastrear. Muchas gracias. He estado buscando por todas partes algo como esto.
rjgonzo
1
Esto funciona como un encanto! Eso era exactamente lo que estaba buscando, esto es mejor que agregar el controlador de excepciones, ya que agregar el punto de interrupción puede llevarlo a donde se produjo la excepción, el controlador de excepciones funciona pero solo le da una idea.
im8bit
21

Aquí hay una solución más, no tan elegante como la anterior, pero si no agregó puntos de interrupción o controladores de excepción, puede ser solo un camino a seguir.
Cuando la aplicación se bloquea y obtiene su pila de llamadas de primer lanzamiento sin procesar (en números hexadecimales), escriba en la consola Xcode info line *hex(no olvide el 0xespecificador de estrella y hexadecimal), por ejemplo:

(gdb) info line *0x2658
Line 15 of "path/to/file/main.m" starts at address 0x25f2 <main+50>
and ends at 0x267e <main+190>.

Si está utilizando lldb , puede escribirimage lookup -a hex (sin en esta situación) y obtendrá un resultado similar.

Con este método, puede atravesar desde la parte superior de la pila de lanzamiento (habrá aproximadamente 5-7 propagadores de excepción del sistema) a su función que causó un bloqueo, y determinar el archivo y la línea de código exactos.

Además, para un efecto similar, puede usar la utilidad atos en la terminal, simplemente escriba:

atos -o path/to/AplicationBundle.app/Executable 0xAdress1 0xAdress2 0xAdress3 ...

y obtiene un seguimiento de pila simbolizado (al menos para las funciones que tiene símbolos de depuración). Este método es más preferible, ya que no tiene para cada llamada de dirección info line, simplemente copie las direcciones de la salida de la consola y péguelas en la terminal.

Alejandro
fuente
9

Puede agregar un punto de interrupción de excepción (usando el + en la parte inferior del navegador del punto de interrupción) y agregarle la acción bt (haga clic en el botón Agregar acción, seleccione Comando del depurador, ingrese "bt" en el campo de texto). Esto mostrará el seguimiento de la pila tan pronto como se produzca una excepción.

MonsieurDart
fuente
6

Este es un problema común, no obtener rastros de pila en 4.2. Puede intentar cambiar entre LLDB y GDB para ver si obtiene mejores resultados.

Presente un informe de error aquí.

http://developer.apple.com/bugreporter/

EDITAR:

Creo que si vuelve a cambiar a LLVM GCC 4.2, no verá que esto suceda. Sin embargo, puede perder las características que necesita.

logancautrell
fuente
Sí, intenté cambiar los compiladores, sin embargo, el problema persiste. pero gracias de todos modos :)
cekisakurek
Sugirió cambiar los depuradores, no los compiladores.
bames53
1
FYI: en este caso, no tiene nada que ver con la versión del compilador o depurador que está utilizando. Este es un cambio en la salida de la consola desde iOS.
clarkcox3
Interesante cuánto varían las experiencias de esto: creo que hay algunos problemas. No pude hacer que el depurador se detuviera en el punto de interrupción de excepción. Cambiar de GDB a LLDB resolvió el problema.
Matt
6

Use este código en su función principal:

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    int retVal;
    @try {
        retVal = UIApplicationMain(argc, argv, nil, nil);
    }
    @catch (NSException *exception) {
        NSLog(@"CRASH: %@", exception);
        NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    }
    @finally {
        [pool release];
    }
    return retVal;
}
wilson lin
fuente
Esto no parece funcionar con guiones gráficos. 2012-06-04 20: 34: 52.211 Problemas [1944: 207] El delegado de la aplicación debe implementar la propiedad de ventana si desea utilizar un archivo principal de guión gráfico. 2012-06-04 20: 34: 52.213 Problemas [1944: 207] Se espera que las aplicaciones tengan un controlador de vista raíz al final del lanzamiento de la aplicación
macasas
6

En el indicador de consola de depuración de Xcode, escriba:

image lookup -a 0x1234

Y te mostrará algo como:

  Address: MyApp[0x00018eb0] (MyApp.__TEXT.__text + 91088)
  Summary: MyApp`-[MyViewController viewDidAppear:] + 192 at MyViewController.m:202
Matt Connolly
fuente
Gracias, realmente estaba buscando esto. Sorprendentemente, no hay un atajo para mostrar toda la "pila de llamadas de primer lanzamiento" como una pila de llamadas, ya que supongo que un script Python lldb se puede escribir fácilmente.
Ilya
1

Activar 'Compilar para Thumb' nuevamente (configuración de depuración) funcionó para mí.

Bradweiser86
fuente