Comment imprimer une trace de pile sur la console / se connecter dans Cocoa?

293

J'aimerais enregistrer la trace des appels à certains moments, comme les assertions ayant échoué ou les exceptions non capturées.

robottobor
la source

Réponses:

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

Ce code fonctionne sur n'importe quel thread.

smokris
la source
14
Nouveau dans Mac OS X 10.6, qui n'existait pas lorsque cette question a été posée à l'origine. Pour pré-Snow-Leopard, utilisez les fonctions backtraceet backtrace_symbols; voir la page de manuel backtrace (3).
Peter Hosey
6
Uniquement sur iOS 4.0 et supérieur.
Danra
Merci! Existe-t-il un moyen pour que cela n'imprime que la trace de la pile, disons, 6 niveaux au lieu de tout le chemin?
sudo
9000, utilisez backtrace/backtrace_symbolsdirectement
dymv
34

la réponse de n13 n'a pas tout à fait fonctionné - je l'ai légèrement modifiée pour arriver à cette

#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
la source
4
Gah ... Apple devrait en faire une norme au moins lors du développement d'une application. Un tas d'adresses mémoire est ... archaïque
Russ
J'ai mis vos améliorations dans ma réponse; Je l'ai fait avant ARC. Merci.
n13
1
Cela ne fonctionne pas dans toutes les situations. C'est une meilleure approche si vous souhaitez intercepter toutes les exceptions non capturées : codereview.stackexchange.com/questions/56162/… (Le code dans cette question est un peu trop compliqué, mais il fait aussi plus que simplement enregistrer les symboles de la pile d'appels.)
nhgrif
Vous pouvez ajouter NSLog(@"[Error] - %@ %@", exception.name, exception.reason);si vous voulez aussi l'exception réelle
Corentin S.
9

Cocoa enregistre déjà la trace de la pile sur les exceptions non capturées de la console, bien qu'il ne s'agisse que d'adresses de mémoire brute. Si vous voulez des informations symboliques dans la console, il y a un exemple de code d'Apple.

Si vous souhaitez générer une trace de pile à un point arbitraire de votre code (et que vous êtes sur Leopard), consultez la page de manuel de backtrace. Avant Leopard, vous deviez réellement fouiller dans la pile d'appels elle-même.

Vermont.
la source
6
Apparemment disponible dans iOS 4 mais pas 3.2. Voici ce que j'ai utilisé, copié sans vergogne à partir de la page de manuel de backtrace: #include <execinfo.h> ... void * callstack [128]; int i, frames = backtrace (callstack, 128); char ** strs = backtrace_symbols (callstack, frames); for (i = 0; i <frames; ++ i) {printf ("% s \ n", strs [i]); } gratuit (strs);
mharper
Appelé dans HandleException, il réécrit la trace de la fonction de gestionnaire lui-même, tandis que [NSException callStackSymbols] affiche la pile de l'endroit où l'exception s'est déclenchée. Mais si vous remplacez "backtrace (...)" par: "NSArray arr = [ex callStackReturnAddresses]; int frames = arr.count; for (i = 0; i <frames; ++ i) callstack [i] = ( void) [((NSNumber *) [arr objectAtIndex: i]) intValue]; " vous obtiendrez la trace de la pile d'exceptions actuelle. Voici comment fonctionne [NSException callStackSymbols], je suppose: les traces qu'elles renvoient sont égales et dans les deux appels d'application sont remplacées par _mh_execute_header dans la version.
Tertium
6

Cela vous dit à peu près quoi faire.

Essentiellement, vous devez configurer la gestion des exceptions des applications pour vous connecter, quelque chose comme:

#import <ExceptionHandling/NSExceptionHandler.h>

[[NSExceptionHandler defaultExceptionHandler] 
                  setExceptionHandlingMask: NSLogUncaughtExceptionMask | 
                                            NSLogUncaughtSystemExceptionMask | 
                                            NSLogUncaughtRuntimeErrorMask]
Max Stewart
la source
1
Notez, cependant, que cela ne fonctionnera que dans un gestionnaire d'exceptions enregistré (pas, par exemple, dans un bloc @catch)
Barry Wark
1

En impression rapide de cette façon:

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