Stack Trace
zeus
Membre
Bonjour,
Je cherche désepérément comment on peut imprimer le stack trace dans une application.
Je m'explique je suis pas mal habitué à Java et dans ce language quand on a une erreur au runtime, on obtient, dans le terminal, la trace d'exécution qui a fait planter le programme.
Alors que là , quand j'ai des exceptions avec objective C, par exemple lorsque j'apelle une méthode qui n'existe pas, j'ai juste un message m'indiquant que sélecteur n'a pas été reconnu. Moi je voudrai bien que pour le même prix on me dise dans quelle classe, à quelle ligne l'exception a été levée et aussi quelles sont les méthodes qui on fait cet appel.
J'ai bien trouvé quelque chose à l'adresse http://www.cocoadev.com/index.pl?StackTraces mais je dois dire qu'il me faudrait plutôt un pas à pas, parceque les explications qui sont sur cette page restent assez mistérieuses pour moi (je suis incapable de comprendre, entre autre, où ajouter les bouts de code qui sont fournis).
Voila j'espère qu'une âme charitable pourra éclairer ma lanterne.
Merci d'avance.
Jérôme
Je cherche désepérément comment on peut imprimer le stack trace dans une application.
Je m'explique je suis pas mal habitué à Java et dans ce language quand on a une erreur au runtime, on obtient, dans le terminal, la trace d'exécution qui a fait planter le programme.
Alors que là , quand j'ai des exceptions avec objective C, par exemple lorsque j'apelle une méthode qui n'existe pas, j'ai juste un message m'indiquant que sélecteur n'a pas été reconnu. Moi je voudrai bien que pour le même prix on me dise dans quelle classe, à quelle ligne l'exception a été levée et aussi quelles sont les méthodes qui on fait cet appel.
J'ai bien trouvé quelque chose à l'adresse http://www.cocoadev.com/index.pl?StackTraces mais je dois dire qu'il me faudrait plutôt un pas à pas, parceque les explications qui sont sur cette page restent assez mistérieuses pour moi (je suis incapable de comprendre, entre autre, où ajouter les bouts de code qui sont fournis).
Voila j'espère qu'une âme charitable pourra éclairer ma lanterne.
Merci d'avance.
Jérôme
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
installHandle() pour l'installer à l'init de ton app
//
//
- (void)startStackTrace:(NSException*)exception
{
// http://www.cocoadev.com/index.pl?StackTraces //
NSLog(@"
startStackTrace
");
NSLog(@NAME %@",[exception name]);
NSLog(@REASON %@",[exception reason]);
NSString *stackTrace=[[exception userInfo] objectForKey:NSStackTraceKey];
if (stackTrace==nil)
return;
NSString *str=[NSString stringWithFormat:@/usr/bin/atos -p %d %@ | tail -n +3 | head -n +%d | c++filt | cat -n",
getpid(),
stackTrace,
([[stackTrace componentsSeparatedByString:@ ] count] - 4)];
FILE *F=popen([str UTF8String],"r");
if (F)
{
char buffer[512];
size_t length;
NSMutableString *ms=[NSMutableString string];
while(length=fread(buffer,1,sizeof(buffer),F))
{
[ms appendString:[NSString stringWithCString:buffer length:length]];
}
pclose(F);
NSArray *rows=[ms componentsSeparatedByString:@\n];
int i;
for (i=0;i<[rows count];i++)
NSLog(@%@",[rows objectAtIndex:i]);
}
NSLog(@"
");
}
- (BOOL)exceptionHandler:(NSExceptionHandler *)sender shouldHandleException:(NSException *)exception mask:(unsigned int)aMask
{
NSLog(@exceptionHandler\n\n);
NSLog(@sender %@",sender);
if (controlException)
[self startStackTrace:exception];
NSLog(@\n\nexceptionHandler);
if ([appController DEBUGMODE]==0)
[crashReport showCrashReport:NO];
return NO;
}
- (void)setControlException:(BOOL)v { controlException=v; }
- (void)installHandle
{
NSExceptionHandler *handler = [NSExceptionHandler defaultExceptionHandler];
[handler setExceptionHandlingMask:NSLogAndHandleEveryExceptionMask];
[handler setDelegate:self];
}
//
//
Jérôme
Là s'arrête la comparaison entre Java (tes anciennes habitudes de travail) et Obj-C (tes nouvelles).
Java est interprété et, de ce fait, possède une très forte relation entre byte-code et source qui a généré ce byte-code.
Obj-C est compilé, donc sans outil de debugging et environnement de test adapté, il n'y plus aucune relation entre le programme compilé et le source qui l'a créé.
Il est possible d'obtenir un stacktrace sur réception d'une exception, mais cela ne te donnera rien de plus que les adresses mémoire des différents appels antérieurs : c'est inutilisable.
.
Il donne surtout les objects et les methodes qu'ils ont appelés du main à l'exception ! Je trouve pas ça inutilisable !
Je suis d'accord avec toi, mais en utilisant la commande atos, qui est un outil externe...
Et qui dans certains cas de plantage sévère ne peut pas fonctionner.
.
-[TLLEntry _fastCStringContents:]: selector not recognized [self = 0x4d4a850]
Alors la grosse question qui se cache la derrière c'est: Je fais comment pour déverminer ce code? Parce que je ne sais pas qui à fait l'appel fautif, je peux pas vraiment déduire quelque chose de ce message d'erreur si ce n'est que, pour une raison qui m'est inconue, le runtime a décidé d'appeler une méthode sur un de mes objets qui n'existe pas. J'ai bien essayé de mettre des breakpoints avec GDB mais visiblement c'est une méthode qui est appelée par un quelconque élément graphique sur lequel je n'ai pas de pouvoir direct. Donc on fait comment dans ce cas, on plante des breakpoints au petit bonheur la chance pour espérer trouver la source de l'appel?
Ceci dit je n'ai toujours pas compris ou je devais mettre le code proposé par Supermic.
Jérôme
Dans Xcode, ajoute un fichier source source NSApplication.m. En fait, on ajoute une catégorie à NSApplication, qui permet de personnaliser la méthode reportException:. On a pas besoin d'un fichier header.
Dans ce fichier source, insère le code suivant :
Ensuite, insère un breakpoint sur la ligne [tt]NSlog[/tt] du fichier NSApplication.m.
Enfin, build-and-debug dans Xcode (menu Build > Build and Debug).
Normalement, GDB va s'arrêter sur ton point d'arrêt dès réception d'une exception, et dans la section Thread du debugger, tu n'as plus qu'à étudier les stack-frames...
.
J'explique: Histoire de voire la tête d'un stacktrace différent de celle de mon erreur j'ai mis une bonne grosse erreur dans mon code (j'ai releasé un objet et je l'ai utilisé ensuite). J'ai ensuite enlevé la bonne grosse erreur et là il n'y avait plus la petite erreur initiale non plus. Je vous met le run log pour prouver mes dire.
Bon alors merci encore une fois a Bru qui m'a magiquement sortit d'embaras.
Jérôme
[EDIT] je viens de re-essayer et pof l'erreur est de retour [/EDIT]
Que dit le stack-trace ?
.
Voila le résultat du stack trace. Autant dire que l'on en sait pas vraiment plus avant qu'après. Mais ce qui est le plus bizzarre c'est que vraiment cette erreur fait des vas et viens. Dès fois elle est là , je bricole deux truc dans le code puis je rétablis la version originale et pouf plus rien. Je me doute bien qu'il doit y avoir quelque chose qui change mais je sais vraiment pas quoi. J'ai bien sûr fait des cleans avant de compiler.
Jérôme
Cela signifie qu'à un moment donné, ton objet TLLEntry est pris pour une NSString...
Un tel cas apparait souvent lors d'un memory-leak.
Vérifie bien que toutes tes instances TLLEntry sont bien correctement "retain" et ne sont "dealloc" qu'au bon moment.
.
Ha Java tu me manques. Je suis définitivement perplexe au sujet de la gestion de la mémoire à la main.
Je suis trop crevé pour fouiller ça ce soir mais je m'y recolle demain (espérons que la nuit porte conseil).
Merci bien pour ton aide.
Je suis en plein java actuellement (développement de potlets pour un portail applicatif).
J'avoue que la gestion des objets où on ne se préoccupe pas de leur allocation mémoire est pratique.
Mais...
On est amené à manipuler des objets "lourds" dans des boucles... Et là , quand le garbage-collector se met en route, c'est la cata au niveau des performances de la JVM.
La gestion de la mémoire sous cocoa demande un peu plus de rigueur. Mais une fois le concept acquis, tu n'y penses plus (crois-moi sur parole !).
Bon courage pour la suite.
.
qui devrait être:
Bon dis comme ça, ça parrait évident, je considère que deux éléments sont égaux s'ils ont le même nom. Logiquement il faut donc demander le nom du paramètre anObject. Conclusion, le programmeur, donc moi, est un imbécil fini.
Là où je suis décu par Objective-C c'est que même un interceptant l'erreur j'ai jamais pu découvrir dans le stacktrace que l'erreur était initialement issue de la méthode . Alors que Objective-C soit faiblement typé et que je n'ai pas d'erreur à la compilation, soit, je fais avec, mais que je ne sois même pas capable de découvrir au runtime d'où sort mon erreur je trouve ça assez nul.
Au final je me demande si ma méthode du stacktrace est applicable à Objective-C? Vous auriez fais comment, vous, pour trouver cette erreur.
Jérôme
bon, ca va, je te charrie.
J'aurai très bien pu la faire et je l'ai certainement faite d'ailleurs.
Moi, je trouve qu'en général, les messages t'orientent pas trop mal.
Mais il est vrai que parfois...
Dans ces cas là , je fonctionne à l'ancienne, à savoir, NSLog + GDB avec des points d'arrêts.
Et quand je sèche, ObjectiveCocoa :P
Petite anecdote :
Concernant le debugger, dans le milieu de l'informatique, on dit souvent que les debugger sont faits pour les mauvais développeurs :-)
Bien sûr, c'est un peu exagéré ... Et je l'utilise assez souvent :-\\