Le fournisseur pid vous permet de suivre toutes les instructions d'un processus. Contrairement à la plupart des autres fournisseurs, les sondes pid sont créées à la demande en fonction des descriptions de sonde figurant dans vos programmes en D. En conséquence, aucune sonde pid n'est répertoriée dans la sortie de dtrace -l tant que vous ne les activez pas vous-même.
Le mode de fonctionnement le plus simple du fournisseur pid est, tout comme l'espace utilisateur, analogue au fournisseur fbt. L'exemple de programme suivant suit toutes les entrées et tous les renvois de fonction effectués à partir d'une fonction simple. La variable de macro $1 (le premier opérande sur la ligne de commande) correspond à l'ID de processus du processus à suivre. La variable de macro $2 (le second opérande sur la ligne de commande) correspond au nom de la fonction à partir de laquelle les appels de fonction doivent être suivis.
pid$1::$2:entry { self->trace = 1; } pid$1::$2:return /self->trace/ { self->trace = 0; } pid$1:::entry, pid$1:::return /self->trace/ { }
Saisissez l'exemple de script ci-dessus et enregistrez-le dans le fichier userfunc.d, puis appliquez-lui la commande chmod pour le rendre exécutable. Ce script engendre une sortie similaire à l'exemple suivant :
# ./userfunc.d 15032 execute dtrace: script './userfunc.d' matched 11594 probes 0 -> execute 0 -> execute 0 -> Dfix 0 <- Dfix 0 -> s_strsave 0 -> malloc 0 <- malloc 0 <- s_strsave 0 -> set 0 -> malloc 0 <- malloc 0 <- set 0 -> set1 0 -> tglob 0 <- tglob 0 <- set1 0 -> setq 0 -> s_strcmp 0 <- s_strcmp ... |
Vous ne pouvez utiliser le fournisseur pid que sur les processus dont l'exécution est déjà en cours. Vous pouvez utiliser la variable de macro $target (reportez-vous au Chapitre15Scripts) et les options dtrace -c et -p pour créer et extraire les processus qui vous intéressent, puis les instrumenter à l'aide de DTrace. Par exemple, vous pouvez utiliser l'exemple de script en D suivant pour déterminer la répartition des appels de fonction exécutés vers libc par un processus sujet particulier :
pid$target:libc.so::entry { @[probefunc] = count(); }
Pour déterminer la répartition des appels exécutés par la commande date(1), enregistrez le script dans le fichier libc.d et exécutez la commande suivante :
# dtrace -s libc.d -c date dtrace: script 'libc.d' matched 2476 probes Fri Jul 30 14:08:54 PDT 2004 dtrace: pid 109196 has exited pthread_rwlock_unlock 1 _fflush_u 1 rwlock_lock 1 rw_write_held 1 strftime 1 _close 1 _read 1 __open 1 _open 1 strstr 1 load_zoneinfo 1 ... _ti_bind_guard 47 _ti_bind_clear 94 |
Vous pouvez utiliser le fournisseur pid pour suivre une instruction dans une fonction utilisateur. Le fournisseur pid crée une sonde à la demande pour chaque instruction d'une fonction. Le nom de chaque sonde correspond au décalage de l'instruction correspondante dans la fonction exprimée sous la forme d'un entier hexadécimal. Par exemple, pour activer une sonde associée à l'instruction au niveau du décalage 0x1c dans la fonction foo du module bar.so dans le processus avec PID 123, vous pouvez utiliser la commande suivante :
# dtrace -n pid123:bar.so:foo:1c |
Pour activer toutes les sondes de la fonction foo, y compris la sonde de chaque instruction, vous pouvez utiliser la commande :
# dtrace -n pid123:bar.so:foo: |
Cette commande fait preuve d'une technique extrêmement puissante de débogage et d'analyse des applications utilisateur. Il peut s'avérer difficile de déboguer les erreurs peu fréquentes car elles peuvent être difficiles à reproduire. En règle générale, vous pouvez identifier un problème après l'apparition de la défaillance, soit trop tard pour reconstruire le chemin d'accès au code. L'exemple suivant montre la méthode de combinaison du fournisseur pid avec le suivi spéculatif (reportez-vous au Chapitre13Suivi spéculatif) pour résoudre ce problème en suivant chaque instruction d'une fonction.
pid$1::$2:entry { self->spec = speculation(); speculate(self->spec); printf("%x %x %x %x %x", arg0, arg1, arg2, arg3, arg4); } pid$1::$2: /self->spec/ { speculate(self->spec); } pid$1::$2:return /self->spec && arg1 == 0/ { discard(self->spec); self->spec = 0; } pid$1::$2:return /self->spec && arg1 != 0/ { commit(self->spec); self->spec = 0; }
L'exécution de errorpath.d produit une sortie similaire à l'exemple suivant :
# ./errorpath.d 100461 _chdir dtrace: script './errorpath.d' matched 19 probes CPU ID FUNCTION:NAME 0 25253 _chdir:entry 81e08 6d140 ffbfcb20 656c73 0 0 25253 _chdir:entry 0 25269 _chdir:0 0 25270 _chdir:4 0 25271 _chdir:8 0 25272 _chdir:c 0 25273 _chdir:10 0 25274 _chdir:14 0 25275 _chdir:18 0 25276 _chdir:1c 0 25277 _chdir:20 0 25278 _chdir:24 0 25279 _chdir:28 0 25280 _chdir:2c 0 25268 _chdir:return |