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

140

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

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

Dans iOS 4, j'obtiens une trace de pile utile de nombres hexadécimaux. Mais dans iOS 5, cela 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.

cekisakurek
la source

Réponses:

256

Rien de ce que j'ai essayé ne résoudrait cela (j'ai essayé les deux compilateurs, les deux débogueurs, etc.) Après la mise à niveau de XCode pour la mise à jour iOS 5, aucune trace de pile ne semblait fonctionner.

Cependant, j'ai trouvé une solution efficace: créer mon propre gestionnaire d'exceptions (ce qui est également utile pour d'autres raisons). Tout d'abord, créez une fonction qui gérera l'erreur et la sortira sur 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'exceptions à votre délégué d'application:

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

C'est tout!

Si cela ne fonctionne pas, il n'y a que deux raisons possibles :

  1. Quelque chose écrase votre NSSetUncaughtExceptionHandlerappel (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 uncaughtExceptionHandler. Alors, essayez de le définir à la FIN de votre didFinishLaunchingWithOptionsfonction (ou de désactiver sélectivement les bibliothèques tierces). Ou mieux encore, définissez un point de rupture symbolique NSSetUncaughtExceptionHandlerpour voir rapidement qui l'appelle. Ce que vous voudrez peut-être faire est de modifier votre version actuelle plutôt que d'en ajouter une autre.
  2. Vous ne rencontrez pas réellement d'exception (par exemple, ce EXC_BAD_ACCESSn'est pas une exception; merci aux commentaires de @Erik B, ci-dessous)
Zane Claes
la source
1
Content de l'entendre :) Je trouve utile d'écrire le journal des plantages dans un fichier et d'inviter l'utilisateur à le soumettre au prochain lancement (en mode release uniquement, pour ne pas gêner le débogage). Cela me permet d'obtenir d'excellents rapports de bogues ... et les utilisateurs savent que leur problème est en train d'être résolu :)
Zane Claes
2
Cela ne semble pas fonctionner - la uncaughtExceptionHandlerroutine n'est jamais invoquée.
Hot Licks
1
Pouvez-vous être plus précis sur la façon de l'utiliser? Cela ne semble pas fonctionner pour moi.
Danut Pralea
1
Assez triste xCode ne l'affiche pas pour nous.
Authman Apatira
1
Très appréciée! Il est déconcertant qu'Apple n'implémente pas ce type de fonctionnalité rudimentaire dans l'EDI.
devios1
110

Il existe une option utile pour ajouter un point d'arrêt d'exception (en utilisant le + en bas du navigateur de point d'arrêt). Cela cassera sur 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 l'ai finalement remarqué 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 navigateur de débogage pour parcourir la pile d'appels, examiner les variables, etc. comme d'habitude.

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

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

(etc)

WiseVieux Canard
la source
3
Cela fonctionne parfaitement pour moi jusqu'à présent. Le débogueur s'arrête maintenant sur la ligne en panne, pas besoin de la trace arrière.
Tim
1
Cela fonctionne parfaitement pour moi aussi. Merci beaucoup, je devenais fou sans ce point d'arrêt ...
William Denniss
+1 pour cela a fonctionné. Cela ne vous donne pas un si beau message d'erreur expliquant la raison de l'exception, mais c'est un début ...
Nicu Surdu
tu es mon HotD @WiseOldDuck.
Maverick
Cela rétablit le comportement attendu pour moi. REMARQUE: n'oubliez pas de rajouter ce point d'arrêt sur les nouveaux projets!
MechEthan
46

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 produisait sur 4.0.

Sur le "Breakpoint Navigator", ajoutez un "Exception Breakpoint" et appuyez simplement sur "Done" dans la fenêtre des options.

C'est tout!

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

Pedro
la source
C'est définitivement la solution pour moi.
bradgonesurfing
C'était le problème pour moi. Un collègue et moi partageons le même projet Xcode et je lui ai demandé s'il avait le problème, et ce n'était pas le cas. La différence était que son projet cassait sur les exceptions objective-c (objc_exception_throw)
horseshoe7
Vous venez d'aider à trouver un bogue introuvable. Merci beaucoup. J'ai cherché partout pour quelque chose comme cela.
rjgonzo
1
Ça fonctionne super bien! C'était exactement ce que je cherchais, c'est mieux que d'ajouter le gestionnaire d'exceptions car l'ajout du point d'arrêt peut vous emmener là où l'exception a été levée, le gestionnaire d'exceptions fonctionne mais vous donne juste une idée.
im8bit
21

Voici une autre solution, pas aussi élégante que la précédente, mais si vous n'avez pas ajouté de points d'arrêt ou de gestionnaires d'exception, cela ne peut être qu'une solution.
Lorsque l'application tombe en panne et que vous obtenez votre première pile d'appels bruts (en nombres hexadécimaux), tapez dans la console Xcode info line *hex(n'oubliez pas les 0xspécificateurs étoile et hexadécimal), 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 une sortie similaire.

Avec cette méthode, vous pouvez passer du haut de la pile de jet (il y aura environ 5 à 7 propagateurs d'exceptions système) jusqu'à votre fonction qui a causé un plantage, et déterminer le fichier exact et la ligne de code.

De plus, 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, vous avez des symboles de débogage). Cette méthode est plus préférable, car vous n'avez pas pour chaque appel d'adresse info line, copiez simplement les adresses de la sortie de la console et collez-les dans le terminal.

Alexandre
la source
9

Vous pouvez ajouter un point d' arrêt d'exception (en utilisant le + en bas du navigateur de point d'arrêt) et y 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 affichera la trace de la pile dès qu'une exception est levée.

MonsieurDart
la source
6

C'est un problème courant, ne pas obtenir de traces de pile dans 4.2. Vous pouvez essayer de permuter entre LLDB et GDB pour voir si vous obtenez de meilleurs résultats.

Déposez un rapport de bogue ici.

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

ÉDITER:

Je crois que si vous revenez à LLVM GCC 4.2, vous ne verrez pas cela se produire. Cependant, vous risquez de perdre les fonctionnalités dont vous avez besoin.

logancautrell
la source
oui j'ai essayé de changer de compilateur, mais le problème demeure. mais merci quand même :)
cekisakurek
Il a suggéré de changer de débogueur, pas de compilateurs.
bames53
1
FYI: Dans ce cas, cela n'a rien à voir avec la version du compilateur ou du débogueur que vous utilisez. Il s'agit d'un changement dans la sortie de la console depuis iOS.
clarkcox3
Intéressant combien les expériences de cela varient - je pense qu'il y a quelques problèmes. Je n'ai pas pu arrêter le débogueur sur le point d'arrêt d'exception. Le passage de GDB à LLDB a résolu le problème.
Matt
6

Utilisez ce code dans votre fonction principale:

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
la source
Cela ne semble pas fonctionner avec les storyboards. 2012-06-04 20: 34: 52.211 Problèmes [1944: 207] Le délégué d'application doit implémenter la propriété window s'il veut utiliser un fichier de storyboard principal. 2012-06-04 20: 34: 52.213 Problèmes [1944: 207] Les applications devraient avoir un contrôleur de vue racine à la fin du lancement de l'application
macasas
6

Au type d'invite de la console de débogage de Xcode:

image lookup -a 0x1234

Et cela vous montrera quelque chose comme:

  Address: MyApp[0x00018eb0] (MyApp.__TEXT.__text + 91088)
  Summary: MyApp`-[MyViewController viewDidAppear:] + 192 at MyViewController.m:202
Matt Connolly
la source
Merci, je cherchais vraiment ça. Étonnamment, il n'y a pas de raccourci pour afficher toute la "première pile d'appels de lancement" sous forme de pile d'appels, car je suppose qu'un script Python lldb peut être facilement écrit.
Ilya
1

Réactiver 'Compile for Thumb' (configuration de débogage) a fonctionné pour moi.

Bradweiser86
la source