2009-07-29 6 views
5

Mon programme:Pourquoi DTrace me donne-t-il parfois des erreurs d'adresse invalide, mais pas toujours?

typedef struct objc_class { 
    struct objc_class *isa; 
    struct objc_class *super_class; 
    char *name; 
    long version; 
    long info; 
    long instance_size; 
    void *ivars; 
    void *methodLists; 
    void *cache; 
    void *protocols; 
} *Class; 
struct objc_object { 
    Class isa; 
}; 

/* Code to extract the class name from arg0 based on a snippet by Bill Bumgarner: http://friday.com/bbum/2008/01/26/objective-c-printing-class-name-from-dtrace/ */ 

objc$target:NSObject:-init:entry { 
    printf("time: %llu\n", timestamp); 
    printf("arg0: %p\n", arg0); 
    obj = (struct objc_object *)copyin(arg0, sizeof(struct objc_object)); 
    printf("obj: %p\n", obj); 
    printf("obj->isa: %p\n", obj->isa); 
    isa = (Class)copyin((user_addr_t)obj->isa, sizeof(struct objc_class)); 
    printf("isa: %p\n", obj->isa); 
    classname = copyinstr((user_addr_t)(isa->name)); 
    printf("classname: %s\n", classname); 
} 

Quelques sortie:

dtrace: script 'test.d' matched 1 probe 
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28 
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28 
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28 
CPU  ID     FUNCTION:NAME 
    0 61630      -init:entry time: 28391086668386 
arg0: 1291ae10 
obj: 6f0a1158 
obj->isa: a023f360 
isa: a023f360 
classname: NSBitmapImageRep 

    1 61630      -init:entry time: 28391586872297 
arg0: 12943560 
obj: 6f4a1158 
obj->isa: 2fca0 
isa: 2fca0 
classname: GrowlApplicationTicket 

    1 61630      -init:entry time: 28391586897807 
arg0: 152060 
obj: 6f4a1280 
obj->isa: 2fe20 
isa: 2fe20 
classname: GrowlNotificationTicket 

    2 61630      -init:entry time: 28391079142905 
arg0: 129482d0 
obj: 700a1128 
obj->isa: a0014140 
isa: a0014140 
classname: NSDistributedObjectsStatistics 

    2 61630      -init:entry time: 28391079252640 
arg0: 147840 
obj: 700a1250 
obj->isa: a0014780 
isa: a0014780 
classname: NSDistantObjectTableEntry 

Pourquoi les erreurs? Il semble être le nom de classe (c'est le seul %s, et je ne reçois aucune erreur si je l'enlève), mais pourquoi pense-t-il que les noms de certaines classes sont des pointeurs invalides?

Y at-il un moyen d'obtenir les messages d'erreur pour me dire quelle ligne de mon programme DTrace a causé un problème?

Existe-t-il un moyen d'appeler object_getClassName au lieu de faire cette danse de structure-inspection?

Pour ce que ça vaut, le programme que je trace fonctionne très bien, il ne plante pas, donc je ne crois pas que les classes soient vraiment cassées.

Répondre

0

C'est ma meilleure estimation sur la base des informations fournies. DTrace a été délibérément conçu de manière à rendre les scripts DTrace aussi déterministes que possible. C'est pourquoi il n'y a pas de if instructions, boucles, sous-programmes (autres que les pseudo-sous-routines fournies par DTrace lui-même), etc. Le code de votre script DTrace s'exécute en mode noyau, pas par user-land dans le processus (es) en cours de traçage. En général, l'information à laquelle DTrace a accès est "en lecture seule" (comme la plupart des généralisations, ce n'est pas vrai), être capable de tourner des bits dans les programmes, ou le noyau, avec quelque chose d'aussi puissant que DTrace. très, très mal, très très rapidement.

Dollars aux beignets, le problème que vous rencontrez est dû au fait que la page vers laquelle pointe le pointeur n'est pas mappée au cœur par le système VM. DTrace peut seulement examiner les informations de la mémoire qui est dans le noyau - il ne peut pas double-faute pour obtenir le système VM à charger dans la page.

Vous pouvez probablement aider à résoudre le problème si vous avez une idée de ce que les classes "devraient" être et forcer les pages à être mappés dans le noyau en faisant un tas d'instructions NSLog() factice qui référencent le nécessaire les cours à un moment opportun au début de vos programmes démarrent.

+0

J'avais une pensée à ce sujet hier soir. La conception de DTrace réduit au minimum la quantité de 'code' qui est exécutée dans le noyau et aussi 'sûre' que possible. La résolution de nom de symbole se produit en dehors du noyau. Le noyau enregistre uniquement l'adresse dans le tampon, un programme externe se traduit par quelque chose de lisible après le fait. L'idée était pourquoi ne pas ajouter la résolution de nom de classe ObjC à l'une de ces activités "en dehors du noyau"? Cela pourrait valoir un peu d'enquête pour voir si c'est faisable, et ensuite un rapport de bogue RFE à Apple. – johne

2

Je ne l'ai pas entièrement retrouvé moi-même. Il est possible que DTrace essaie de résoudre certains symboles Objective-C. Bien que DTrace soit un outil de traçage dynamique, il ne s'harmonise pas avec Objective-C en chargeant dynamiquement des choses à l'exécution. Quand Objective-C charge de nouvelles classes, etc. DTrace doit résoudre ce problème et cela prend un peu de temps, surtout lorsque votre application démarre. Même si les objets sont chargés, et que votre application objc charge encore de nouvelles classes sur le runtime d'objc, son DTrace possible pourrait être foiré et imprimer les méthodes dans le mauvais ordre (si vous voulez voir les bonnes méthodes de commande s'exécuter) , imprime des résultats de synchronisation incorrects, etc.

5

Colin est assez proche de corriger.

Voir:

http://www.friday.com/bbum/2008/01/03/objective-c-using-dtrace-to-trace-messages-to-nil/

Plus probable qu'improbable, vous devez définir la variable d'environnement DYLD_SHARED_REGION à avoid. dtrace ne fonctionne vraiment que contre la mémoire mappée qui réside réellement dans la mémoire physique.

Vous pouvez déterminer ce qui manque en utilisant l'outil de ligne de commande vmmap.

Effectuez un vmmap PID sur votre application après la génération des messages d'échec ci-dessus. En regardant la sortie, voir dans quelle région se trouvent les adresses comme 0x90206b98. Compte tenu de cette adresse, il est probable que dans un fragment de mémoire partagé non inscriptible qui n'est probablement pas résident et, par conséquent, dtrace ne peut pas en lire.

3

Cette erreur se produit lorsque copyin/copyinstr est utilisé sur une page qui n'est pas encore en défaut. Une solution de contournement commune consiste à laisser la fonction utiliser les données en question, puis copyin [str] dans une clause de retour :: ::. Par exemple:

syscall::open:entry 
{ 
    self->filename = arg0; /* Hang on to the file name pointer. */ 
} 

syscall::open:return 
/self->filename/ 
{ 
    @files[copyinstr(self->filename)] = count(); 
    self->filename = 0; 
} 

END 
{ 
    trunc(@files, 5); 
}