140 votes

Le débogage de Xcode 4.2 ne symbolise pas l'appel de pile

J'ai un problème avec le débogage de Xcode 4.2 dans un simulateur/appareil iOS 5. Le code suivant se plante, comme prévu :

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

Dans iOS 4, j'obtiens une trace utile de la pile de chiffres hexadécimaux. Mais dans iOS 5, ça me donne juste :

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

Merci.

256voto

Zane Claes Points 4001

Rien de ce que j'ai essayé n'a pu résoudre ce problème (j'ai essayé les deux compilateurs, les deux débogueurs, etc.). Après avoir mis à jour XCode pour la mise à jour d'iOS 5, aucune trace de pile ne semble fonctionner.

Toutefois, j'ai trouvé une solution de contournement efficace : créer mon propre gestionnaire d'exceptions (qui est également utile pour d'autres raisons). Tout d'abord, créez une fonction qui traitera l'erreur et l'affichera dans la console (ainsi que tout ce que vous voulez en faire) :

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

Ensuite, ajoutez le gestionnaire d'exception au délégué de votre application :

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

C'est ça !

Si cela ne fonctionne pas, alors il y a seulement deux raisons possibles :

  1. Quelque chose écrase votre NSSetUncaughtExceptionHandler (il ne peut y avoir qu'un seul gestionnaire pour l'ensemble de votre application). Par exemple, certaines bibliothèques tierces définissent leur propre gestionnaire uncaughtExceptionHandler. Essayez donc de le définir à la FIN de votre fichier didFinishLaunchingWithOptions (ou la désactivation sélective de bibliothèques tierces). Ou mieux encore, définissez un point d'arrêt symbolique sur NSSetUncaughtExceptionHandler pour voir rapidement qui l'appelle. Ce que vous pouvez faire, c'est modifier votre système actuel plutôt que d'en ajouter un autre.
  2. Vous ne rencontrez pas réellement d'exception (par exemple, EXC_BAD_ACCESS es no une exception ; crédit aux commentaires de @Erik B, ci-dessous)

109voto

WiseOldDuck Points 1646

Il est possible d'ajouter un point d'arrêt d'exception (en utilisant le signe + en bas du navigateur de points d'arrêt). Cette option s'applique à toute exception (ou vous pouvez définir des conditions). Je ne sais pas si ce choix est nouveau dans la version 4.2 ou si je ne l'ai remarqué qu'en essayant de contourner le problème des symboles manquants.

Une fois que vous avez atteint ce point d'arrêt, vous pouvez utiliser le Debug Navigator pour naviguer dans la pile d'appels, examiner les variables, etc. comme d'habitude.

Si vous voulez une pile d'appels symboliques adaptée au copier/coller ou autre, le backtrace de gdb fonctionnera très bien à partir de là :

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

(etc)

46voto

Pedro Points 873

Il y a une nouvelle fonctionnalité sur le débogueur. Vous pouvez définir un point d'arrêt à chaque fois qu'une exception est levée et arrêter l'exécution à cet endroit, comme cela se passait dans la version 4.0.

Dans le "Breakpoint Navigator", ajoutez un "Exception Breakpoint" et cliquez simplement sur "Done" dans la fenêtre d'options.

C'est tout !

PS : Dans certains cas, il serait préférable de ne casser que les exceptions Objective-C.

21voto

goodfella Points 505

Voici une autre solution, moins élégante que la précédente, mais si vous n'avez pas ajouté de points d'arrêt ou de gestionnaires d'exception, c'est la seule solution possible.
Quand l'application se plante, et que vous obtenez vos données brutes premier lancer la pile d'appel (en chiffres hexagonaux), tapez dans la console Xcode info line *hex (n'oubliez pas l'étoile et 0x spécificateur hexagonal), par exemple :

(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 vous utilisez lldb vous pouvez taper image lookup -a hex (sans étoile dans cette situation), et vous obtenez un résultat similaire.

Avec cette méthode, vous pouvez remonter du haut de la pile de lancement (il y aura environ 5 à 7 propagateurs d'exceptions système) jusqu'à la fonction qui a provoqué le crash, et déterminer le fichier et la ligne de code exacts.

De même, pour un effet similaire, vous pouvez utiliser l'utilitaire atos dans le terminal, tapez simplement :

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

et vous obtenez une trace de pile symbolisée (au moins pour les fonctions pour lesquelles vous avez des symboles de débogage). Cette méthode est plus préférable, car vous n'avez pas, pour chaque appel à l'adresse info line il suffit de copier les adresses de la sortie de la console et de les coller dans le terminal.

9voto

MonsieurDart Points 3133

Vous pouvez ajouter un Point d'arrêt d'exception (en utilisant le + au bas du navigateur de points d'arrêt) et ajouter l'action bt (cliquez sur le bouton Ajouter une action, sélectionnez Commande du débogueur, entrez "bt" dans le champ de texte). Cela permettra d'afficher la trace de la pile dès qu'une exception est levée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X