¿Cómo imprime un seguimiento de pila en la consola / inicia sesión en Cocoa?

293

Me gustaría registrar el seguimiento de llamadas durante ciertos puntos, como aserciones fallidas o excepciones no detectadas.

robottobor
fuente

Respuestas:

544
 NSLog(@"%@",[NSThread callStackSymbols]);

Este código funciona en cualquier hilo.

smokris
fuente
14
Nuevo en Mac OS X 10.6, que no existía cuando se hizo originalmente esta pregunta. Para pre-Snow-Leopard, use las funciones backtracey backtrace_symbols; consulte la página de manual de traza inversa (3).
Peter Hosey
66
Solo en iOS 4.0 y superior.
Danra
¡Gracias! ¿Hay alguna manera de hacer que esto solo imprima el seguimiento de la pila, por ejemplo, 6 niveles hacia abajo en lugar de todo el camino?
sudo
9000, el uso backtrace/backtrace_symbolsdirecto
dymv
34

La respuesta de n13 no funcionó del todo: la modifiqué un poco para llegar a esto

#import <UIKit/UIKit.h>

#import "AppDelegate.h"

int main(int argc, char *argv[])
{
    @autoreleasepool {
        int retval;
        @try{
            retval = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
        @catch (NSException *exception)
        {
            NSLog(@"Gosh!!! %@", [exception callStackSymbols]);
            @throw;
        }
        return retval;
    }
}
Zayin Krige
fuente
44
Gah ... Apple debería hacer de esto un estándar al menos mientras desarrolla una aplicación. Un montón de direcciones de memoria es ... arcaico
Russ
Puse tus mejoras en mi respuesta; Hice esto antes de ARC. Gracias.
n13
1
Esto no funciona en todas las situaciones. Este es un mejor enfoque si desea detectar todas las excepciones no detectadas : codereview.stackexchange.com/questions/56162/… (El código en esa pregunta es un poco complicado, pero también hace más que simplemente registrar los símbolos de la pila de llamadas).
nhgrif
También puede agregar NSLog(@"[Error] - %@ %@", exception.name, exception.reason);si desea la excepción real
Corentin S.
9

Cocoa ya registra el seguimiento de la pila en excepciones no detectadas en la consola, aunque solo son direcciones de memoria sin procesar. Si desea información simbólica en la consola, hay algunos códigos de muestra de Apple.

Si desea generar un seguimiento de la pila en un punto arbitrario de su código (y está en Leopard), consulte la página del manual de seguimiento. Antes de Leopard, en realidad tenía que cavar a través de la pila de llamadas.

Vermont.
fuente
66
Aparentemente disponible en iOS 4 pero no 3.2. Esto es lo que usé, copiado descaradamente de la página de manual de seguimiento: #include <execinfo.h> ... void * callstack [128]; int i, frames = backtrace (callstack, 128); char ** strs = backtrace_symbols (callstack, frames); para (i = 0; i <cuadros; ++ i) {printf ("% s \ n", strs [i]); } libre (strs);
mharper
Al ser llamado en HandleException, vuelve a escribir el rastro de la función del controlador en sí, mientras que [NSException callStackSymbols] muestra la pila del lugar donde ha surgido la excepción. Pero si reemplaza "backtrace (...)" con: "NSArray arr = [ex callStackReturnAddresses]; int frames = arr.count; for (i = 0; i <frames; ++ i) callstack [i] = ( nulo) [((NSNumber *) [arr objectAtIndex: i]) intValue]; " obtendrá el seguimiento actual de la pila de excepciones. Así es como funciona [NSException callStackSymbols], supongo: las trazas que devuelven son iguales y en ambas llamadas a la aplicación se reemplazan por _mh_execute_header en la versión.
Tertium
6

Esto prácticamente te dice qué hacer.

Esencialmente, necesita configurar el manejo de excepciones de aplicaciones para iniciar sesión, algo como:

#import <ExceptionHandling/NSExceptionHandler.h>

[[NSExceptionHandler defaultExceptionHandler] 
                  setExceptionHandlingMask: NSLogUncaughtExceptionMask | 
                                            NSLogUncaughtSystemExceptionMask | 
                                            NSLogUncaughtRuntimeErrorMask]
Max Stewart
fuente
1
Tenga en cuenta, sin embargo, que esto solo funcionará dentro de un controlador de excepciones registrado (no, por ejemplo, en un bloque @catch)
Barry Wark
1

En impresión rápida de esta manera:

print("stack trace:\(Thread.callStackSymbols)")
Deepak
fuente