Manuel de suivi dynamique Solaris

Actions destructrices

Certaines actions DTrace sont destructrices dans la mesure où elles modifient radicalement l'état du système. Il n'est possible de les utiliser que si elles ont été activées de manière explicite. Lors de l'utilisation de dtrace(1M), vous pouvez activer des actions destructrices en utilisant l'option -w. En cas de tentative d'activation non explicite d'actions destructrices dans dtrace(1M), dtrace échouera, affichant un message similaire à ce qui suit :


dtrace: failed to enable 'syscall': destructive actions not allowed

Actions destructrices de processus

Certaines actions destructrices ne le sont que dans un processus particulier. Ces actions sont disponibles pour les utilisateurs disposant de privilèges dtrace_proc ou dtrace_user. Pour plus d'informations sur les privilèges de sécurité DTrace, reportez-vous au Chapitre35Sécurité.

stop()

void stop(void)

L'action stop() force le processus qui déclenche l'arrêt de la sonde activée lorsque celle-ci quitte le noyau, comme si elle était arrêtée par une action proc(4). L'utilitaire prun(1) peut être utilisé pour la reprise d'un processus ayant été arrêté par l'action stop(). L'action stop() peut être utilisée pour arrêter un processus à un point de sonde DTrace quelconque. Cette action peut être utilisée pour capturer un programme dans un état particulier, qu'il serait difficile d'obtenir avec un point d'interruption simple puis pour joindre au processus un débogueur classique tel que mdb(1). Vous pouvez également utiliser l'utilitaire gcore(1) pour enregistrer l'état d'un processus arrêté dans un fichier Core à des fins d'analyses ultérieures.

raise()

void raise(int signal)

L'action raise() envoie le signal spécifié au processus en cours d'exécution. Recourir à cette action revient à utiliser la commande kill(1) permettant d'envoyer un signal à un processus. Il est possible d'utiliser l'action raise() pour envoyer un signal à un point précis de l'exécution d'un processus.

copyout()

void copyout(void *buf, uintptr_t addr, size_t nbytes)

L'action copyout() copie nbytes à partir du tampon buf à l'adresse addr dans l'espace d'adressage du processus associé au thread actuel. Si l'adresse de l'espace utilisateur ne correspond pas à une page valide, par défaut, dans l'espace d'adressage, une erreur est générée.

copyoutstr()

void copyoutstr(string str, uintptr_t addr, size_t maxlen)

L'action copyoutstr() copie la chaîne str vers l'adresse addr dans l'espace d'adressage du processus associé au thread actuel. Si l'adresse de l'espace utilisateur ne correspond pas à une page valide, par défaut, dans l'espace d'adressage, une erreur est générée. La longueur de chaîne est limitée à la valeur définie par l'option strsize. Pour de plus amples informations, reportez-vous au Chapitre16Options et paramètres réglables.

system()

void system(string program, ...) 

L'action system() provoque l'exécution du programme program comme s'il était saisi dans le shell. La chaîne program peut contenir n'importe quelle conversion de format printf()/printa. () Des arguments correspondant aux conversions de format doivent être spécifiés. Pour plus d'informations sur les conversions dans des formats valides, reportez-vous au Chapitre12Format de sortie.

L'exemple suivant exécute la commande date(1) une fois par seconde :


# dtrace -wqn tick-1sec'{system("date")}'
 Tue Jul 20 11:56:26 CDT 2004
 Tue Jul 20 11:56:27 CDT 2004
 Tue Jul 20 11:56:28 CDT 2004
 Tue Jul 20 11:56:29 CDT 2004
 Tue Jul 20 11:56:30 CDT 2004

L'exemple suivant illustre une utilisation élaborée de l'action, avec des conversions printf() dans la chaîne program et des outils de filtre traditionnels comme des tubes :

#pragma D option destructive
#pragma D option quiet

proc:::signal-send
/args[2] == SIGINT/
{
	printf("SIGINT sent to %s by ", args[1]->pr_fname);
	system("getent passwd %d | cut -d: -f5", uid);
}

Exécuter le script ci-dessus engendre une sortie similaire à l'exemple suivant :


# ./whosend.d
SIGINT sent to MozillaFirebird- by Bryan Cantrill
SIGINT sent to run-mozilla.sh by Bryan Cantrill
^C
SIGINT sent to dtrace by Bryan Cantrill

L'exécution de la commande spécifiée n'a pas lieu dans le cadre du déclenchement d'une sonde, mais lorsque le tampon contenant les détails sur l'action system() est traité au niveau utilisateur. La manière dont ce traitement a lieu et le moment auquel il a lieu dépendent de la stratégie de mise en tampon, décrite dans le Chapitre11Tampons et mise en tampon Avec la stratégie de mise en tampon par défaut, la vitesse de traitement du tampon est spécifiée par l'option switchrate. Vous pouvez voir le délai inhérent au system() si vous réglez de façon explicite switchrate sur une vitesse supérieure à la valeur par défaut de une seconde, comme illustré dans l'exemple suivant :

#pragma D option quiet
#pragma D option destructive
#pragma D option switchrate=5sec

tick-1sec
/n++ < 5/
{
	printf("walltime  : %Y\n", walltimestamp);
	printf("date      : ");
	system("date");
	printf("\n");
}

tick-1sec
/n == 5/
{
	exit(0);
}

Exécuter le script ci-dessus engendre une sortie similaire à l'exemple suivant :


# dtrace -s ./time.d
 walltime  : 2004 Jul 20 13:26:30
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:31
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:32
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:33
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:34
date      : Tue Jul 20 13:26:35 CDT 2004

Vous remarquerez que les valeurs walltime diffèrent mais que les valeurs date sont identiques. Ce résultat reflète le fait que l'exécution de la commande date(1) a eu lieu uniquement lors du traitement du tampon et non lors de l'enregistrement de l'action system().

Actions destructrices de noyau

Certaines actions destructrices le sont dans l'intégralité du système. Ces actions doivent évidemment être utilisées avec un très grand soin car elles affectent tous les processus du système ainsi que ceux de tous les autres systèmes dépendant de manière implicite ou explicite des services réseau du système affecté.

breakpoint()

void breakpoint(void)

L'action breakpoint() provoque un point d'interruption dans le noyau, engendrant l'arrêt et le transfert de la commande vers le débogueur du noyau. Le débogueur du noyau émet une chaîne dénotant la sonde DTrace ayant engendré l'action. Par exemple, si l'on exécute le programme suivant :


# dtrace -w -n clock:entry'{breakpoint()}'
dtrace: allowing destructive actions
dtrace: description 'clock:entry' matched 1 probe

Avec Solaris fonctionnant sous SPARC, le message suivant risque de s'afficher sur la console :


dtrace: breakpoint action at probe fbt:genunix:clock:entry (ecb 30002765700)
Type  'go' to resume
ok

Avec Solaris fonctionnant sous x86, le message suivant risque de s'afficher sur la console :


dtrace: breakpoint action at probe fbt:genunix:clock:entry (ecb d2b97060)
stopped at      int20+0xb:      ret
kmdb[0]:

L'adresse suivant la description de sonde est l'adresse du bloc de contrôle d'activation (ECB) au sein de DTrace. Vous pouvez utiliser cette adresse pour obtenir plus d'informations sur l'activation de sonde ayant provoqué l'action de point d'interruption.

En cas d'erreur relative à l'action breakpoint(), le nombre d'appels de cette action risque d'être largement supérieur au nombre prévu. Ce comportement peut par ailleurs vous empêcher de mettre fin au consommateur DTrace engendrant les actions de point d'interruption. Dans ce cas, définissez la variable de nombre entier du noyau, dtrace_destructive_disallow sur 1. Ce paramétrage interdira toutes les actions destructives sur la machine. Appliquez ce réglage uniquement dans ce cas de figure précis.

La méthode exacte permettant de régler dtrace_destructive_disallow dépend du débogueur du noyau utilisé. Si vous utilisez le programme OpenBoot PROM sur un système SPARC, utilisez w!:


ok 1 dtrace_destructive_disallow w!
ok

Confirmez que la variable a été définie en utilisant w? :


ok dtrace_destructive_disallow w?
1
ok

Continuez en tapant go :


ok go

En cas d'utilisation de kmdb(1) sur des systèmes x86 ou SPARC, utilisez le modificateur d'écriture à 4 octets (W) avec le formatage dcmd / :


kmdb[0]: dtrace_destructive_disallow/W 1
dtrace_destructive_disallow:    0x0             =       0x1
kmdb[0]:

Continuez en utilisant :c :


kadb[0]: :c

Pour réactiver des actions destructrices après avoir continué, vous devez réinitialiser de façon explicite dtrace_destructive_disallow en lui réattribuant la valeur 0 avec mdb(1) :


# echo "dtrace_destructive_disallow/W 0" | mdb -kw
dtrace_destructive_disallow:    0x1             =       0x0
#

panic()

void panic(void)

Lorsqu'elle est déclenchée, l'action panic() provoque une erreur grave de noyau. Cette action doit être utilisée pour forcer un vidage mémoire sur incident sur un système à un moment stratégique. Vous pouvez utiliser conjointement à cette action des analyses postmortem et de mise en tampon circulaire pour mieux comprendre le problème. Pour plus d'informations, reportez-vous au Chapitre11Tampons et mise en tampon et au Chapitre37Suivi post-mortem. Lorsque l'action d'erreur grave est utilisée, un message d'erreur grave s'affiche, dénotant la sonde qui en est à l'origine. Exemple :


  panic[cpu0]/thread=30001830b80: dtrace: panic action at probe
  syscall::mmap:entry (ecb 300000acfc8)

  000002a10050b840 dtrace:dtrace_probe+518 (fffe, 0, 1830f88, 1830f88,
    30002fb8040, 300000acfc8)
    %l0-3: 0000000000000000 00000300030e4d80 0000030003418000 00000300018c0800
    %l4-7: 000002a10050b980 0000000000000500 0000000000000000 0000000000000502
  000002a10050ba30 genunix:dtrace_systrace_syscall32+44 (0, 2000, 5,
    80000002, 3, 1898400)
    %l0-3: 00000300030de730 0000000002200008 00000000000000e0 000000000184d928
    %l4-7: 00000300030de000 0000000000000730 0000000000000073 0000000000000010

  syncing file systems... 2 done
  dumping to /dev/dsk/c0t0d0s1, offset 214827008, content: kernel
  100% done: 11837 pages dumped, compression ratio 4.66, dump
  succeeded
  rebooting...

syslogd(1M) émet également un message au moment de la réinitialisation :


  Jun 10 16:56:31 machine1 savecore: [ID 570001 auth.error] reboot after panic:
  dtrace: panic action at probe syscall::mmap:entry (ecb 300000acfc8)

Le tampon du message de vidage mémoire sur incident contient également la sonde et l'ECB responsable de l'action panic().

chill()

void chill(int nanoseconds)

L'action chill() provoque la rotation de DTrace pendant un nombre de nanosecondes spécifié. chill() est essentiellement utilisé pour l'exploration de problèmes de synchronisation. Par exemple, vous pouvez utiliser cette action pour ouvrir des fenêtres de condition de compétitivité ou pour mettre des événements périodiques en phase ou hors phase les uns avec les autres. Étant donné que les interruptions sont désactivées lorsqu'elles sont dans un contexte de sonde DTrace, toute utilisation de chill() provoquera une latence d'interruption, de planification et de répartition. Par conséquent, chill() peut provoquer des effets inattendus sur le système. Il convient donc de l'utiliser à bon escient. Étant donné que l'activité du système repose sur la gestion des interruptions périodiques, DTrace refusera d'exécuter l'action chill() pendant plus de 500 millisecondes par intervalle d'une seconde sur une CPU donnée. En cas de dépassement de l'intervalle chill(), l'erreur d'opération illégale fera l'objet d'un rapport dans DTrace, comme illustré dans l'exemple suivant :


# dtrace -w -n syscall::open:entry'{chill(500000001)}'
dtrace: allowing destructive actions
dtrace: description 'syscall::open:entry' matched 1 probe
dtrace: 57 errors
CPU     ID                    FUNCTION:NAME
dtrace: error on enabled probe ID 1 (ID 14: syscall::open:entry): \
  illegal operation in action #1

Cette limite s'applique même si le temps est réparti sur plusieurs appels à chill() ou sur plusieurs consommateurs DTrace d'une sonde unique. Par exemple, la même erreur peut être générée par la commande suivante :


# dtrace -w -n syscall::open:entry'{chill(250000000); chill(250000001);}'