Manuel de suivi dynamique Solaris

Chapitre 15 Scripts

Vous pouvez utiliser l'utilitaire dtrace(1M) pour créer des fichiers interpréteurs tirés de programmes en D similaires aux scripts de shell que vous pouvez installer en tant qu'outils DTrace interactifs réutilisables. Le compilateur D et la commande dtrace fournissent un ensemble de variables de macro étendues par le compilateur en D qui facilite la création de scripts à l'aide de DTrace. Ce chapitre fournit des informations de référence sur la fonction de variables de macro et des conseils sur la création de scripts persistants.

Fichiers interpréteurs

De même que votre shell et des utilitaires comme awk(1) et perl(1), vous pouvez utiliser dtrace(1M) pour créer des fichiers interpréteurs exécutables. Un fichier interpréteur commence par une ligne se présentant comme suit :

#! nom_chemin arg

pathname correspondant au chemin de l'interpréteur et arg à un argument en option simple. Lorsqu'un fichier interpréteur est exécuté, le système invoque l'interpréteur spécifié. Si arg a été spécifié dans le fichier interpréteur, il est transmis sous forme d'argument à l'interpréteur. Le chemin d'accès au fichier interpréteur lui-même, ainsi que tous les arguments supplémentaires spécifiés lors de son exécution sont ajoutés à la liste des arguments de l'interpréteur. Par conséquent, vous devrez toujours créer des fichiers interpréteurs DTrace à l'aide d'au moins les arguments suivants :

#!/usr/sbin/dtrace -s

Si votre fichier interpréteur est exécuté, l'argument à l'option - s sera donc le nom du chemin d'accès au fichier interpréteur lui-même. dtrace va ensuite lire, compiler et exécuter ce fichier comme si vous aviez tapé la commande suivante dans votre shell :


# dtrace -s interpreter-file

L'exemple suivant montre comment créer et exécuter un fichier interpréteur dtrace. Entrez le code source en langage D suivant et enregistrez-le dans le fichier interp.d :

#!/usr/sbin/dtrace -s
BEGIN
{
	trace("hello");
	exit(0);
}

Marquez le fichier interp.d comme exécutable et exécutez-le comme suit :


# chmod a+rx interp.d
# ./interp.d
dtrace: script './interp.d' matched 1 probe
CPU     ID                    FUNCTION:NAME
  1      1                           :BEGIN   hello
#

N'oubliez pas que la directive #! doit comprendre les deux premiers caractères de votre fichier sans espace intermédiaire ou précédent. Le compilateur D ignore automatiquement cette ligne lorsqu'il traite le fichier interpréteur.

dtrace utilise getopt(3C) pour traiter les options de ligne de commande de manière à vous permettre de combiner plusieurs options dans votre argument interpréteur unique. Par exemple, pour ajouter l'option -q à l'exemple précédent, vous pouvez modifier la directive de l'interpréteur comme suit :

#!/usr/sbin/dtrace -qs

Si vous spécifiez plusieurs lettres d'option, l'option -s doit toujours terminer la liste d'options booléennes de sorte que l'argument suivant (le nom du fichier interpréteur) soit traité comme un argument correspondant à l'option -s.

Si vous devez spécifier plus d'une option nécessitant un argument dans votre fichier interpréteur, vous ne pourrez pas intégrer toutes vos options et tous vos arguments dans l'argument interpréteur unique. Utilisez plutôt la syntaxe de directive #pragma D option pour définir vos options. Toutes les options de ligne de commande de dtrace possèdent un équivalent #pragma que vous pouvez utiliser, comme illustré dans le Chapitre16Options et paramètres réglables.

Variables de macro

Le compilateur D définit un ensemble de variables de macro que vous pouvez utiliser lors de l'écriture de programmes ou de fichiers interpréteurs en D. Les variables de macro sont des identificateurs précédés du préfixe $ et sont étendues une seule fois par le compilateur D lors du traitement de votre fichier d'entrée. Le compilateur D fournit les variables de macro suivantes :

Tableau 15–1 Variables de macro en D

Nom 

Description 

Texte de référence 

$[0-9]+

arguments de la macro 

Reportez-vous à la section Arguments de macro

$egid

ID groupe effectif 

getegid(2)

$euid

ID utilisateur effectif 

geteuid(2)

$gid

ID groupe réel 

getgid(2)

$pid

ID de processus 

getpid(2)

$pgid

ID groupe de processus 

getpgid(2)

$ppid

ID processus parent 

getppid(2)

$projid

ID projet 

getprojid(2)

$sid

ID session 

getsid(2)

$target

ID processus cible 

Reportez-vous à la section ID processus cible

$taskid

ID tâche 

gettaskid(2)

$uid

ID utilisateur réel 

getuid(2)

À l'exception de l'argument de macro $[0-9]+ et de la variable de macro $target, les variables de macro sont toutes étendues au nombre entier correspondant aux attributs du système comme l'ID de processus ou l'ID utilisateur. Les variables développent la valeur d'attribut associée au processus dtrace courant lui-même ou à n'importe quel processus en cours d'exécution par le compilateur D.

L'utilisation de variables de macro dans les fichiers interpréteurs vous permet de créer des programmes en D persistants que vous n'êtes pas contraint d'éditer à chaque fois que vous souhaitez les utiliser. Par exemple, pour compter tous les appels système à l'exception de ceux exécutés par la commande dtrace, vous pouvez utiliser la clause de programme en D suivante dans laquelle figure $pid :

syscall:::entry
/pid != $pid/
{
	@calls = count();
}

Cette clause engendre toujours le résultat souhaité, même si chaque évocation de la commande dtrace a un ID de processus différent.

Vous pouvez utiliser les variables de macro partout où vous pouvez utiliser un nombre entier, un identificateur ou une chaîne dans un programme en D. Les variables de macro ne sont étendues qu'une seule fois (et non de manière récursive) lorsque le fichier d'entrée est analysé. Chaque variable de macro est étendue pour former un jeton d'entrée et ne peut être concaténée avec un autre texte pour produire un seul jeton. Par exemple, si $pid est étendu à la valeur 456, le code en D :

123$pid

sera étendu aux deux jetons adjacents 123 et 456, engendrant ainsi une syntaxe d'erreur, plutôt qu'au jeton entier unique 123456.

Les variables de macro sont étendues et concaténées au texte adjacent à l'intérieur des descriptions de sondes en D au début des clauses de votre programme. Par exemple, la clause suivante utilise le fournisseur pid de DTrace pour instrumenter la commande dtrace :

pid$pid:libc.so:printf:entry
{
	...
}

Les variables de macro ne sont développées qu'une seule fois à l'intérieur de chaque champ de description de sonde. Elles peuvent ne pas contenir de délimiteurs de description de sonde (:).

Arguments de macro

Le compilateur D fournit également un ensemble de variables de macro correspondant à tous les opérandes d'argument supplémentaires spécifiés dans le cadre de l'invocation de la commande dtrace. Il est possible d'accéder à ces arguments de macro en utilisant les noms $0 intégrés comme nom de fichier du programme en D ou de la commande dtrace, $1 pour le premier opérande supplémentaire, $2 pour le second opérande, etc. Si vous utilisez l'option dtrace -s, $0 est étendu à la valeur du nom du fichier d'entrée utilisé avec cette option. Pour les programmes en D spécifiés sur la ligne de commande, $0 est étendu à la valeur de argv[0] utilisée pour exécuter dtrace lui-même.

Les arguments de macro peuvent être étendus aux nombres entiers, aux identificateurs ou aux chaînes en fonction de la forme du texte correspondant. De même que toutes les variables de macro, vous pouvez utiliser les arguments de macro partout où vous pouvez utiliser des jetons de nombre entier, d'identificateur ou de chaîne dans un programme en D. Tous les exemples suivants peuvent constituer des expressions en D valides en adoptant des valeurs d'argument de macro appropriées :

execname == $1    /* with a string macro argument */
x += $1           /* with an integer macro argument */
trace(x->$1)      /* with an identifier macro argument */

Vous pouvez utiliser les arguments de macro pour créer des fichiers interpréteurs dtrace qui agissent comme de vraies commandes Solaris et modifient leur comportement à l'aide des informations spécifiées par un utilisateur ou un autre outil. Par exemple, le fichier interpréteur en D suit les appels système write(2) exécutés par un ID de processus particulier :

#!/usr/sbin/dtrace -s

syscall::write:entry
/pid == $1/
{
}

Si vous rendez ce fichier interpréteur exécutable, vous pouvez spécifier la valeur de $1 à l'aide d'un argument de ligne de commande supplémentaire dans votre fichier interpréteur :


# chmod a+rx ./tracewrite
# ./tracewrite 12345

L'invocation de commande qui en résulte compte chaque appel système write(2) exécuté par l'ID de processus 12345.

Si votre programme en D référence un argument de macro ne figurant pas sur la ligne de commande, un message d'erreur approprié est imprimé et la compilation de votre programme échoue :


# ./tracewrite
dtrace: failed to compile script ./tracewrite: line 4:
  macro argument $1 is not defined

Les programmes en D peuvent référencer des arguments de macro non spécifiés si l'option defaultargs est définie. Si l'option defaultargs est définie, les arguments non spécifiés ont la valeur 0. Pour plus d'informations sur les options du compilateur D, reportez-vous au Chapitre16Options et paramètres réglables. Le compilateur D engendre également un message d'erreur si d'autres arguments spécifiés sur la ligne de commande ne sont pas référencés par votre programme en D.

Les valeurs des arguments de commande doivent correspondre à la forme d'un nombre entier, d'un identificateur ou d'une chaîne. Si l'argument ne correspond pas à l'un de ces formats, le compilateur D envoie un message d'erreur approprié. Lorsque vous spécifiez des arguments de macro au format chaîne dans un fichier interpréteur DTrace, ajoutez une paire de guillemets simples supplémentaires pour éviter que les guillemets doubles et le contenu des chaînes ne soient interprétés par votre shell :


# ./foo '"a string argument"'

Si vous souhaitez que vos arguments de macro en D soient interprétés comme des jetons de chaîne, y compris avec un format de nombre entier ou d'identificateur, ajoutez deux symboles dollar en préfixe au nom de l'argument ou de la variable de macro (par exemple, $$1) pour contraindre le compilateur D à interpréter la valeur de l'argument comme une chaîne entre guillemets doubles. Toutes les séquences d'échappement de chaîne en D usuelles (voir le Tableau 2–5) sont étendues à l'intérieur de n'importe quel argument de macro au format chaîne, qu'elles soient référencées sous la forme $arg ou $$arg de la macro. Si l'option defaultargs est définie, les arguments non spécifiés au format $$arg possèdent la valeur d'une chaîne vide ("").

ID processus cible

Utilisez la variable de macro $target pour créer des scripts applicables au processus utilisateur qui nous intéresse, ce dernier étant sélectionné sur la ligne de commande dtrace à l'aide de l'option -p ou créé à l'aide de l'option -c. Les programmes en D spécifiés sur la ligne de commande ou à l'aide de l'option -s sont compilés après la création ou l'extraction des processus et l'extension de la variable $target à l'ID de traitement des nombres entiers d'un tel processus initial. Par exemple, le script en D suivant peut permettre de déterminer la répartition des appels système exécutés par un processus objet particulier :

syscall:::entry
/pid == $target/
{
	@[probefunc] = count();
}

Pour déterminer le nombre d'appels système exécutés par la commande date(1), enregistrez le script dans le fichier syscall.d et exécutez la commande suivante :


# dtrace -s syscall.d -c date
dtrace: script 'syscall.d' matched 227 probes
Fri Jul 30 13:46:06 PDT 2004
dtrace: pid 109058 has exited

  gtime                                                             1
  getpid                                                            1
  getrlimit                                                         1
  rexit                                                             1
  ioctl                                                             1
  resolvepath                                                       1
  read                                                              1
  stat                                                              1
  write                                                             1
  munmap                                                            1
  close                                                             2
  fstat64                                                           2
  setcontext                                                        2
  mmap                                                              2
  open                                                              2
  brk                                                               4