web-dev-qa-db-fra.com

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

J'ai un problème avec le débogage 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, je reçois une trace de pile utile de nombres hexadécimaux. Mais dans iOS 5, cela me donne simplement:

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

Merci.

140
cekisakurek

Rien de ce que j'ai essayé ne résoudrait ce problème (essayé avec 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é un moyen efficace de contourner le problème en créant mon propre gestionnaire d'exceptions (qui est également utile pour d'autres raisons). Tout d’abord, créez une fonction qui gérera l’erreur et la transmettra à la console (ainsi que tout ce que vous voulez faire avec):

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 ça!

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

  1. Quelque chose remplace votre appel 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 uncaughtExceptionHandler. Essayez donc de le définir à la fin de votre fonction didFinishLaunchingWithOptions (ou de désactiver sélectivement les bibliothèques tierces). Ou mieux encore, définissez un point de rupture symbolique sur NSSetUncaughtExceptionHandler pour voir rapidement qui l'appelle. Ce que vous voudrez peut-être faire, c'est modifier votre actuel plutôt que d'en ajouter un autre.
  2. Vous ne rencontrez pas réellement d'exception (par exemple, EXC_BAD_ACCESS est not une exception; crédit aux commentaires de @Erik B, ci-dessous)
255
Zane Claes

Il existe une option utile pour ajouter un point d'arrêt d'exception (à l'aide du signe + situé en bas du navigateur de point d'arrêt). Cela se cassera à n'importe quelle exception (ou vous pourrez définir des conditions). Je ne sais pas si ce choix est nouveau dans la version 4.2 ou si j'ai seulement finalement remarqué qu'il essayait de résoudre 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 symbolique appropriée pour copier/coller ou similaire, gdb backtrace fonctionnera parfaitement à partir de là:

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

(etc)

109
WiseOldDuck

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

Sur le "Navigateur de points d'arrêt", ajoutez un "Point d'arrêt d'exception" et appuyez simplement sur "Terminé" dans la fenêtre d'options.

C'est tout!

PS: Dans certains cas, il serait préférable d’interrompre uniquement les exceptions Objective-C.

46
Pedro

Voici une autre solution, moins élégante que la précédente, mais si vous n’ajoutez pas de points de contrôle ou de gestionnaires d’exception, il ne peut y avoir qu’une solution.
Lorsque l'application se bloque et que vous obtenez votre première pile d'appels brute (en nombres hexadécimaux), tapez dans la console Xcode info line *hex (n'oubliez pas star et 0x hex spécificateur), 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 parcourir du haut de la pile (il y aura environ 5 à 7 propagateurs d’exceptions système) jusqu’à votre fonction qui a provoqué un blocage et déterminer le fichier exact et la ligne de code.

En outre, pour un effet similaire, vous pouvez utiliser l'utilitaire atos dans un terminal, tapez simplement:

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

et vous obtenez une trace de pile symbolique (au moins pour les fonctions pour lesquelles vous avez des symboles de débogage). Cette méthode est préférable, car vous n'avez pas pour chaque adresse l'adresse info line, copiez simplement les adresses de la sortie de la console et collez-les dans le terminal.

21
Alexander

Vous pouvez ajouter un point d'arrêt d'exception (à l'aide du signe + en bas du navigateur de point d'arrêt) et ajouter l'actionbt (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.

9
MonsieurDart

À l'invite de la console de débogage de Xcode, tapez:

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
6
Matt Connolly

Ceci est un problème courant, ne pas obtenir les 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/

MODIFIER:

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

6
logancautrell

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;
}
6
wilson lin

L'activation de "Compiler pour le pouce" (configuration de débogage) a fonctionné pour moi.

1
Bradweiser86