Guía de seguimiento dinámico de Solaris

Acciones destructivas

Algunas acciones de DTrace son destructivas, en el sentido de que modifican el estado del sistema de una forma bien definida. Las acciones destructivas no pueden utilizarse a menos que se habiliten explícitamente. Al utilizar dtrace(1M), puede habilitar las acciones destructivas mediante la opción -w. Si se intentan utilizar las acciones destructivas en dtrace(1M) sin habilitarlas explícitamente, dtrace fallará y generará un mensaje similar al siguiente:


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

Acciones destructivas de procesos

Algunas acciones son sólo destructivas para un proceso determinado. Estas acciones están disponibles para los usuarios con los privilegios dtrace_proc o dtrace_user. Consulte el Capítulo 35Seguridad para obtener más información sobre los privilegios de seguridad de DTrace.

stop()

void stop(void)

La acción stop() fuerza la detención del proceso que activa el sondeo habilitado cuando se abandona el núcleo a continuación, como si lo hubiera detenido la acción proc(4). La utilidad prun(1) puede usarse para reanudar un proceso detenido por la acción stop(). La acción stop() puede utilizarse para detener un proceso en cualquier punto del sondeo de DTrace. Esta acción puede utilizarse para capturar un programa en un estado específico que sería difícil de conseguir con un simple punto de interrupción y, a continuación, adjuntar al proceso un depurador tradicional como, por ejemplo, mdb(1). También puede usar la utilidad gcore(1) para guardar el estado de un proceso detenido en un archivo del núcleo central para su posterior análisis.

raise()

void raise(int signal)

La acción raise() envía la señal especificada al proceso que se está ejecutando en ese momento. Esta acción es similar al uso del comando kill(1) para enviar una señal a un proceso. La acción raise() puede utilizarse para enviar una señal en un momento específico de la ejecución de un proceso.

copyout()

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

La acción copyout() copia nbytes de la memoria intermedia especificada por buf en la dirección especificada por addr en el espacio de direccionamiento del proceso asociado al subproceso actual. Si la dirección de espacio de usuario no se corresponde con una página fallida válida en el espacio de direccionamiento actual, se generará un error.

copyoutstr()

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

La acción copyoutstr() copia la cadena especificada por str en la dirección especificada por addr en el espacio de nombre del proceso asociado al subproceso actual. Si la dirección de espacio de usuario no se corresponde con una página fallida válida en el espacio de direccionamiento actual, se generará un error. La longitud de la cadena está limitada por el valor definido por la opción strsize. Consulte el Capítulo 16Opciones y optimizables para obtener más información.

system()

void system(string program, ...) 

La acción system() provoca que se ejecute el programa especificado por program como si se hubiera especificado en la shell como entrada. La cadena program puede contener cualquiera de las conversiones de formato de printf()/printa. () Deben especificar los argumentos que coincidan con las conversiones de formato. Consulte el Capítulo 12Formato de salida para obtener información sobre las conversiones de formato válidas.

En el ejemplo siguiente, se ejecuta el comando date(1) una vez por segundo:


# 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

En el siguiente ejemplo, se muestra un uso más elaborado de la acción, utilizando las conversiones de printf() en la cadena program junto con las herramientas de filtrado tradicionales como, por ejemplo, las conducciones:

#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);
}

La ejecución de la secuencia de comandos anterior devuelve una salida similar al siguiente ejemplo:


# ./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

La ejecución de los comandos especificados no se produce en el contexto de la activación del sondeo, sino cuando la memoria intermedia que contiene los detalles de la acción system() se procesa a nivel de usuario. El momento y la ubicación en que tiene lugar este procesamiento dependen de la directiva de almacenamiento en memoria intermedia, descrita en el Capítulo 11Memorias intermedias y almacenamiento en memoria intermedia. Con la directiva de almacenamiento en memoria intermedia, la velocidad de procesamiento se especifica mediante la opción switchrate. Puede observar el retraso inherente a system() si ajusta de forma explícita switchrate con un valor superior al valor predeterminado de un segundo, como se muestra en el siguiente ejemplo:

#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);
}

La ejecución de la secuencia de comandos anterior devuelve una salida similar al siguiente ejemplo:


# 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

Tenga en cuenta que el valor de walltime varía, aunque los valores de date sean idénticos. Este resultado refleja el hecho de que la ejecución del comando date(1) sólo se ha producido cuando se ha procesado la memoria intermedia y no cuando se ha registrado la acción system().

Acciones destructivas del núcleo

Algunas acciones son destructivas para todo el sistema. Evidentemente, estas acciones deben utilizarse con mucha precaución, ya que afectarán a todos los procesos del sistema y a cualquier otro sistema que dependa implícita o explícitamente de los servicios de red del sistema afectado.

breakpoint()

void breakpoint(void)

La acción breakpoint() induce un punto de interrupción del núcleo, provocando que el sistema se detenga y transfiera el control al depurador del núcleo, que emitirá una cadena que indicará que el sondeo de DTrace ha desencadenado la acción. Por ejemplo, si se va a realizar lo siguiente:


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

En el sistema Solaris que se ejecuta en SPARC, es posible que aparezca el siguiente mensaje en la consola:


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

En el sistema Solaris que se ejecuta en x86, es posible que aparezca el siguiente mensaje en la consola:


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

La dirección que aparece después de la descripción del sondeo es la dirección del bloque de control de habilitación (ECB) de DTrace. Puede utilizar esta dirección para determinar detalles adicionales acerca de la habilitación del sondeo que ha provocado la acción de punto de interrupción.

Si se comete un error con la acción breakpoint(), es posible que se llame a esta acción con mayor frecuencia de la prevista. Este comportamiento podría a su vez impedir que finalice el consumidor de DTrace que está desencadenando las acciones de punto de interrupción. En esta situación, establezca la variable de entero del núcleo dtrace_destructive_disallow en 1. Esta configuración prohibirá el uso de todas las acciones destructivas en el equipo. Aplique esta configuración sólo en esta situación específica.

El método exacto para establecer dtrace_destructive_disallow dependerá del depurador del núcleo que utilice. Si utiliza OpenBoot PROM en un sistema SPARC, use w!:


ok 1 dtrace_destructive_disallow w!
ok

Confirme que la variable se haya establecido mediante w?:


ok dtrace_destructive_disallow w?
1
ok

A continuación, escriba go:


ok go

Si utiliza kmdb(1) en sistemas x86 o SPARC, use el modificador de escritura de 4 bytes (W) con el formato / dcmd:


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

A continuación, utilice :c:


kadb[0]: :c

Para volver a habilitar las acciones destructivas después de continuar con el proceso, deberá restablecer explícitamente dtrace_destructive_disallow a 0 utilizando mdb(1):


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

panic()

void panic(void)

La acción panic() genera un aviso grave del núcleo cuando se desencadena. Esta acción debe utilizarse para forzar un volcado por fallo del sistema en el momento pertinente. Puede utilizar esta acción con el almacenamiento en memoria intermedia circular y el análisis postmortem para comprender un problema. Para obtener más información, consulte el Capítulo 11Memorias intermedias y almacenamiento en memoria intermedia y el Capítulo 37Seguimiento postmortem. Cuando se utiliza una acción de pánico, aparece un mensaje grave que indica el sondeo que está provocando la situación. Por ejemplo:


  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) también emitirá un mensaje al reiniciar:


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

La memoria intermedia de mensajes del volcado por fallo del sistema también contiene el sondeo y el ECB responsable de la acción panic().

chill()

void chill(int nanoseconds)

La acción chill() provoca que DTrace gire durante el número especificado de nanosegundos. chill() es útil, sobre todo, para examinar problemas que puedan estar relacionados con el control del tiempo. Por ejemplo, puede utilizar esta acción para abrir las ventanas de condiciones de competencia, o sincronizar y desincronizar eventos periódicos unos con otros. Como las interrupciones están deshabilitadas cuando se encuentra el contexto de sondeo de DTrace, el uso de chill() inducirá la latencia de interrupción, programación y distribución. Por lo tanto, chill() puede provocar efectos sistémicos inesperados, y no debería utilizarse indiscriminadamente. Como las actividades del sistema utilizan la administración de interrupciones periódicas, DTrace no ejecutará la acción chill() durante más de 500 milisegundos para cada intervalo de un segundo en cualquier CPU especificada. Si se supera el intervalo máximo de chill(), DTrace informará de un error de operación no válida, como se muestra en el siguiente ejemplo:


# 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

Se aplicará obligatoriamente este límite, aunque el tiempo se divida en varias llamadas a chill() o en varios consumidores de DTrace de un único sondeo. Por ejemplo, el siguiente comando generaría el mismo error:


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